def solve_and_print(request, remote_repositories, installed_repository, print_ids, prune=True, prefer_installed=True, debug=0, simple=False, strict=False): pool = Pool(remote_repositories) pool.add_repository(installed_repository) policy = InstalledFirstPolicy(pool, installed_repository, prefer_installed=prefer_installed) solver = DependencySolver( pool, remote_repositories, installed_repository, policy=policy, use_pruning=prune, strict=strict) fmt = "ELAPSED : {description:20} : {elapsed:e}" try: transaction = solver.solve(request) if simple: print(transaction.to_simple_string()) else: print(transaction) except SatisfiabilityError as e: msg = "UNSATISFIABLE: {}" print(msg.format(e.unsat.to_string(pool))) print(e.unsat._find_requirement_time.pretty(fmt), file=sys.stderr) if debug: counts, hist = solver._policy._log_histogram() print(hist, file=sys.stderr) report = solver._policy._log_report(with_assignments=debug > 1) print(report, file=sys.stderr) print(solver._last_rules_time.pretty(fmt), file=sys.stderr) print(solver._last_solver_init_time.pretty(fmt), file=sys.stderr) print(solver._last_solve_time.pretty(fmt), file=sys.stderr)
def packages_from_requirements(packages, requirements, modifiers=None): """ Return a new tuple that only contains packages explicitly mentioned in the requirements. Parameters ---------- packages : iterable of PackageMetadata The packages available for inclusion in the result. requirements : list of Requirement The requirements used to identify relevant packages. All packages that satisfy any of the requirements will be included. modifiers : ConstraintModifiers, optional If not None, modify requirements before resolving packages. Returns ------- Tuple of PackageMetadata A tuple containing the relevant packages. """ pool = Pool((Repository(packages),), modifiers=modifiers) listed_packages = set() for requirement in requirements: listed_packages.update(pool.what_provides(requirement)) return tuple(sorted(listed_packages, key=lambda p: p._key))
def _check_solution(self, filename, prefer_installed=True): # Test that the solution described in the scenario file matches with # what the SAT solver computes. # Given scenario = Scenario.from_yaml( os.path.join(os.path.dirname(__file__), filename) ) request = scenario.request # When pool = Pool(scenario.remote_repositories) pool.add_repository(scenario.installed_repository) solver = DependencySolver( pool, scenario.remote_repositories, scenario.installed_repository, ) # Then try: transaction = solver.solve(request) except SatisfiabilityError as failure: self.assertFailureEqual(pool, failure, scenario) else: if scenario.failed: msg = "Solver unexpectedly succeeded, but {0}" self.fail(msg.format(scenario.failure['raw'])) self.assertEqualOperations(transaction.operations, scenario.operations) if (scenario.pretty_operations or transaction.operations != transaction.pretty_operations): self.assertEqualOperations(transaction.pretty_operations, scenario.pretty_operations)
def simplify_requirements(packages, requirements): """ Return a reduced, but equivalent set of requirements. Parameters ---------- packages : iterable of PackageMetadata The packages available to draw from when satisfying requirements. requirements : list of Requirement The requirements used to identify relevent packages. Returns ------- tuple of Requirement The reduced requirements. """ needed_packages = packages_from_requirements(packages, requirements) pool = Pool([Repository(packages)]) R = InstallRequirement.from_constraints dependencies = set(itertools.chain.from_iterable( pool.what_provides(R(con)) for package in needed_packages for con in package.install_requires )) simple_requirements = requirements_from_packages( package for package in needed_packages if package not in dependencies ) return simple_requirements
def _check_solution(self, filename, prefer_installed=True): # Test that the solution described in the scenario file matches with # what the SAT solver computes. # Given scenario = Scenario.from_yaml( os.path.join(os.path.dirname(__file__), filename) ) request = scenario.request # When pool = Pool(scenario.remote_repositories) pool.add_repository(scenario.installed_repository) policy = InstalledFirstPolicy(pool, scenario.installed_repository, prefer_installed=prefer_installed) solver = DependencySolver( pool, scenario.remote_repositories, scenario.installed_repository, policy=policy, ) # Then try: transaction = solver.solve(request) except SatisfiabilityError as failure: if not scenario.failed: msg = "Solver unexpectedly failed" if failure.reason: msg += " because {0}".format(failure.reason) self.fail(msg) else: if scenario.failed: msg = "Solver unexpectedly succeeded, but {0}." self.fail(msg.format(scenario.failure)) self.assertEqualOperations(transaction.operations, scenario.operations)
def print_rules(request, remote_repositories, installed_repository): pool = Pool(remote_repositories) pool.add_repository(installed_repository) solver = DependencySolver(pool, remote_repositories, installed_repository) _, rules = solver._create_rules_and_initialize_policy(request) for rule in rules: print(rule.to_string(pool))
def _solve(self, top_core, flags={}, only_matching_vlnv=False): def eq_vln(this, that): return \ this.vendor == that.vendor and \ this.library == that.library and \ this.name == that.name repo = Repository() _flags = flags.copy() cores = [x['core'] for x in self._cores.values()] for core in cores: if only_matching_vlnv: if not eq_vln(core.name, top_core): continue package_str = "{} {}-{}".format(self._package_name(core.name), core.name.version, core.name.revision) if not only_matching_vlnv: _flags['is_toplevel'] = (core.name == top_core) _depends = core.get_depends(_flags) if _depends: _s = "; depends ( {} )" package_str += _s.format(self._parse_depend(_depends)) parser = PrettyPackageStringParser(EnpkgVersion.from_string) package = parser.parse_to_package(package_str) package.core = core repo.add_package(package) request = Request() _top_dep = "{} {} {}".format(self._package_name(top_core), top_core.relation, self._package_version(top_core)) requirement = Requirement._from_string(_top_dep) request.install(requirement) installed_repository = Repository() pool = Pool([repo]) pool.add_repository(installed_repository) solver = DependencySolver(pool, [repo], installed_repository) try: transaction = solver.solve(request) except SatisfiabilityError as e: raise DependencyError(top_core.name, msg=e.unsat.to_string(pool)) except NoPackageFound as e: raise DependencyError(top_core.name) return [op.package.core for op in transaction.operations]
def initialize(request, remote_repositories, installed_repository, debug=0): pool = Pool(remote_repositories) pool.add_repository(installed_repository) policy = InstalledFirstPolicy(pool, installed_repository) solver = DependencySolver( pool, remote_repositories, installed_repository, policy=policy) requirement_ids, rules = solver._create_rules_and_initialize_policy( request) sat_solver = MiniSATSolver.from_rules(rules, policy) return pool, sat_solver, requirement_ids
def initialize(request, remote_repositories, installed_repository, debug=0): pool = Pool(remote_repositories) pool.add_repository(installed_repository) policy = InstalledFirstPolicy(pool, installed_repository) solver = DependencySolver(pool, remote_repositories, installed_repository, policy=policy) requirement_ids, rules = solver._create_rules_and_initialize_policy( request) sat_solver = MiniSATSolver.from_rules(rules, policy) return pool, sat_solver, requirement_ids
def resolve_with_hint(self, request, strict=False): pool = Pool([self.repository, self.installed_repository]) solver = DependencySolver(pool, [self.repository], self.installed_repository, use_pruning=False, strict=strict) return solver.solve_with_hint(request)
def requirements_are_satisfiable(packages, requirements, modifiers=None): """ Determine if the `requirements` can be satisfied together. Parameters ---------- packages : iterable of PackageMetadata The packages available to draw from when satisfying requirements. requirements : list of Requirement The requirements used to identify relevent packages. modifiers : ConstraintModifiers, optional If not None, modify requirements before resolving packages. Returns ------- bool Return True if the `requirements` can be satisfied by the `packages`. """ modifiers = modifiers or ConstraintModifiers() Result = collections.namedtuple("Result", "is_satisfiable message") request = Request(modifiers=modifiers) for requirement in requirements: request.install(requirement) repositories = (Repository(packages),) pool = Pool(repositories, modifiers=modifiers) try: DependencySolver(pool, repositories, []).solve(request) return Result(is_satisfiable=True, message="") except SatisfiabilityError as e: return Result( is_satisfiable=False, message=e.unsat.to_string(pool=pool) )
def solve_and_print(request, remote_repositories, installed_repository, print_ids, prune=True, prefer_installed=True, debug=False): pool = Pool(remote_repositories) pool.add_repository(installed_repository) policy = InstalledFirstPolicy(pool, installed_repository, prefer_installed=prefer_installed) solver = DependencySolver( pool, remote_repositories, installed_repository, policy=policy, use_pruning=prune) transaction = solver.solve(request) print(transaction) fmt = "ELAPSED : {description:20} : {elapsed:e}" print(solver._last_rules_time.pretty(fmt), file=sys.stderr) print(solver._last_solver_init_time.pretty(fmt), file=sys.stderr) print(solver._last_solve_time.pretty(fmt), file=sys.stderr) if debug: print(solver._policy._log_report(), file=sys.stderr)
def solve(self, top_core, tool): repo = Repository() for core in self._cores.values(): package_str = "{} {}-{}".format(self._package_name(core.name), core.name.version, core.name.revision) _depends = core.depend try: _depends += getattr(core, tool).depend except (AttributeError, KeyError): pass if _depends: _s = "; depends ( {} )" package_str += _s.format(self._parse_depend(_depends)) parser = PrettyPackageStringParser(EnpkgVersion.from_string) package = parser.parse_to_package(package_str) package.core = core repo.add_package(package) request = Request() _top_dep = "{} {} {}".format(self._package_name(top_core), top_core.relation, self._package_version(top_core)) requirement = Requirement._from_string(_top_dep) request.install(requirement) installed_repository = Repository() pool = Pool([repo]) pool.add_repository(installed_repository) solver = DependencySolver(pool, repo, installed_repository) try: transaction = solver.solve(request) except SatisfiabilityError as e: msg = "UNSATISFIABLE: {}" raise RuntimeError(msg.format(e.unsat.to_string(pool))) except NoPackageFound as e: raise DependencyError(top_core.name) return [op.package.core for op in transaction.operations]
def satisfy_requirements(packages, requirements, modifiers=None): """ Find a collection of packages that satisfy the requirements. Parameters ---------- packages : iterable of PackageMetadata The packages available to draw from when satisfying requirements. requirements : list of Requirement The requirements used to identify relevent packages. modifiers : ConstraintModifiers, optional If not None, modify requirements before resolving packages. Returns ------- tuple of PackageMetadata Return a tuple of packages that together satisfy all of the `requirements`. The packages are in topological order. Raises ------ SatisfiabilityError If the `requirements` cannot be satisfied using the `packages`. """ request = Request(modifiers=modifiers) for requirement in requirements: request.install(requirement) repositories = (Repository(packages),) pool = Pool(repositories, modifiers=modifiers) transaction = DependencySolver(pool, repositories, []).solve(request) msg = (""" Unexpected operation in the transaction. This should never occur. Something in simplesat is broken. {!r}""") for op in transaction.operations: # Our installed repository was empty so everything should be an install # operation assert isinstance(op, InstallOperation), msg.format(op) packages = tuple(op.package for op in transaction.operations) return packages
def _solve(self, top_core, flags={}, only_matching_vlnv=False): def eq_vln(this, that): return ( this.vendor == that.vendor and this.library == that.library and this.name == that.name ) # Try to return a cached result solver_cache_key = (top_core, self._hash_flags_dict(flags), only_matching_vlnv) cached_solution = self._solver_cache_lookup(solver_cache_key) if cached_solution: return cached_solution repo = Repository() _flags = flags.copy() cores = [x["core"] for x in self._cores.values()] for core in cores: if only_matching_vlnv: if not eq_vln(core.name, top_core): continue package_str = "{} {}-{}".format( self._package_name(core.name), core.name.version, core.name.revision ) if not only_matching_vlnv: _flags["is_toplevel"] = core.name == top_core _depends = core.get_depends(_flags) if _depends: _s = "; depends ( {} )" package_str += _s.format(self._parse_depend(_depends)) parser = PrettyPackageStringParser(EnpkgVersion.from_string) package = parser.parse_to_package(package_str) package.core = core repo.add_package(package) request = Request() simplevlnvs = top_core.simpleVLNVs() for sv in simplevlnvs: _top_dep = "{} {} {}".format( self._package_name(top_core), top_core.relation, self._package_version(top_core), ) request.install(Requirement._from_string(_top_dep)) installed_repository = Repository() pool = Pool([repo]) pool.add_repository(installed_repository) solver = DependencySolver(pool, [repo], installed_repository) try: transaction = solver.solve(request) except SatisfiabilityError as e: raise DependencyError(top_core.name, msg=e.unsat.to_string(pool)) except NoPackageFound as e: raise DependencyError(top_core.name) objdict = {} depdict = {} if len(transaction.operations) > 1: for op in transaction.operations: objdict[op.package._name] = str(op.package.core.name) depdict[str(op.package.core.name)] = [ objdict[n[0]] for n in op.package.install_requires ] op.package.core.direct_deps = [ objdict[n[0]] for n in op.package.install_requires ] result = [op.package.core for op in transaction.operations] # Cache the solution for further lookups self._solver_cache_store(solver_cache_key, result) return result
def pool_and_repository_from_packages(packages): repository = Repository(packages_from_definition(packages)) pool = Pool([repository]) return pool, repository