Add support for Package provides

Add "provides" field in packages (which affect both runtime and buildtime deps).
It replaces all the occurences in the deptree before solving, actually
allowing to swap packages and provide virtuals. Along with a mechanism
for package rename #25.
This commit is contained in:
Ettore Di Giacinto
2019-12-17 19:32:31 +01:00
committed by Ettore Di Giacinto
parent 0627b03121
commit 15250bd991
21 changed files with 463 additions and 20 deletions

View File

@@ -441,6 +441,7 @@ func (cs *LuetCompiler) ComputeDepTree(p CompilationSpec) (solver.PackagesAssert
} }
dependencies := solution.Order(cs.Database, p.GetPackage().GetFingerPrint()) dependencies := solution.Order(cs.Database, p.GetPackage().GetFingerPrint())
assertions := solver.PackagesAssertions{} assertions := solver.PackagesAssertions{}
for _, assertion := range dependencies { //highly dependent on the order for _, assertion := range dependencies { //highly dependent on the order
if assertion.Value { if assertion.Value {

View File

@@ -316,6 +316,90 @@ var _ = Describe("Compiler", func() {
Expect(helpers.Exists(spec.Rel("extra-layer-0.1.package.tar"))).To(BeTrue()) Expect(helpers.Exists(spec.Rel("extra-layer-0.1.package.tar"))).To(BeTrue())
}) })
It("Compiles with provides support", func() {
generalRecipe := tree.NewCompilerRecipe(pkg.NewInMemoryDatabase(false))
tmpdir, err := ioutil.TempDir("", "package")
Expect(err).ToNot(HaveOccurred())
defer os.RemoveAll(tmpdir) // clean up
err = generalRecipe.Load("../../tests/fixtures/provides")
Expect(err).ToNot(HaveOccurred())
Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(3))
compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(), generalRecipe.GetDatabase())
spec, err := compiler.FromPackage(&pkg.DefaultPackage{Name: "d", Category: "test", Version: "1.0"})
Expect(err).ToNot(HaveOccurred())
// err = generalRecipe.Tree().ResolveDeps(3)
// Expect(err).ToNot(HaveOccurred())
spec.SetOutputPath(tmpdir)
artifacts, errs := compiler.CompileParallel(1, false, NewLuetCompilationspecs(spec))
Expect(errs).To(BeNil())
Expect(len(artifacts)).To(Equal(1))
Expect(len(artifacts[0].GetDependencies())).To(Equal(1))
for _, artifact := range artifacts {
Expect(helpers.Exists(artifact.GetPath())).To(BeTrue())
Expect(helpers.Untar(artifact.GetPath(), tmpdir, false)).ToNot(HaveOccurred())
}
Expect(helpers.Untar(spec.Rel("c-test-1.0.package.tar"), tmpdir, false)).ToNot(HaveOccurred())
Expect(helpers.Exists(spec.Rel("d"))).To(BeTrue())
Expect(helpers.Exists(spec.Rel("dd"))).To(BeTrue())
Expect(helpers.Exists(spec.Rel("c"))).To(BeTrue())
Expect(helpers.Exists(spec.Rel("cd"))).To(BeTrue())
Expect(helpers.Exists(spec.Rel("d-test-1.0.metadata.yaml"))).To(BeTrue())
Expect(helpers.Exists(spec.Rel("c-test-1.0.metadata.yaml"))).To(BeTrue())
})
It("Compiles with provides and selectors support", func() {
// Same test as before, but fixtures differs
generalRecipe := tree.NewCompilerRecipe(pkg.NewInMemoryDatabase(false))
tmpdir, err := ioutil.TempDir("", "package")
Expect(err).ToNot(HaveOccurred())
defer os.RemoveAll(tmpdir) // clean up
err = generalRecipe.Load("../../tests/fixtures/provides_selector")
Expect(err).ToNot(HaveOccurred())
Expect(len(generalRecipe.GetDatabase().GetPackages())).To(Equal(3))
compiler := NewLuetCompiler(sd.NewSimpleDockerBackend(), generalRecipe.GetDatabase())
spec, err := compiler.FromPackage(&pkg.DefaultPackage{Name: "d", Category: "test", Version: "1.0"})
Expect(err).ToNot(HaveOccurred())
// err = generalRecipe.Tree().ResolveDeps(3)
// Expect(err).ToNot(HaveOccurred())
spec.SetOutputPath(tmpdir)
artifacts, errs := compiler.CompileParallel(1, false, NewLuetCompilationspecs(spec))
Expect(errs).To(BeNil())
Expect(len(artifacts)).To(Equal(1))
Expect(len(artifacts[0].GetDependencies())).To(Equal(1))
for _, artifact := range artifacts {
Expect(helpers.Exists(artifact.GetPath())).To(BeTrue())
Expect(helpers.Untar(artifact.GetPath(), tmpdir, false)).ToNot(HaveOccurred())
}
Expect(helpers.Untar(spec.Rel("c-test-1.0.package.tar"), tmpdir, false)).ToNot(HaveOccurred())
Expect(helpers.Exists(spec.Rel("d"))).To(BeTrue())
Expect(helpers.Exists(spec.Rel("dd"))).To(BeTrue())
Expect(helpers.Exists(spec.Rel("c"))).To(BeTrue())
Expect(helpers.Exists(spec.Rel("cd"))).To(BeTrue())
Expect(helpers.Exists(spec.Rel("d-test-1.0.metadata.yaml"))).To(BeTrue())
Expect(helpers.Exists(spec.Rel("c-test-1.0.metadata.yaml"))).To(BeTrue())
})
It("Compiles revdeps", func() { It("Compiles revdeps", func() {
generalRecipe := tree.NewCompilerRecipe(pkg.NewInMemoryDatabase(false)) generalRecipe := tree.NewCompilerRecipe(pkg.NewInMemoryDatabase(false))
tmpdir, err := ioutil.TempDir("", "revdep") tmpdir, err := ioutil.TempDir("", "revdep")

View File

@@ -34,7 +34,8 @@ import (
type BoltDatabase struct { type BoltDatabase struct {
sync.Mutex sync.Mutex
Path string Path string
ProvidesDatabase map[string]map[string]Package
} }
func NewBoltDatabase(path string) PackageDatabase { func NewBoltDatabase(path string) PackageDatabase {
@@ -42,7 +43,7 @@ func NewBoltDatabase(path string) PackageDatabase {
// BoltInstance = &BoltDatabase{Path: path} // BoltInstance = &BoltDatabase{Path: path}
// } // }
//return BoltInstance, nil //return BoltInstance, nil
return &BoltDatabase{Path: path} return &BoltDatabase{Path: path, ProvidesDatabase: map[string]map[string]Package{}}
} }
func (db *BoltDatabase) Get(s string) (string, error) { func (db *BoltDatabase) Get(s string) (string, error) {
@@ -85,6 +86,11 @@ func (db *BoltDatabase) Retrieve(ID string) ([]byte, error) {
} }
func (db *BoltDatabase) FindPackage(tofind Package) (Package, error) { func (db *BoltDatabase) FindPackage(tofind Package) (Package, error) {
// Provides: Return the replaced package here
if provided, err := db.getProvide(tofind); err == nil {
return provided, nil
}
p := &DefaultPackage{} p := &DefaultPackage{}
bolt, err := storm.Open(db.Path, storm.BoltOptions(0600, &bbolt.Options{Timeout: 30 * time.Second})) bolt, err := storm.Open(db.Path, storm.BoltOptions(0600, &bbolt.Options{Timeout: 30 * time.Second}))
if err != nil { if err != nil {
@@ -196,9 +202,62 @@ func (db *BoltDatabase) CreatePackage(p Package) (string, error) {
return "", errors.Wrap(err, "Error saving package to "+db.Path) return "", errors.Wrap(err, "Error saving package to "+db.Path)
} }
// Create extra cache between package -> []versions
db.Lock()
defer db.Unlock()
// TODO: Replace with a bolt implementation (and not in memory)
// Provides: Store package provides, we will reuse this when walking deps
for _, provide := range dp.Provides {
if _, ok := db.ProvidesDatabase[provide.GetPackageName()]; !ok {
db.ProvidesDatabase[provide.GetPackageName()] = make(map[string]Package)
}
db.ProvidesDatabase[provide.GetPackageName()][provide.GetVersion()] = p
}
return strconv.Itoa(dp.ID), err return strconv.Itoa(dp.ID), err
} }
// Dup from memory implementation
func (db *BoltDatabase) getProvide(p Package) (Package, error) {
db.Lock()
pa, ok := db.ProvidesDatabase[p.GetPackageName()][p.GetVersion()]
if !ok {
versions, ok := db.ProvidesDatabase[p.GetPackageName()]
db.Unlock()
if !ok {
return nil, errors.New("No versions found for package")
}
for ve, _ := range versions {
v, err := version.NewVersion(p.GetVersion())
if err != nil {
return nil, err
}
constraints, err := version.NewConstraint(ve)
if err != nil {
return nil, err
}
if constraints.Check(v) {
pa, ok := db.ProvidesDatabase[p.GetPackageName()][ve]
if !ok {
return nil, errors.New("No versions found for package")
}
return pa, nil //pick the first (we shouldn't have providers that are conflicting)
// TODO: A find dbcall here would recurse, but would give chance to have providers of providers
}
}
return nil, errors.New("No package provides this")
}
db.Unlock()
return db.FindPackage(pa)
}
func (db *BoltDatabase) Clean() error { func (db *BoltDatabase) Clean() error {
db.Lock() db.Lock()
defer db.Unlock() defer db.Unlock()
@@ -298,6 +357,10 @@ func (db *BoltDatabase) FindPackageCandidate(p Package) (Package, error) {
// FindPackages return the list of the packages beloging to cat/name (any versions in requested range) // FindPackages return the list of the packages beloging to cat/name (any versions in requested range)
// FIXME: Optimize, see inmemorydb // FIXME: Optimize, see inmemorydb
func (db *BoltDatabase) FindPackages(p Package) ([]Package, error) { func (db *BoltDatabase) FindPackages(p Package) ([]Package, error) {
// Provides: Treat as the replaced package here
if provided, err := db.getProvide(p); err == nil {
p = provided
}
var versionsInWorld []Package var versionsInWorld []Package
for _, w := range db.World() { for _, w := range db.World() {
if w.GetName() != p.GetName() || w.GetCategory() != p.GetCategory() { if w.GetName() != p.GetName() || w.GetCategory() != p.GetCategory() {

View File

@@ -25,27 +25,30 @@ import (
) )
var DBInMemoryInstance = &InMemoryDatabase{ var DBInMemoryInstance = &InMemoryDatabase{
Mutex: &sync.Mutex{}, Mutex: &sync.Mutex{},
FileDatabase: map[string][]string{}, FileDatabase: map[string][]string{},
Database: map[string]string{}, Database: map[string]string{},
CacheNoVersion: map[string]map[string]interface{}{}, CacheNoVersion: map[string]map[string]interface{}{},
ProvidesDatabase: map[string]map[string]Package{},
} }
type InMemoryDatabase struct { type InMemoryDatabase struct {
*sync.Mutex *sync.Mutex
Database map[string]string Database map[string]string
FileDatabase map[string][]string FileDatabase map[string][]string
CacheNoVersion map[string]map[string]interface{} CacheNoVersion map[string]map[string]interface{}
ProvidesDatabase map[string]map[string]Package
} }
func NewInMemoryDatabase(singleton bool) PackageDatabase { func NewInMemoryDatabase(singleton bool) PackageDatabase {
// In memoryDB is a singleton // In memoryDB is a singleton
if !singleton { if !singleton {
return &InMemoryDatabase{ return &InMemoryDatabase{
Mutex: &sync.Mutex{}, Mutex: &sync.Mutex{},
FileDatabase: map[string][]string{}, FileDatabase: map[string][]string{},
Database: map[string]string{}, Database: map[string]string{},
CacheNoVersion: map[string]map[string]interface{}{}, CacheNoVersion: map[string]map[string]interface{}{},
ProvidesDatabase: map[string]map[string]Package{},
} }
} }
return DBInMemoryInstance return DBInMemoryInstance
@@ -142,6 +145,17 @@ func (db *InMemoryDatabase) CreatePackage(p Package) (string, error) {
// Create extra cache between package -> []versions // Create extra cache between package -> []versions
db.Lock() db.Lock()
defer db.Unlock() defer db.Unlock()
// Provides: Store package provides, we will reuse this when walking deps
for _, provide := range pd.Provides {
if _, ok := db.ProvidesDatabase[provide.GetPackageName()]; !ok {
db.ProvidesDatabase[provide.GetPackageName()] = make(map[string]Package)
}
db.ProvidesDatabase[provide.GetPackageName()][provide.GetVersion()] = p
}
_, ok = db.CacheNoVersion[p.GetPackageName()] _, ok = db.CacheNoVersion[p.GetPackageName()]
if !ok { if !ok {
db.CacheNoVersion[p.GetPackageName()] = make(map[string]interface{}) db.CacheNoVersion[p.GetPackageName()] = make(map[string]interface{})
@@ -151,6 +165,43 @@ func (db *InMemoryDatabase) CreatePackage(p Package) (string, error) {
return ID, nil return ID, nil
} }
func (db *InMemoryDatabase) getProvide(p Package) (Package, error) {
db.Lock()
pa, ok := db.ProvidesDatabase[p.GetPackageName()][p.GetVersion()]
if !ok {
versions, ok := db.ProvidesDatabase[p.GetPackageName()]
db.Unlock()
if !ok {
return nil, errors.New("No versions found for package")
}
for ve, _ := range versions {
v, err := version.NewVersion(p.GetVersion())
if err != nil {
return nil, err
}
constraints, err := version.NewConstraint(ve)
if err != nil {
return nil, err
}
if constraints.Check(v) {
pa, ok := db.ProvidesDatabase[p.GetPackageName()][ve]
if !ok {
return nil, errors.New("No versions found for package")
}
return pa, nil
}
}
return nil, errors.New("No package provides this")
}
db.Unlock()
return db.FindPackage(pa)
}
func (db *InMemoryDatabase) encodePackage(p Package) (string, string, error) { func (db *InMemoryDatabase) encodePackage(p Package) (string, string, error) {
pd, ok := p.(*DefaultPackage) pd, ok := p.(*DefaultPackage)
if !ok { if !ok {
@@ -167,6 +218,12 @@ func (db *InMemoryDatabase) encodePackage(p Package) (string, string, error) {
} }
func (db *InMemoryDatabase) FindPackage(p Package) (Package, error) { func (db *InMemoryDatabase) FindPackage(p Package) (Package, error) {
// Provides: Return the replaced package here
if provided, err := db.getProvide(p); err == nil {
return provided, nil
}
return db.GetPackage(p.GetFingerPrint()) return db.GetPackage(p.GetFingerPrint())
} }
@@ -189,6 +246,11 @@ func (db *InMemoryDatabase) FindPackageVersions(p Package) ([]Package, error) {
// FindPackages return the list of the packages beloging to cat/name (any versions in requested range) // FindPackages return the list of the packages beloging to cat/name (any versions in requested range)
func (db *InMemoryDatabase) FindPackages(p Package) ([]Package, error) { func (db *InMemoryDatabase) FindPackages(p Package) ([]Package, error) {
// Provides: Treat as the replaced package here
if provided, err := db.getProvide(p); err == nil {
p = provided
}
versions, ok := db.CacheNoVersion[p.GetPackageName()] versions, ok := db.CacheNoVersion[p.GetPackageName()]
if !ok { if !ok {
return nil, errors.New("No versions found for package") return nil, errors.New("No versions found for package")

View File

@@ -76,6 +76,31 @@ var _ = Describe("Database", func() {
Expect(pack).To(Equal(a3)) Expect(pack).To(Equal(a3))
}) })
It("Provides replaces definitions", func() {
db := NewInMemoryDatabase(false)
a := NewPackage("A", "1.0", []*DefaultPackage{}, []*DefaultPackage{})
a1 := NewPackage("A", "1.1", []*DefaultPackage{}, []*DefaultPackage{})
a3 := NewPackage("A", "1.3", []*DefaultPackage{}, []*DefaultPackage{})
a3.SetProvides([]*DefaultPackage{{Name: "A", Category: "", Version: "1.0"}})
Expect(a3.GetProvides()).To(Equal([]*DefaultPackage{{Name: "A", Category: "", Version: "1.0"}}))
_, err := db.CreatePackage(a)
Expect(err).ToNot(HaveOccurred())
_, err = db.CreatePackage(a1)
Expect(err).ToNot(HaveOccurred())
_, err = db.CreatePackage(a3)
Expect(err).ToNot(HaveOccurred())
s := NewPackage("A", "1.0", []*DefaultPackage{}, []*DefaultPackage{})
pack, err := db.FindPackage(s)
Expect(err).ToNot(HaveOccurred())
Expect(pack).To(Equal(a3))
})
}) })
}) })

View File

@@ -46,6 +46,9 @@ type Package interface {
Conflicts([]*DefaultPackage) Package Conflicts([]*DefaultPackage) Package
Revdeps(PackageDatabase) []Package Revdeps(PackageDatabase) []Package
GetProvides() []*DefaultPackage
SetProvides([]*DefaultPackage) Package
GetRequires() []*DefaultPackage GetRequires() []*DefaultPackage
GetConflicts() []*DefaultPackage GetConflicts() []*DefaultPackage
Expand(PackageDatabase) ([]Package, error) Expand(PackageDatabase) ([]Package, error)
@@ -132,6 +135,7 @@ type DefaultPackage struct {
PackageRequires []*DefaultPackage `json:"requires"` // Affects YAML field names too. PackageRequires []*DefaultPackage `json:"requires"` // Affects YAML field names too.
PackageConflicts []*DefaultPackage `json:"conflicts"` // Affects YAML field names too. PackageConflicts []*DefaultPackage `json:"conflicts"` // Affects YAML field names too.
IsSet bool `json:"set"` // Affects YAML field names too. IsSet bool `json:"set"` // Affects YAML field names too.
Provides []*DefaultPackage `json:"provides"` // Affects YAML field names too.
// TODO: Annotations? // TODO: Annotations?
@@ -270,7 +274,13 @@ func (p *DefaultPackage) SetCategory(s string) {
func (p *DefaultPackage) GetUses() []string { func (p *DefaultPackage) GetUses() []string {
return p.UseFlags return p.UseFlags
} }
func (p *DefaultPackage) GetProvides() []*DefaultPackage {
return p.Provides
}
func (p *DefaultPackage) SetProvides(req []*DefaultPackage) Package {
p.Provides = req
return p
}
func (p *DefaultPackage) GetRequires() []*DefaultPackage { func (p *DefaultPackage) GetRequires() []*DefaultPackage {
return p.PackageRequires return p.PackageRequires
} }
@@ -436,7 +446,11 @@ func (pack *DefaultPackage) BuildFormula(definitiondb PackageDatabase, db Packag
var formulas []bf.Formula var formulas []bf.Formula
for _, requiredDef := range p.GetRequires() { for _, requiredDef := range p.GetRequires() {
required, err := definitiondb.FindPackage(requiredDef) required, err := definitiondb.FindPackage(requiredDef)
if err != nil { if err != nil || requiredDef.IsSelector() {
if err == nil {
requiredDef = required.(*DefaultPackage)
}
packages, err := definitiondb.FindPackages(requiredDef) packages, err := definitiondb.FindPackages(requiredDef)
if err != nil || len(packages) == 0 { if err != nil || len(packages) == 0 {
required = requiredDef required = requiredDef
@@ -515,8 +529,11 @@ func (pack *DefaultPackage) BuildFormula(definitiondb PackageDatabase, db Packag
for _, requiredDef := range p.GetConflicts() { for _, requiredDef := range p.GetConflicts() {
required, err := definitiondb.FindPackage(requiredDef) required, err := definitiondb.FindPackage(requiredDef)
if err != nil { if err != nil || requiredDef.IsSelector() {
packages, err := requiredDef.Expand(definitiondb) if err == nil {
requiredDef = required.(*DefaultPackage)
}
packages, err := definitiondb.FindPackages(requiredDef)
if err != nil || len(packages) == 0 { if err != nil || len(packages) == 0 {
required = requiredDef required = requiredDef
} else { } else {

View File

@@ -129,6 +129,9 @@ var _ = Describe("Package", func() {
Expect(a01.RequiresContains(definitions, a11)).To(BeTrue()) Expect(a01.RequiresContains(definitions, a11)).To(BeTrue())
Expect(a01.RequiresContains(definitions, a)).To(BeTrue()) Expect(a01.RequiresContains(definitions, a)).To(BeTrue())
Expect(a.RequiresContains(definitions, a11)).ToNot(BeTrue()) Expect(a.RequiresContains(definitions, a11)).ToNot(BeTrue())
Expect(a.IsSelector()).To(BeTrue())
Expect(a1.IsSelector()).To(BeFalse())
}) })
}) })

View File

@@ -168,12 +168,16 @@ func (assertions PackagesAssertions) Order(definitiondb pkg.PackageDatabase, fin
} }
sort.Sort(unorderedAssertions) sort.Sort(unorderedAssertions)
// Build a topological graph // Build a topological graph
//graph := toposort.NewGraph(len(unorderedAssertions)) //graph := toposort.NewGraph(len(unorderedAssertions))
// graph.AddNodes(fingerprints...) // graph.AddNodes(fingerprints...)
for _, a := range unorderedAssertions { for _, a := range unorderedAssertions {
for _, requiredDef := range a.Package.GetRequires() { currentPkg := a.Package
for _, requiredDef := range currentPkg.GetRequires() {
if def, err := definitiondb.FindPackage(requiredDef); err == nil { // Provides: Get a chance of being override here
requiredDef = def.(*pkg.DefaultPackage)
}
// We cannot search for fingerprint, as we could have selector in versions. // We cannot search for fingerprint, as we could have selector in versions.
// We know that the assertions are unique for packages, so look for a package with such name in the assertions // We know that the assertions are unique for packages, so look for a package with such name in the assertions
req := assertions.SearchByName(requiredDef.GetPackageName()) req := assertions.SearchByName(requiredDef.GetPackageName())
@@ -182,7 +186,7 @@ func (assertions PackagesAssertions) Order(definitiondb pkg.PackageDatabase, fin
} }
// Expand also here, as we need to order them (or instead the solver should give back the dep correctly?) // Expand also here, as we need to order them (or instead the solver should give back the dep correctly?)
graph.AddEdge(a.Package.GetFingerPrint(), requiredDef.GetFingerPrint()) graph.AddEdge(currentPkg.GetFingerPrint(), requiredDef.GetFingerPrint())
} }
} }
result, err := graph.TopSort(fingerprint) result, err := graph.TopSort(fingerprint)

View File

@@ -393,6 +393,128 @@ var _ = Describe("Solver", func() {
Expect(len(solution)).To(Equal(5)) Expect(len(solution)).To(Equal(5))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
}) })
It("Support provides", func() {
E := pkg.NewPackage("E", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
D2 := pkg.NewPackage("D", "1.9", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
D := pkg.NewPackage("D", "1.8", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
D1 := pkg.NewPackage("D", "1.4", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
B := pkg.NewPackage("B", "1.1", []*pkg.DefaultPackage{&pkg.DefaultPackage{Name: "D", Version: ">=1.0"}}, []*pkg.DefaultPackage{})
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{&pkg.DefaultPackage{Name: "D", Version: ">=1.0"}}, []*pkg.DefaultPackage{})
D2.SetProvides([]*pkg.DefaultPackage{{Name: "E"}})
A2 := pkg.NewPackage("A", "1.3", []*pkg.DefaultPackage{&pkg.DefaultPackage{Name: "E", Version: ""}}, []*pkg.DefaultPackage{})
for _, p := range []pkg.Package{A, B, C, D, D1, D2, A2, E} {
_, err := dbDefinitions.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
for _, p := range []pkg.Package{} {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
s = NewSolver(dbInstalled, dbDefinitions, db)
solution, err := s.Install([]pkg.Package{A2, B})
Expect(solution).To(ContainElement(PackageAssert{Package: A2, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true}))
Expect(solution).ToNot(ContainElement(PackageAssert{Package: D1, Value: true}))
Expect(solution).ToNot(ContainElement(PackageAssert{Package: D, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: D2, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: false}))
Expect(solution).To(ContainElement(PackageAssert{Package: D1, Value: false}))
Expect(solution).ToNot(ContainElement(PackageAssert{Package: E, Value: true}))
Expect(len(solution)).To(Equal(5))
Expect(err).ToNot(HaveOccurred())
})
It("Support provides with versions", func() {
E := pkg.NewPackage("E", "1.3", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
D2 := pkg.NewPackage("D", "1.9", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
D := pkg.NewPackage("D", "1.8", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
D1 := pkg.NewPackage("D", "1.4", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
B := pkg.NewPackage("B", "1.1", []*pkg.DefaultPackage{&pkg.DefaultPackage{Name: "D", Version: ">=1.0"}}, []*pkg.DefaultPackage{})
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{&pkg.DefaultPackage{Name: "D", Version: ">=1.0"}}, []*pkg.DefaultPackage{})
D2.SetProvides([]*pkg.DefaultPackage{{Name: "E", Version: "1.3"}})
A2 := pkg.NewPackage("A", "1.3", []*pkg.DefaultPackage{&pkg.DefaultPackage{Name: "E", Version: ">=1.0"}}, []*pkg.DefaultPackage{})
for _, p := range []pkg.Package{A, B, C, D, D1, D2, A2, E} {
_, err := dbDefinitions.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
for _, p := range []pkg.Package{} {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
s = NewSolver(dbInstalled, dbDefinitions, db)
solution, err := s.Install([]pkg.Package{A2})
Expect(solution).To(ContainElement(PackageAssert{Package: A2, Value: true}))
Expect(solution).ToNot(ContainElement(PackageAssert{Package: B, Value: true}))
Expect(solution).ToNot(ContainElement(PackageAssert{Package: D1, Value: true}))
Expect(solution).ToNot(ContainElement(PackageAssert{Package: D, Value: true}))
Expect(solution).ToNot(ContainElement(PackageAssert{Package: C, Value: true}))
Expect(solution).ToNot(ContainElement(PackageAssert{Package: A, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: D2, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: false}))
Expect(solution).To(ContainElement(PackageAssert{Package: D1, Value: false}))
Expect(solution).ToNot(ContainElement(PackageAssert{Package: E, Value: true}))
Expect(len(solution)).To(Equal(4))
Expect(err).ToNot(HaveOccurred())
})
It("Support provides with selectors", func() {
E := pkg.NewPackage("E", "1.3", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
D2 := pkg.NewPackage("D", "1.9", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
D := pkg.NewPackage("D", "1.8", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
D1 := pkg.NewPackage("D", "1.4", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
B := pkg.NewPackage("B", "1.1", []*pkg.DefaultPackage{&pkg.DefaultPackage{Name: "D", Version: ">=1.0"}}, []*pkg.DefaultPackage{})
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{&pkg.DefaultPackage{Name: "D", Version: ">=1.0"}}, []*pkg.DefaultPackage{})
D2.SetProvides([]*pkg.DefaultPackage{{Name: "E", Version: ">=1.3"}})
A2 := pkg.NewPackage("A", "1.3", []*pkg.DefaultPackage{&pkg.DefaultPackage{Name: "E", Version: ">=1.0"}}, []*pkg.DefaultPackage{})
for _, p := range []pkg.Package{A, B, C, D, D1, D2, A2, E} {
_, err := dbDefinitions.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
for _, p := range []pkg.Package{} {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
s = NewSolver(dbInstalled, dbDefinitions, db)
solution, err := s.Install([]pkg.Package{A2})
Expect(solution).To(ContainElement(PackageAssert{Package: A2, Value: true}))
Expect(solution).ToNot(ContainElement(PackageAssert{Package: B, Value: true}))
Expect(solution).ToNot(ContainElement(PackageAssert{Package: D1, Value: true}))
Expect(solution).ToNot(ContainElement(PackageAssert{Package: D, Value: true}))
Expect(solution).ToNot(ContainElement(PackageAssert{Package: C, Value: true}))
Expect(solution).ToNot(ContainElement(PackageAssert{Package: A, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: D2, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: false}))
Expect(solution).To(ContainElement(PackageAssert{Package: D1, Value: false}))
Expect(solution).ToNot(ContainElement(PackageAssert{Package: E, Value: true}))
Expect(len(solution)).To(Equal(4))
Expect(err).ToNot(HaveOccurred())
})
It("Uninstalls simple package correctly", func() { It("Uninstalls simple package correctly", func() {
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})

7
tests/fixtures/provides/c/build.yaml vendored Normal file
View File

@@ -0,0 +1,7 @@
image: "alpine"
prelude:
- echo foo > /test
- echo bar > /test2
steps:
- echo c > /c
- echo c > /cd

View File

@@ -0,0 +1,7 @@
category: "test"
name: "c"
version: "1.0"
provides:
- category: "bar"
name: "foo"
version: "1.0"

11
tests/fixtures/provides/d/build.yaml vendored Normal file
View File

@@ -0,0 +1,11 @@
prelude:
- echo foo > /test
- echo bar > /test2
steps:
- echo s > /d
- echo dd > /dd
requires:
- category: "bar"
name: "foo"
version: "1.0"

View File

@@ -0,0 +1,3 @@
category: "test"
name: "d"
version: "1.0"

View File

View File

@@ -0,0 +1,3 @@
name: "foo"
version: "1.0"
category: "bar"

View File

@@ -0,0 +1,7 @@
image: "alpine"
prelude:
- echo foo > /test
- echo bar > /test2
steps:
- echo c > /c
- echo c > /cd

View File

@@ -0,0 +1,7 @@
category: "test"
name: "c"
version: "1.0"
provides:
- category: "bar"
name: "foo"
version: ">=1.0"

View File

@@ -0,0 +1,11 @@
prelude:
- echo foo > /test
- echo bar > /test2
steps:
- echo s > /d
- echo dd > /dd
requires:
- category: "bar"
name: "foo"
version: ">=1.0"

View File

@@ -0,0 +1,3 @@
category: "test"
name: "d"
version: "1.0"

View File

@@ -0,0 +1,3 @@
name: "foo"
version: "1.1"
category: "bar"