mirror of
https://github.com/mudler/luet.git
synced 2025-09-02 07:45:02 +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
|
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) {
|
func (assertions PackagesAssertions) Order(definitiondb pkg.PackageDatabase, fingerprint string) (PackagesAssertions, error) {
|
||||||
|
|
||||||
orderedAssertions := PackagesAssertions{}
|
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
|
// 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) {
|
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) {
|
return func(defDB pkg.PackageDatabase, installDB pkg.PackageDatabase) (pkg.Packages, pkg.Packages, pkg.PackageDatabase, []pkg.Package) {
|
||||||
toUninstall := pkg.Packages{}
|
toUninstall := pkg.Packages{}
|
||||||
toInstall := pkg.Packages{}
|
toInstall := pkg.Packages{}
|
||||||
|
|
||||||
// we do this in memory so we take into account of provides, and its faster
|
// we do this in memory so we take into account of provides, and its faster
|
||||||
universe, _ := defDB.Copy()
|
universe, _ := defDB.Copy()
|
||||||
|
|
||||||
installedcopy := pkg.NewInMemoryDatabase(false)
|
installedcopy := pkg.NewInMemoryDatabase(false)
|
||||||
|
|
||||||
for _, p := range installDB.World() {
|
for _, p := range installDB.World() {
|
||||||
installedcopy.CreatePackage(p)
|
installedcopy.CreatePackage(p)
|
||||||
packages, err := universe.FindPackageVersions(p)
|
packages, err := universe.FindPackageVersions(p)
|
||||||
|
|
||||||
if err == nil && len(packages) != 0 {
|
if err == nil && len(packages) != 0 {
|
||||||
best := packages.Best(nil)
|
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)
|
toUninstall = append(toUninstall, p)
|
||||||
toInstall = append(toInstall, best)
|
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) {
|
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 := fn(defDB, installDB)
|
|
||||||
|
|
||||||
|
toUninstall, toInstall, installedcopy, packsToUpgrade := fn(defDB, installDB)
|
||||||
s2 := NewSolver(Options{Type: SingleCoreSimple}, installedcopy, defDB, pkg.NewInMemoryDatabase(false))
|
s2 := NewSolver(Options{Type: SingleCoreSimple}, installedcopy, defDB, pkg.NewInMemoryDatabase(false))
|
||||||
s2.SetResolver(s.Resolver)
|
s2.SetResolver(s.Resolver)
|
||||||
if !full {
|
if !full {
|
||||||
@@ -560,14 +565,42 @@ func (s *Solver) upgrade(fn func(defDB pkg.PackageDatabase, installDB pkg.Packag
|
|||||||
}
|
}
|
||||||
return toUninstall, ass, nil
|
return toUninstall, ass, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
assertions, err := s2.RelaxedInstall(toInstall.Unique())
|
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
|
return toUninstall, assertions, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Solver) Upgrade(checkconflicts, full bool) (pkg.Packages, PackagesAssertions, error) {
|
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
|
// 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)
|
systemAfterInstall := pkg.NewInMemoryDatabase(false)
|
||||||
|
|
||||||
toUpgrade := pkg.Packages{}
|
toUpgrade := pkg.Packages{}
|
||||||
|
toNotUpgrade := pkg.Packages{}
|
||||||
for _, p := range c {
|
for _, p := range c {
|
||||||
if p.GetVersion() == ">=0" || p.GetVersion() == ">0" {
|
if p.GetVersion() == ">=0" || p.GetVersion() == ">0" {
|
||||||
toUpgrade = append(toUpgrade, p)
|
toUpgrade = append(toUpgrade, p)
|
||||||
|
} else {
|
||||||
|
toNotUpgrade = append(toNotUpgrade, p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, p := range assertions {
|
for _, p := range assertions {
|
||||||
if p.Value {
|
if p.Value {
|
||||||
systemAfterInstall.CreatePackage(p.Package)
|
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)
|
toUpgrade = append(toUpgrade, p.Package)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -805,10 +840,13 @@ func (s *Solver) Install(c pkg.Packages) (PackagesAssertions, error) {
|
|||||||
if len(toUpgrade) == 0 {
|
if len(toUpgrade) == 0 {
|
||||||
return assertions, nil
|
return assertions, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toUninstall, _, _, _ := s.computeUpgrade(toUpgrade, toNotUpgrade)(s.DefinitionDatabase, systemAfterInstall)
|
||||||
|
if len(toUninstall) > 0 {
|
||||||
// do partial upgrade based on input.
|
// do partial upgrade based on input.
|
||||||
// IF there is no version specified in the input, or >=0 is specified,
|
// IF there is no version specified in the input, or >=0 is specified,
|
||||||
// then compute upgrade for those
|
// 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 {
|
if err != nil {
|
||||||
// TODO: Emit warning.
|
// TODO: Emit warning.
|
||||||
// We were not able to compute upgrades (maybe for some pinned packages, or a conflict)
|
// 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 {
|
if len(newassertions) == 0 && len(assertions) > 0 {
|
||||||
return assertions, nil
|
return assertions, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return newassertions, nil
|
return newassertions, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return assertions, nil
|
||||||
|
}
|
||||||
|
@@ -16,8 +16,6 @@
|
|||||||
package solver_test
|
package solver_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
pkg "github.com/mudler/luet/pkg/package"
|
pkg "github.com/mudler/luet/pkg/package"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
@@ -40,6 +38,7 @@ var _ = Describe("Solver", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
Context("Select of best available package", 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() {
|
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)
|
s = NewSolver(Options{Type: SingleCoreSimple}, dbInstalled, dbDefinitions, db)
|
||||||
|
|
||||||
solution, err := s.(*Solver).Install([]pkg.Package{D})
|
solution, err := s.(*Solver).Install([]pkg.Package{D})
|
||||||
fmt.Println(solution)
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(len(solution)).To(Equal(8))
|
Expect(len(solution)).To(Equal(8))
|
||||||
|
|
||||||
@@ -91,7 +90,6 @@ var _ = Describe("Solver", func() {
|
|||||||
s = NewSolver(Options{Type: SingleCoreSimple}, dbInstalled, dbDefinitions, db)
|
s = NewSolver(Options{Type: SingleCoreSimple}, dbInstalled, dbDefinitions, db)
|
||||||
|
|
||||||
solution, err = s.(*Solver).Install([]pkg.Package{D, B2})
|
solution, err = s.(*Solver).Install([]pkg.Package{D, B2})
|
||||||
fmt.Println(solution)
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(len(solution)).To(Equal(8))
|
Expect(len(solution)).To(Equal(8))
|
||||||
|
|
||||||
@@ -140,7 +138,6 @@ var _ = Describe("Solver", func() {
|
|||||||
s = NewSolver(Options{Type: SingleCoreSimple}, dbInstalled, dbDefinitions, db)
|
s = NewSolver(Options{Type: SingleCoreSimple}, dbInstalled, dbDefinitions, db)
|
||||||
|
|
||||||
solution, err := s.(*Solver).Install([]pkg.Package{pkg.NewPackage("D", ">=0", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})})
|
solution, err := s.(*Solver).Install([]pkg.Package{pkg.NewPackage("D", ">=0", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})})
|
||||||
fmt.Println(solution)
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(len(solution)).To(Equal(8))
|
Expect(len(solution)).To(Equal(8))
|
||||||
|
|
||||||
@@ -158,7 +155,6 @@ var _ = Describe("Solver", func() {
|
|||||||
s = NewSolver(Options{Type: SingleCoreSimple}, dbInstalled, dbDefinitions, db)
|
s = NewSolver(Options{Type: SingleCoreSimple}, dbInstalled, dbDefinitions, db)
|
||||||
|
|
||||||
solution, err = s.(*Solver).Install([]pkg.Package{pkg.NewPackage("D", ">=0", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}), B2})
|
solution, err = s.(*Solver).Install([]pkg.Package{pkg.NewPackage("D", ">=0", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{}), B2})
|
||||||
fmt.Println(solution)
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(len(solution)).To(Equal(8))
|
Expect(len(solution)).To(Equal(8))
|
||||||
|
|
||||||
@@ -174,7 +170,10 @@ var _ = Describe("Solver", func() {
|
|||||||
Expect(solution).To(ContainElement(PackageAssert{Package: B3, Value: false}))
|
Expect(solution).To(ContainElement(PackageAssert{Package: B3, Value: false}))
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
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() {
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user