mmd_resolver: allow configuring output of solve() by policy

Also make results more determenistic.

Signed-off-by: Igor Gnatenko <ignatenko@redhat.com>
This commit is contained in:
Igor Gnatenko
2018-03-06 21:47:26 +01:00
committed by mprahl
parent 52e73b64c2
commit ebd6dba78f
2 changed files with 36 additions and 12 deletions

View File

@@ -23,11 +23,18 @@
# Written by Jan Kaluža <jkaluza@redhat.com>
# Igor Gnatenko <ignatenko@redhat.com>
import enum
import collections
import itertools
import solv
from module_build_service import log
class MMDResolverPolicy(enum.Enum):
All = "all" # All possible top-level combinations
First = "first" # All possible top-level combinations (filtered by N:S, first picked)
class MMDResolver(object):
"""
Resolves dependencies between Module metadata objects.
@@ -110,7 +117,7 @@ class MMDResolver(object):
return solvables
def solve(self, mmd):
def solve(self, mmd, policy=MMDResolverPolicy.First):
"""
Solves dependencies of module defined by `mmd` object. Returns set
containing frozensets with all the possible combinations which
@@ -124,20 +131,23 @@ class MMDResolver(object):
raise ValueError("No module(s) found for resolving")
self.pool.createwhatprovides()
s2nsvc = lambda s: "%s:%s" % (s.name, s.arch)
s2ns = lambda s: ":".join(s.name.split(":", 2)[:2])
solver = self.pool.Solver()
alternatives = {}
alternatives = collections.OrderedDict()
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)
alts = alternatives[src] = {}
# XXX: can be optimized by favoring just by name, but requires additional handling
# of context due to name which would contain just N:S.
src_alternatives = alternatives[src] = collections.OrderedDict()
for opt in itertools.product(*[self.pool.whatprovides(dep) for dep in requires]):
log.debug("Testing %s with combination: %s", src, opt)
key = tuple(":".join(s.name.split(":", 2)[:2]) for s in opt)
if key in alts:
log.debug("%s was already resolved, skipping", key)
continue
if policy == MMDResolverPolicy.All:
kfunc = s2nsvc
elif policy == MMDResolverPolicy.First:
kfunc = s2ns
key = tuple(kfunc(s) for s in opt)
alternative = src_alternatives.setdefault(key, [])
jobs = [self.pool.Job(solv.Job.SOLVER_FAVOR | solv.Job.SOLVER_SOLVABLE, s.id)
for s in opt] + [job]
log.debug("Jobs:")
@@ -151,7 +161,20 @@ class MMDResolver(object):
log.debug("Transaction:")
for s in newsolvables:
log.debug(" - %s", s)
alts[key] = newsolvables
alternative.append(newsolvables)
return set(frozenset("%s:%s" % (s.name, s.arch) for s in t)
for trans in alternatives.values() for t in trans.values())
if policy == MMDResolverPolicy.First:
# Prune
for transactions in alternatives.values():
for ns, trans in transactions.items():
try:
transactions[ns] = [next(t for t in trans
if set(ns) <= set(s2ns(s) for s in t))]
except StopIteration:
# No transactions found for requested N:S
del transactions[ns]
continue
return set(frozenset(s2nsvc(s) for s in transactions[0])
for src_alternatives in alternatives.values()
for transactions in src_alternatives.values())

View File

@@ -1,3 +1,4 @@
enum34
Flask
Flask-Migrate
Flask-SQLAlchemy