Make solver consume databases instead of world lists

first step - it is slower in the implementation for now, but all cases
seems to be sorted out.
Drop Flagged() and IsSet() from solver. the solver wont care, and only
the assertion value does matter (exception for uninstall)
This commit is contained in:
Ettore Di Giacinto
2019-11-29 19:01:41 +01:00
parent da9e14fb45
commit b5381e0248
4 changed files with 446 additions and 161 deletions

View File

@@ -22,7 +22,7 @@ import (
"unicode" "unicode"
pkg "github.com/mudler/luet/pkg/package" pkg "github.com/mudler/luet/pkg/package"
"github.com/philopon/go-toposort" toposort "github.com/philopon/go-toposort"
"github.com/stevenle/topsort" "github.com/stevenle/topsort"
) )
@@ -88,7 +88,7 @@ func (assertions PackagesAssertions) EnsureOrder() PackagesAssertions {
fingerprints = append(fingerprints, a.Package.GetFingerPrint()) fingerprints = append(fingerprints, a.Package.GetFingerPrint())
unorderedAssertions = append(unorderedAssertions, a) // Build a list of the ones that must be ordered unorderedAssertions = append(unorderedAssertions, a) // Build a list of the ones that must be ordered
if a.Package.Flagged() && a.Value { if a.Value {
unorderedAssertions = append(unorderedAssertions, a) // Build a list of the ones that must be ordered unorderedAssertions = append(unorderedAssertions, a) // Build a list of the ones that must be ordered
} else { } else {
orderedAssertions = append(orderedAssertions, a) // Keep last the ones which are not meant to be installed orderedAssertions = append(orderedAssertions, a) // Keep last the ones which are not meant to be installed
@@ -137,7 +137,7 @@ func (assertions PackagesAssertions) Order(fingerprint string) PackagesAssertion
fingerprints = append(fingerprints, a.Package.GetFingerPrint()) fingerprints = append(fingerprints, a.Package.GetFingerPrint())
unorderedAssertions = append(unorderedAssertions, a) // Build a list of the ones that must be ordered unorderedAssertions = append(unorderedAssertions, a) // Build a list of the ones that must be ordered
if a.Package.Flagged() && a.Value { if a.Value {
unorderedAssertions = append(unorderedAssertions, a) // Build a list of the ones that must be ordered unorderedAssertions = append(unorderedAssertions, a) // Build a list of the ones that must be ordered
} else { } else {
orderedAssertions = append(orderedAssertions, a) // Keep last the ones which are not meant to be installed orderedAssertions = append(orderedAssertions, a) // Keep last the ones which are not meant to be installed
@@ -215,7 +215,7 @@ func (a PackagesAssertions) Less(i, j int) bool {
func (assertions PackagesAssertions) AssertionHash() string { func (assertions PackagesAssertions) AssertionHash() string {
var fingerprint string var fingerprint string
for _, assertion := range assertions { // Note: Always order them first! for _, assertion := range assertions { // Note: Always order them first!
if assertion.Value && assertion.Package.Flagged() { // Tke into account only dependencies installed (get fingerprint of subgraph) if assertion.Value { // Tke into account only dependencies installed (get fingerprint of subgraph)
fingerprint += assertion.ToString() + "\n" fingerprint += assertion.ToString() + "\n"
} }
} }

View File

@@ -26,11 +26,22 @@ import (
) )
var _ = Describe("Decoder", func() { var _ = Describe("Decoder", func() {
db := pkg.NewInMemoryDatabase(false)
dbInstalled := pkg.NewInMemoryDatabase(false)
dbDefinitions := pkg.NewInMemoryDatabase(false)
s := NewSolver(dbInstalled, dbDefinitions, db)
BeforeEach(func() {
db = pkg.NewInMemoryDatabase(false)
dbInstalled = pkg.NewInMemoryDatabase(false)
dbDefinitions = pkg.NewInMemoryDatabase(false)
s = NewSolver(dbInstalled, dbDefinitions, db)
})
Context("Assertion ordering", func() { Context("Assertion ordering", func() {
eq := 0 eq := 0
for index := 0; index < 300; index++ { // Just to make sure we don't have false positives for index := 0; index < 300; index++ { // Just to make sure we don't have false positives
It("Orders them correctly #"+strconv.Itoa(index), func() { It("Orders them correctly #"+strconv.Itoa(index), func() {
db := pkg.NewInMemoryDatabase(false)
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
E := pkg.NewPackage("E", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) E := pkg.NewPackage("E", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
@@ -41,15 +52,23 @@ var _ = Describe("Decoder", func() {
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{})
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
s := NewSolver([]pkg.Package{C}, []pkg.Package{A, B, C, D, E, F, G}, db) for _, p := range []pkg.Package{A, B, C, D, E, F, G} {
_, err := dbDefinitions.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
for _, p := range []pkg.Package{C} {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
solution, err := s.Install([]pkg.Package{A}) solution, err := s.Install([]pkg.Package{A})
Expect(solution).To(ContainElement(PackageAssert{Package: A.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: A, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: B.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: D.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: C.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: H.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: H, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: G.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: G, Value: true}))
Expect(len(solution)).To(Equal(6)) Expect(len(solution)).To(Equal(6))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
@@ -73,7 +92,6 @@ var _ = Describe("Decoder", func() {
equality := 0 equality := 0
for index := 0; index < 300; index++ { // Just to make sure we don't have false positives for index := 0; index < 300; index++ { // Just to make sure we don't have false positives
It("Doesn't order them correctly otherwise #"+strconv.Itoa(index), func() { It("Doesn't order them correctly otherwise #"+strconv.Itoa(index), func() {
db := pkg.NewInMemoryDatabase(false)
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
E := pkg.NewPackage("E", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) E := pkg.NewPackage("E", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
@@ -84,15 +102,23 @@ var _ = Describe("Decoder", func() {
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{})
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
s := NewSolver([]pkg.Package{C}, []pkg.Package{A, B, C, D, E, F, G}, db) for _, p := range []pkg.Package{A, B, C, D, E, F, G} {
_, err := dbDefinitions.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
for _, p := range []pkg.Package{C} {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
solution, err := s.Install([]pkg.Package{A}) solution, err := s.Install([]pkg.Package{A})
Expect(solution).To(ContainElement(PackageAssert{Package: A.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: A, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: B.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: D.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: C.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: H.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: H, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: G.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: G, Value: true}))
Expect(len(solution)).To(Equal(6)) Expect(len(solution)).To(Equal(6))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
@@ -132,7 +158,6 @@ var _ = Describe("Decoder", func() {
Context("Assertion hashing", func() { Context("Assertion hashing", func() {
It("Hashes them, and could be used for comparison", func() { It("Hashes them, and could be used for comparison", func() {
db := pkg.NewInMemoryDatabase(false)
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
E := pkg.NewPackage("E", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) E := pkg.NewPackage("E", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
@@ -143,15 +168,23 @@ var _ = Describe("Decoder", func() {
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{})
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
s := NewSolver([]pkg.Package{C}, []pkg.Package{A, B, C, D, E, F, G}, db) for _, p := range []pkg.Package{A, B, C, D, E, F, G} {
_, err := dbDefinitions.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
for _, p := range []pkg.Package{C} {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
solution, err := s.Install([]pkg.Package{A}) solution, err := s.Install([]pkg.Package{A})
Expect(solution).To(ContainElement(PackageAssert{Package: A.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: A, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: B.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: D.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: C.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: H.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: H, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: G.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: G, Value: true}))
Expect(len(solution)).To(Equal(6)) Expect(len(solution)).To(Equal(6))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
@@ -165,11 +198,11 @@ var _ = Describe("Decoder", func() {
hash := solution.AssertionHash() hash := solution.AssertionHash()
solution, err = s.Install([]pkg.Package{B}) solution, err = s.Install([]pkg.Package{B})
Expect(solution).To(ContainElement(PackageAssert{Package: B.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: D.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: C.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: H.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: H, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: G.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: G, Value: true}))
Expect(len(solution)).To(Equal(6)) Expect(len(solution)).To(Equal(6))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
@@ -183,18 +216,29 @@ var _ = Describe("Decoder", func() {
Expect(solution[3].Package.GetName()).To(Equal("D")) Expect(solution[3].Package.GetName()).To(Equal("D"))
Expect(solution[4].Package.GetName()).To(Equal("B")) Expect(solution[4].Package.GetName()).To(Equal("B"))
Expect(solution[0].Value).ToNot(BeTrue()) Expect(solution[0].Value).ToNot(BeTrue())
Expect(solution[0].Package.Flagged()).To(BeTrue())
Expect(hash).ToNot(Equal("")) Expect(hash).ToNot(Equal(""))
Expect(hash2).ToNot(Equal("")) Expect(hash2).ToNot(Equal(""))
Expect(hash != hash2).To(BeTrue()) Expect(hash != hash2).To(BeTrue())
db2 := pkg.NewInMemoryDatabase(false)
})
It("Hashes them, and could be used for comparison", func() {
X := pkg.NewPackage("X", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) X := pkg.NewPackage("X", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
Y := pkg.NewPackage("Y", "", []*pkg.DefaultPackage{X}, []*pkg.DefaultPackage{}) Y := pkg.NewPackage("Y", "", []*pkg.DefaultPackage{X}, []*pkg.DefaultPackage{})
Z := pkg.NewPackage("Z", "", []*pkg.DefaultPackage{X}, []*pkg.DefaultPackage{}) Z := pkg.NewPackage("Z", "", []*pkg.DefaultPackage{X}, []*pkg.DefaultPackage{})
s = NewSolver([]pkg.Package{}, []pkg.Package{X, Y, Z}, db2)
solution, err = s.Install([]pkg.Package{Y}) for _, p := range []pkg.Package{X, Y, Z} {
_, err := dbDefinitions.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
for _, p := range []pkg.Package{} {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
solution, err := s.Install([]pkg.Package{Y})
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
solution2, err := s.Install([]pkg.Package{Z}) solution2, err := s.Install([]pkg.Package{Z})

View File

@@ -16,9 +16,11 @@
package solver package solver
import ( import (
"errors"
"sort" "sort"
//. "github.com/mudler/luet/pkg/logger"
"github.com/pkg/errors"
"github.com/crillab/gophersat/bf" "github.com/crillab/gophersat/bf"
version "github.com/hashicorp/go-version" version "github.com/hashicorp/go-version"
pkg "github.com/mudler/luet/pkg/package" pkg "github.com/mudler/luet/pkg/package"
@@ -26,32 +28,57 @@ import (
// PackageSolver is an interface to a generic package solving algorithm // PackageSolver is an interface to a generic package solving algorithm
type PackageSolver interface { type PackageSolver interface {
SetWorld(p []pkg.Package) SetDefinitionDatabase(pkg.PackageDatabase)
Install(p []pkg.Package) (PackagesAssertions, error) Install(p []pkg.Package) (PackagesAssertions, error)
Uninstall(candidate pkg.Package) ([]pkg.Package, error) Uninstall(candidate pkg.Package) ([]pkg.Package, error)
ConflictsWithInstalled(p pkg.Package) (bool, error) ConflictsWithInstalled(p pkg.Package) (bool, error)
ConflictsWith(p pkg.Package, ls []pkg.Package) (bool, error) ConflictsWith(p pkg.Package, ls []pkg.Package) (bool, error)
Best([]pkg.Package) pkg.Package Best([]pkg.Package) pkg.Package
World() []pkg.Package
} }
// Solver is the default solver for luet // Solver is the default solver for luet
type Solver struct { type Solver struct {
DefinitionDatabase pkg.PackageDatabase
SolverDatabase pkg.PackageDatabase SolverDatabase pkg.PackageDatabase
Wanted []pkg.Package Wanted []pkg.Package
Installed []pkg.Package InstalledDatabase pkg.PackageDatabase
World []pkg.Package
} }
// NewSolver accepts as argument two lists of packages, the first is the initial set, // NewSolver accepts as argument two lists of packages, the first is the initial set,
// the second represent all the known packages. // the second represent all the known packages.
func NewSolver(init []pkg.Package, w []pkg.Package, solverdb pkg.PackageDatabase) PackageSolver { func NewSolver(installed pkg.PackageDatabase, definitiondb pkg.PackageDatabase, solverdb pkg.PackageDatabase) PackageSolver {
for _, v := range init { // inst := pkg.NewInMemoryDatabase(false)
pkg.NormalizeFlagged(v) // def := pkg.NewInMemoryDatabase(false)
} // // // FIXME: This should all be locked in the db - for now forbid the solver to be run in threads.
for _, v := range w { // for _, k := range installed.GetPackages() {
pkg.NormalizeFlagged(v) // pack, err := installed.GetPackage(k)
} // if err == nil {
return &Solver{Installed: init, World: w, SolverDatabase: solverdb} // inst.CreatePackage(pack)
// }
// }
// for _, k := range definitiondb.GetPackages() {
// pack, err := definitiondb.GetPackage(k)
// if err == nil {
// def.CreatePackage(pack)
// }
// }
// // FIXME:
// for _, k := range inst.GetPackages() {
// pack, err := inst.GetPackage(k)
// if err == nil {
// pkg.NormalizeFlagged(inst, pack)
// }
// }
// for _, k := range def.GetPackages() {
// pack, err := def.GetPackage(k)
// if err == nil {
// pkg.NormalizeFlagged(def, pack)
// }
// }
return &Solver{InstalledDatabase: installed, DefinitionDatabase: definitiondb, SolverDatabase: solverdb}
} }
// TODO: []pkg.Package should have its own type with this kind of methods in (+Unique, sort, etc.) // TODO: []pkg.Package should have its own type with this kind of methods in (+Unique, sort, etc.)
@@ -81,12 +108,36 @@ func (s *Solver) Best(set []pkg.Package) pkg.Package {
// SetWorld is a setter for the list of all known packages to the solver // SetWorld is a setter for the list of all known packages to the solver
func (s *Solver) SetWorld(p []pkg.Package) { func (s *Solver) SetDefinitionDatabase(db pkg.PackageDatabase) {
s.World = p s.DefinitionDatabase = db
}
func (s *Solver) World() []pkg.Package {
var all []pkg.Package
// FIXME: This should all be locked in the db - for now forbid the solver to be run in threads.
for _, k := range s.DefinitionDatabase.GetPackages() {
pack, err := s.DefinitionDatabase.GetPackage(k)
if err == nil {
all = append(all, pack)
}
}
return all
}
func (s *Solver) Installed() []pkg.Package {
var all []pkg.Package
// FIXME: This should all be locked in the db - for now forbid the solver to be run in threads.
for _, k := range s.InstalledDatabase.GetPackages() {
pack, err := s.InstalledDatabase.GetPackage(k)
if err == nil {
all = append(all, pack)
}
}
return all
} }
func (s *Solver) noRulesWorld() bool { func (s *Solver) noRulesWorld() bool {
for _, p := range s.World { for _, p := range s.World() {
if len(p.GetConflicts()) != 0 || len(p.GetRequires()) != 0 { if len(p.GetConflicts()) != 0 || len(p.GetRequires()) != 0 {
return false return false
} }
@@ -97,8 +148,8 @@ func (s *Solver) noRulesWorld() bool {
func (s *Solver) BuildInstalled() (bf.Formula, error) { func (s *Solver) BuildInstalled() (bf.Formula, error) {
var formulas []bf.Formula var formulas []bf.Formula
for _, p := range s.Installed { for _, p := range s.Installed() {
solvable, err := p.BuildFormula(s.SolverDatabase) solvable, err := p.BuildFormula(s.DefinitionDatabase, s.SolverDatabase)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -124,8 +175,8 @@ func (s *Solver) BuildWorld(includeInstalled bool) (bf.Formula, error) {
formulas = append(formulas, solvable) formulas = append(formulas, solvable)
} }
for _, p := range s.World { for _, p := range s.World() {
solvable, err := p.BuildFormula(s.SolverDatabase) solvable, err := p.BuildFormula(s.DefinitionDatabase, s.SolverDatabase)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -134,15 +185,42 @@ func (s *Solver) BuildWorld(includeInstalled bool) (bf.Formula, error) {
return bf.And(formulas...), nil return bf.And(formulas...), nil
} }
func (s *Solver) ConflictsWith(p pkg.Package, ls []pkg.Package) (bool, error) { func (s *Solver) getList(db pkg.PackageDatabase, lsp []pkg.Package) ([]pkg.Package, error) {
pkg.NormalizeFlagged(p) var ls []pkg.Package
for _, pp := range lsp {
cp, err := db.FindPackage(pp)
if err != nil {
cp = pp //Relax search, otherwise we cannot compute solutions for packages not in definitions
//return nil, errors.Wrap(err, "Package not found in db")
}
ls = append(ls, cp)
}
return ls, nil
}
func (s *Solver) ConflictsWith(pack pkg.Package, lsp []pkg.Package) (bool, error) {
p, err := s.DefinitionDatabase.FindPackage(pack)
if err != nil {
p = pack //Relax search, otherwise we cannot compute solutions for packages not in definitions
// return false, errors.Wrap(err, "Package not found in definition db")
}
ls, err := s.getList(s.DefinitionDatabase, lsp)
if err != nil {
return false, errors.Wrap(err, "Package not found in definition db")
}
// TODO: Needs to be find in package def before encoding!
// pkg.NormalizeFlagged(s.DefinitionDatabase, p)
var formulas []bf.Formula var formulas []bf.Formula
if s.noRulesWorld() { if s.noRulesWorld() {
return false, nil return false, nil
} }
encodedP, err := p.IsFlagged(true).Encode(s.SolverDatabase) encodedP, err := p.Encode(s.SolverDatabase)
if err != nil { if err != nil {
return false, err return false, err
} }
@@ -181,33 +259,45 @@ func (s *Solver) ConflictsWith(p pkg.Package, ls []pkg.Package) (bool, error) {
} }
func (s *Solver) ConflictsWithInstalled(p pkg.Package) (bool, error) { func (s *Solver) ConflictsWithInstalled(p pkg.Package) (bool, error) {
return s.ConflictsWith(p, s.Installed) return s.ConflictsWith(p, s.Installed())
} }
// Uninstall takes a candidate package and return a list of packages that would be removed // Uninstall takes a candidate package and return a list of packages that would be removed
// in order to purge the candidate. Returns error if unsat. // in order to purge the candidate. Returns error if unsat.
func (s *Solver) Uninstall(candidate pkg.Package) ([]pkg.Package, error) { func (s *Solver) Uninstall(c pkg.Package) ([]pkg.Package, error) {
var res []pkg.Package var res []pkg.Package
candidate, err := s.InstalledDatabase.FindPackage(c)
if err != nil {
candidate = c //Relax search, otherwise we cannot compute solutions for packages not in definitions
// return nil, errors.Wrap(err, "Package not found between installed")
}
// Build a fake "Installed" - Candidate and its requires tree // Build a fake "Installed" - Candidate and its requires tree
var InstalledMinusCandidate []pkg.Package var InstalledMinusCandidate []pkg.Package
for _, i := range s.Installed {
if !i.Matches(candidate) && !candidate.RequiresContains(i) { // TODO: Can be optimized
for _, i := range s.Installed() {
if !i.Matches(candidate) {
contains, err := candidate.RequiresContains(s.SolverDatabase, i)
if err != nil {
return nil, errors.Wrap(err, "Failed getting installed list")
}
if !contains {
InstalledMinusCandidate = append(InstalledMinusCandidate, i) InstalledMinusCandidate = append(InstalledMinusCandidate, i)
} }
} }
}
// Get the requirements to install the candidate // Get the requirements to install the candidate
saved := s.Installed saved := s.InstalledDatabase
s.Installed = []pkg.Package{} s.InstalledDatabase = pkg.NewInMemoryDatabase(false)
asserts, err := s.Install([]pkg.Package{candidate}) asserts, err := s.Install([]pkg.Package{candidate})
if err != nil { if err != nil {
return nil, err return nil, err
} }
s.Installed = saved s.InstalledDatabase = saved
for _, a := range asserts { for _, a := range asserts {
if a.Value && a.Package.Flagged() { if a.Value {
c, err := s.ConflictsWithInstalled(a.Package) c, err := s.ConflictsWithInstalled(a.Package)
if err != nil { if err != nil {
@@ -249,13 +339,14 @@ func (s *Solver) BuildFormula() (bf.Formula, error) {
return nil, err return nil, err
} }
W := bf.Var(encodedW) W := bf.Var(encodedW)
installedWorld := s.Installed()
if len(s.Installed) == 0 { //TODO:Optimize
if len(installedWorld) == 0 {
formulas = append(formulas, W) //bf.And(bf.True, W)) formulas = append(formulas, W) //bf.And(bf.True, W))
continue continue
} }
for _, installed := range s.Installed { for _, installed := range installedWorld {
encodedI, err := installed.Encode(s.SolverDatabase) encodedI, err := installed.Encode(s.SolverDatabase)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -297,23 +388,23 @@ func (s *Solver) Solve() (PackagesAssertions, error) {
// Install given a list of packages, returns package assertions to indicate the packages that must be installed in the system in order // Install given a list of packages, returns package assertions to indicate the packages that must be installed in the system in order
// to statisfy all the constraints // to statisfy all the constraints
func (s *Solver) Install(coll []pkg.Package) (PackagesAssertions, error) { func (s *Solver) Install(c []pkg.Package) (PackagesAssertions, error) {
for _, v := range coll {
v.IsFlagged(false) coll, err := s.getList(s.DefinitionDatabase, c)
if err != nil {
return nil, errors.Wrap(err, "Packages not found in definition db")
} }
s.Wanted = coll s.Wanted = coll
if s.noRulesWorld() { if s.noRulesWorld() {
var ass PackagesAssertions var ass PackagesAssertions
for _, p := range s.Installed { for _, p := range s.Installed() {
pp := p.IsFlagged(true) ass = append(ass, PackageAssert{Package: p.(*pkg.DefaultPackage), Value: true})
ass = append(ass, PackageAssert{Package: pp.(*pkg.DefaultPackage), Value: true})
} }
for _, p := range s.Wanted { for _, p := range s.Wanted {
pp := p.IsFlagged(true) ass = append(ass, PackageAssert{Package: p.(*pkg.DefaultPackage), Value: true})
ass = append(ass, PackageAssert{Package: pp.(*pkg.DefaultPackage), Value: true})
} }
return ass, nil return ass, nil
} }

View File

@@ -17,7 +17,6 @@ package solver_test
import ( import (
pkg "github.com/mudler/luet/pkg/package" pkg "github.com/mudler/luet/pkg/package"
"github.com/mudler/luet/pkg/solver"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
@@ -26,38 +25,66 @@ import (
var _ = Describe("Solver", func() { var _ = Describe("Solver", func() {
db := pkg.NewInMemoryDatabase(false)
dbInstalled := pkg.NewInMemoryDatabase(false)
dbDefinitions := pkg.NewInMemoryDatabase(false)
s := NewSolver(dbInstalled, dbDefinitions, db)
BeforeEach(func() {
db = pkg.NewInMemoryDatabase(false)
dbInstalled = pkg.NewInMemoryDatabase(false)
dbDefinitions = pkg.NewInMemoryDatabase(false)
s = NewSolver(dbInstalled, dbDefinitions, db)
})
Context("Simple set", func() { Context("Simple set", func() {
It("Solves correctly if the selected package has no requirements or conflicts and we have nothing installed yet", func() { It("Solves correctly if the selected package has no requirements or conflicts and we have nothing installed yet", func() {
db := pkg.NewInMemoryDatabase(false)
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
s := NewSolver([]pkg.Package{}, []pkg.Package{A, B, C}, db) for _, p := range []pkg.Package{A, B, C} {
_, 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{A}) solution, err := s.Install([]pkg.Package{A})
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(solution).To(ContainElement(PackageAssert{Package: A.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: A, Value: true}))
Expect(len(solution)).To(Equal(1)) Expect(len(solution)).To(Equal(1))
}) })
It("Solves correctly if the selected package has no requirements or conflicts and we have installed one package", func() { It("Solves correctly if the selected package has no requirements or conflicts and we have installed one package", func() {
db := pkg.NewInMemoryDatabase(false)
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
s := NewSolver([]pkg.Package{C}, []pkg.Package{A, B, C}, db) for _, p := range []pkg.Package{A, B, C} {
_, err := dbDefinitions.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
for _, p := range []pkg.Package{C} {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
s = NewSolver(dbInstalled, dbDefinitions, db)
solution, err := s.Install([]pkg.Package{B}) solution, err := s.Install([]pkg.Package{B})
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(solution).To(ContainElement(PackageAssert{Package: B.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: C.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true}))
Expect(len(solution)).To(Equal(2)) Expect(len(solution)).To(Equal(2))
}) })
It("Solves correctly if the selected package to install has no requirement or conflicts, but in the world there is one with a requirement", func() { It("Solves correctly if the selected package to install has no requirement or conflicts, but in the world there is one with a requirement", func() {
db := pkg.NewInMemoryDatabase(false)
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
@@ -65,72 +92,107 @@ var _ = Describe("Solver", func() {
D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{}) D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
E := pkg.NewPackage("E", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) E := pkg.NewPackage("E", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
s := NewSolver([]pkg.Package{E, C}, []pkg.Package{A, B, C, D, E}, db) for _, p := range []pkg.Package{A, B, C, D, E} {
_, err := dbDefinitions.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
for _, p := range []pkg.Package{E, C} {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
s = NewSolver(dbInstalled, dbDefinitions, db)
solution, err := s.Install([]pkg.Package{A}) solution, err := s.Install([]pkg.Package{A})
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(solution).To(ContainElement(PackageAssert{Package: A.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: A, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: C.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: E.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: E, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: B.IsFlagged(true).(*pkg.DefaultPackage), Value: false})) Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: false}))
Expect(solution).To(ContainElement(PackageAssert{Package: D.IsFlagged(true).(*pkg.DefaultPackage), Value: false})) Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: false}))
Expect(len(solution)).To(Equal(5)) Expect(len(solution)).To(Equal(5))
}) })
It("Solves correctly if the selected package to install has requirements", func() { It("Solves correctly if the selected package to install has requirements", func() {
db := pkg.NewInMemoryDatabase(false)
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{})
s := NewSolver([]pkg.Package{C}, []pkg.Package{A, B, C, D}, db) for _, p := range []pkg.Package{A, B, C, D} {
_, err := dbDefinitions.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
for _, p := range []pkg.Package{C} {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
s = NewSolver(dbInstalled, dbDefinitions, db)
solution, err := s.Install([]pkg.Package{A}) solution, err := s.Install([]pkg.Package{A})
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(solution).To(ContainElement(PackageAssert{Package: A.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: A, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: C.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: D.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: true}))
Expect(len(solution)).To(Equal(3)) Expect(len(solution)).To(Equal(3))
}) })
It("Solves correctly", func() { It("Solves correctly", func() {
db := pkg.NewInMemoryDatabase(false)
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
s := NewSolver([]pkg.Package{C}, []pkg.Package{A, B, C}, db) for _, p := range []pkg.Package{A, B, C} {
_, err := dbDefinitions.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
for _, p := range []pkg.Package{C} {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
s = NewSolver(dbInstalled, dbDefinitions, db)
solution, err := s.Install([]pkg.Package{A}) solution, err := s.Install([]pkg.Package{A})
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(solution).To(ContainElement(PackageAssert{Package: A.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: A, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: B.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: C.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true}))
Expect(len(solution)).To(Equal(3)) Expect(len(solution)).To(Equal(3))
}) })
It("Solves correctly more complex ones", func() { It("Solves correctly more complex ones", func() {
db := pkg.NewInMemoryDatabase(false)
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{})
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
s := NewSolver([]pkg.Package{C}, []pkg.Package{A, B, C, D}, db) for _, p := range []pkg.Package{A, B, C, D} {
_, err := dbDefinitions.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
for _, p := range []pkg.Package{C} {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
s = NewSolver(dbInstalled, dbDefinitions, db)
solution, err := s.Install([]pkg.Package{A}) solution, err := s.Install([]pkg.Package{A})
Expect(solution).To(ContainElement(PackageAssert{Package: A.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: A, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: B.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: D.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: C.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true}))
Expect(len(solution)).To(Equal(4)) Expect(len(solution)).To(Equal(4))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
}) })
It("Solves correctly more complex ones", func() { It("Solves correctly more complex ones", func() {
db := pkg.NewInMemoryDatabase(false)
E := pkg.NewPackage("E", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) E := pkg.NewPackage("E", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
@@ -138,37 +200,53 @@ var _ = Describe("Solver", func() {
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{})
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
s := NewSolver([]pkg.Package{}, []pkg.Package{A, B, C, D, E}, db) for _, p := range []pkg.Package{A, B, C, D, 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{A}) solution, err := s.Install([]pkg.Package{A})
Expect(solution).To(ContainElement(PackageAssert{Package: A.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: A, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: B.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: D.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: true}))
Expect(len(solution)).To(Equal(3)) Expect(len(solution)).To(Equal(3))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
}) })
It("Uninstalls simple package correctly", func() { It("Uninstalls simple package correctly", func() {
db := pkg.NewInMemoryDatabase(false)
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
s := NewSolver([]pkg.Package{A, B, C, D}, []pkg.Package{A, B, C, D}, db) for _, p := range []pkg.Package{A, B, C, D} {
_, err := dbDefinitions.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
for _, p := range []pkg.Package{A, B, C, D} {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
s = NewSolver(dbInstalled, dbDefinitions, db)
solution, err := s.Uninstall(A) solution, err := s.Uninstall(A)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(solution).To(ContainElement(A.IsFlagged(false))) Expect(solution).To(ContainElement(A.IsFlagged(false)))
// Expect(solution).To(ContainElement(PackageAssert{Package: C.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) // Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true}))
Expect(len(solution)).To(Equal(1)) Expect(len(solution)).To(Equal(1))
}) })
It("Find conflicts", func() { It("Find conflicts", func() {
db := pkg.NewInMemoryDatabase(false)
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
@@ -176,7 +254,16 @@ var _ = Describe("Solver", func() {
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{A}, []*pkg.DefaultPackage{}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{A}, []*pkg.DefaultPackage{})
s := NewSolver([]pkg.Package{A, B, C, D}, []pkg.Package{A, B, C, D}, db) for _, p := range []pkg.Package{A, B, C, D} {
_, err := dbDefinitions.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
for _, p := range []pkg.Package{A, B, C, D} {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
val, err := s.ConflictsWithInstalled(A) val, err := s.ConflictsWithInstalled(A)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(val).To(BeTrue()) Expect(val).To(BeTrue())
@@ -184,7 +271,6 @@ var _ = Describe("Solver", func() {
}) })
It("Find nested conflicts", func() { It("Find nested conflicts", func() {
db := pkg.NewInMemoryDatabase(false)
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
@@ -192,14 +278,22 @@ var _ = Describe("Solver", func() {
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{A}, []*pkg.DefaultPackage{}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{A}, []*pkg.DefaultPackage{})
s := NewSolver([]pkg.Package{A, B, C, D}, []pkg.Package{A, B, C, D}, db) for _, p := range []pkg.Package{A, B, C, D} {
_, err := dbDefinitions.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
for _, p := range []pkg.Package{A, B, C, D} {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
val, err := s.ConflictsWithInstalled(D) val, err := s.ConflictsWithInstalled(D)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(val).To(BeTrue()) Expect(val).To(BeTrue())
}) })
It("Doesn't find nested conflicts", func() { It("Doesn't find nested conflicts", func() {
db := pkg.NewInMemoryDatabase(false)
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
@@ -207,14 +301,22 @@ var _ = Describe("Solver", func() {
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{A}, []*pkg.DefaultPackage{}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{A}, []*pkg.DefaultPackage{})
s := NewSolver([]pkg.Package{A, B, C, D}, []pkg.Package{A, B, C, D}, db) for _, p := range []pkg.Package{A, B, C, D} {
_, err := dbDefinitions.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
for _, p := range []pkg.Package{A, B, C, D} {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
val, err := s.ConflictsWithInstalled(C) val, err := s.ConflictsWithInstalled(C)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(val).ToNot(BeTrue()) Expect(val).ToNot(BeTrue())
}) })
It("Doesn't find conflicts", func() { It("Doesn't find conflicts", func() {
db := pkg.NewInMemoryDatabase(false)
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
@@ -222,40 +324,59 @@ var _ = Describe("Solver", func() {
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
s := NewSolver([]pkg.Package{A, B, C, D}, []pkg.Package{A, B, C, D}, db) for _, p := range []pkg.Package{A, B, C, D} {
_, err := dbDefinitions.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
for _, p := range []pkg.Package{A, B, C, D} {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
val, err := s.ConflictsWithInstalled(C) val, err := s.ConflictsWithInstalled(C)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(val).ToNot(BeTrue()) Expect(val).ToNot(BeTrue())
}) })
It("Uninstalls simple packages not in world correctly", func() { It("Uninstalls simple packages not in world correctly", func() {
db := pkg.NewInMemoryDatabase(false)
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
s := NewSolver([]pkg.Package{A, B, C, D}, []pkg.Package{B, C, D}, db) for _, p := range []pkg.Package{B, C, D} {
_, err := dbDefinitions.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
for _, p := range []pkg.Package{A, B, C, D} {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
solution, err := s.Uninstall(A) solution, err := s.Uninstall(A)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(solution).To(ContainElement(A.IsFlagged(false))) Expect(solution).To(ContainElement(A.IsFlagged(false)))
// Expect(solution).To(ContainElement(PackageAssert{Package: C.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) // Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true}))
Expect(len(solution)).To(Equal(1)) Expect(len(solution)).To(Equal(1))
}) })
It("Uninstalls complex packages not in world correctly", func() { It("Uninstalls complex packages not in world correctly", func() {
db := pkg.NewInMemoryDatabase(false)
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
s := NewSolver([]pkg.Package{A, B, C, D}, []pkg.Package{B, C, D}, db) for _, p := range []pkg.Package{B, C, D} {
_, err := dbDefinitions.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
for _, p := range []pkg.Package{A, B, C, D} {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
solution, err := s.Uninstall(A) solution, err := s.Uninstall(A)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
@@ -265,15 +386,20 @@ var _ = Describe("Solver", func() {
}) })
It("Uninstalls complex packages correctly, even if shared deps are required by system packages", func() { It("Uninstalls complex packages correctly, even if shared deps are required by system packages", func() {
db := pkg.NewInMemoryDatabase(false)
D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{}) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
s := NewSolver([]pkg.Package{A, B, C, D}, []pkg.Package{A, B, C, D}, db) for _, p := range []pkg.Package{A, B, C, D} {
_, err := dbDefinitions.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
for _, p := range []pkg.Package{A, B, C, D} {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
solution, err := s.Uninstall(A) solution, err := s.Uninstall(A)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
@@ -284,14 +410,20 @@ var _ = Describe("Solver", func() {
}) })
It("Uninstalls complex packages in world correctly", func() { It("Uninstalls complex packages in world correctly", func() {
db := pkg.NewInMemoryDatabase(false)
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{C}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{C}, []*pkg.DefaultPackage{})
s := NewSolver([]pkg.Package{A, C, D}, []pkg.Package{A, B, C, D}, db) for _, p := range []pkg.Package{A, B, C, D} {
_, err := dbDefinitions.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
for _, p := range []pkg.Package{A, C, D} {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
solution, err := s.Uninstall(A) solution, err := s.Uninstall(A)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
@@ -303,23 +435,30 @@ var _ = Describe("Solver", func() {
}) })
It("Uninstalls complex package correctly", func() { It("Uninstalls complex package correctly", func() {
db := pkg.NewInMemoryDatabase(false)
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{})
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
C.IsFlagged(true) // installed // C // installed
s := NewSolver([]pkg.Package{A, B, C, D}, []pkg.Package{A, B, C, D}, db) for _, p := range []pkg.Package{A, B, C, D} {
_, err := dbDefinitions.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
for _, p := range []pkg.Package{A, B, C, D} {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
solution, err := s.Uninstall(A) solution, err := s.Uninstall(A)
Expect(err).ToNot(HaveOccurred())
Expect(solution).To(ContainElement(A.IsFlagged(false))) Expect(solution).To(ContainElement(A.IsFlagged(false)))
Expect(solution).To(ContainElement(B.IsFlagged(false))) Expect(solution).To(ContainElement(B.IsFlagged(false)))
Expect(solution).To(ContainElement(D.IsFlagged(false))) Expect(solution).To(ContainElement(D.IsFlagged(false)))
Expect(len(solution)).To(Equal(3)) Expect(len(solution)).To(Equal(3))
Expect(err).ToNot(HaveOccurred())
}) })
@@ -328,14 +467,20 @@ var _ = Describe("Solver", func() {
Context("Conflict set", func() { Context("Conflict set", func() {
It("is unsolvable - as we something we ask to install conflict with system stuff", func() { It("is unsolvable - as we something we ask to install conflict with system stuff", func() {
db := pkg.NewInMemoryDatabase(false)
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
// D := pkg.NewPackage("D", "", []pkg.Package{}, []pkg.Package{}) // D := pkg.NewPackage("D", "", []pkg.Package{}, []pkg.Package{})
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{C}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{C})
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
s := NewSolver([]pkg.Package{C}, []pkg.Package{A, B, C}, db) for _, p := range []pkg.Package{A, B, C} {
_, err := dbDefinitions.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
for _, p := range []pkg.Package{C} {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
solution, err := s.Install([]pkg.Package{A}) solution, err := s.Install([]pkg.Package{A})
Expect(len(solution)).To(Equal(0)) Expect(len(solution)).To(Equal(0))
@@ -346,8 +491,6 @@ var _ = Describe("Solver", func() {
Context("Complex data sets", func() { Context("Complex data sets", func() {
It("Solves them correctly", func() { It("Solves them correctly", func() {
db := pkg.NewInMemoryDatabase(false)
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
E := pkg.NewPackage("E", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) E := pkg.NewPackage("E", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
F := pkg.NewPackage("F", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}) F := pkg.NewPackage("F", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
@@ -357,18 +500,26 @@ var _ = Describe("Solver", func() {
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{}) B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{})
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{}) A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
s := NewSolver([]pkg.Package{C}, []pkg.Package{A, B, C, D, E, F, G}, db) for _, p := range []pkg.Package{A, B, C, D, E, F, G} {
_, err := dbDefinitions.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
for _, p := range []pkg.Package{C} {
_, err := dbInstalled.CreatePackage(p)
Expect(err).ToNot(HaveOccurred())
}
solution, err := s.Install([]pkg.Package{A}) solution, err := s.Install([]pkg.Package{A})
Expect(solution).To(ContainElement(PackageAssert{Package: A.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(err).ToNot(HaveOccurred())
Expect(solution).To(ContainElement(PackageAssert{Package: B.IsFlagged(true).(*pkg.DefaultPackage), Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: D.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: A, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: C.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: H.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: G.IsFlagged(true).(*pkg.DefaultPackage), Value: true})) Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: H, Value: true}))
Expect(solution).To(ContainElement(PackageAssert{Package: G, Value: true}))
Expect(len(solution)).To(Equal(6)) Expect(len(solution)).To(Equal(6))
Expect(err).ToNot(HaveOccurred())
}) })
}) })
@@ -391,7 +542,6 @@ var _ = Describe("Solver", func() {
Expect(lst).To(ContainElement(a03)) Expect(lst).To(ContainElement(a03))
Expect(lst).ToNot(ContainElement(old)) Expect(lst).ToNot(ContainElement(old))
Expect(len(lst)).To(Equal(5)) Expect(len(lst)).To(Equal(5))
s := solver.NewSolver([]pkg.Package{}, []pkg.Package{}, pkg.NewInMemoryDatabase(false))
p := s.Best(lst) p := s.Best(lst)
Expect(p).To(Equal(a03)) Expect(p).To(Equal(a03))
}) })