diff options
author | Christopher Baines <mail@cbaines.net> | 2016-05-16 22:20:12 +0100 |
---|---|---|
committer | Christopher Baines <mail@cbaines.net> | 2016-09-04 23:05:14 +0100 |
commit | 86de22b526313a68e5c8bb8a361d5904c30d8b51 (patch) | |
tree | c3307b2e032ac87f8d5c2ff79e57eff692cecf2b /solver | |
download | guix-pypi-utils-86de22b526313a68e5c8bb8a361d5904c30d8b51.tar guix-pypi-utils-86de22b526313a68e5c8bb8a361d5904c30d8b51.tar.gz |
Initial commit
Diffstat (limited to 'solver')
-rw-r--r-- | solver/__init__.py | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/solver/__init__.py b/solver/__init__.py new file mode 100644 index 0000000..0b8160a --- /dev/null +++ b/solver/__init__.py @@ -0,0 +1,184 @@ +import solv + +OPERATOR_TO_FLAGS = { + "=": solv.REL_EQ, + "<": solv.REL_LT, + ">": solv.REL_GT, + "<=": solv.REL_EQ | solv.REL_LT, + ">=": solv.REL_EQ | solv.REL_GT, +} + +def get_operator_and_version(spec): + spec.strip() + for operator in OPERATOR_TO_FLAGS.keys(): + if spec.startswith(operator): + version = spec[len(operator):].strip() + + return operator, version + + raise Exception("Could not parse %s" % spec) + +def get_versions_or_error(sdists, overall_requirements, debug=False): + def log(*args): + if debug: + print(args) + + if sdists is None or (len(sdists) == 1 and sdists[0] is None): + sdists = [] + + if overall_requirements is None or ( + len(overall_requirements) == 1 and overall_requirements[0] is None + ): + overall_requirements = [] + + if len(overall_requirements) == 0: + log("overall_requirements", overall_requirements) + return [] + + log(sdists) + log(overall_requirements) + + pool = solv.Pool() + pool.setarch() + + sysrepo = pool.add_repo("@System") + + repo = pool.add_repo("test") + repo.create_stubs() + + solvables = {} + + log("Creating solvables") + for name, version, requirements in sdists: + solvable = repo.add_solvable() + + solvable.name = name + solvable.evr = version + solvable.arch = "noarch" + + log(solvable.name, solvable.id) + + solvables[(name, version)] = solvable + + rel_id = pool.rel2id( + solvable.nameid, + solvable.evrid, + OPERATOR_TO_FLAGS["="], + True, + ) + + solvable.add_deparray(solv.SOLVABLE_PROVIDES, rel_id) + + log("Adding requirements") + for name, version, requirements in sdists: + if requirements is None: + requirements = [] + + solvable = solvables[(name, version)] + + log("requirements for", name, version) + + for requirement_name, requirement_specifiers in requirements: + log("requirement name ", requirement_name) + requirement_name_id = pool.str2id(requirement_name, False) + + if requirement_name_id == 0: + return "Could not find package for requirement %s" % requirement_name + + if requirement_specifiers is None: + requirement_specifiers = [] + + log("specifiers ", requirement_specifiers) + if len(requirement_specifiers) == 0: + solvable.add_deparray(solv.SOLVABLE_REQUIRES, requirement_name_id) + else: + for spec in requirement_specifiers: + if "!=" in spec: + # TODO: Support this + continue + + try: + spec_operator, spec_version = get_operator_and_version(spec) + except Exception as e: + return str(e) + + requirement_evr_id = pool.str2id(spec_version, True) + + log(requirement_name_id, requirement_evr_id) + rel_id = pool.rel2id( + requirement_name_id, + requirement_evr_id, + OPERATOR_TO_FLAGS[spec_operator], + True, + ) + + log("rel_id", rel_id, requirement_name, spec_operator, spec_version) + + solvable.add_deparray(solv.SOLVABLE_REQUIRES, rel_id) + + addedprovides = pool.addfileprovides_queue() + if addedprovides: + sysrepo.updateaddedprovides(addedprovides) + repo.updateaddedprovides(addedprovides) + + pool.createwhatprovides() + + jobs = [] + + for arg in overall_requirements: + flags = ( + solv.Selection.SELECTION_REL | + solv.Selection.SELECTION_NAME | + solv.Selection.SELECTION_WITH_SOURCE + ) + + sel = pool.select(arg, flags) + + if sel.isempty(): + error = "nothing matches '%s'" % arg + log(error) + return error + + if sel.flags() & solv.Selection.SELECTION_FILELIST: + log("[using file list match for '%s']" % arg) + if sel.flags() & solv.Selection.SELECTION_PROVIDES: + log("[using capability match for '%s']" % arg) + + jobs += sel.jobs(solv.Job.SOLVER_INSTALL) + + for job in jobs: + for solvable in job.solvables(): + solvable_url = solvable.lookup_str(solv.SOLVABLE_URL) + if solvable_url: + log("Url: %s" % solvable_url) + solvable_license = solvable.lookup_str(solv.SOLVABLE_LICENSE) + if solvable_license: + log("License: %s" % solvable_license) + + pool.set_debuglevel(0) + solver = pool.Solver() + + while True: + problems = solver.solve(jobs) + if not problems: + break + + return str([str(p) for p in problems]) + + # no problems, show transaction + trans = solver.transaction() + del solver + if trans.isempty(): + return "transaction is empty" + + for cl in trans.classify( + solv.Transaction.SOLVER_TRANSACTION_SHOW_OBSOLETES | + solv.Transaction.SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE, + ): + if cl.type == solv.Transaction.SOLVER_TRANSACTION_INSTALL: + versions = [] + for p in cl.solvables(): + log(" - %s" % p) + versions.append((p.name, p.evr)) + return versions + return "unknown error" |