mirror of
https://github.com/mudler/luet.git
synced 2025-09-01 07:09:13 +00:00
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:
committed by
Ettore Di Giacinto
parent
0627b03121
commit
15250bd991
@@ -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 {
|
||||||
|
@@ -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")
|
||||||
|
@@ -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() {
|
||||||
|
@@ -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")
|
||||||
|
@@ -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))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
@@ -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 {
|
||||||
|
@@ -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())
|
||||||
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@@ -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)
|
||||||
|
@@ -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
7
tests/fixtures/provides/c/build.yaml
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
image: "alpine"
|
||||||
|
prelude:
|
||||||
|
- echo foo > /test
|
||||||
|
- echo bar > /test2
|
||||||
|
steps:
|
||||||
|
- echo c > /c
|
||||||
|
- echo c > /cd
|
7
tests/fixtures/provides/c/definition.yaml
vendored
Normal file
7
tests/fixtures/provides/c/definition.yaml
vendored
Normal 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
11
tests/fixtures/provides/d/build.yaml
vendored
Normal 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"
|
||||||
|
|
3
tests/fixtures/provides/d/definition.yaml
vendored
Normal file
3
tests/fixtures/provides/d/definition.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
category: "test"
|
||||||
|
name: "d"
|
||||||
|
version: "1.0"
|
0
tests/fixtures/provides/virtual/foo/build.yaml
vendored
Normal file
0
tests/fixtures/provides/virtual/foo/build.yaml
vendored
Normal file
3
tests/fixtures/provides/virtual/foo/definition.yaml
vendored
Normal file
3
tests/fixtures/provides/virtual/foo/definition.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
name: "foo"
|
||||||
|
version: "1.0"
|
||||||
|
category: "bar"
|
7
tests/fixtures/provides_selector/c/build.yaml
vendored
Normal file
7
tests/fixtures/provides_selector/c/build.yaml
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
image: "alpine"
|
||||||
|
prelude:
|
||||||
|
- echo foo > /test
|
||||||
|
- echo bar > /test2
|
||||||
|
steps:
|
||||||
|
- echo c > /c
|
||||||
|
- echo c > /cd
|
7
tests/fixtures/provides_selector/c/definition.yaml
vendored
Normal file
7
tests/fixtures/provides_selector/c/definition.yaml
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
category: "test"
|
||||||
|
name: "c"
|
||||||
|
version: "1.0"
|
||||||
|
provides:
|
||||||
|
- category: "bar"
|
||||||
|
name: "foo"
|
||||||
|
version: ">=1.0"
|
11
tests/fixtures/provides_selector/d/build.yaml
vendored
Normal file
11
tests/fixtures/provides_selector/d/build.yaml
vendored
Normal 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"
|
||||||
|
|
3
tests/fixtures/provides_selector/d/definition.yaml
vendored
Normal file
3
tests/fixtures/provides_selector/d/definition.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
category: "test"
|
||||||
|
name: "d"
|
||||||
|
version: "1.0"
|
0
tests/fixtures/provides_selector/virtual/foo/build.yaml
vendored
Normal file
0
tests/fixtures/provides_selector/virtual/foo/build.yaml
vendored
Normal file
3
tests/fixtures/provides_selector/virtual/foo/definition.yaml
vendored
Normal file
3
tests/fixtures/provides_selector/virtual/foo/definition.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
name: "foo"
|
||||||
|
version: "1.1"
|
||||||
|
category: "bar"
|
Reference in New Issue
Block a user