aboutsummaryrefslogtreecommitdiff
path: root/solver
diff options
context:
space:
mode:
authorChristopher Baines <mail@cbaines.net>2016-05-16 22:20:12 +0100
committerChristopher Baines <mail@cbaines.net>2016-09-04 23:05:14 +0100
commit86de22b526313a68e5c8bb8a361d5904c30d8b51 (patch)
treec3307b2e032ac87f8d5c2ff79e57eff692cecf2b /solver
downloadguix-pypi-utils-86de22b526313a68e5c8bb8a361d5904c30d8b51.tar
guix-pypi-utils-86de22b526313a68e5c8bb8a361d5904c30d8b51.tar.gz
Initial commit
Diffstat (limited to 'solver')
-rw-r--r--solver/__init__.py184
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"