| |
@@ -1,3 +1,4 @@
|
| |
+ import collections
|
| |
import configparser
|
| |
import itertools
|
| |
import logging
|
| |
@@ -69,39 +70,45 @@
|
| |
assert len(solvables) == 1
|
| |
return solvables[0]
|
| |
|
| |
- def print_transaction(pool, transaction):
|
| |
+ def _get_dependency_details(pool, transaction):
|
| |
candq = transaction.newpackages()
|
| |
- if log.getEffectiveLevel() <= logging.INFO:
|
| |
- tb = smartcols.Table()
|
| |
- tb.title = "DEPENDENCY INFORMATION"
|
| |
- cl = tb.new_column("INFO")
|
| |
- cl.tree = True
|
| |
- cl_match = tb.new_column("MATCH")
|
| |
- for p in candq:
|
| |
- ln = tb.new_line()
|
| |
- ln[cl] = str(p)
|
| |
- for dep in p.lookup_deparray(solv.SOLVABLE_REQUIRES):
|
| |
- lns = tb.new_line(ln)
|
| |
- lns[cl] = str(dep)
|
| |
- matches = set(s for s in candq if s.matchesdep(solv.SOLVABLE_PROVIDES, dep))
|
| |
- if not matches and str(dep).startswith("/"):
|
| |
- # Append provides by files
|
| |
- # TODO: use Dataiterator for getting filelist
|
| |
- matches = set(s for s in pool.select(str(dep), solv.Selection.SELECTION_FILELIST).solvables() if s in candq)
|
| |
- # It was possible to resolve set, so something is wrong here
|
| |
- assert matches
|
| |
- first = True
|
| |
- for m in matches:
|
| |
- if first:
|
| |
- lnc = lns
|
| |
- else:
|
| |
- lnss = tb.new_line(lns)
|
| |
- lnc = lnss
|
| |
- first = False
|
| |
- lnc[cl_match] = str(m)
|
| |
- log.info(tb)
|
| |
-
|
| |
- def _solve(solver, pkgnames):
|
| |
+ result = {}
|
| |
+ for p in candq:
|
| |
+ pkg_details = {}
|
| |
+ for dep in p.lookup_deparray(solv.SOLVABLE_REQUIRES):
|
| |
+ matches = set(s for s in candq if s.matchesdep(solv.SOLVABLE_PROVIDES, dep))
|
| |
+ if not matches and str(dep).startswith("/"):
|
| |
+ # Append provides by files
|
| |
+ # TODO: use Dataiterator for getting filelist
|
| |
+ matches = set(s for s in pool.select(str(dep), solv.Selection.SELECTION_FILELIST).solvables() if s in candq)
|
| |
+ # It was possible to resolve set, so something is wrong here
|
| |
+ assert matches
|
| |
+ # While multiple packages providing the same thing is certainly possible, it is rare, and
|
| |
+ # the confusion from picking one at random is worth the the simplification.
|
| |
+ pkg_details[str(dep)] = sorted(str(m) for m in matches)[0]
|
| |
+ result[str(p)] = pkg_details
|
| |
+
|
| |
+ return result
|
| |
+
|
| |
+ def print_transaction(details):
|
| |
+ tb = smartcols.Table()
|
| |
+ tb.title = "DEPENDENCY INFORMATION"
|
| |
+ cl = tb.new_column("INFO")
|
| |
+ cl.tree = True
|
| |
+ cl_match = tb.new_column("MATCH")
|
| |
+ for p in sorted(details):
|
| |
+ ln = tb.new_line()
|
| |
+ ln[cl] = p
|
| |
+ deps = details[p]
|
| |
+ for dep in sorted(deps):
|
| |
+ lns = tb.new_line(ln)
|
| |
+ lns[cl] = dep
|
| |
+ lns[cl_match] = deps[dep]
|
| |
+ log.info(tb)
|
| |
+
|
| |
+ FullInfo = collections.namedtuple('FullInfo', ['name', 'rpm', 'srpm', 'requires'])
|
| |
+
|
| |
+ def _solve(solver, pkgnames, full_info=False):
|
| |
"""Given a set of package names, returns a list of solvables to install"""
|
| |
pool = solver.pool
|
| |
|
| |
@@ -125,19 +132,31 @@
|
| |
for problem in problems:
|
| |
log.warn(problem)
|
| |
|
| |
- print_transaction(pool, solver.transaction())
|
| |
- result = set()
|
| |
+ if log.getEffectiveLevel() <= logging.INFO or full_info:
|
| |
+ dep_details = _get_dependency_details(pool, solver.transaction())
|
| |
+ if log.getEffectiveLevel() <= logging.INFO:
|
| |
+ print_transaction(dep_details)
|
| |
+
|
| |
+ if full_info:
|
| |
+ result = []
|
| |
+ else:
|
| |
+ result = set()
|
| |
for s in solver.transaction().newpackages():
|
| |
if s.name.startswith("fedora-release"):
|
| |
# Relying on the F27 metadata injects irrelevant fedora-release deps
|
| |
continue
|
| |
if s.arch in ("src", "nosrc"):
|
| |
continue
|
| |
- # Ensure the solvables don't outlive the solver that created them
|
| |
- result.add(s.name)
|
| |
+ # Ensure the solvables don't outlive the solver that created them by
|
| |
+ # extracting the information we want but not returning the solvable.
|
| |
+ if full_info:
|
| |
+ rpm = str(s)
|
| |
+ result.append(FullInfo(s.name, rpm, s.lookup_sourcepkg()[:-4], dep_details[rpm]))
|
| |
+ else:
|
| |
+ result.add(s.name)
|
| |
return result
|
| |
|
| |
- def ensure_buildable(pool, pkgnames):
|
| |
+ def ensure_buildable(pool, pkgnames, full_info=False):
|
| |
"""Given a set of solvables, returns a set of source packages & build deps"""
|
| |
# The given package set may not be installable on its own
|
| |
# That's OK, since other modules will provide those packages
|
| |
@@ -152,7 +171,8 @@
|
| |
|
| |
_DEFAULT_HINTS = ("glibc-minimal-langpack",)
|
| |
|
| |
- def ensure_installable(pool, pkgnames, hints=_DEFAULT_HINTS, recommendations=False):
|
| |
+ def ensure_installable(pool, pkgnames, hints=_DEFAULT_HINTS,
|
| |
+ recommendations=False, full_info=False):
|
| |
"""Iterate over the resolved dependency set for the given packages
|
| |
|
| |
*hints*: Packages that have higher priority when more than one package
|
| |
@@ -174,7 +194,7 @@
|
| |
# Ignore weak deps
|
| |
solver.set_flag(solv.Solver.SOLVER_FLAG_IGNORE_RECOMMENDED, 1)
|
| |
|
| |
- return _solve(solver, pkgnames)
|
| |
+ return _solve(solver, pkgnames, full_info=full_info)
|
| |
|
| |
def print_reldeps(pool, pkg):
|
| |
sel = pool.select(pkg, solv.Selection.SELECTION_NAME | solv.Selection.SELECTION_DOTARCH)
|
| |
I just migrated the CLI option handling fully over to click, so this will need to move up to be a new
@click.option
entry on thedef resolve_deps
command.The decorator call will need to be something like:
and then add a new
json
parameter to the function.