diff --git a/module_build_service/mmd_resolver.py b/module_build_service/mmd_resolver.py index b23a047e..15676289 100644 --- a/module_build_service/mmd_resolver.py +++ b/module_build_service/mmd_resolver.py @@ -23,90 +23,11 @@ # Written by Jan Kaluža # Igor Gnatenko +import itertools import solv from module_build_service import log -def _gather_alternatives(pool, favor=None, tested=None, level=1, transactions=None): - if tested is None: - tested = set() - if transactions is None: - transactions = [] - solver = pool.Solver() - - jobs = [] - jobs.extend(pool.Job(solv.Job.SOLVER_FAVOR | solv.Job.SOLVER_SOLVABLE, s.id) - for s in favor or []) - jobs.extend(pool.Job(solv.Job.SOLVER_DISFAVOR | solv.Job.SOLVER_SOLVABLE, s.id) - for s in tested) - problems = solver.solve(jobs) - if problems: - raise RuntimeError("Problems were found during solve(): %s" % ", ".join( - str(p) for p in problems)) - newsolvables = solver.transaction().newsolvables() - transactions.append(newsolvables) - alternatives = solver.all_alternatives() - if not alternatives: - return transactions - - if [alt for alt in alternatives if alt.type != solv.Alternative.SOLVER_ALTERNATIVE_TYPE_RULE]: - raise SystemError("Encountered alternative with type != rule") - - log.debug("Jobs:") - for job in pool.getpooljobs(): - log.debug(" * %s [pool]", job) - for job in jobs: - log.debug(" * %s", job) - log.debug("Transaction:") - for s in newsolvables: - log.debug(" * %s", s) - log.debug("Alternatives:") - auto_minimized = False - for alt in alternatives: - raw_choices = alt.choices_raw() - log.debug(" %d: %s", alt.level, alt) - for choice in alt.choices(): - if choice == alt.chosen: - sign = "+" - elif -choice.id in raw_choices: - sign = "-" - auto_minimized = True - else: - sign = " " - log.debug(" * %s%s", sign, choice) - if auto_minimized: - raise NotImplementedError("Transaction was auto-minimized") - - current_alternatives = [alt for alt in alternatives if alt.level == level] - if len(current_alternatives) > 1: - raise SystemError("Encountered multiple alternatives on the same level") - - alternative = current_alternatives[0] - raw_choices = alternative.choices_raw() - tested.add(alternative.chosen) - - for choice in (choice for choice in alternative.choices() if choice not in tested): - _gather_alternatives(pool, - favor=favor, - tested=tested, - level=level, - transactions=transactions) - - max_level = max(alt.level for alt in alternatives) - if level == max_level: - return transactions - - next_favor = [alt.chosen for alt in alternatives if alt.level <= level] - next_tested = set(alt.chosen for alt in alternatives if alt.level == level + 1) - _gather_alternatives(pool, - favor=next_favor, - tested=next_tested, - level=level + 1, - transactions=transactions) - - return transactions - - class MMDResolver(object): """ Resolves dependencies between Module metadata objects. @@ -131,7 +52,7 @@ class MMDResolver(object): raise ValueError( "The built module contains different runtime dependencies: %s" % mmd.dumps()) - # $n:$s:$c-$v.$a + # $n:$s:$v:$c-$v.$a solvable = self.available_repo.add_solvable() solvable.name = "%s:%s:%d:%s" % (n, s, v, c) solvable.evr = str(v) @@ -170,7 +91,7 @@ class MMDResolver(object): for c, deps in enumerate(mmd.get_dependencies()): # $n:$s:$c-$v.src solvable = self.build_repo.add_solvable() - solvable.name = "%s:%s:%s:%d" % (n, s, v, c) + solvable.name = "%s:%s:%d:%d" % (n, s, v, c) solvable.evr = str(v) solvable.arch = "src" @@ -203,17 +124,33 @@ class MMDResolver(object): raise ValueError("No module(s) found for resolving") self.pool.createwhatprovides() - # XXX: Using SOLVABLE_ONE_OF should be faster & more convenient. - # There must be a bug in _gather_alternatives(), possibly when processing l1 alternatives. - # Use pool.towhatprovides() to combine solvables. - - alternatives = [] - jobs = self.pool.getpooljobs() - for s in solvables: - new_job = self.pool.Job(solv.Job.SOLVER_INSTALL | solv.Job.SOLVER_SOLVABLE, s.id) - self.pool.setpooljobs(jobs + [new_job]) - alternatives.extend(_gather_alternatives(self.pool)) - self.pool.setpooljobs(jobs) + solver = self.pool.Solver() + alternatives = {} + for src in solvables: + job = self.pool.Job(solv.Job.SOLVER_INSTALL | solv.Job.SOLVER_SOLVABLE, src.id) + requires = src.lookup_deparray(solv.SOLVABLE_REQUIRES) + # XXX: can be optimized by favoring just by name, but requires additional handling + # of context due to name which would contain just N:S. + for opt in itertools.product(*[self.pool.whatprovides(dep) for dep in requires]): + log.debug("Testing combination: %s", opt) + key = tuple(":".join(s.name.split(":", 2)[:2]) for s in opt) + if key in alternatives: + log.debug("%s was already resolved, skipping", key) + continue + jobs = [self.pool.Job(solv.Job.SOLVER_FAVOR | solv.Job.SOLVER_SOLVABLE, s.id) + for s in opt] + [job] + log.debug("Jobs:") + for j in jobs: + log.debug(" - %s", j) + problems = solver.solve(jobs) + if problems: + raise RuntimeError("Problems were found during solve(): %s" % ", ".join( + str(p) for p in problems)) + newsolvables = solver.transaction().newsolvables() + log.debug("Transaction:") + for s in newsolvables: + log.debug(" - %s", s) + alternatives[key] = newsolvables return set(frozenset("%s:%s" % (s.name, s.arch) for s in trans) - for trans in alternatives) + for trans in alternatives.values()) diff --git a/tests/test_mmd_resolver.py b/tests/test_mmd_resolver.py index 73560b03..ebb3da7d 100644 --- a/tests/test_mmd_resolver.py +++ b/tests/test_mmd_resolver.py @@ -116,34 +116,10 @@ class TestMMDResolver: "font:a:0:c6:x86_64", "gtk:1:0:c2:x86_64", "platform:f28:0:c10:x86_64"]), - frozenset(["app:1:0:0:src", - "font:a:0:c7:x86_64", - "gtk:1:0:c3:x86_64", - "platform:f29:0:c11:x86_64"]), - frozenset(["app:1:0:0:src", - "font:b:0:c8:x86_64", - "gtk:1:0:c2:x86_64", - "platform:f28:0:c10:x86_64"]), - frozenset(["app:1:0:0:src", - "font:b:0:c9:x86_64", - "gtk:1:0:c3:x86_64", - "platform:f29:0:c11:x86_64"]), frozenset(["app:1:0:0:src", "font:a:0:c6:x86_64", "gtk:2:0:c4:x86_64", "platform:f28:0:c10:x86_64"]), - frozenset(["app:1:0:0:src", - "font:b:0:c9:x86_64", - "gtk:2:0:c5:x86_64", - "platform:f29:0:c11:x86_64"]), - frozenset(["app:1:0:0:src", - "font:b:0:c8:x86_64", - "gtk:2:0:c4:x86_64", - "platform:f28:0:c10:x86_64"]), - frozenset(["app:1:0:0:src", - "font:a:0:c7:x86_64", - "gtk:2:0:c5:x86_64", - "platform:f29:0:c11:x86_64"]), ]) assert expanded == expected @@ -160,18 +136,10 @@ class TestMMDResolver: "font:a:0:c6:x86_64", "gtk:2:0:c4:x86_64", "platform:f28:0:c10:x86_64"]), - frozenset(["app:1:0:0:src", - "font:b:0:c8:x86_64", - "gtk:1:0:c2:x86_64", - "platform:f28:0:c10:x86_64"]), frozenset(["app:1:0:0:src", "font:a:0:c6:x86_64", "gtk:1:0:c2:x86_64", "platform:f28:0:c10:x86_64"]), - frozenset(["app:1:0:0:src", - "font:b:0:c8:x86_64", - "gtk:2:0:c4:x86_64", - "platform:f28:0:c10:x86_64"]), ]) assert expanded == expected @@ -184,26 +152,10 @@ class TestMMDResolver: expanded = self.mmd_resolver.solve(app) expected = set([ - frozenset(["app:1:0:0:src", - "foo:1:0:c3:x86_64", - "gtk:1:0:c3:x86_64", - "platform:f29:0:c11:x86_64"]), - frozenset(["app:1:0:0:src", - "foo:2:0:c5:x86_64", - "gtk:1:0:c3:x86_64", - "platform:f29:0:c11:x86_64"]), frozenset(["app:1:0:0:src", "foo:1:0:c2:x86_64", "gtk:2:0:c4:x86_64", "platform:f28:0:c10:x86_64"]), - frozenset(["app:1:0:0:src", - "foo:1:0:c3:x86_64", - "gtk:2:0:c5:x86_64", - "platform:f29:0:c11:x86_64"]), - frozenset(["app:1:0:0:src", - "foo:2:0:c5:x86_64", - "gtk:2:0:c5:x86_64", - "platform:f29:0:c11:x86_64"]), frozenset(["app:1:0:0:src", "foo:2:0:c4:x86_64", "gtk:2:0:c4:x86_64", @@ -231,18 +183,6 @@ class TestMMDResolver: expanded = self.mmd_resolver.solve(app) expected = set([ - frozenset(["app:1:0:1:src", - "foo:1:0:c3:x86_64", - "gtk:2:0:c5:x86_64", - "platform:f29:0:c11:x86_64"]), - frozenset(["app:1:0:1:src", - "foo:2:0:c5:x86_64", - "gtk:2:0:c5:x86_64", - "platform:f29:0:c11:x86_64"]), - frozenset(["app:1:0:0:src", - "foo:1:0:c3:x86_64", - "gtk:1:0:c3:x86_64", - "platform:f29:0:c11:x86_64"]), frozenset(["app:1:0:1:src", "foo:1:0:c2:x86_64", "gtk:2:0:c4:x86_64", @@ -270,10 +210,6 @@ class TestMMDResolver: expanded = self.mmd_resolver.solve(app) expected = set([ - frozenset(["app:1:0:0:src", - "foo:1:0:c3:x86_64", - "gtk:1:0:c3:x86_64", - "platform:f29:0:c11:x86_64"]), frozenset(["app:1:0:1:src", "foo:1:0:c2:x86_64", "gtk:2:0:c4:x86_64", @@ -301,10 +237,6 @@ class TestMMDResolver: expanded = self.mmd_resolver.solve(app) expected = set([ - frozenset(["app:1:0:0:src", - "font:a:0:c7:x86_64", - "gtk:1:0:c3:x86_64", - "platform:f29:0:c11:x86_64"]), frozenset(["app:1:0:1:src", "font:b:0:c8:x86_64", "gtk:2:0:c4:x86_64", @@ -313,10 +245,6 @@ class TestMMDResolver: "font:a:0:c6:x86_64", "gtk:1:0:c2:x86_64", "platform:f28:0:c10:x86_64"]), - frozenset(["app:1:0:1:src", - "font:b:0:c9:x86_64", - "gtk:2:0:c5:x86_64", - "platform:f29:0:c11:x86_64"]), ]) assert expanded == expected