From 4d4a23c6192d8bae1aca602cf6ca56f170fd4ec0 Mon Sep 17 00:00:00 2001 From: Thomas Leonard Date: Sun, 19 Aug 2012 18:27:01 +0100 Subject: [PATCH] Interfaces now conflict with their replacements This is intended for the case where e.g. one dependency depends on the original Java interface URI and another depends on the new URI. We can't satisfy that by selecting two versions of Java. --- tests/Replaced.xml | 2 ++ tests/ReplacedConflicts.xml | 21 +++++++++++++++++++++ tests/testsolver.py | 24 ++++++++++++++++++++++++ zeroinstall/injector/solver.py | 17 +++++++++++++++++ 4 files changed, 64 insertions(+) create mode 100644 tests/ReplacedConflicts.xml diff --git a/tests/Replaced.xml b/tests/Replaced.xml index 95e49b3..fa90ce1 100644 --- a/tests/Replaced.xml +++ b/tests/Replaced.xml @@ -3,4 +3,6 @@ Hello Hello + + diff --git a/tests/ReplacedConflicts.xml b/tests/ReplacedConflicts.xml new file mode 100644 index 0000000..09ff125 --- /dev/null +++ b/tests/ReplacedConflicts.xml @@ -0,0 +1,21 @@ + + + ReplacedConflicts + replaced-by conflicts + + + + + + + + + + + + + + + + + diff --git a/tests/testsolver.py b/tests/testsolver.py index 475ac9b..e50484a 100755 --- a/tests/testsolver.py +++ b/tests/testsolver.py @@ -317,5 +317,29 @@ class TestSolver(BaseTest): assert s.ready, s.get_failure_reason() assert s.selections + def testReplacedConflicts(self): + self.import_feed('http://localhost:8000/Hello', 'Hello') + s = solver.DefaultSolver(self.config) + replaced_path = model.canonical_iface_uri(os.path.join(mydir, 'Replaced.xml')) + replaced_conflicts_path = model.canonical_iface_uri(os.path.join(mydir, 'ReplacedConflicts.xml')) + r = Requirements(replaced_conflicts_path) + s.solve_for(r) + assert s.ready, s.get_failure_reason() + assert s.selections + self.assertEqual("b", s.selections.selections[replaced_conflicts_path].id) + self.assertEqual("2", s.selections.selections[replaced_conflicts_path].version) + self.assertEqual("sha1=3ce644dc725f1d21cfcf02562c76f375944b266a", s.selections.selections["http://localhost:8000/Hello"].id) + self.assertEqual(2, len(s.selections.selections)) + + s.extra_restrictions[self.config.iface_cache.get_interface(r.interface_uri)] = [ + model.VersionRangeRestriction(model.parse_version('2'), None)] + + s.solve_for(r) + assert s.ready, s.get_failure_reason() + assert s.selections + self.assertEqual("1", s.selections.selections[replaced_conflicts_path].version) + self.assertEqual("0", s.selections.selections[replaced_path].version) + self.assertEqual(2, len(s.selections.selections)) + if __name__ == '__main__': unittest.main() diff --git a/zeroinstall/injector/solver.py b/zeroinstall/injector/solver.py index 49a9e60..626b30e 100644 --- a/zeroinstall/injector/solver.py +++ b/zeroinstall/injector/solver.py @@ -422,6 +422,8 @@ class SATSolver(Solver): # Must choose one version of d if impl is selected find_dependency_candidates(requiring_var, d) + replacement_for = {} # Interface -> Replacement Interface + def add_iface(uri, arch): """Name implementations from feed and assert that only one can be selected.""" if uri in ifaces_processed: return @@ -429,6 +431,12 @@ class SATSolver(Solver): iface = iface_cache.get_interface(uri) + main_feed = iface_cache.get_feed(uri) + if main_feed: + replacement = main_feed.get_replaced_by() + if replacement is not None: + replacement_for[iface] = iface_cache.get_interface(replacement) + impls = [] for f in usable_feeds(iface, arch): self.feeds_used.add(f) @@ -608,6 +616,15 @@ class SATSolver(Solver): else: m_groups_clause = None + # Can't select an implementation of an interface and of its replacement + for original, replacement in replacement_for.items(): + rep_impls = iface_to_vars.get(replacement, None) + if rep_impls is None: + # We didn't even look at the replacement interface, so no risk here + continue + all_impls = list(rep_impls.values()) + list(iface_to_vars[original].values()) + problem.at_most_one(all_impls) + def decide(): """This is called by the SAT solver when it cannot simplify the problem further. Our job is to find the most-optimal next selection to try. -- 2.11.4.GIT