diff --git a/solve_bimodal_test.go b/solve_bimodal_test.go index 3ee7493f2c..2f9ce4c10b 100644 --- a/solve_bimodal_test.go +++ b/solve_bimodal_test.go @@ -285,6 +285,33 @@ var bimodalFixtures = map[string]bimodalFixture{ "a 1.0.0", ), }, + "project cycle involving root with backtracking": { + ds: []depspec{ + dsp(mkDepspec("root 0.0.0", "a ~1.0.0"), + pkg("root", "a", "b"), + pkg("root/foo"), + ), + dsp(mkDepspec("a 1.0.0"), + pkg("a", "root/foo"), + ), + dsp(mkDepspec("a 1.0.1"), + pkg("a", "root/foo"), + ), + dsp(mkDepspec("b 1.0.0", "a 1.0.0"), + pkg("b", "a"), + ), + dsp(mkDepspec("b 1.0.1", "a 1.0.0"), + pkg("b", "a"), + ), + dsp(mkDepspec("b 1.0.2", "a 1.0.0"), + pkg("b", "a"), + ), + }, + r: mksolution( + "a 1.0.0", + "b 1.0.2", + ), + }, "project cycle not involving root": { ds: []depspec{ dsp(mkDepspec("root 0.0.0", "a ~1.0.0"), diff --git a/solver.go b/solver.go index 95c913c72f..7c12da8b81 100644 --- a/solver.go +++ b/solver.go @@ -1152,6 +1152,12 @@ func (s *solver) unselectLast() (atomWithPackages, bool) { } for _, dep := range deps { + // Skip popping if the dep is the root project, which can occur if + // there's a project-level import cycle. (This occurs frequently with + // e.g. kubernetes and docker) + if s.rd.isRoot(dep.Ident.ProjectRoot) { + continue + } s.sel.popDep(dep.Ident) // if no parents/importers, remove from unselected queue