예제 #1
0
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)
예제 #2
0
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))
예제 #3
0
    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)
예제 #4
0
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
예제 #5
0
    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)
예제 #6
0
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))
예제 #7
0
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))
예제 #8
0
    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]
예제 #9
0
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
예제 #10
0
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
예제 #11
0
 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)
예제 #12
0
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)
        )
예제 #13
0
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)
예제 #14
0
    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]
예제 #15
0
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
예제 #16
0
    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
예제 #17
0
def pool_and_repository_from_packages(packages):
    repository = Repository(packages_from_definition(packages))
    pool = Pool([repository])
    return pool, repository