mirror of
https://github.com/mudler/luet.git
synced 2025-09-25 06:24:46 +00:00
🎨 Port package to types
This refactors DefaultPackage into types.Package and gets rid of the interface. This is a preceeding for a follow up where accessors will be removed from the code. It also does several cleanup, so we get rid also of some unneeded dependencies.
This commit is contained in:
@@ -21,7 +21,8 @@ import (
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
pkg "github.com/mudler/luet/pkg/package"
|
||||
types "github.com/mudler/luet/pkg/api/core/types"
|
||||
pkg "github.com/mudler/luet/pkg/database"
|
||||
"github.com/mudler/luet/tests/helpers"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
@@ -33,14 +34,14 @@ var _ = Describe("Solver Benchmarks", func() {
|
||||
db := pkg.NewInMemoryDatabase(false)
|
||||
dbInstalled := pkg.NewInMemoryDatabase(false)
|
||||
dbDefinitions := pkg.NewInMemoryDatabase(false)
|
||||
var s PackageSolver
|
||||
var s types.PackageSolver
|
||||
|
||||
Context("Complex data sets", func() {
|
||||
BeforeEach(func() {
|
||||
db = pkg.NewInMemoryDatabase(false)
|
||||
dbInstalled = pkg.NewInMemoryDatabase(false)
|
||||
dbDefinitions = pkg.NewInMemoryDatabase(false)
|
||||
s = NewSolver(Options{Type: SingleCoreSimple}, dbInstalled, dbDefinitions, db)
|
||||
s = NewSolver(types.SolverOptions{Type: types.SolverSingleCoreSimple}, dbInstalled, dbDefinitions, db)
|
||||
if os.Getenv("BENCHMARK_TESTS") != "true" {
|
||||
Skip("BENCHMARK_TESTS not enabled")
|
||||
}
|
||||
@@ -49,15 +50,15 @@ var _ = Describe("Solver Benchmarks", func() {
|
||||
|
||||
runtime := b.Time("runtime", func() {
|
||||
for i := 0; i < 50000; i++ {
|
||||
C := pkg.NewPackage("C"+strconv.Itoa(i), "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
E := pkg.NewPackage("E"+strconv.Itoa(i), "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
F := pkg.NewPackage("F"+strconv.Itoa(i), "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
G := pkg.NewPackage("G"+strconv.Itoa(i), "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
H := pkg.NewPackage("H"+strconv.Itoa(i), "", []*pkg.DefaultPackage{G}, []*pkg.DefaultPackage{})
|
||||
D := pkg.NewPackage("D"+strconv.Itoa(i), "", []*pkg.DefaultPackage{H}, []*pkg.DefaultPackage{})
|
||||
B := pkg.NewPackage("B"+strconv.Itoa(i), "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{})
|
||||
A := pkg.NewPackage("A"+strconv.Itoa(i), "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
|
||||
for _, p := range []pkg.Package{A, B, C, D, E, F, G} {
|
||||
C := types.NewPackage("C"+strconv.Itoa(i), "", []*types.Package{}, []*types.Package{})
|
||||
E := types.NewPackage("E"+strconv.Itoa(i), "", []*types.Package{}, []*types.Package{})
|
||||
F := types.NewPackage("F"+strconv.Itoa(i), "", []*types.Package{}, []*types.Package{})
|
||||
G := types.NewPackage("G"+strconv.Itoa(i), "", []*types.Package{}, []*types.Package{})
|
||||
H := types.NewPackage("H"+strconv.Itoa(i), "", []*types.Package{G}, []*types.Package{})
|
||||
D := types.NewPackage("D"+strconv.Itoa(i), "", []*types.Package{H}, []*types.Package{})
|
||||
B := types.NewPackage("B"+strconv.Itoa(i), "", []*types.Package{D}, []*types.Package{})
|
||||
A := types.NewPackage("A"+strconv.Itoa(i), "", []*types.Package{B}, []*types.Package{})
|
||||
for _, p := range []*types.Package{A, B, C, D, E, F, G} {
|
||||
_, err := dbDefinitions.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
@@ -66,22 +67,22 @@ var _ = Describe("Solver Benchmarks", func() {
|
||||
}
|
||||
|
||||
for i := 0; i < 1; i++ {
|
||||
C := pkg.NewPackage("C"+strconv.Itoa(i), "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
G := pkg.NewPackage("G"+strconv.Itoa(i), "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
H := pkg.NewPackage("H"+strconv.Itoa(i), "", []*pkg.DefaultPackage{G}, []*pkg.DefaultPackage{})
|
||||
D := pkg.NewPackage("D"+strconv.Itoa(i), "", []*pkg.DefaultPackage{H}, []*pkg.DefaultPackage{})
|
||||
B := pkg.NewPackage("B"+strconv.Itoa(i), "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{})
|
||||
A := pkg.NewPackage("A"+strconv.Itoa(i), "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
|
||||
C := types.NewPackage("C"+strconv.Itoa(i), "", []*types.Package{}, []*types.Package{})
|
||||
G := types.NewPackage("G"+strconv.Itoa(i), "", []*types.Package{}, []*types.Package{})
|
||||
H := types.NewPackage("H"+strconv.Itoa(i), "", []*types.Package{G}, []*types.Package{})
|
||||
D := types.NewPackage("D"+strconv.Itoa(i), "", []*types.Package{H}, []*types.Package{})
|
||||
B := types.NewPackage("B"+strconv.Itoa(i), "", []*types.Package{D}, []*types.Package{})
|
||||
A := types.NewPackage("A"+strconv.Itoa(i), "", []*types.Package{B}, []*types.Package{})
|
||||
|
||||
solution, err := s.Install([]pkg.Package{A})
|
||||
solution, err := s.Install([]*types.Package{A})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(solution).To(ContainElement(PackageAssert{Package: A, Value: true}))
|
||||
Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true}))
|
||||
Expect(solution).To(ContainElement(PackageAssert{Package: D, 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(solution).To(ContainElement(types.PackageAssert{Package: A, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: B, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: D, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: C, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: H, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: G, Value: true}))
|
||||
}
|
||||
})
|
||||
|
||||
@@ -94,7 +95,7 @@ var _ = Describe("Solver Benchmarks", func() {
|
||||
db = pkg.NewInMemoryDatabase(false)
|
||||
dbInstalled = pkg.NewInMemoryDatabase(false)
|
||||
dbDefinitions = pkg.NewInMemoryDatabase(false)
|
||||
s = NewSolver(Options{Type: SingleCoreSimple, Concurrency: 10}, dbInstalled, dbDefinitions, db)
|
||||
s = NewSolver(types.SolverOptions{Type: types.SolverSingleCoreSimple, Concurrency: 10}, dbInstalled, dbDefinitions, db)
|
||||
if os.Getenv("BENCHMARK_TESTS") != "true" {
|
||||
Skip("BENCHMARK_TESTS not enabled")
|
||||
}
|
||||
@@ -102,15 +103,15 @@ var _ = Describe("Solver Benchmarks", func() {
|
||||
Measure("it should be fast in resolution from a 50000 dataset", func(b Benchmarker) {
|
||||
runtime := b.Time("runtime", func() {
|
||||
for i := 0; i < 50000; i++ {
|
||||
C := pkg.NewPackage("C"+strconv.Itoa(i), "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
E := pkg.NewPackage("E"+strconv.Itoa(i), "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
F := pkg.NewPackage("F"+strconv.Itoa(i), "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
G := pkg.NewPackage("G"+strconv.Itoa(i), "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
H := pkg.NewPackage("H"+strconv.Itoa(i), "", []*pkg.DefaultPackage{G}, []*pkg.DefaultPackage{})
|
||||
D := pkg.NewPackage("D"+strconv.Itoa(i), "", []*pkg.DefaultPackage{H}, []*pkg.DefaultPackage{})
|
||||
B := pkg.NewPackage("B"+strconv.Itoa(i), "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{})
|
||||
A := pkg.NewPackage("A"+strconv.Itoa(i), "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
|
||||
for _, p := range []pkg.Package{A, B, C, D, E, F, G} {
|
||||
C := types.NewPackage("C"+strconv.Itoa(i), "", []*types.Package{}, []*types.Package{})
|
||||
E := types.NewPackage("E"+strconv.Itoa(i), "", []*types.Package{}, []*types.Package{})
|
||||
F := types.NewPackage("F"+strconv.Itoa(i), "", []*types.Package{}, []*types.Package{})
|
||||
G := types.NewPackage("G"+strconv.Itoa(i), "", []*types.Package{}, []*types.Package{})
|
||||
H := types.NewPackage("H"+strconv.Itoa(i), "", []*types.Package{G}, []*types.Package{})
|
||||
D := types.NewPackage("D"+strconv.Itoa(i), "", []*types.Package{H}, []*types.Package{})
|
||||
B := types.NewPackage("B"+strconv.Itoa(i), "", []*types.Package{D}, []*types.Package{})
|
||||
A := types.NewPackage("A"+strconv.Itoa(i), "", []*types.Package{B}, []*types.Package{})
|
||||
for _, p := range []*types.Package{A, B, C, D, E, F, G} {
|
||||
_, err := dbDefinitions.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
@@ -118,22 +119,22 @@ var _ = Describe("Solver Benchmarks", func() {
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
for i := 0; i < 1; i++ {
|
||||
C := pkg.NewPackage("C"+strconv.Itoa(i), "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
G := pkg.NewPackage("G"+strconv.Itoa(i), "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
H := pkg.NewPackage("H"+strconv.Itoa(i), "", []*pkg.DefaultPackage{G}, []*pkg.DefaultPackage{})
|
||||
D := pkg.NewPackage("D"+strconv.Itoa(i), "", []*pkg.DefaultPackage{H}, []*pkg.DefaultPackage{})
|
||||
B := pkg.NewPackage("B"+strconv.Itoa(i), "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{})
|
||||
A := pkg.NewPackage("A"+strconv.Itoa(i), "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
|
||||
C := types.NewPackage("C"+strconv.Itoa(i), "", []*types.Package{}, []*types.Package{})
|
||||
G := types.NewPackage("G"+strconv.Itoa(i), "", []*types.Package{}, []*types.Package{})
|
||||
H := types.NewPackage("H"+strconv.Itoa(i), "", []*types.Package{G}, []*types.Package{})
|
||||
D := types.NewPackage("D"+strconv.Itoa(i), "", []*types.Package{H}, []*types.Package{})
|
||||
B := types.NewPackage("B"+strconv.Itoa(i), "", []*types.Package{D}, []*types.Package{})
|
||||
A := types.NewPackage("A"+strconv.Itoa(i), "", []*types.Package{B}, []*types.Package{})
|
||||
|
||||
solution, err := s.Install([]pkg.Package{A})
|
||||
solution, err := s.Install([]*types.Package{A})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(solution).To(ContainElement(PackageAssert{Package: A, Value: true}))
|
||||
Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true}))
|
||||
Expect(solution).To(ContainElement(PackageAssert{Package: D, 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(solution).To(ContainElement(types.PackageAssert{Package: A, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: B, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: D, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: C, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: H, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: G, Value: true}))
|
||||
|
||||
// Expect(len(solution)).To(Equal(6))
|
||||
}
|
||||
@@ -152,7 +153,7 @@ var _ = Describe("Solver Benchmarks", func() {
|
||||
|
||||
// dbInstalled = pkg.NewInMemoryDatabase(false)
|
||||
dbDefinitions = pkg.NewInMemoryDatabase(false)
|
||||
s = NewSolver(Options{Type: SingleCoreSimple, Concurrency: 100}, dbInstalled, dbDefinitions, db)
|
||||
s = NewSolver(types.SolverOptions{Type: types.SolverSingleCoreSimple, Concurrency: 100}, dbInstalled, dbDefinitions, db)
|
||||
if os.Getenv("BENCHMARK_TESTS") != "true" {
|
||||
Skip("BENCHMARK_TESTS not enabled")
|
||||
}
|
||||
@@ -161,26 +162,26 @@ var _ = Describe("Solver Benchmarks", func() {
|
||||
Measure("it should be fast in resolution from a 10000*8 dataset", func(b Benchmarker) {
|
||||
runtime := b.Time("runtime", func() {
|
||||
for i := 2; i < 10000; i++ {
|
||||
C := pkg.NewPackage("C", strconv.Itoa(i), []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
E := pkg.NewPackage("E", strconv.Itoa(i), []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
F := pkg.NewPackage("F", strconv.Itoa(i), []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
G := pkg.NewPackage("G", strconv.Itoa(i), []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
H := pkg.NewPackage("H", strconv.Itoa(i), []*pkg.DefaultPackage{G}, []*pkg.DefaultPackage{})
|
||||
D := pkg.NewPackage("D", strconv.Itoa(i), []*pkg.DefaultPackage{H}, []*pkg.DefaultPackage{})
|
||||
B := pkg.NewPackage("B", strconv.Itoa(i), []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{})
|
||||
A := pkg.NewPackage("A", strconv.Itoa(i), []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
|
||||
for _, p := range []pkg.Package{A, B, C, D, E, F, G, H} {
|
||||
C := types.NewPackage("C", strconv.Itoa(i), []*types.Package{}, []*types.Package{})
|
||||
E := types.NewPackage("E", strconv.Itoa(i), []*types.Package{}, []*types.Package{})
|
||||
F := types.NewPackage("F", strconv.Itoa(i), []*types.Package{}, []*types.Package{})
|
||||
G := types.NewPackage("G", strconv.Itoa(i), []*types.Package{}, []*types.Package{})
|
||||
H := types.NewPackage("H", strconv.Itoa(i), []*types.Package{G}, []*types.Package{})
|
||||
D := types.NewPackage("D", strconv.Itoa(i), []*types.Package{H}, []*types.Package{})
|
||||
B := types.NewPackage("B", strconv.Itoa(i), []*types.Package{D}, []*types.Package{})
|
||||
A := types.NewPackage("A", strconv.Itoa(i), []*types.Package{B}, []*types.Package{})
|
||||
for _, p := range []*types.Package{A, B, C, D, E, F, G, H} {
|
||||
_, err := dbDefinitions.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
}
|
||||
|
||||
//C := pkg.NewPackage("C", "1", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
G := pkg.NewPackage("G", "1", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
H := pkg.NewPackage("H", "1", []*pkg.DefaultPackage{G}, []*pkg.DefaultPackage{})
|
||||
D := pkg.NewPackage("D", "1", []*pkg.DefaultPackage{H}, []*pkg.DefaultPackage{})
|
||||
B := pkg.NewPackage("B", "1", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{})
|
||||
A := pkg.NewPackage("A", "1", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
|
||||
//C := types.NewPackage("C", "1", []*types.Package{}, []*types.Package{})
|
||||
G := types.NewPackage("G", "1", []*types.Package{}, []*types.Package{})
|
||||
H := types.NewPackage("H", "1", []*types.Package{G}, []*types.Package{})
|
||||
D := types.NewPackage("D", "1", []*types.Package{H}, []*types.Package{})
|
||||
B := types.NewPackage("B", "1", []*types.Package{D}, []*types.Package{})
|
||||
A := types.NewPackage("A", "1", []*types.Package{B}, []*types.Package{})
|
||||
_, err := dbInstalled.CreatePackage(A)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
_, err = dbInstalled.CreatePackage(B)
|
||||
@@ -198,12 +199,12 @@ var _ = Describe("Solver Benchmarks", func() {
|
||||
|
||||
Expect(packages).To(ContainElement(A))
|
||||
|
||||
G = pkg.NewPackage("G", "9999", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
H = pkg.NewPackage("H", "9999", []*pkg.DefaultPackage{G}, []*pkg.DefaultPackage{})
|
||||
D = pkg.NewPackage("D", "9999", []*pkg.DefaultPackage{H}, []*pkg.DefaultPackage{})
|
||||
B = pkg.NewPackage("B", "9999", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{})
|
||||
A = pkg.NewPackage("A", "9999", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
|
||||
Expect(ass).To(ContainElement(PackageAssert{Package: A, Value: true}))
|
||||
G = types.NewPackage("G", "9999", []*types.Package{}, []*types.Package{})
|
||||
H = types.NewPackage("H", "9999", []*types.Package{G}, []*types.Package{})
|
||||
D = types.NewPackage("D", "9999", []*types.Package{H}, []*types.Package{})
|
||||
B = types.NewPackage("B", "9999", []*types.Package{D}, []*types.Package{})
|
||||
A = types.NewPackage("A", "9999", []*types.Package{B}, []*types.Package{})
|
||||
Expect(ass).To(ContainElement(types.PackageAssert{Package: A, Value: true}))
|
||||
|
||||
Expect(len(packages)).To(Equal(5))
|
||||
// Expect(len(solution)).To(Equal(6))
|
||||
@@ -216,15 +217,15 @@ var _ = Describe("Solver Benchmarks", func() {
|
||||
Measure("it should be fast in installation with 12000 packages installed and 2000*8 available", func(b Benchmarker) {
|
||||
runtime := b.Time("runtime", func() {
|
||||
for i := 0; i < 2000; i++ {
|
||||
C := pkg.NewPackage("C", strconv.Itoa(i), []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
E := pkg.NewPackage("E", strconv.Itoa(i), []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
F := pkg.NewPackage("F", strconv.Itoa(i), []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
G := pkg.NewPackage("G", strconv.Itoa(i), []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
H := pkg.NewPackage("H", strconv.Itoa(i), []*pkg.DefaultPackage{G}, []*pkg.DefaultPackage{})
|
||||
D := pkg.NewPackage("D", strconv.Itoa(i), []*pkg.DefaultPackage{H}, []*pkg.DefaultPackage{})
|
||||
B := pkg.NewPackage("B", strconv.Itoa(i), []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{})
|
||||
A := pkg.NewPackage("A", strconv.Itoa(i), []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
|
||||
for _, p := range []pkg.Package{A, B, C, D, E, F, G} {
|
||||
C := types.NewPackage("C", strconv.Itoa(i), []*types.Package{}, []*types.Package{})
|
||||
E := types.NewPackage("E", strconv.Itoa(i), []*types.Package{}, []*types.Package{})
|
||||
F := types.NewPackage("F", strconv.Itoa(i), []*types.Package{}, []*types.Package{})
|
||||
G := types.NewPackage("G", strconv.Itoa(i), []*types.Package{}, []*types.Package{})
|
||||
H := types.NewPackage("H", strconv.Itoa(i), []*types.Package{G}, []*types.Package{})
|
||||
D := types.NewPackage("D", strconv.Itoa(i), []*types.Package{H}, []*types.Package{})
|
||||
B := types.NewPackage("B", strconv.Itoa(i), []*types.Package{D}, []*types.Package{})
|
||||
A := types.NewPackage("A", strconv.Itoa(i), []*types.Package{B}, []*types.Package{})
|
||||
for _, p := range []*types.Package{A, B, C, D, E, F, G} {
|
||||
_, err := dbDefinitions.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
@@ -237,16 +238,16 @@ var _ = Describe("Solver Benchmarks", func() {
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
G := pkg.NewPackage("G", strconv.Itoa(50000), []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
H := pkg.NewPackage("H", strconv.Itoa(50000), []*pkg.DefaultPackage{G}, []*pkg.DefaultPackage{})
|
||||
D := pkg.NewPackage("D", strconv.Itoa(50000), []*pkg.DefaultPackage{H}, []*pkg.DefaultPackage{})
|
||||
B := pkg.NewPackage("B", strconv.Itoa(50000), []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{})
|
||||
A := pkg.NewPackage("A", strconv.Itoa(50000), []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
|
||||
G := types.NewPackage("G", strconv.Itoa(50000), []*types.Package{}, []*types.Package{})
|
||||
H := types.NewPackage("H", strconv.Itoa(50000), []*types.Package{G}, []*types.Package{})
|
||||
D := types.NewPackage("D", strconv.Itoa(50000), []*types.Package{H}, []*types.Package{})
|
||||
B := types.NewPackage("B", strconv.Itoa(50000), []*types.Package{D}, []*types.Package{})
|
||||
A := types.NewPackage("A", strconv.Itoa(50000), []*types.Package{B}, []*types.Package{})
|
||||
|
||||
ass, err := s.Install([]pkg.Package{A})
|
||||
ass, err := s.Install([]*types.Package{A})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(ass).To(ContainElement(PackageAssert{Package: pkg.NewPackage("A", "50000", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{}), Value: true}))
|
||||
Expect(ass).To(ContainElement(types.PackageAssert{Package: types.NewPackage("A", "50000", []*types.Package{B}, []*types.Package{}), Value: true}))
|
||||
//Expect(ass).To(Equal(5))
|
||||
// Expect(len(solution)).To(Equal(6))
|
||||
|
||||
@@ -258,26 +259,26 @@ var _ = Describe("Solver Benchmarks", func() {
|
||||
Measure("it should be fast in resolution from a 50000 dataset with upgrade universe", func(b Benchmarker) {
|
||||
runtime := b.Time("runtime", func() {
|
||||
for i := 0; i < 2; i++ {
|
||||
C := pkg.NewPackage("C", strconv.Itoa(i), []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
E := pkg.NewPackage("E", strconv.Itoa(i), []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
F := pkg.NewPackage("F", strconv.Itoa(i), []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
G := pkg.NewPackage("G", strconv.Itoa(i), []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
H := pkg.NewPackage("H", strconv.Itoa(i), []*pkg.DefaultPackage{G}, []*pkg.DefaultPackage{})
|
||||
D := pkg.NewPackage("D", strconv.Itoa(i), []*pkg.DefaultPackage{H}, []*pkg.DefaultPackage{})
|
||||
B := pkg.NewPackage("B", strconv.Itoa(i), []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{})
|
||||
A := pkg.NewPackage("A", strconv.Itoa(i), []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
|
||||
for _, p := range []pkg.Package{A, B, C, D, E, F, G} {
|
||||
C := types.NewPackage("C", strconv.Itoa(i), []*types.Package{}, []*types.Package{})
|
||||
E := types.NewPackage("E", strconv.Itoa(i), []*types.Package{}, []*types.Package{})
|
||||
F := types.NewPackage("F", strconv.Itoa(i), []*types.Package{}, []*types.Package{})
|
||||
G := types.NewPackage("G", strconv.Itoa(i), []*types.Package{}, []*types.Package{})
|
||||
H := types.NewPackage("H", strconv.Itoa(i), []*types.Package{G}, []*types.Package{})
|
||||
D := types.NewPackage("D", strconv.Itoa(i), []*types.Package{H}, []*types.Package{})
|
||||
B := types.NewPackage("B", strconv.Itoa(i), []*types.Package{D}, []*types.Package{})
|
||||
A := types.NewPackage("A", strconv.Itoa(i), []*types.Package{B}, []*types.Package{})
|
||||
for _, p := range []*types.Package{A, B, C, D, E, F, G} {
|
||||
_, err := dbDefinitions.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
fmt.Println("Creating package, run", i)
|
||||
}
|
||||
|
||||
G := pkg.NewPackage("G", "1", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
H := pkg.NewPackage("H", "1", []*pkg.DefaultPackage{G}, []*pkg.DefaultPackage{})
|
||||
D := pkg.NewPackage("D", "1", []*pkg.DefaultPackage{H}, []*pkg.DefaultPackage{})
|
||||
B := pkg.NewPackage("B", "1", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{})
|
||||
A := pkg.NewPackage("A", "1", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
|
||||
G := types.NewPackage("G", "1", []*types.Package{}, []*types.Package{})
|
||||
H := types.NewPackage("H", "1", []*types.Package{G}, []*types.Package{})
|
||||
D := types.NewPackage("D", "1", []*types.Package{H}, []*types.Package{})
|
||||
B := types.NewPackage("B", "1", []*types.Package{D}, []*types.Package{})
|
||||
A := types.NewPackage("A", "1", []*types.Package{B}, []*types.Package{})
|
||||
_, err := dbInstalled.CreatePackage(A)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
fmt.Println("Upgrade starts")
|
||||
@@ -285,8 +286,8 @@ var _ = Describe("Solver Benchmarks", func() {
|
||||
packages, ass, err := s.UpgradeUniverse(true)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(ass).To(ContainElement(PackageAssert{Package: pkg.NewPackage("A", "50000", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{}), Value: true}))
|
||||
Expect(packages).To(ContainElement(pkg.NewPackage("A", "50000", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})))
|
||||
Expect(ass).To(ContainElement(types.PackageAssert{Package: types.NewPackage("A", "50000", []*types.Package{B}, []*types.Package{}), Value: true}))
|
||||
Expect(packages).To(ContainElement(types.NewPackage("A", "50000", []*types.Package{B}, []*types.Package{})))
|
||||
Expect(packages).To(Equal(5))
|
||||
// Expect(len(solution)).To(Equal(6))
|
||||
|
||||
|
@@ -16,339 +16,19 @@
|
||||
package solver
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"sort"
|
||||
"unicode"
|
||||
|
||||
pkg "github.com/mudler/luet/pkg/package"
|
||||
"github.com/mudler/topsort"
|
||||
toposort "github.com/philopon/go-toposort"
|
||||
"github.com/pkg/errors"
|
||||
types "github.com/mudler/luet/pkg/api/core/types"
|
||||
)
|
||||
|
||||
type PackagesAssertions []PackageAssert
|
||||
|
||||
type PackageHash struct {
|
||||
BuildHash string
|
||||
PackageHash string
|
||||
}
|
||||
|
||||
// PackageAssert represent a package assertion.
|
||||
// It is composed of a Package and a Value which is indicating the absence or not
|
||||
// of the associated package state.
|
||||
type PackageAssert struct {
|
||||
Package *pkg.DefaultPackage
|
||||
Value bool
|
||||
Hash PackageHash
|
||||
}
|
||||
|
||||
// DecodeModel decodes a model from the SAT solver to package assertions (PackageAssert)
|
||||
func DecodeModel(model map[string]bool, db pkg.PackageDatabase) (PackagesAssertions, error) {
|
||||
ass := make(PackagesAssertions, 0)
|
||||
// DecodeModel decodes a model from the SAT solver to package assertions (types.PackageAssert)
|
||||
func DecodeModel(model map[string]bool, db types.PackageDatabase) (types.PackagesAssertions, error) {
|
||||
ass := make(types.PackagesAssertions, 0)
|
||||
for k, v := range model {
|
||||
a, err := pkg.DecodePackage(k, db)
|
||||
a, err := types.DecodePackage(k, db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
}
|
||||
ass = append(ass, PackageAssert{Package: a.(*pkg.DefaultPackage), Value: v})
|
||||
ass = append(ass, types.PackageAssert{Package: a, Value: v})
|
||||
}
|
||||
return ass, nil
|
||||
}
|
||||
|
||||
func (a *PackageAssert) Explain() {
|
||||
fmt.Println(a.ToString())
|
||||
a.Package.Explain()
|
||||
}
|
||||
|
||||
func (a *PackageAssert) String() string {
|
||||
return a.ToString()
|
||||
}
|
||||
|
||||
func (a *PackageAssert) ToString() string {
|
||||
var msg string
|
||||
if a.Value {
|
||||
msg = "installed"
|
||||
} else {
|
||||
msg = "not installed"
|
||||
}
|
||||
return fmt.Sprintf("%s/%s %s %s", a.Package.GetCategory(), a.Package.GetName(), a.Package.GetVersion(), msg)
|
||||
}
|
||||
|
||||
func (assertions PackagesAssertions) EnsureOrder() PackagesAssertions {
|
||||
|
||||
orderedAssertions := PackagesAssertions{}
|
||||
unorderedAssertions := PackagesAssertions{}
|
||||
fingerprints := []string{}
|
||||
|
||||
tmpMap := map[string]PackageAssert{}
|
||||
|
||||
for _, a := range assertions {
|
||||
tmpMap[a.Package.GetFingerPrint()] = a
|
||||
fingerprints = append(fingerprints, a.Package.GetFingerPrint())
|
||||
unorderedAssertions = append(unorderedAssertions, a) // Build a list of the ones that must be ordered
|
||||
|
||||
if a.Value {
|
||||
unorderedAssertions = append(unorderedAssertions, a) // Build a list of the ones that must be ordered
|
||||
} else {
|
||||
orderedAssertions = append(orderedAssertions, a) // Keep last the ones which are not meant to be installed
|
||||
}
|
||||
}
|
||||
|
||||
sort.Sort(unorderedAssertions)
|
||||
|
||||
// Build a topological graph
|
||||
graph := toposort.NewGraph(len(unorderedAssertions))
|
||||
graph.AddNodes(fingerprints...)
|
||||
for _, a := range unorderedAssertions {
|
||||
for _, req := range a.Package.GetRequires() {
|
||||
graph.AddEdge(a.Package.GetFingerPrint(), req.GetFingerPrint())
|
||||
}
|
||||
}
|
||||
result, ok := graph.Toposort()
|
||||
if !ok {
|
||||
panic("Cycle found")
|
||||
}
|
||||
for _, res := range result {
|
||||
a, ok := tmpMap[res]
|
||||
if !ok {
|
||||
panic("fail")
|
||||
// continue
|
||||
}
|
||||
orderedAssertions = append(orderedAssertions, a)
|
||||
// orderedAssertions = append(PackagesAssertions{a}, orderedAssertions...) // push upfront
|
||||
}
|
||||
//helpers.ReverseAny(orderedAssertions)
|
||||
return orderedAssertions
|
||||
}
|
||||
|
||||
func (assertions PackagesAssertions) SearchByName(f string) *PackageAssert {
|
||||
for _, a := range assertions {
|
||||
if a.Value {
|
||||
if a.Package.GetPackageName() == f {
|
||||
return &a
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func (assertions PackagesAssertions) Search(f string) *PackageAssert {
|
||||
for _, a := range assertions {
|
||||
if a.Value {
|
||||
if a.Package.GetFingerPrint() == f {
|
||||
return &a
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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{}
|
||||
unorderedAssertions := PackagesAssertions{}
|
||||
|
||||
tmpMap := map[string]PackageAssert{}
|
||||
graph := topsort.NewGraph()
|
||||
for _, a := range assertions {
|
||||
graph.AddNode(a.Package.GetFingerPrint())
|
||||
tmpMap[a.Package.GetFingerPrint()] = a
|
||||
unorderedAssertions = append(unorderedAssertions, a) // Build a list of the ones that must be ordered
|
||||
}
|
||||
|
||||
sort.Sort(unorderedAssertions)
|
||||
// Build a topological graph
|
||||
for _, a := range unorderedAssertions {
|
||||
currentPkg := a.Package
|
||||
added := map[string]interface{}{}
|
||||
REQUIRES:
|
||||
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 know that the assertions are unique for packages, so look for a package with such name in the assertions
|
||||
req := assertions.SearchByName(requiredDef.GetPackageName())
|
||||
if req != nil {
|
||||
requiredDef = req.Package
|
||||
}
|
||||
if _, ok := added[requiredDef.GetFingerPrint()]; ok {
|
||||
continue REQUIRES
|
||||
}
|
||||
// Expand also here, as we need to order them (or instead the solver should give back the dep correctly?)
|
||||
graph.AddEdge(currentPkg.GetFingerPrint(), requiredDef.GetFingerPrint())
|
||||
added[requiredDef.GetFingerPrint()] = true
|
||||
}
|
||||
}
|
||||
result, err := graph.TopSort(fingerprint)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fail on sorting "+fingerprint)
|
||||
}
|
||||
for _, res := range result {
|
||||
a, ok := tmpMap[res]
|
||||
if !ok {
|
||||
//return nil, errors.New("fail looking for " + res)
|
||||
// Since now we don't return the entire world as part of assertions
|
||||
// if we don't find any reference must be because fingerprint we are analyzing (which is the one we are ordering against)
|
||||
// is not part of the assertions, thus we can omit it from the result
|
||||
continue
|
||||
}
|
||||
orderedAssertions = append(orderedAssertions, a)
|
||||
// orderedAssertions = append(PackagesAssertions{a}, orderedAssertions...) // push upfront
|
||||
}
|
||||
//helpers.ReverseAny(orderedAssertions)
|
||||
return orderedAssertions, nil
|
||||
}
|
||||
|
||||
func (assertions PackagesAssertions) Explain() string {
|
||||
var fingerprint string
|
||||
for _, assertion := range assertions { // Always order them
|
||||
fingerprint += assertion.ToString() + "\n"
|
||||
}
|
||||
return fingerprint
|
||||
}
|
||||
|
||||
func (a PackagesAssertions) Len() int { return len(a) }
|
||||
func (a PackagesAssertions) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a PackagesAssertions) Less(i, j int) bool {
|
||||
|
||||
iRunes := []rune(a[i].Package.GetName())
|
||||
jRunes := []rune(a[j].Package.GetName())
|
||||
|
||||
max := len(iRunes)
|
||||
if max > len(jRunes) {
|
||||
max = len(jRunes)
|
||||
}
|
||||
|
||||
for idx := 0; idx < max; idx++ {
|
||||
ir := iRunes[idx]
|
||||
jr := jRunes[idx]
|
||||
|
||||
lir := unicode.ToLower(ir)
|
||||
ljr := unicode.ToLower(jr)
|
||||
|
||||
if lir != ljr {
|
||||
return lir < ljr
|
||||
}
|
||||
|
||||
// the lowercase runes are the same, so compare the original
|
||||
if ir != jr {
|
||||
return ir < jr
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
|
||||
}
|
||||
|
||||
func (a PackagesAssertions) TrueLen() int {
|
||||
count := 0
|
||||
for _, ass := range a {
|
||||
if ass.Value {
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
// HashFrom computes the assertion hash From a given package. It drops it from the assertions
|
||||
// and checks it's not the only one. if it's unique it marks it specially - so the hash
|
||||
// which is generated is unique for the selected package
|
||||
func (assertions PackagesAssertions) HashFrom(p pkg.Package) string {
|
||||
return assertions.SaltedHashFrom(p, map[string]string{})
|
||||
}
|
||||
|
||||
func (assertions PackagesAssertions) AssertionHash() string {
|
||||
return assertions.SaltedAssertionHash(map[string]string{})
|
||||
}
|
||||
|
||||
func (assertions PackagesAssertions) SaltedHashFrom(p pkg.Package, salts map[string]string) string {
|
||||
var assertionhash string
|
||||
|
||||
// When we don't have any solution to hash for, we need to generate an UUID by ourselves
|
||||
latestsolution := assertions.Drop(p)
|
||||
if latestsolution.TrueLen() == 0 {
|
||||
// Preserve the hash if supplied of marked packages
|
||||
marked := p.Mark()
|
||||
if markedHash, exists := salts[p.GetFingerPrint()]; exists {
|
||||
salts[marked.GetFingerPrint()] = markedHash
|
||||
}
|
||||
assertionhash = assertions.Mark(p).SaltedAssertionHash(salts)
|
||||
} else {
|
||||
assertionhash = latestsolution.SaltedAssertionHash(salts)
|
||||
}
|
||||
return assertionhash
|
||||
}
|
||||
|
||||
func (assertions PackagesAssertions) SaltedAssertionHash(salts map[string]string) string {
|
||||
var fingerprint string
|
||||
for _, assertion := range assertions { // Note: Always order them first!
|
||||
if assertion.Value { // Tke into account only dependencies installed (get fingerprint of subgraph)
|
||||
salt, exists := salts[assertion.Package.GetFingerPrint()]
|
||||
if exists {
|
||||
fingerprint += assertion.ToString() + salt + "\n"
|
||||
|
||||
} else {
|
||||
fingerprint += assertion.ToString() + "\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
hash := sha256.Sum256([]byte(fingerprint))
|
||||
return fmt.Sprintf("%x", hash)
|
||||
}
|
||||
|
||||
func (assertions PackagesAssertions) Drop(p pkg.Package) PackagesAssertions {
|
||||
ass := PackagesAssertions{}
|
||||
|
||||
for _, a := range assertions {
|
||||
if !a.Package.Matches(p) {
|
||||
ass = append(ass, a)
|
||||
}
|
||||
}
|
||||
return ass
|
||||
}
|
||||
|
||||
// Cut returns an assertion list of installed (filter by Value) "cutted" until the package is found (included)
|
||||
func (assertions PackagesAssertions) Cut(p pkg.Package) PackagesAssertions {
|
||||
ass := PackagesAssertions{}
|
||||
|
||||
for _, a := range assertions {
|
||||
if a.Value {
|
||||
ass = append(ass, a)
|
||||
if a.Package.Matches(p) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return ass
|
||||
}
|
||||
|
||||
// Mark returns a new assertion with the package marked
|
||||
func (assertions PackagesAssertions) Mark(p pkg.Package) PackagesAssertions {
|
||||
ass := PackagesAssertions{}
|
||||
|
||||
for _, a := range assertions {
|
||||
if a.Package.Matches(p) {
|
||||
marked := a.Package.Mark()
|
||||
a = PackageAssert{Package: marked.(*pkg.DefaultPackage), Value: a.Value, Hash: a.Hash}
|
||||
}
|
||||
ass = append(ass, a)
|
||||
}
|
||||
return ass
|
||||
}
|
||||
|
@@ -18,8 +18,8 @@ package solver_test
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
pkg "github.com/mudler/luet/pkg/package"
|
||||
"github.com/mudler/luet/pkg/solver"
|
||||
"github.com/mudler/luet/pkg/api/core/types"
|
||||
pkg "github.com/mudler/luet/pkg/database"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
@@ -30,13 +30,13 @@ var _ = Describe("Decoder", func() {
|
||||
db := pkg.NewInMemoryDatabase(false)
|
||||
dbInstalled := pkg.NewInMemoryDatabase(false)
|
||||
dbDefinitions := pkg.NewInMemoryDatabase(false)
|
||||
s := NewSolver(Options{Type: SingleCoreSimple}, dbInstalled, dbDefinitions, db)
|
||||
s := NewSolver(types.SolverOptions{Type: types.SolverSingleCoreSimple}, dbInstalled, dbDefinitions, db)
|
||||
|
||||
BeforeEach(func() {
|
||||
db = pkg.NewInMemoryDatabase(false)
|
||||
dbInstalled = pkg.NewInMemoryDatabase(false)
|
||||
dbDefinitions = pkg.NewInMemoryDatabase(false)
|
||||
s = NewSolver(Options{Type: SingleCoreSimple}, dbInstalled, dbDefinitions, db)
|
||||
s = NewSolver(types.SolverOptions{Type: types.SolverSingleCoreSimple}, dbInstalled, dbDefinitions, db)
|
||||
})
|
||||
|
||||
Context("Assertion ordering", func() {
|
||||
@@ -44,32 +44,32 @@ var _ = Describe("Decoder", func() {
|
||||
for index := 0; index < 300; index++ { // Just to make sure we don't have false positives
|
||||
It("Orders them correctly #"+strconv.Itoa(index), func() {
|
||||
|
||||
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
E := pkg.NewPackage("E", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
F := pkg.NewPackage("F", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
G := pkg.NewPackage("G", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
H := pkg.NewPackage("H", "", []*pkg.DefaultPackage{G}, []*pkg.DefaultPackage{})
|
||||
D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{H}, []*pkg.DefaultPackage{})
|
||||
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{})
|
||||
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
|
||||
C := types.NewPackage("C", "", []*types.Package{}, []*types.Package{})
|
||||
E := types.NewPackage("E", "", []*types.Package{}, []*types.Package{})
|
||||
F := types.NewPackage("F", "", []*types.Package{}, []*types.Package{})
|
||||
G := types.NewPackage("G", "", []*types.Package{}, []*types.Package{})
|
||||
H := types.NewPackage("H", "", []*types.Package{G}, []*types.Package{})
|
||||
D := types.NewPackage("D", "", []*types.Package{H}, []*types.Package{})
|
||||
B := types.NewPackage("B", "", []*types.Package{D}, []*types.Package{})
|
||||
A := types.NewPackage("A", "", []*types.Package{B}, []*types.Package{})
|
||||
|
||||
for _, p := range []pkg.Package{A, B, C, D, E, F, G} {
|
||||
for _, p := range []*types.Package{A, B, C, D, E, F, G} {
|
||||
_, err := dbDefinitions.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
for _, p := range []pkg.Package{C} {
|
||||
for _, p := range []*types.Package{C} {
|
||||
_, err := dbInstalled.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
solution, err := s.Install([]pkg.Package{A})
|
||||
Expect(solution).To(ContainElement(PackageAssert{Package: A, Value: true}))
|
||||
Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true}))
|
||||
Expect(solution).To(ContainElement(PackageAssert{Package: D, 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}))
|
||||
solution, err := s.Install([]*types.Package{A})
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: A, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: B, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: D, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: C, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: H, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: G, Value: true}))
|
||||
|
||||
Expect(len(solution)).To(Equal(6))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
@@ -95,32 +95,32 @@ var _ = Describe("Decoder", func() {
|
||||
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() {
|
||||
|
||||
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
E := pkg.NewPackage("E", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
F := pkg.NewPackage("F", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
G := pkg.NewPackage("G", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
H := pkg.NewPackage("H", "", []*pkg.DefaultPackage{G}, []*pkg.DefaultPackage{})
|
||||
D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{H}, []*pkg.DefaultPackage{})
|
||||
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{})
|
||||
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
|
||||
C := types.NewPackage("C", "", []*types.Package{}, []*types.Package{})
|
||||
E := types.NewPackage("E", "", []*types.Package{}, []*types.Package{})
|
||||
F := types.NewPackage("F", "", []*types.Package{}, []*types.Package{})
|
||||
G := types.NewPackage("G", "", []*types.Package{}, []*types.Package{})
|
||||
H := types.NewPackage("H", "", []*types.Package{G}, []*types.Package{})
|
||||
D := types.NewPackage("D", "", []*types.Package{H}, []*types.Package{})
|
||||
B := types.NewPackage("B", "", []*types.Package{D}, []*types.Package{})
|
||||
A := types.NewPackage("A", "", []*types.Package{B}, []*types.Package{})
|
||||
|
||||
for _, p := range []pkg.Package{A, B, C, D, E, F, G} {
|
||||
for _, p := range []*types.Package{A, B, C, D, E, F, G} {
|
||||
_, err := dbDefinitions.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
for _, p := range []pkg.Package{C} {
|
||||
for _, p := range []*types.Package{C} {
|
||||
_, err := dbInstalled.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
solution, err := s.Install([]pkg.Package{A})
|
||||
Expect(solution).To(ContainElement(PackageAssert{Package: A, Value: true}))
|
||||
Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true}))
|
||||
Expect(solution).To(ContainElement(PackageAssert{Package: D, 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}))
|
||||
solution, err := s.Install([]*types.Package{A})
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: A, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: B, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: D, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: C, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: H, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: G, Value: true}))
|
||||
|
||||
Expect(len(solution)).To(Equal(6))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
@@ -161,32 +161,32 @@ var _ = Describe("Decoder", func() {
|
||||
Context("Assertion hashing", func() {
|
||||
It("Hashes them, and could be used for comparison", func() {
|
||||
|
||||
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
E := pkg.NewPackage("E", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
F := pkg.NewPackage("F", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
G := pkg.NewPackage("G", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
H := pkg.NewPackage("H", "", []*pkg.DefaultPackage{G}, []*pkg.DefaultPackage{})
|
||||
D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{H}, []*pkg.DefaultPackage{})
|
||||
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{D}, []*pkg.DefaultPackage{})
|
||||
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
|
||||
C := types.NewPackage("C", "", []*types.Package{}, []*types.Package{})
|
||||
E := types.NewPackage("E", "", []*types.Package{}, []*types.Package{})
|
||||
F := types.NewPackage("F", "", []*types.Package{}, []*types.Package{})
|
||||
G := types.NewPackage("G", "", []*types.Package{}, []*types.Package{})
|
||||
H := types.NewPackage("H", "", []*types.Package{G}, []*types.Package{})
|
||||
D := types.NewPackage("D", "", []*types.Package{H}, []*types.Package{})
|
||||
B := types.NewPackage("B", "", []*types.Package{D}, []*types.Package{})
|
||||
A := types.NewPackage("A", "", []*types.Package{B}, []*types.Package{})
|
||||
|
||||
for _, p := range []pkg.Package{A, B, C, D, E, F, G} {
|
||||
for _, p := range []*types.Package{A, B, C, D, E, F, G} {
|
||||
_, err := dbDefinitions.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
for _, p := range []pkg.Package{C} {
|
||||
for _, p := range []*types.Package{C} {
|
||||
_, err := dbInstalled.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
solution, err := s.Install([]pkg.Package{A})
|
||||
Expect(solution).To(ContainElement(PackageAssert{Package: A, Value: true}))
|
||||
Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true}))
|
||||
Expect(solution).To(ContainElement(PackageAssert{Package: D, 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}))
|
||||
solution, err := s.Install([]*types.Package{A})
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: A, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: B, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: D, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: C, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: H, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: G, Value: true}))
|
||||
|
||||
Expect(len(solution)).To(Equal(6))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
@@ -200,12 +200,12 @@ var _ = Describe("Decoder", func() {
|
||||
|
||||
hash := solution.AssertionHash()
|
||||
|
||||
solution, err = s.Install([]pkg.Package{B})
|
||||
Expect(solution).To(ContainElement(PackageAssert{Package: B, Value: true}))
|
||||
Expect(solution).To(ContainElement(PackageAssert{Package: D, 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}))
|
||||
solution, err = s.Install([]*types.Package{B})
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: B, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: D, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: C, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: H, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: G, Value: true}))
|
||||
|
||||
Expect(len(solution)).To(Equal(6))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
@@ -226,24 +226,24 @@ var _ = Describe("Decoder", func() {
|
||||
})
|
||||
It("Hashes them, and could be used for comparison", func() {
|
||||
|
||||
X := pkg.NewPackage("X", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
Y := pkg.NewPackage("Y", "", []*pkg.DefaultPackage{X}, []*pkg.DefaultPackage{})
|
||||
Z := pkg.NewPackage("Z", "", []*pkg.DefaultPackage{X}, []*pkg.DefaultPackage{})
|
||||
X := types.NewPackage("X", "", []*types.Package{}, []*types.Package{})
|
||||
Y := types.NewPackage("Y", "", []*types.Package{X}, []*types.Package{})
|
||||
Z := types.NewPackage("Z", "", []*types.Package{X}, []*types.Package{})
|
||||
|
||||
for _, p := range []pkg.Package{X, Y, Z} {
|
||||
for _, p := range []*types.Package{X, Y, Z} {
|
||||
_, err := dbDefinitions.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
for _, p := range []pkg.Package{} {
|
||||
for _, p := range []*types.Package{} {
|
||||
_, err := dbInstalled.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
solution, err := s.Install([]pkg.Package{Y})
|
||||
solution, err := s.Install([]*types.Package{Y})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
solution2, err := s.Install([]pkg.Package{Z})
|
||||
solution2, err := s.Install([]*types.Package{Z})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
orderY, err := solution.Order(dbDefinitions, Y.GetFingerPrint())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
@@ -254,24 +254,24 @@ var _ = Describe("Decoder", func() {
|
||||
|
||||
It("Hashes them, Cuts them and could be used for comparison", func() {
|
||||
|
||||
X := pkg.NewPackage("X", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
Y := pkg.NewPackage("Y", "", []*pkg.DefaultPackage{X}, []*pkg.DefaultPackage{})
|
||||
Z := pkg.NewPackage("Z", "", []*pkg.DefaultPackage{X}, []*pkg.DefaultPackage{})
|
||||
X := types.NewPackage("X", "", []*types.Package{}, []*types.Package{})
|
||||
Y := types.NewPackage("Y", "", []*types.Package{X}, []*types.Package{})
|
||||
Z := types.NewPackage("Z", "", []*types.Package{X}, []*types.Package{})
|
||||
|
||||
for _, p := range []pkg.Package{X, Y, Z} {
|
||||
for _, p := range []*types.Package{X, Y, Z} {
|
||||
_, err := dbDefinitions.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
for _, p := range []pkg.Package{} {
|
||||
for _, p := range []*types.Package{} {
|
||||
_, err := dbInstalled.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
solution, err := s.Install([]pkg.Package{Y})
|
||||
solution, err := s.Install([]*types.Package{Y})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
solution2, err := s.Install([]pkg.Package{Z})
|
||||
solution2, err := s.Install([]*types.Package{Z})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
orderY, err := solution.Order(dbDefinitions, Y.GetFingerPrint())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
@@ -284,24 +284,24 @@ var _ = Describe("Decoder", func() {
|
||||
|
||||
It("HashFrom can be used equally", func() {
|
||||
|
||||
X := pkg.NewPackage("X", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
Y := pkg.NewPackage("Y", "", []*pkg.DefaultPackage{X}, []*pkg.DefaultPackage{})
|
||||
Z := pkg.NewPackage("Z", "", []*pkg.DefaultPackage{X}, []*pkg.DefaultPackage{})
|
||||
X := types.NewPackage("X", "", []*types.Package{}, []*types.Package{})
|
||||
Y := types.NewPackage("Y", "", []*types.Package{X}, []*types.Package{})
|
||||
Z := types.NewPackage("Z", "", []*types.Package{X}, []*types.Package{})
|
||||
|
||||
for _, p := range []pkg.Package{X, Y, Z} {
|
||||
for _, p := range []*types.Package{X, Y, Z} {
|
||||
_, err := dbDefinitions.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
for _, p := range []pkg.Package{} {
|
||||
for _, p := range []*types.Package{} {
|
||||
_, err := dbInstalled.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
solution, err := s.Install([]pkg.Package{Y})
|
||||
solution, err := s.Install([]*types.Package{Y})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
solution2, err := s.Install([]pkg.Package{Z})
|
||||
solution2, err := s.Install([]*types.Package{Z})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
orderY, err := solution.Order(dbDefinitions, Y.GetFingerPrint())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
@@ -314,27 +314,27 @@ var _ = Describe("Decoder", func() {
|
||||
|
||||
It("Unique hashes for single packages", func() {
|
||||
|
||||
X := pkg.NewPackage("X", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
F := pkg.NewPackage("F", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
D := pkg.NewPackage("X", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
X := types.NewPackage("X", "", []*types.Package{}, []*types.Package{})
|
||||
F := types.NewPackage("F", "", []*types.Package{}, []*types.Package{})
|
||||
D := types.NewPackage("X", "", []*types.Package{}, []*types.Package{})
|
||||
|
||||
for _, p := range []pkg.Package{X, F, D} {
|
||||
for _, p := range []*types.Package{X, F, D} {
|
||||
_, err := dbDefinitions.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
for _, p := range []pkg.Package{} {
|
||||
for _, p := range []*types.Package{} {
|
||||
_, err := dbInstalled.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
solution, err := s.Install([]pkg.Package{X})
|
||||
solution, err := s.Install([]*types.Package{X})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
solution2, err := s.Install([]pkg.Package{F})
|
||||
solution2, err := s.Install([]*types.Package{F})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
solution3, err := s.Install([]pkg.Package{D})
|
||||
solution3, err := s.Install([]*types.Package{D})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(solution.AssertionHash()).ToNot(Equal(solution2.AssertionHash()))
|
||||
@@ -343,41 +343,41 @@ var _ = Describe("Decoder", func() {
|
||||
})
|
||||
|
||||
It("Unique hashes for empty assertions", func() {
|
||||
empty := solver.PackagesAssertions{}
|
||||
empty2 := solver.PackagesAssertions{}
|
||||
empty := types.PackagesAssertions{}
|
||||
empty2 := types.PackagesAssertions{}
|
||||
|
||||
Expect(empty.AssertionHash()).To(Equal(empty2.AssertionHash()))
|
||||
})
|
||||
|
||||
It("Unique hashes for single packages with HashFrom", func() {
|
||||
|
||||
X := pkg.NewPackage("X", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
F := pkg.NewPackage("F", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
D := pkg.NewPackage("X", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
Y := pkg.NewPackage("Y", "", []*pkg.DefaultPackage{X}, []*pkg.DefaultPackage{})
|
||||
X := types.NewPackage("X", "", []*types.Package{}, []*types.Package{})
|
||||
F := types.NewPackage("F", "", []*types.Package{}, []*types.Package{})
|
||||
D := types.NewPackage("X", "", []*types.Package{}, []*types.Package{})
|
||||
Y := types.NewPackage("Y", "", []*types.Package{X}, []*types.Package{})
|
||||
|
||||
empty := solver.PackagesAssertions{}
|
||||
empty := types.PackagesAssertions{}
|
||||
|
||||
for _, p := range []pkg.Package{X, F, D, Y} {
|
||||
for _, p := range []*types.Package{X, F, D, Y} {
|
||||
_, err := dbDefinitions.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
for _, p := range []pkg.Package{} {
|
||||
for _, p := range []*types.Package{} {
|
||||
_, err := dbInstalled.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
solution, err := s.Install([]pkg.Package{X})
|
||||
solution, err := s.Install([]*types.Package{X})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
solution2, err := s.Install([]pkg.Package{F})
|
||||
solution2, err := s.Install([]*types.Package{F})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
solution3, err := s.Install([]pkg.Package{D})
|
||||
solution3, err := s.Install([]*types.Package{D})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
solution4, err := s.Install([]pkg.Package{Y})
|
||||
solution4, err := s.Install([]*types.Package{Y})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(solution.HashFrom(X)).ToNot(Equal(solution2.HashFrom(F)))
|
||||
@@ -395,22 +395,22 @@ var _ = Describe("Decoder", func() {
|
||||
|
||||
It("Always same solution", func() {
|
||||
|
||||
X := pkg.NewPackage("X", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
Y := pkg.NewPackage("Y", "", []*pkg.DefaultPackage{X}, []*pkg.DefaultPackage{})
|
||||
Z := pkg.NewPackage("Z", "", []*pkg.DefaultPackage{X}, []*pkg.DefaultPackage{})
|
||||
W := pkg.NewPackage("W", "", []*pkg.DefaultPackage{Z, Y}, []*pkg.DefaultPackage{})
|
||||
X := types.NewPackage("X", "", []*types.Package{}, []*types.Package{})
|
||||
Y := types.NewPackage("Y", "", []*types.Package{X}, []*types.Package{})
|
||||
Z := types.NewPackage("Z", "", []*types.Package{X}, []*types.Package{})
|
||||
W := types.NewPackage("W", "", []*types.Package{Z, Y}, []*types.Package{})
|
||||
|
||||
for _, p := range []pkg.Package{X, Y, Z} {
|
||||
for _, p := range []*types.Package{X, Y, Z} {
|
||||
_, err := dbDefinitions.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
for _, p := range []pkg.Package{} {
|
||||
for _, p := range []*types.Package{} {
|
||||
_, err := dbInstalled.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
solution, err := s.Install([]pkg.Package{W})
|
||||
solution, err := s.Install([]*types.Package{W})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
orderW, err := solution.Order(dbDefinitions, W.GetFingerPrint())
|
||||
|
135
pkg/solver/explainer.go
Normal file
135
pkg/solver/explainer.go
Normal file
@@ -0,0 +1,135 @@
|
||||
// Copyright © 2021-2022 Ettore Di Giacinto <mudler@mocaccino.org>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package solver
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/crillab/gophersat/bf"
|
||||
"github.com/crillab/gophersat/explain"
|
||||
types "github.com/mudler/luet/pkg/api/core/types"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type Explainer struct{}
|
||||
|
||||
func decodeDimacs(vars map[string]string, dimacs string) (string, error) {
|
||||
res := ""
|
||||
sc := bufio.NewScanner(bytes.NewBufferString(dimacs))
|
||||
lines := strings.Split(dimacs, "\n")
|
||||
linenum := 1
|
||||
SCAN:
|
||||
for sc.Scan() {
|
||||
|
||||
line := sc.Text()
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) == 0 {
|
||||
continue
|
||||
}
|
||||
switch fields[0] {
|
||||
case "p":
|
||||
continue SCAN
|
||||
default:
|
||||
for i := 0; i < len(fields)-1; i++ {
|
||||
v := fields[i]
|
||||
negative := false
|
||||
if strings.HasPrefix(fields[i], "-") {
|
||||
v = strings.TrimLeft(fields[i], "-")
|
||||
negative = true
|
||||
}
|
||||
variable := vars[v]
|
||||
if negative {
|
||||
res += fmt.Sprintf("!(%s)", variable)
|
||||
} else {
|
||||
res += variable
|
||||
}
|
||||
|
||||
if i != len(fields)-2 {
|
||||
res += fmt.Sprintf(" or ")
|
||||
}
|
||||
}
|
||||
if linenum != len(lines)-1 {
|
||||
res += fmt.Sprintf(" and \n")
|
||||
}
|
||||
}
|
||||
linenum++
|
||||
}
|
||||
if err := sc.Err(); err != nil {
|
||||
return res, fmt.Errorf("could not parse problem: %v", err)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func parseVars(r io.Reader) (map[string]string, error) {
|
||||
sc := bufio.NewScanner(r)
|
||||
res := map[string]string{}
|
||||
for sc.Scan() {
|
||||
line := sc.Text()
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) == 0 {
|
||||
continue
|
||||
}
|
||||
switch fields[0] {
|
||||
case "c":
|
||||
data := strings.Split(fields[1], "=")
|
||||
res[data[1]] = data[0]
|
||||
|
||||
default:
|
||||
continue
|
||||
|
||||
}
|
||||
}
|
||||
if err := sc.Err(); err != nil {
|
||||
return nil, fmt.Errorf("could not parse problem: %v", err)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Solve tries to find the MUS (minimum unsat) formula from the original problem.
|
||||
// it returns an error with the decoded dimacs
|
||||
func (*Explainer) Solve(f bf.Formula, s types.PackageSolver) (types.PackagesAssertions, error) {
|
||||
buf := bytes.NewBufferString("")
|
||||
if err := bf.Dimacs(f, buf); err != nil {
|
||||
return nil, errors.Wrap(err, "cannot extract dimacs from formula")
|
||||
}
|
||||
|
||||
copy := *buf
|
||||
|
||||
pb, err := explain.ParseCNF(©)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not parse problem")
|
||||
}
|
||||
pb2, err := pb.MUS()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not extract subset")
|
||||
}
|
||||
|
||||
variables, err := parseVars(buf)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not parse variables")
|
||||
}
|
||||
|
||||
res, err := decodeDimacs(variables, pb2.CNF())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not parse dimacs")
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("could not satisfy the constraints: \n%s", res)
|
||||
}
|
@@ -16,21 +16,16 @@
|
||||
package solver
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/crillab/gophersat/bf"
|
||||
"github.com/crillab/gophersat/explain"
|
||||
"github.com/mudler/luet/pkg/api/core/types"
|
||||
"github.com/mudler/luet/pkg/helpers"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/ecooper/qlearning"
|
||||
pkg "github.com/mudler/luet/pkg/package"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -56,117 +51,6 @@ const (
|
||||
QLearningResolverType = "qlearning"
|
||||
)
|
||||
|
||||
// PackageResolver assists PackageSolver on unsat cases
|
||||
type PackageResolver interface {
|
||||
Solve(bf.Formula, PackageSolver) (PackagesAssertions, error)
|
||||
}
|
||||
|
||||
type Explainer struct{}
|
||||
|
||||
func decodeDimacs(vars map[string]string, dimacs string) (string, error) {
|
||||
res := ""
|
||||
sc := bufio.NewScanner(bytes.NewBufferString(dimacs))
|
||||
lines := strings.Split(dimacs, "\n")
|
||||
linenum := 1
|
||||
SCAN:
|
||||
for sc.Scan() {
|
||||
|
||||
line := sc.Text()
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) == 0 {
|
||||
continue
|
||||
}
|
||||
switch fields[0] {
|
||||
case "p":
|
||||
continue SCAN
|
||||
default:
|
||||
for i := 0; i < len(fields)-1; i++ {
|
||||
v := fields[i]
|
||||
negative := false
|
||||
if strings.HasPrefix(fields[i], "-") {
|
||||
v = strings.TrimLeft(fields[i], "-")
|
||||
negative = true
|
||||
}
|
||||
variable := vars[v]
|
||||
if negative {
|
||||
res += fmt.Sprintf("!(%s)", variable)
|
||||
} else {
|
||||
res += variable
|
||||
}
|
||||
|
||||
if i != len(fields)-2 {
|
||||
res += fmt.Sprintf(" or ")
|
||||
}
|
||||
}
|
||||
if linenum != len(lines)-1 {
|
||||
res += fmt.Sprintf(" and \n")
|
||||
}
|
||||
}
|
||||
linenum++
|
||||
}
|
||||
if err := sc.Err(); err != nil {
|
||||
return res, fmt.Errorf("could not parse problem: %v", err)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func parseVars(r io.Reader) (map[string]string, error) {
|
||||
sc := bufio.NewScanner(r)
|
||||
res := map[string]string{}
|
||||
for sc.Scan() {
|
||||
line := sc.Text()
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) == 0 {
|
||||
continue
|
||||
}
|
||||
switch fields[0] {
|
||||
case "c":
|
||||
data := strings.Split(fields[1], "=")
|
||||
res[data[1]] = data[0]
|
||||
|
||||
default:
|
||||
continue
|
||||
|
||||
}
|
||||
}
|
||||
if err := sc.Err(); err != nil {
|
||||
return nil, fmt.Errorf("could not parse problem: %v", err)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Solve tries to find the MUS (minimum unsat) formula from the original problem.
|
||||
// it returns an error with the decoded dimacs
|
||||
func (*Explainer) Solve(f bf.Formula, s PackageSolver) (PackagesAssertions, error) {
|
||||
buf := bytes.NewBufferString("")
|
||||
if err := bf.Dimacs(f, buf); err != nil {
|
||||
return nil, errors.Wrap(err, "cannot extract dimacs from formula")
|
||||
}
|
||||
|
||||
copy := *buf
|
||||
|
||||
pb, err := explain.ParseCNF(©)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not parse problem")
|
||||
}
|
||||
pb2, err := pb.MUS()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not extract subset")
|
||||
}
|
||||
|
||||
variables, err := parseVars(buf)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not parse variables")
|
||||
}
|
||||
|
||||
res, err := decodeDimacs(variables, pb2.CNF())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not parse dimacs")
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("could not satisfy the constraints: \n%s", res)
|
||||
}
|
||||
|
||||
type QLearningResolver struct {
|
||||
Attempts int
|
||||
|
||||
@@ -176,24 +60,24 @@ type QLearningResolver struct {
|
||||
|
||||
Attempted map[string]bool
|
||||
|
||||
Solver PackageSolver
|
||||
Solver types.PackageSolver
|
||||
Formula bf.Formula
|
||||
|
||||
Targets pkg.Packages
|
||||
Current pkg.Packages
|
||||
Targets types.Packages
|
||||
Current types.Packages
|
||||
|
||||
observedDelta int
|
||||
observedDeltaChoice pkg.Packages
|
||||
observedDeltaChoice types.Packages
|
||||
|
||||
Agent *qlearning.SimpleAgent
|
||||
}
|
||||
|
||||
func SimpleQLearningSolver() PackageResolver {
|
||||
func SimpleQLearningSolver() types.PackageResolver {
|
||||
return NewQLearningResolver(DefaultLearningRate, DefaultDiscount, DefaultMaxAttempts, DefaultInitialObserved)
|
||||
}
|
||||
|
||||
// Defaults LearningRate 0.7, Discount 1.0
|
||||
func NewQLearningResolver(LearningRate, Discount float32, MaxAttempts, initialObservedDelta int) PackageResolver {
|
||||
func NewQLearningResolver(LearningRate, Discount float32, MaxAttempts, initialObservedDelta int) types.PackageResolver {
|
||||
return &QLearningResolver{
|
||||
Agent: qlearning.NewSimpleAgent(LearningRate, Discount),
|
||||
observedDelta: initialObservedDelta,
|
||||
@@ -201,7 +85,7 @@ func NewQLearningResolver(LearningRate, Discount float32, MaxAttempts, initialOb
|
||||
}
|
||||
}
|
||||
|
||||
func (resolver *QLearningResolver) Solve(f bf.Formula, s PackageSolver) (PackagesAssertions, error) {
|
||||
func (resolver *QLearningResolver) Solve(f bf.Formula, s types.PackageSolver) (types.PackagesAssertions, error) {
|
||||
// Info("Using QLearning solver to resolve conflicts. Please be patient.")
|
||||
resolver.Solver = s
|
||||
|
||||
@@ -276,10 +160,10 @@ func (resolver *QLearningResolver) IsComplete() int {
|
||||
|
||||
func (resolver *QLearningResolver) Try(c Choice) error {
|
||||
pack := c.Package
|
||||
packtoAdd := pkg.FromString(pack)
|
||||
packtoAdd := types.PackageFromString(pack)
|
||||
resolver.Attempted[pack+strconv.Itoa(int(c.Action))] = true // increase the count
|
||||
s, _ := resolver.Solver.(*Solver)
|
||||
var filtered pkg.Packages
|
||||
var filtered types.Packages
|
||||
|
||||
switch c.Action {
|
||||
case ActionAdded:
|
||||
|
@@ -16,7 +16,9 @@
|
||||
package solver_test
|
||||
|
||||
import (
|
||||
pkg "github.com/mudler/luet/pkg/package"
|
||||
"github.com/mudler/luet/pkg/api/core/types"
|
||||
|
||||
pkg "github.com/mudler/luet/pkg/database"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
@@ -28,65 +30,65 @@ var _ = Describe("Resolver", func() {
|
||||
db := pkg.NewInMemoryDatabase(false)
|
||||
dbInstalled := pkg.NewInMemoryDatabase(false)
|
||||
dbDefinitions := pkg.NewInMemoryDatabase(false)
|
||||
s := NewSolver(Options{Type: SingleCoreSimple}, dbInstalled, dbDefinitions, db)
|
||||
s := NewSolver(types.SolverOptions{Type: types.SolverSingleCoreSimple}, dbInstalled, dbDefinitions, db)
|
||||
|
||||
BeforeEach(func() {
|
||||
db = pkg.NewInMemoryDatabase(false)
|
||||
dbInstalled = pkg.NewInMemoryDatabase(false)
|
||||
dbDefinitions = pkg.NewInMemoryDatabase(false)
|
||||
s = NewSolver(Options{Type: SingleCoreSimple}, dbInstalled, dbDefinitions, db)
|
||||
s = NewSolver(types.SolverOptions{Type: types.SolverSingleCoreSimple}, dbInstalled, dbDefinitions, db)
|
||||
})
|
||||
|
||||
Context("Conflict set", func() {
|
||||
Context("Explainer", func() {
|
||||
It("is unsolvable - as we something we ask to install conflict with system stuff", func() {
|
||||
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{C})
|
||||
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
|
||||
C := types.NewPackage("C", "", []*types.Package{}, []*types.Package{})
|
||||
B := types.NewPackage("B", "", []*types.Package{}, []*types.Package{C})
|
||||
A := types.NewPackage("A", "", []*types.Package{B}, []*types.Package{})
|
||||
|
||||
for _, p := range []pkg.Package{A, B, C} {
|
||||
for _, p := range []*types.Package{A, B, C} {
|
||||
_, err := dbDefinitions.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
for _, p := range []pkg.Package{C} {
|
||||
for _, p := range []*types.Package{C} {
|
||||
_, err := dbInstalled.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
solution, err := s.Install([]pkg.Package{A})
|
||||
solution, err := s.Install([]*types.Package{A})
|
||||
Expect(len(solution)).To(Equal(0))
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
It("succeeds to install D and F if explictly requested", func() {
|
||||
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{C})
|
||||
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
|
||||
D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
E := pkg.NewPackage("E", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
|
||||
F := pkg.NewPackage("F", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
C := types.NewPackage("C", "", []*types.Package{}, []*types.Package{})
|
||||
B := types.NewPackage("B", "", []*types.Package{}, []*types.Package{C})
|
||||
A := types.NewPackage("A", "", []*types.Package{B}, []*types.Package{})
|
||||
D := types.NewPackage("D", "", []*types.Package{}, []*types.Package{})
|
||||
E := types.NewPackage("E", "", []*types.Package{B}, []*types.Package{})
|
||||
F := types.NewPackage("F", "", []*types.Package{}, []*types.Package{})
|
||||
|
||||
for _, p := range []pkg.Package{A, B, C, D, E, F} {
|
||||
for _, p := range []*types.Package{A, B, C, D, E, F} {
|
||||
_, err := dbDefinitions.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
for _, p := range []pkg.Package{C} {
|
||||
for _, p := range []*types.Package{C} {
|
||||
_, err := dbInstalled.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
solution, err := s.Install([]pkg.Package{D, F}) // D and F should go as they have no deps. A/E should be filtered by QLearn
|
||||
solution, err := s.Install([]*types.Package{D, F}) // D and F should go as they have no deps. A/E should be filtered by QLearn
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(len(solution)).To(Equal(6))
|
||||
|
||||
Expect(solution).ToNot(ContainElement(PackageAssert{Package: A, Value: true}))
|
||||
Expect(solution).ToNot(ContainElement(PackageAssert{Package: B, Value: true}))
|
||||
Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true}))
|
||||
Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: true}))
|
||||
Expect(solution).ToNot(ContainElement(PackageAssert{Package: E, Value: true}))
|
||||
Expect(solution).To(ContainElement(PackageAssert{Package: F, Value: true}))
|
||||
Expect(solution).ToNot(ContainElement(types.PackageAssert{Package: A, Value: true}))
|
||||
Expect(solution).ToNot(ContainElement(types.PackageAssert{Package: B, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: C, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: D, Value: true}))
|
||||
Expect(solution).ToNot(ContainElement(types.PackageAssert{Package: E, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: F, Value: true}))
|
||||
|
||||
})
|
||||
|
||||
@@ -94,82 +96,82 @@ var _ = Describe("Resolver", func() {
|
||||
Context("QLearningResolver", func() {
|
||||
It("will find out that we can install D by ignoring A", func() {
|
||||
s.SetResolver(SimpleQLearningSolver())
|
||||
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{C})
|
||||
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
|
||||
D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
C := types.NewPackage("C", "", []*types.Package{}, []*types.Package{})
|
||||
B := types.NewPackage("B", "", []*types.Package{}, []*types.Package{C})
|
||||
A := types.NewPackage("A", "", []*types.Package{B}, []*types.Package{})
|
||||
D := types.NewPackage("D", "", []*types.Package{}, []*types.Package{})
|
||||
|
||||
for _, p := range []pkg.Package{A, B, C, D} {
|
||||
for _, p := range []*types.Package{A, B, C, D} {
|
||||
_, err := dbDefinitions.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
for _, p := range []pkg.Package{C} {
|
||||
for _, p := range []*types.Package{C} {
|
||||
_, err := dbInstalled.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
solution, err := s.Install([]pkg.Package{A, D})
|
||||
solution, err := s.Install([]*types.Package{A, D})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(solution).ToNot(ContainElement(PackageAssert{Package: A, Value: true}))
|
||||
Expect(solution).ToNot(ContainElement(PackageAssert{Package: B, Value: true}))
|
||||
Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true}))
|
||||
Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: true}))
|
||||
Expect(solution).ToNot(ContainElement(types.PackageAssert{Package: A, Value: true}))
|
||||
Expect(solution).ToNot(ContainElement(types.PackageAssert{Package: B, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: C, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: D, Value: true}))
|
||||
|
||||
Expect(len(solution)).To(Equal(4))
|
||||
})
|
||||
|
||||
It("will find out that we can install D and F by ignoring E and A", func() {
|
||||
s.SetResolver(SimpleQLearningSolver())
|
||||
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{C})
|
||||
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
|
||||
D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
E := pkg.NewPackage("E", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
|
||||
F := pkg.NewPackage("F", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
C := types.NewPackage("C", "", []*types.Package{}, []*types.Package{})
|
||||
B := types.NewPackage("B", "", []*types.Package{}, []*types.Package{C})
|
||||
A := types.NewPackage("A", "", []*types.Package{B}, []*types.Package{})
|
||||
D := types.NewPackage("D", "", []*types.Package{}, []*types.Package{})
|
||||
E := types.NewPackage("E", "", []*types.Package{B}, []*types.Package{})
|
||||
F := types.NewPackage("F", "", []*types.Package{}, []*types.Package{})
|
||||
|
||||
for _, p := range []pkg.Package{A, B, C, D, E, F} {
|
||||
for _, p := range []*types.Package{A, B, C, D, E, F} {
|
||||
_, err := dbDefinitions.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
for _, p := range []pkg.Package{C} {
|
||||
for _, p := range []*types.Package{C} {
|
||||
_, err := dbInstalled.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
solution, err := s.Install([]pkg.Package{A, D, E, F}) // D and F should go as they have no deps. A/E should be filtered by QLearn
|
||||
solution, err := s.Install([]*types.Package{A, D, E, F}) // D and F should go as they have no deps. A/E should be filtered by QLearn
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(solution).ToNot(ContainElement(PackageAssert{Package: A, Value: true}))
|
||||
Expect(solution).ToNot(ContainElement(PackageAssert{Package: B, Value: true}))
|
||||
Expect(solution).To(ContainElement(PackageAssert{Package: C, Value: true})) // Was already installed
|
||||
Expect(solution).To(ContainElement(PackageAssert{Package: D, Value: true}))
|
||||
Expect(solution).ToNot(ContainElement(PackageAssert{Package: E, Value: true}))
|
||||
Expect(solution).To(ContainElement(PackageAssert{Package: F, Value: true}))
|
||||
Expect(solution).ToNot(ContainElement(types.PackageAssert{Package: A, Value: true}))
|
||||
Expect(solution).ToNot(ContainElement(types.PackageAssert{Package: B, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: C, Value: true})) // Was already installed
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: D, Value: true}))
|
||||
Expect(solution).ToNot(ContainElement(types.PackageAssert{Package: E, Value: true}))
|
||||
Expect(solution).To(ContainElement(types.PackageAssert{Package: F, Value: true}))
|
||||
Expect(len(solution)).To(Equal(6))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Explainer", func() {
|
||||
It("cannot find a solution", func() {
|
||||
C := pkg.NewPackage("C", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
B := pkg.NewPackage("B", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{C})
|
||||
A := pkg.NewPackage("A", "", []*pkg.DefaultPackage{B}, []*pkg.DefaultPackage{})
|
||||
D := pkg.NewPackage("D", "", []*pkg.DefaultPackage{}, []*pkg.DefaultPackage{})
|
||||
C := types.NewPackage("C", "", []*types.Package{}, []*types.Package{})
|
||||
B := types.NewPackage("B", "", []*types.Package{}, []*types.Package{C})
|
||||
A := types.NewPackage("A", "", []*types.Package{B}, []*types.Package{})
|
||||
D := types.NewPackage("D", "", []*types.Package{}, []*types.Package{})
|
||||
|
||||
for _, p := range []pkg.Package{A, B, C, D} {
|
||||
for _, p := range []*types.Package{A, B, C, D} {
|
||||
_, err := dbDefinitions.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
for _, p := range []pkg.Package{C} {
|
||||
for _, p := range []*types.Package{C} {
|
||||
_, err := dbInstalled.CreatePackage(p)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
solution, err := s.Install([]pkg.Package{A, D})
|
||||
solution, err := s.Install([]*types.Package{A, D})
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.Error()).To(Equal(`could not satisfy the constraints:
|
||||
A-- and
|
||||
|
@@ -19,68 +19,52 @@ import (
|
||||
|
||||
//. "github.com/mudler/luet/pkg/logger"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/crillab/gophersat/bf"
|
||||
pkg "github.com/mudler/luet/pkg/package"
|
||||
"github.com/mudler/luet/pkg/api/core/types"
|
||||
pkg "github.com/mudler/luet/pkg/database"
|
||||
)
|
||||
|
||||
type SolverType int
|
||||
|
||||
const (
|
||||
SingleCoreSimple = 0
|
||||
)
|
||||
|
||||
// PackageSolver is an interface to a generic package solving algorithm
|
||||
type PackageSolver interface {
|
||||
SetDefinitionDatabase(pkg.PackageDatabase)
|
||||
Install(p pkg.Packages) (PackagesAssertions, error)
|
||||
RelaxedInstall(p pkg.Packages) (PackagesAssertions, error)
|
||||
|
||||
Uninstall(checkconflicts, full bool, candidate ...pkg.Package) (pkg.Packages, error)
|
||||
ConflictsWithInstalled(p pkg.Package) (bool, error)
|
||||
ConflictsWith(p pkg.Package, ls pkg.Packages) (bool, error)
|
||||
Conflicts(pack pkg.Package, lsp pkg.Packages) (bool, error)
|
||||
|
||||
World() pkg.Packages
|
||||
Upgrade(checkconflicts, full bool) (pkg.Packages, PackagesAssertions, error)
|
||||
|
||||
UpgradeUniverse(dropremoved bool) (pkg.Packages, PackagesAssertions, error)
|
||||
UninstallUniverse(toremove pkg.Packages) (pkg.Packages, error)
|
||||
|
||||
SetResolver(PackageResolver)
|
||||
|
||||
Solve() (PackagesAssertions, error)
|
||||
// BestInstall(c pkg.Packages) (PackagesAssertions, error)
|
||||
}
|
||||
var AvailableResolvers = strings.Join([]string{QLearningResolverType}, " ")
|
||||
|
||||
// Solver is the default solver for luet
|
||||
type Solver struct {
|
||||
DefinitionDatabase pkg.PackageDatabase
|
||||
SolverDatabase pkg.PackageDatabase
|
||||
Wanted pkg.Packages
|
||||
InstalledDatabase pkg.PackageDatabase
|
||||
DefinitionDatabase types.PackageDatabase
|
||||
SolverDatabase types.PackageDatabase
|
||||
Wanted types.Packages
|
||||
InstalledDatabase types.PackageDatabase
|
||||
|
||||
Resolver PackageResolver
|
||||
}
|
||||
|
||||
type Options struct {
|
||||
Type SolverType `yaml:"type,omitempty"`
|
||||
Concurrency int `yaml:"concurrency,omitempty"`
|
||||
Resolver types.PackageResolver
|
||||
}
|
||||
|
||||
// NewSolver accepts as argument two lists of packages, the first is the initial set,
|
||||
// the second represent all the known packages.
|
||||
func NewSolver(t Options, installed pkg.PackageDatabase, definitiondb pkg.PackageDatabase, solverdb pkg.PackageDatabase) PackageSolver {
|
||||
func NewSolver(t types.SolverOptions, installed types.PackageDatabase, definitiondb types.PackageDatabase, solverdb types.PackageDatabase) types.PackageSolver {
|
||||
return NewResolver(t, installed, definitiondb, solverdb, &Explainer{})
|
||||
}
|
||||
|
||||
func NewSolverFromOptions(t types.LuetSolverOptions) types.PackageResolver {
|
||||
switch t.Type {
|
||||
case QLearningResolverType:
|
||||
if t.LearnRate != 0.0 {
|
||||
return NewQLearningResolver(t.LearnRate, t.Discount, t.MaxAttempts, 999999)
|
||||
|
||||
}
|
||||
return SimpleQLearningSolver()
|
||||
}
|
||||
|
||||
return &Explainer{}
|
||||
|
||||
}
|
||||
|
||||
// NewResolver accepts as argument two lists of packages, the first is the initial set,
|
||||
// the second represent all the known packages.
|
||||
// Using constructors as in the future we foresee warmups for hot-restore solver cache
|
||||
func NewResolver(t Options, installed pkg.PackageDatabase, definitiondb pkg.PackageDatabase, solverdb pkg.PackageDatabase, re PackageResolver) PackageSolver {
|
||||
var s PackageSolver
|
||||
func NewResolver(t types.SolverOptions, installed types.PackageDatabase, definitiondb types.PackageDatabase, solverdb types.PackageDatabase, re types.PackageResolver) types.PackageSolver {
|
||||
var s types.PackageSolver
|
||||
switch t.Type {
|
||||
default:
|
||||
s = &Solver{InstalledDatabase: installed, DefinitionDatabase: definitiondb, SolverDatabase: solverdb, Resolver: re}
|
||||
@@ -91,20 +75,20 @@ func NewResolver(t Options, installed pkg.PackageDatabase, definitiondb pkg.Pack
|
||||
|
||||
// SetDefinitionDatabase is a setter for the definition Database
|
||||
|
||||
func (s *Solver) SetDefinitionDatabase(db pkg.PackageDatabase) {
|
||||
func (s *Solver) SetDefinitionDatabase(db types.PackageDatabase) {
|
||||
s.DefinitionDatabase = db
|
||||
}
|
||||
|
||||
// SetResolver is a setter for the unsat resolver backend
|
||||
func (s *Solver) SetResolver(r PackageResolver) {
|
||||
func (s *Solver) SetResolver(r types.PackageResolver) {
|
||||
s.Resolver = r
|
||||
}
|
||||
|
||||
func (s *Solver) World() pkg.Packages {
|
||||
func (s *Solver) World() types.Packages {
|
||||
return s.DefinitionDatabase.World()
|
||||
}
|
||||
|
||||
func (s *Solver) Installed() pkg.Packages {
|
||||
func (s *Solver) Installed() types.Packages {
|
||||
|
||||
return s.InstalledDatabase.World()
|
||||
}
|
||||
@@ -131,7 +115,7 @@ func (s *Solver) noRulesInstalled() bool {
|
||||
|
||||
func (s *Solver) BuildInstalled() (bf.Formula, error) {
|
||||
var formulas []bf.Formula
|
||||
var packages pkg.Packages
|
||||
var packages types.Packages
|
||||
for _, p := range s.Installed() {
|
||||
packages = append(packages, p)
|
||||
for _, dep := range p.Related(s.InstalledDatabase) {
|
||||
@@ -190,7 +174,7 @@ func (s *Solver) BuildPartialWorld(includeInstalled bool) (bf.Formula, error) {
|
||||
formulas = append(formulas, solvable)
|
||||
}
|
||||
|
||||
var packages pkg.Packages
|
||||
var packages types.Packages
|
||||
for _, p := range s.Wanted {
|
||||
// packages = append(packages, p)
|
||||
for _, dep := range p.Related(s.DefinitionDatabase) {
|
||||
@@ -214,8 +198,8 @@ func (s *Solver) BuildPartialWorld(includeInstalled bool) (bf.Formula, error) {
|
||||
return bf.True, nil
|
||||
}
|
||||
|
||||
func (s *Solver) getList(db pkg.PackageDatabase, lsp pkg.Packages) (pkg.Packages, error) {
|
||||
var ls pkg.Packages
|
||||
func (s *Solver) getList(db types.PackageDatabase, lsp types.Packages) (types.Packages, error) {
|
||||
var ls types.Packages
|
||||
|
||||
for _, pp := range lsp {
|
||||
cp, err := db.FindPackage(pp)
|
||||
@@ -235,7 +219,7 @@ func (s *Solver) getList(db pkg.PackageDatabase, lsp pkg.Packages) (pkg.Packages
|
||||
|
||||
// Conflicts acts like ConflictsWith, but uses package's reverse dependencies to
|
||||
// determine if it conflicts with the given set
|
||||
func (s *Solver) Conflicts(pack pkg.Package, lsp pkg.Packages) (bool, error) {
|
||||
func (s *Solver) Conflicts(pack *types.Package, lsp types.Packages) (bool, error) {
|
||||
p, err := s.DefinitionDatabase.FindPackage(pack)
|
||||
if err != nil {
|
||||
p = pack
|
||||
@@ -273,7 +257,7 @@ func (s *Solver) Conflicts(pack pkg.Package, lsp pkg.Packages) (bool, error) {
|
||||
|
||||
// ConflictsWith return true if a package is part of the requirement set of a list of package
|
||||
// return false otherwise (and thus it is NOT relevant to the given list)
|
||||
func (s *Solver) ConflictsWith(pack pkg.Package, lsp pkg.Packages) (bool, error) {
|
||||
func (s *Solver) ConflictsWith(pack *types.Package, lsp types.Packages) (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
|
||||
@@ -329,7 +313,7 @@ func (s *Solver) ConflictsWith(pack pkg.Package, lsp pkg.Packages) (bool, error)
|
||||
|
||||
}
|
||||
|
||||
func (s *Solver) ConflictsWithInstalled(p pkg.Package) (bool, error) {
|
||||
func (s *Solver) ConflictsWithInstalled(p *types.Package) (bool, error) {
|
||||
return s.ConflictsWith(p, s.Installed())
|
||||
}
|
||||
|
||||
@@ -339,7 +323,7 @@ func (s *Solver) ConflictsWithInstalled(p pkg.Package) (bool, error) {
|
||||
// It can be compared to the counterpart Uninstall as this method acts like a uninstall --full
|
||||
// it removes all the packages and its deps. taking also in consideration other packages that might have
|
||||
// revdeps
|
||||
func (s *Solver) UninstallUniverse(toremove pkg.Packages) (pkg.Packages, error) {
|
||||
func (s *Solver) UninstallUniverse(toremove types.Packages) (types.Packages, error) {
|
||||
|
||||
if s.noRulesInstalled() {
|
||||
return s.getList(s.InstalledDatabase, toremove)
|
||||
@@ -367,7 +351,7 @@ func (s *Solver) UninstallUniverse(toremove pkg.Packages) (pkg.Packages, error)
|
||||
formulas = append(formulas, bf.And(bf.Not(P), r))
|
||||
}
|
||||
|
||||
markedForRemoval := pkg.Packages{}
|
||||
markedForRemoval := types.Packages{}
|
||||
model := bf.Solve(bf.And(formulas...))
|
||||
if model == nil {
|
||||
return nil, errors.New("Failed finding a solution")
|
||||
@@ -390,14 +374,14 @@ func (s *Solver) UninstallUniverse(toremove pkg.Packages) (pkg.Packages, error)
|
||||
// UpgradeUniverse mark packages for removal and returns a solution. It considers
|
||||
// the Universe db as authoritative
|
||||
// See also on the subject: https://arxiv.org/pdf/1007.1021.pdf
|
||||
func (s *Solver) UpgradeUniverse(dropremoved bool) (pkg.Packages, PackagesAssertions, error) {
|
||||
func (s *Solver) UpgradeUniverse(dropremoved bool) (types.Packages, types.PackagesAssertions, error) {
|
||||
// we first figure out which aren't up-to-date
|
||||
// which has to be removed
|
||||
// and which needs to be upgraded
|
||||
notUptodate := pkg.Packages{}
|
||||
removed := pkg.Packages{}
|
||||
toUpgrade := pkg.Packages{}
|
||||
replacements := map[pkg.Package]pkg.Package{}
|
||||
notUptodate := types.Packages{}
|
||||
removed := types.Packages{}
|
||||
toUpgrade := types.Packages{}
|
||||
replacements := map[*types.Package]*types.Package{}
|
||||
|
||||
// TODO: this is memory expensive, we need to optimize this
|
||||
universe, err := s.DefinitionDatabase.Copy()
|
||||
@@ -467,10 +451,10 @@ func (s *Solver) UpgradeUniverse(dropremoved bool) (pkg.Packages, PackagesAssert
|
||||
|
||||
//formulas = append(formulas, r)
|
||||
|
||||
markedForRemoval := pkg.Packages{}
|
||||
markedForRemoval := types.Packages{}
|
||||
|
||||
if len(formulas) == 0 {
|
||||
return pkg.Packages{}, PackagesAssertions{}, nil
|
||||
return types.Packages{}, types.PackagesAssertions{}, nil
|
||||
}
|
||||
model := bf.Solve(bf.And(formulas...))
|
||||
if model == nil {
|
||||
@@ -493,7 +477,7 @@ func (s *Solver) UpgradeUniverse(dropremoved bool) (pkg.Packages, PackagesAssert
|
||||
return markedForRemoval, assertion, nil
|
||||
}
|
||||
|
||||
func inPackage(list []pkg.Package, p pkg.Package) bool {
|
||||
func inPackage(list []*types.Package, p *types.Package) bool {
|
||||
for _, l := range list {
|
||||
if l.AtomMatches(p) {
|
||||
return true
|
||||
@@ -503,10 +487,10 @@ 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(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{}
|
||||
func (s *Solver) computeUpgrade(ppsToUpgrade, ppsToNotUpgrade []*types.Package) func(defDB types.PackageDatabase, installDB types.PackageDatabase) (types.Packages, types.Packages, types.PackageDatabase, []*types.Package) {
|
||||
return func(defDB types.PackageDatabase, installDB types.PackageDatabase) (types.Packages, types.Packages, types.PackageDatabase, []*types.Package) {
|
||||
toUninstall := types.Packages{}
|
||||
toInstall := types.Packages{}
|
||||
|
||||
// we do this in memory so we take into account of provides, and its faster
|
||||
universe, _ := defDB.Copy()
|
||||
@@ -535,15 +519,25 @@ func (s *Solver) computeUpgrade(ppsToUpgrade, ppsToNotUpgrade []pkg.Package) fun
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
func assertionToMemDB(assertions types.PackagesAssertions) types.PackageDatabase {
|
||||
db := pkg.NewInMemoryDatabase(false)
|
||||
for _, a := range assertions {
|
||||
if a.Value {
|
||||
db.CreatePackage(a.Package)
|
||||
}
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
func (s *Solver) upgrade(psToUpgrade, psToNotUpgrade types.Packages, fn func(defDB types.PackageDatabase, installDB types.PackageDatabase) (types.Packages, types.Packages, types.PackageDatabase, []*types.Package), defDB types.PackageDatabase, installDB types.PackageDatabase, checkconflicts, full bool) (types.Packages, types.PackagesAssertions, error) {
|
||||
|
||||
toUninstall, toInstall, installedcopy, packsToUpgrade := fn(defDB, installDB)
|
||||
s2 := NewSolver(Options{Type: SingleCoreSimple}, installedcopy, defDB, pkg.NewInMemoryDatabase(false))
|
||||
s2 := NewSolver(types.SolverOptions{Type: types.SolverSingleCoreSimple}, installedcopy, defDB, pkg.NewInMemoryDatabase(false))
|
||||
s2.SetResolver(s.Resolver)
|
||||
if !full {
|
||||
ass := PackagesAssertions{}
|
||||
ass := types.PackagesAssertions{}
|
||||
for _, i := range toInstall {
|
||||
ass = append(ass, PackageAssert{Package: i.(*pkg.DefaultPackage), Value: true})
|
||||
ass = append(ass, types.PackageAssert{Package: i, Value: true})
|
||||
}
|
||||
}
|
||||
// Then try to uninstall the versions in the system, and store that tree
|
||||
@@ -559,23 +553,23 @@ func (s *Solver) upgrade(psToUpgrade, psToNotUpgrade pkg.Packages, fn func(defDB
|
||||
}
|
||||
|
||||
if len(toInstall) == 0 {
|
||||
ass := PackagesAssertions{}
|
||||
ass := types.PackagesAssertions{}
|
||||
for _, i := range installDB.World() {
|
||||
ass = append(ass, PackageAssert{Package: i.(*pkg.DefaultPackage), Value: true})
|
||||
ass = append(ass, types.PackageAssert{Package: i, Value: true})
|
||||
}
|
||||
return toUninstall, ass, nil
|
||||
}
|
||||
assertions, err := s2.RelaxedInstall(toInstall.Unique())
|
||||
|
||||
wantedSystem := assertions.ToDB()
|
||||
wantedSystem := assertionToMemDB(assertions)
|
||||
|
||||
fn = s.computeUpgrade(pkg.Packages{}, pkg.Packages{})
|
||||
fn = s.computeUpgrade(types.Packages{}, types.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
|
||||
var selectedPackages []*types.Package
|
||||
|
||||
for _, p := range assertions {
|
||||
if p.Value && !inPackage(psToUpgrade, p.Package) {
|
||||
@@ -593,25 +587,25 @@ func (s *Solver) upgrade(psToUpgrade, psToNotUpgrade pkg.Packages, fn func(defDB
|
||||
return toUninstall, assertions, err
|
||||
}
|
||||
|
||||
func (s *Solver) Upgrade(checkconflicts, full bool) (pkg.Packages, PackagesAssertions, error) {
|
||||
func (s *Solver) Upgrade(checkconflicts, full bool) (types.Packages, types.PackagesAssertions, error) {
|
||||
|
||||
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)
|
||||
return s.upgrade(types.Packages{}, types.Packages{}, s.computeUpgrade(types.Packages{}, types.Packages{}), s.DefinitionDatabase, installedcopy, checkconflicts, full)
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (s *Solver) Uninstall(checkconflicts, full bool, packs ...pkg.Package) (pkg.Packages, error) {
|
||||
func (s *Solver) Uninstall(checkconflicts, full bool, packs ...*types.Package) (types.Packages, error) {
|
||||
if len(packs) == 0 {
|
||||
return pkg.Packages{}, nil
|
||||
return types.Packages{}, nil
|
||||
}
|
||||
var res pkg.Packages
|
||||
var res types.Packages
|
||||
|
||||
toRemove := pkg.Packages{}
|
||||
toRemove := types.Packages{}
|
||||
|
||||
for _, c := range packs {
|
||||
candidate, err := s.InstalledDatabase.FindPackage(c)
|
||||
@@ -633,7 +627,7 @@ func (s *Solver) Uninstall(checkconflicts, full bool, packs ...pkg.Package) (pkg
|
||||
}
|
||||
|
||||
// Build a fake "Installed" - Candidate and its requires tree
|
||||
var InstalledMinusCandidate pkg.Packages
|
||||
var InstalledMinusCandidate types.Packages
|
||||
|
||||
// We are asked to not perform a full uninstall (checking all the possible requires that could
|
||||
// be removed). Let's only check if we can remove the selected package
|
||||
@@ -666,7 +660,7 @@ func (s *Solver) Uninstall(checkconflicts, full bool, packs ...pkg.Package) (pkg
|
||||
}
|
||||
}
|
||||
|
||||
s2 := NewSolver(Options{Type: SingleCoreSimple}, pkg.NewInMemoryDatabase(false), s.InstalledDatabase, pkg.NewInMemoryDatabase(false))
|
||||
s2 := NewSolver(types.SolverOptions{Type: types.SolverSingleCoreSimple}, pkg.NewInMemoryDatabase(false), s.InstalledDatabase, pkg.NewInMemoryDatabase(false))
|
||||
s2.SetResolver(s.Resolver)
|
||||
|
||||
// Get the requirements to install the candidate
|
||||
@@ -756,7 +750,7 @@ func (s *Solver) solve(f bf.Formula) (map[string]bool, bf.Formula, error) {
|
||||
}
|
||||
|
||||
// Solve builds the formula given the current state and returns package assertions
|
||||
func (s *Solver) Solve() (PackagesAssertions, error) {
|
||||
func (s *Solver) Solve() (types.PackagesAssertions, error) {
|
||||
var model map[string]bool
|
||||
var err error
|
||||
|
||||
@@ -780,7 +774,7 @@ 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
|
||||
// to statisfy all the constraints
|
||||
func (s *Solver) RelaxedInstall(c pkg.Packages) (PackagesAssertions, error) {
|
||||
func (s *Solver) RelaxedInstall(c types.Packages) (types.PackagesAssertions, error) {
|
||||
|
||||
coll, err := s.getList(s.DefinitionDatabase, c)
|
||||
if err != nil {
|
||||
@@ -790,13 +784,13 @@ func (s *Solver) RelaxedInstall(c pkg.Packages) (PackagesAssertions, error) {
|
||||
s.Wanted = coll
|
||||
|
||||
if s.noRulesWorld() {
|
||||
var ass PackagesAssertions
|
||||
var ass types.PackagesAssertions
|
||||
for _, p := range s.Installed() {
|
||||
ass = append(ass, PackageAssert{Package: p.(*pkg.DefaultPackage), Value: true})
|
||||
ass = append(ass, types.PackageAssert{Package: p, Value: true})
|
||||
|
||||
}
|
||||
for _, p := range s.Wanted {
|
||||
ass = append(ass, PackageAssert{Package: p.(*pkg.DefaultPackage), Value: true})
|
||||
ass = append(ass, types.PackageAssert{Package: p, Value: true})
|
||||
}
|
||||
return ass, nil
|
||||
}
|
||||
@@ -811,7 +805,7 @@ func (s *Solver) RelaxedInstall(c pkg.Packages) (PackagesAssertions, error) {
|
||||
// Install returns the assertions necessary in order to install the packages in
|
||||
// a system.
|
||||
// It calculates the best result possible, trying to maximize new packages.
|
||||
func (s *Solver) Install(c pkg.Packages) (PackagesAssertions, error) {
|
||||
func (s *Solver) Install(c types.Packages) (types.PackagesAssertions, error) {
|
||||
assertions, err := s.RelaxedInstall(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -819,8 +813,8 @@ func (s *Solver) Install(c pkg.Packages) (PackagesAssertions, error) {
|
||||
|
||||
systemAfterInstall := pkg.NewInMemoryDatabase(false)
|
||||
|
||||
toUpgrade := pkg.Packages{}
|
||||
toNotUpgrade := pkg.Packages{}
|
||||
toUpgrade := types.Packages{}
|
||||
toNotUpgrade := types.Packages{}
|
||||
for _, p := range c {
|
||||
if p.GetVersion() == ">=0" || p.GetVersion() == ">0" {
|
||||
toUpgrade = append(toUpgrade, p)
|
||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user