diff --git a/pkg/solver/decoder.go b/pkg/solver/decoder.go index 301664c22..d3b81baad 100644 --- a/pkg/solver/decoder.go +++ b/pkg/solver/decoder.go @@ -163,7 +163,7 @@ func (assertions PackagesAssertions) Order(definitiondb pkg.PackageDatabase, fin // Build a topological graph for _, a := range unorderedAssertions { currentPkg := a.Package - added := map[string]interface{}{} + added := map[string][]*pkg.DefaultPackage{} REQUIRES: for _, requiredDef := range currentPkg.GetRequires() { if def, err := definitiondb.FindPackage(requiredDef); err == nil { // Provides: Get a chance of being override here @@ -181,7 +181,16 @@ func (assertions PackagesAssertions) Order(definitiondb pkg.PackageDatabase, fin } // Expand also here, as we need to order them (or instead the solver should give back the dep correctly?) graph.AddEdge(currentPkg.GetFingerPrint(), requiredDef.GetFingerPrint()) - added[requiredDef.GetFingerPrint()] = nil + + // The following is optional - it doesn't change the "correctness" of the solver results + // Here we add an extra edge between deps that share common dependendencies. + // This makes the link more stronger and balances the graph so it doesn't show + // different results for the same query, as they could be shuffled as don't have a direct connection. + for _, d := range added[currentPkg.GetFingerPrint()] { + graph.AddEdge(d.GetFingerPrint(), requiredDef.GetFingerPrint()) + } + added[currentPkg.GetFingerPrint()] = append(added[currentPkg.GetFingerPrint()], requiredDef) + } } result, err := graph.TopSort(fingerprint) diff --git a/pkg/solver/decoder_test.go b/pkg/solver/decoder_test.go index 028299ae3..793bf0b5e 100644 --- a/pkg/solver/decoder_test.go +++ b/pkg/solver/decoder_test.go @@ -388,5 +388,37 @@ var _ = Describe("Decoder", func() { Expect(solution4.Drop(Y).AssertionHash()).To(Equal(solution4.HashFrom(Y))) }) + for index := 0; index < 300; index++ { // Just to make sure we don't have false positives + + 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{}) + + for _, p := range []pkg.Package{X, Y, Z} { + _, err := dbDefinitions.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + + for _, p := range []pkg.Package{} { + _, err := dbInstalled.CreatePackage(p) + Expect(err).ToNot(HaveOccurred()) + } + + solution, err := s.Install([]pkg.Package{W}) + Expect(err).ToNot(HaveOccurred()) + + orderW, err := solution.Order(dbDefinitions, W.GetFingerPrint()) + Expect(err).ToNot(HaveOccurred()) + Expect(orderW[0].Package.GetName()).To(Equal("X")) + Expect(orderW[1].Package.GetName()).To(Equal("Y")) + Expect(orderW[2].Package.GetName()).To(Equal("Z")) + Expect(orderW[3].Package.GetName()).To(Equal("W")) + }) + + } + }) })