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"