mirror of
https://github.com/mudler/luet.git
synced 2025-09-01 23:37:07 +00:00
Make sure we do compute the best fit
While install calls upgrade which in turns calls a relaxed install on its results, this doesn't make sure that the new results are at the best available version. We do iterate here over the results to compute the best set. It also expands computeUpgrade with the possibility to selectively choose which packages to upgrade and which not.
This commit is contained in:
@@ -146,6 +146,17 @@ func (assertions PackagesAssertions) Search(f string) *PackageAssert {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (assertions PackagesAssertions) ToDB() pkg.PackageDatabase {
|
||||
db := pkg.NewInMemoryDatabase(false)
|
||||
for _, a := range assertions {
|
||||
if a.Value {
|
||||
db.CreatePackage(a.Package)
|
||||
}
|
||||
}
|
||||
|
||||
return db
|
||||
}
|
||||
|
||||
func (assertions PackagesAssertions) Order(definitiondb pkg.PackageDatabase, fingerprint string) (PackagesAssertions, error) {
|
||||
|
||||
orderedAssertions := PackagesAssertions{}
|
||||
|
@@ -503,36 +503,41 @@ func inPackage(list []pkg.Package, p pkg.Package) bool {
|
||||
}
|
||||
|
||||
// Compute upgrade between packages if specified, or all if none is specified
|
||||
func (s *Solver) computeUpgrade(pps ...pkg.Package) func(defDB pkg.PackageDatabase, installDB pkg.PackageDatabase) (pkg.Packages, pkg.Packages, pkg.PackageDatabase) {
|
||||
return func(defDB pkg.PackageDatabase, installDB pkg.PackageDatabase) (pkg.Packages, pkg.Packages, pkg.PackageDatabase) {
|
||||
func (s *Solver) computeUpgrade(ppsToUpgrade, ppsToNotUpgrade []pkg.Package) func(defDB pkg.PackageDatabase, installDB pkg.PackageDatabase) (pkg.Packages, pkg.Packages, pkg.PackageDatabase, []pkg.Package) {
|
||||
return func(defDB pkg.PackageDatabase, installDB pkg.PackageDatabase) (pkg.Packages, pkg.Packages, pkg.PackageDatabase, []pkg.Package) {
|
||||
toUninstall := pkg.Packages{}
|
||||
toInstall := pkg.Packages{}
|
||||
|
||||
// we do this in memory so we take into account of provides, and its faster
|
||||
universe, _ := defDB.Copy()
|
||||
|
||||
installedcopy := pkg.NewInMemoryDatabase(false)
|
||||
|
||||
for _, p := range installDB.World() {
|
||||
installedcopy.CreatePackage(p)
|
||||
packages, err := universe.FindPackageVersions(p)
|
||||
|
||||
if err == nil && len(packages) != 0 {
|
||||
best := packages.Best(nil)
|
||||
if !best.Matches(p) && len(pps) == 0 ||
|
||||
len(pps) != 0 && inPackage(pps, p) {
|
||||
|
||||
// This make sure that we don't try to upgrade something that was specified
|
||||
// specifically to not be marked for upgrade
|
||||
// At the same time, makes sure that if we mark a package to look for upgrades
|
||||
// it doesn't have to be in the blacklist (the packages to NOT upgrade)
|
||||
if !best.Matches(p) &&
|
||||
((len(ppsToUpgrade) == 0 && len(ppsToNotUpgrade) == 0) ||
|
||||
(inPackage(ppsToUpgrade, p) && !inPackage(ppsToNotUpgrade, p)) ||
|
||||
(len(ppsToUpgrade) == 0 && !inPackage(ppsToNotUpgrade, p))) {
|
||||
toUninstall = append(toUninstall, p)
|
||||
toInstall = append(toInstall, best)
|
||||
}
|
||||
}
|
||||
}
|
||||
return toUninstall, toInstall, installedcopy
|
||||
return toUninstall, toInstall, installedcopy, ppsToUpgrade
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Solver) upgrade(fn func(defDB pkg.PackageDatabase, installDB pkg.PackageDatabase) (pkg.Packages, pkg.Packages, pkg.PackageDatabase), defDB pkg.PackageDatabase, installDB pkg.PackageDatabase, checkconflicts, full bool) (pkg.Packages, PackagesAssertions, error) {
|
||||
|
||||
toUninstall, toInstall, installedcopy := fn(defDB, installDB)
|
||||
func (s *Solver) upgrade(psToUpgrade, psToNotUpgrade pkg.Packages, fn func(defDB pkg.PackageDatabase, installDB pkg.PackageDatabase) (pkg.Packages, pkg.Packages, pkg.PackageDatabase, []pkg.Package), defDB pkg.PackageDatabase, installDB pkg.PackageDatabase, checkconflicts, full bool) (pkg.Packages, PackagesAssertions, error) {
|
||||
|
||||
toUninstall, toInstall, installedcopy, packsToUpgrade := fn(defDB, installDB)
|
||||
s2 := NewSolver(Options{Type: SingleCoreSimple}, installedcopy, defDB, pkg.NewInMemoryDatabase(false))
|
||||
s2.SetResolver(s.Resolver)
|
||||
if !full {
|
||||
@@ -560,14 +565,42 @@ func (s *Solver) upgrade(fn func(defDB pkg.PackageDatabase, installDB pkg.Packag
|
||||
}
|
||||
return toUninstall, ass, nil
|
||||
}
|
||||
|
||||
assertions, err := s2.RelaxedInstall(toInstall.Unique())
|
||||
|
||||
wantedSystem := assertions.ToDB()
|
||||
|
||||
fn = s.computeUpgrade(pkg.Packages{}, pkg.Packages{})
|
||||
if len(packsToUpgrade) > 0 {
|
||||
// If we have packages in input,
|
||||
// compute what we are looking to upgrade.
|
||||
// those are assertions minus packsToUpgrade
|
||||
|
||||
var selectedPackages []pkg.Package
|
||||
|
||||
for _, p := range assertions {
|
||||
if p.Value && !inPackage(psToUpgrade, p.Package) {
|
||||
selectedPackages = append(selectedPackages, p.Package)
|
||||
}
|
||||
}
|
||||
fn = s.computeUpgrade(selectedPackages, psToNotUpgrade)
|
||||
}
|
||||
|
||||
_, toInstall, _, _ = fn(defDB, wantedSystem)
|
||||
if len(toInstall) > 0 {
|
||||
_, toInstall, ass := s.upgrade(psToUpgrade, psToNotUpgrade, fn, defDB, wantedSystem, checkconflicts, full)
|
||||
return toUninstall, toInstall, ass
|
||||
}
|
||||
return toUninstall, assertions, err
|
||||
}
|
||||
|
||||
func (s *Solver) Upgrade(checkconflicts, full bool) (pkg.Packages, PackagesAssertions, error) {
|
||||
return s.upgrade(s.computeUpgrade(), s.DefinitionDatabase, s.InstalledDatabase, checkconflicts, full)
|
||||
|
||||
installedcopy := pkg.NewInMemoryDatabase(false)
|
||||
err := s.InstalledDatabase.Clone(installedcopy)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return s.upgrade(pkg.Packages{}, pkg.Packages{}, s.computeUpgrade(pkg.Packages{}, pkg.Packages{}), s.DefinitionDatabase, installedcopy, checkconflicts, full)
|
||||
}
|
||||
|
||||
// Uninstall takes a candidate package and return a list of packages that would be removed
|
||||
@@ -787,16 +820,18 @@ func (s *Solver) Install(c pkg.Packages) (PackagesAssertions, error) {
|
||||
systemAfterInstall := pkg.NewInMemoryDatabase(false)
|
||||
|
||||
toUpgrade := pkg.Packages{}
|
||||
|
||||
toNotUpgrade := pkg.Packages{}
|
||||
for _, p := range c {
|
||||
if p.GetVersion() == ">=0" || p.GetVersion() == ">0" {
|
||||
toUpgrade = append(toUpgrade, p)
|
||||
} else {
|
||||
toNotUpgrade = append(toNotUpgrade, p)
|
||||
}
|
||||
}
|
||||
for _, p := range assertions {
|
||||
if p.Value {
|
||||
systemAfterInstall.CreatePackage(p.Package)
|
||||
if !inPackage(c, p.Package) {
|
||||
if !inPackage(c, p.Package) && !inPackage(toUpgrade, p.Package) && !inPackage(toNotUpgrade, p.Package) {
|
||||
toUpgrade = append(toUpgrade, p.Package)
|
||||
}
|
||||
}
|
||||
@@ -805,10 +840,13 @@ func (s *Solver) Install(c pkg.Packages) (PackagesAssertions, error) {
|
||||
if len(toUpgrade) == 0 {
|
||||
return assertions, nil
|
||||
}
|
||||
|
||||
toUninstall, _, _, _ := s.computeUpgrade(toUpgrade, toNotUpgrade)(s.DefinitionDatabase, systemAfterInstall)
|
||||
if len(toUninstall) > 0 {
|
||||
// do partial upgrade based on input.
|
||||
// IF there is no version specified in the input, or >=0 is specified,
|
||||
// then compute upgrade for those
|
||||
_, newassertions, err := s.upgrade(s.computeUpgrade(toUpgrade...), s.DefinitionDatabase, systemAfterInstall, false, false)
|
||||
_, newassertions, err := s.upgrade(toUpgrade, toNotUpgrade, s.computeUpgrade(toUpgrade, toNotUpgrade), s.DefinitionDatabase, systemAfterInstall, false, false)
|
||||
if err != nil {
|
||||
// TODO: Emit warning.
|
||||
// We were not able to compute upgrades (maybe for some pinned packages, or a conflict)
|
||||
@@ -820,6 +858,8 @@ func (s *Solver) Install(c pkg.Packages) (PackagesAssertions, error) {
|
||||
if len(newassertions) == 0 && len(assertions) > 0 {
|
||||
return assertions, nil
|
||||
}
|
||||
|
||||
return newassertions, nil
|
||||
}
|
||||
|
||||
return assertions, nil
|
||||
}
|
||||
|
@@ -16,8 +16,6 @@
|
||||
package solver_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
pkg "github.com/mudler/luet/pkg/package"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
@@ -40,6 +38,7 @@ var _ = Describe("Solver", func() {
|
||||
})
|
||||
|
||||
Context("Select of best available package", func() {
|
||||
for i := 0; i < 200; i++ {
|
||||
|
||||
It("picks the best versions available for each package, excluding the ones manually specified while installing", func() {
|
||||
|
||||
@@ -73,7 +72,7 @@ var _ = Describe("Solver", func() {
|
||||
s = NewSolver(Options{Type: SingleCoreSimple}, dbInstalled, dbDefinitions, db)
|
||||
|
||||
solution, err := s.(*Solver).Install([]pkg.Package{D})
|
||||
fmt.Println(solution)
|
||||
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(len(solution)).To(Equal(8))
|
||||
|
||||
@@ -91,7 +90,6 @@ var _ = Describe("Solver", func() {
|
||||
s = NewSolver(Options{Type: SingleCoreSimple}, dbInstalled, dbDefinitions, db)
|
||||
|
||||
solution, err = s.(*Solver).Install([]pkg.Package{D, B2})
|
||||
fmt.Println(solution)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(len(solution)).To(Equal(8))
|
||||
|
||||
@@ -140,7 +138,6 @@ var _ = Describe("Solver", func() {
|
||||
s = NewSolver(Options{Type: SingleCoreSimple}, dbInstalled, dbDefinitions, db)
|
||||
|
||||
solution, err := s.(*Solver).Install([]pkg.Package{pkg.NewPackage("D", ">=0", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})})
|
||||
fmt.Println(solution)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(len(solution)).To(Equal(8))
|
||||
|
||||
@@ -158,7 +155,6 @@ var _ = Describe("Solver", func() {
|
||||
s = NewSolver(Options{Type: SingleCoreSimple}, dbInstalled, dbDefinitions, db)
|
||||
|
||||
solution, err = s.(*Solver).Install([]pkg.Package{pkg.NewPackage("D", ">=0", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}), B2})
|
||||
fmt.Println(solution)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(len(solution)).To(Equal(8))
|
||||
|
||||
@@ -174,7 +170,10 @@ var _ = Describe("Solver", func() {
|
||||
Expect(solution).To(ContainElement(PackageAssert{Package: B3, Value: false}))
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
Context("Simple set", func() {
|
||||
It("Solves correctly if the selected package has no requirements or conflicts and we have nothing installed yet", func() {
|
||||
|
||||
|
Reference in New Issue
Block a user