Ejemplo n.º 1
0
    def _do_refresh(self):
        from poetry.puzzle import Solver

        # Checking extras
        for extra in self._extras:
            if extra not in self._package.extras:
                raise ValueError("Extra [{}] is not specified.".format(extra))

        locked_repository = self._locker.locked_repository(True)
        solver = Solver(
            self._package,
            self._pool,
            locked_repository,
            locked_repository,
            self._io,  # noqa
        )

        ops = solver.solve(use_latest=[])

        local_repo = Repository()
        self._populate_local_repo(local_repo, ops)

        self._write_lock_file(local_repo, force=True)

        return 0
Ejemplo n.º 2
0
def test_solver_chooses_from_correct_repository_if_forced_and_transitive_dependency(
    package, installed, locked, io
):
    package.python_versions = "^3.7"
    package.add_dependency("foo", "^1.0")
    package.add_dependency("tomlkit", {"version": "^0.5", "source": "legacy"})

    repo = Repository()
    foo = get_package("foo", "1.0.0")
    foo.add_dependency("tomlkit", "^0.5.0")
    repo.add_package(foo)
    pool = Pool([MockLegacyRepository(), repo, MockPyPIRepository()])

    solver = Solver(package, pool, installed, locked, io)

    ops = solver.solve()

    check_solver_result(
        ops,
        [
            {"job": "install", "package": get_package("tomlkit", "0.5.2")},
            {"job": "install", "package": foo},
        ],
    )

    assert "legacy" == ops[0].package.source_type
    assert "http://foo.bar" == ops[0].package.source_url

    assert "" == ops[1].package.source_type
    assert "" == ops[1].package.source_url
Ejemplo n.º 3
0
def test_solver_chooses_from_secondary_if_explicit(package, installed, locked, io):
    package.python_versions = "^3.7"
    package.add_dependency("clikit", {"version": "^0.2.0", "source": "PyPI"})

    pool = Pool()
    pool.add_repository(MockPyPIRepository(), secondary=True)
    pool.add_repository(MockLegacyRepository())

    solver = Solver(package, pool, installed, locked, io)

    ops = solver.solve()

    check_solver_result(
        ops,
        [
            {"job": "install", "package": get_package("pastel", "0.1.0")},
            {"job": "install", "package": get_package("pylev", "1.3.0")},
            {"job": "install", "package": get_package("clikit", "0.2.4")},
        ],
    )

    assert "legacy" == ops[0].package.source_type
    assert "http://foo.bar" == ops[0].package.source_url
    assert "" == ops[1].package.source_type
    assert "" == ops[1].package.source_url
    assert "" == ops[2].package.source_type
    assert "" == ops[2].package.source_url
Ejemplo n.º 4
0
def test_solver_discards_packages_with_empty_markers(
    package, installed, locked, io, pool, repo
):
    package.python_versions = "~2.7 || ^3.4"
    package.add_dependency(
        "a", {"version": "^0.1.0", "markers": "python_version >= '3.4'"}
    )

    package_a = get_package("a", "0.1.0")
    package_a.add_dependency(
        "b", {"version": "^0.1.0", "markers": "python_version < '3.2'"}
    )
    package_a.add_dependency("c", "^0.2.0")
    package_b = get_package("b", "0.1.0")
    package_c = get_package("c", "0.2.0")
    repo.add_package(package_a)
    repo.add_package(package_b)
    repo.add_package(package_c)

    solver = Solver(package, pool, installed, locked, io)

    ops = solver.solve()

    check_solver_result(
        ops,
        [
            {"job": "install", "package": package_c},
            {"job": "install", "package": package_a},
        ],
    )
Ejemplo n.º 5
0
def test_solver_can_solve_with_legacy_repository_using_proper_dists(
        package, installed, locked, io):
    repo = MockLegacyRepository()
    pool = Pool([repo])

    solver = Solver(package, pool, installed, locked, io)

    package.add_dependency("isort", "4.3.4")

    ops = solver.solve()

    check_solver_result(
        ops,
        [
            {
                "job": "install",
                "package": get_package("futures", "3.2.0")
            },
            {
                "job": "install",
                "package": get_package("isort", "4.3.4")
            },
        ],
    )

    futures = ops[0].package
    assert futures.python_versions == ">=2.6, <3"
Ejemplo n.º 6
0
    def _do_refresh(self) -> int:
        from poetry.puzzle import Solver

        # Checking extras
        for extra in self._extras:
            if extra not in self._package.extras:
                raise ValueError(f"Extra [{extra}] is not specified.")

        locked_repository = self._locker.locked_repository()
        solver = Solver(
            self._package,
            self._pool,
            locked_repository,
            locked_repository,
            self._io,
        )

        with solver.provider.use_source_root(
            source_root=self._env.path.joinpath("src")
        ):
            ops = solver.solve(use_latest=[]).calculate_operations()

        local_repo = Repository()
        self._populate_local_repo(local_repo, ops)

        self._write_lock_file(local_repo, force=True)

        return 0
Ejemplo n.º 7
0
    def handle(self):
        from poetry.packages import Dependency
        from poetry.packages import ProjectPackage
        from poetry.puzzle import Solver
        from poetry.repositories.repository import Repository
        from poetry.semver import parse_constraint

        packages = self.argument("package")

        if not packages:
            package = self.poetry.package
        else:
            requirements = self._determine_requirements(packages)
            requirements = self._format_requirements(requirements)

            # validate requirements format
            for constraint in requirements.values():
                parse_constraint(constraint)

            dependencies = []
            for name, constraint in requirements.items():
                dep = Dependency(name, constraint)
                extras = []
                for extra in self.option("extras"):
                    if " " in extra:
                        extras += [e.strip() for e in extra.split(" ")]
                    else:
                        extras.append(extra)

                for ex in extras:
                    dep.extras.append(ex)

                dependencies.append(dep)

            package = ProjectPackage(self.poetry.package.name,
                                     self.poetry.package.version)

            package.python_versions = (self.option("python")
                                       or self.poetry.package.python_versions)
            for dep in dependencies:
                package.requires.append(dep)

        solver = Solver(package, self.poetry.pool, Repository(), Repository(),
                        self.output)

        ops = solver.solve()

        self.line("")
        self.line("Resolution results:")
        self.line("")

        for op in ops:
            package = op.package
            self.line("  - <info>{}</info> (<comment>{}</comment>)".format(
                package.name, package.version))
            if package.requirements:
                for req_name, req_value in package.requirements.items():
                    self.line("    - {}: {}".format(req_name, req_value))
Ejemplo n.º 8
0
def test_solver_skips_invalid_versions(package, installed, locked, io):
    package.python_versions = "^3.7"

    repo = MockPyPIRepository()
    pool = Pool([repo])

    solver = Solver(package, pool, installed, locked, io)

    package.add_dependency("trackpy", "^0.4")

    ops = solver.solve()

    check_solver_result(
        ops, [{"job": "install", "package": get_package("trackpy", "0.4.1")}]
    )
Ejemplo n.º 9
0
def test_solver_can_solve_with_legacy_repository_using_proper_python_compatible_dists(
    package, installed, locked, io
):
    package.python_versions = "^3.7"

    repo = MockLegacyRepository()
    pool = Pool([repo])

    solver = Solver(package, pool, installed, locked, io)

    package.add_dependency("isort", "4.3.4")

    ops = solver.solve()

    check_solver_result(
        ops, [{"job": "install", "package": get_package("isort", "4.3.4")}]
    )
Ejemplo n.º 10
0
def test_solver_chooses_most_recent_version_amongst_repositories(
    package, installed, locked, io
):
    package.python_versions = "^3.7"
    package.add_dependency("tomlkit", {"version": "^0.5"})

    repo = MockLegacyRepository()
    pool = Pool([repo, MockPyPIRepository()])

    solver = Solver(package, pool, installed, locked, io)

    ops = solver.solve()

    check_solver_result(
        ops, [{"job": "install", "package": get_package("tomlkit", "0.5.3")}]
    )

    assert "" == ops[0].package.source_type
    assert "" == ops[0].package.source_url
Ejemplo n.º 11
0
def test_solver_chooses_from_correct_repository_if_forced(
    package, installed, locked, io
):
    package.python_versions = "^3.7"
    package.add_dependency("tomlkit", {"version": "^0.5", "source": "legacy"})

    repo = MockLegacyRepository()
    pool = Pool([repo, MockPyPIRepository()])

    solver = Solver(package, pool, installed, locked, io)

    ops = solver.solve()

    check_solver_result(
        ops, [{"job": "install", "package": get_package("tomlkit", "0.5.2")}]
    )

    assert "legacy" == ops[0].package.source_type
    assert "http://foo.bar" == ops[0].package.source_url
Ejemplo n.º 12
0
    def handle(self):
        packages = self.argument('package')

        if not packages:
            package = self.poetry.package
            dependencies = package.requires + package.dev_requires
        else:
            requirements = self._determine_requirements(packages)
            requirements = self._format_requirements(requirements)

            # validate requirements format
            parser = VersionParser()
            for constraint in requirements.values():
                parser.parse_constraints(constraint)

            dependencies = []
            for name, constraint in requirements.items():
                dependencies.append(
                    Dependency(name, constraint)
                )

        solver = Solver(
            self.poetry.package,
            self.poetry.pool,
            Repository(),
            self.output
        )

        ops = solver.solve(dependencies)

        self.line('')
        self.line('Resolution results:')
        self.line('')

        for op in ops:
            package = op.package
            self.line(f'  - <info>{package.name}</info> '
                      f'(<comment>{package.version}</comment>)')
Ejemplo n.º 13
0
    def handle(self):
        from poetry.packages import ProjectPackage
        from poetry.puzzle import Solver
        from poetry.repositories.repository import Repository
        from poetry.semver import parse_constraint
        from poetry.utils.env import EnvManager

        packages = self.argument("package")

        if not packages:
            package = self.poetry.package
        else:
            # Using current pool for determine_requirements()
            self._pool = self.poetry.pool

            package = ProjectPackage(self.poetry.package.name,
                                     self.poetry.package.version)

            # Silencing output
            is_quiet = self.io.output.is_quiet()
            if not is_quiet:
                self.io.output.set_quiet(True)

            requirements = self._determine_requirements(packages)

            if not is_quiet:
                self.io.output.set_quiet(False)

            for constraint in requirements:
                name = constraint.pop("name")
                dep = package.add_dependency(name, constraint)
                extras = []
                for extra in self.option("extras"):
                    if " " in extra:
                        extras += [e.strip() for e in extra.split(" ")]
                    else:
                        extras.append(extra)

                for ex in extras:
                    dep.extras.append(ex)

        package.python_versions = self.option("python") or (
            self.poetry.package.python_versions)

        pool = self.poetry.pool

        solver = Solver(package, pool, Repository(), Repository(), self._io)

        ops = solver.solve()

        self.line("")
        self.line("Resolution results:")
        self.line("")

        if self.option("tree"):
            show_command = self.application.find("show")
            show_command.init_styles(self.io)

            packages = [op.package for op in ops]
            repo = Repository(packages)

            requires = package.requires + package.dev_requires
            for pkg in repo.packages:
                for require in requires:
                    if pkg.name == require.name:
                        show_command.display_package_tree(self.io, pkg, repo)
                        break

            return 0

        env = EnvManager(self.poetry.config).get(self.poetry.file.parent)
        current_python_version = parse_constraint(".".join(
            str(v) for v in env.version_info))
        table = self.table([], style="borderless")
        rows = []
        for op in ops:
            pkg = op.package
            if self.option("install"):
                if not pkg.python_constraint.allows(
                        current_python_version) or not env.is_valid_for_marker(
                            pkg.marker):
                    continue
            row = [
                "<info>{}</info>".format(pkg.name),
                "<b>{}</b>".format(pkg.version),
                "",
            ]

            if not pkg.marker.is_any():
                row[2] = str(pkg.marker)

            rows.append(row)

        table.set_rows(rows)
        table.render(self.io)
Ejemplo n.º 14
0
    def handle(self):
        from poetry.packages import ProjectPackage
        from poetry.puzzle import Solver
        from poetry.repositories.repository import Repository
        from poetry.semver import parse_constraint
        from poetry.utils.env import Env

        packages = self.argument("package")

        if not packages:
            package = self.poetry.package
        else:
            package = ProjectPackage(self.poetry.package.name,
                                     self.poetry.package.version)
            requirements = self._format_requirements(packages)

            for name, constraint in requirements.items():
                dep = package.add_dependency(name, constraint)
                extras = []
                for extra in self.option("extras"):
                    if " " in extra:
                        extras += [e.strip() for e in extra.split(" ")]
                    else:
                        extras.append(extra)

                for ex in extras:
                    dep.extras.append(ex)

        package.python_versions = self.option("python") or (
            self.poetry.package.python_versions)

        pool = self.poetry.pool

        solver = Solver(package, pool, Repository(), Repository(), self.output)

        ops = solver.solve()

        self.line("")
        self.line("Resolution results:")
        self.line("")

        if self.option("tree"):
            show_command = self.get_application().find("show")
            show_command.output = self.output
            show_command.init_styles()

            packages = [op.package for op in ops]
            repo = Repository(packages)

            requires = package.requires + package.dev_requires
            for pkg in repo.packages:
                for require in requires:
                    if pkg.name == require.name:
                        show_command.display_package_tree(pkg, repo)
                        break

            return 0

        env = Env.get()
        current_python_version = parse_constraint(".".join(
            str(v) for v in env.version_info))
        for op in ops:
            pkg = op.package
            if self.option("install"):
                if not pkg.python_constraint.allows(
                        current_python_version) or not env.is_valid_for_marker(
                            pkg.marker):
                    continue

            self.line("  - <info>{}</info> (<comment>{}</comment>)".format(
                pkg.name, pkg.version))
            if not pkg.python_constraint.is_any():
                self.line("    - python: {}".format(pkg.python_versions))

            if not pkg.marker.is_any():
                self.line("    - marker: {}".format(pkg.marker))
Ejemplo n.º 15
0
def solve_pypi(
    pip_specs: Dict[str, src_parser.Dependency],
    use_latest: List[str],
    pip_locked: Dict[str, src_parser.LockedDependency],
    conda_locked: Dict[str, src_parser.LockedDependency],
    python_version: str,
    platform: str,
    verbose: bool = False,
) -> Dict[str, src_parser.LockedDependency]:
    """
    Solve pip dependencies for the given platform

    Parameters
    ----------
    conda :
        Path to conda, mamba, or micromamba
    use_latest :
        Names of packages to update to the latest version compatible with pip_specs
    pip_specs :
        PEP440 package specifications
    pip_locked :
        Previous solution for the given platform (pip packages only)
    conda_locked :
        Current solution of conda-only specs for the given platform
    python_version :
        Version of Python in conda_locked
    platform :
        Target platform
    verbose :
        Print chatter from solver

    """
    dummy_package = ProjectPackage("_dummy_package_", "0.0.0")
    dependencies = [get_dependency(spec) for spec in pip_specs.values()]
    for dep in dependencies:
        dummy_package.add_dependency(dep)

    pypi = PyPiRepository()
    pool = Pool(repositories=[pypi])

    installed = Repository()
    locked = Repository()

    python_packages = dict()
    for dep in conda_locked.values():
        if dep.name.startswith("__"):
            continue
        try:
            pypi_name = conda_name_to_pypi_name(dep.name).lower()
        except KeyError:
            continue
        # Prefer the Python package when its name collides with the Conda package
        # for the underlying library, e.g. python-xxhash (pypi: xxhash) over xxhash
        # (pypi: no equivalent)
        if pypi_name not in python_packages or pypi_name != dep.name:
            python_packages[pypi_name] = dep.version
    # treat conda packages as both locked and installed
    for name, version in python_packages.items():
        for repo in (locked, installed):
            repo.add_package(Package(name=name, version=version))
    # treat pip packages as locked only
    for spec in pip_locked.values():
        locked.add_package(get_package(spec))

    if verbose:
        io = ConsoleIO()
        io.set_verbosity(VERY_VERBOSE)
    else:
        io = NullIO()
    s = Solver(
        dummy_package,
        pool=pool,
        installed=installed,
        locked=locked,
        io=io,
    )
    to_update = list({spec.name
                      for spec in pip_locked.values()
                      }.intersection(use_latest))
    env = PlatformEnv(python_version, platform)
    # find platform-specific solution (e.g. dependencies conditioned on markers)
    with s.use_environment(env):
        result = s.solve(use_latest=to_update)

    chooser = Chooser(pool, env=env)

    # Extract distributions from Poetry package plan, ignoring uninstalls
    # (usually: conda package with no pypi equivalent) and skipped ops
    # (already installed)
    requirements: List[src_parser.LockedDependency] = []
    for op in result:
        if not isinstance(op, Uninstall) and not op.skipped:
            # Take direct references verbatim
            source: Optional[src_parser.DependencySource] = None
            if op.package.source_type == "url":
                url, fragment = urldefrag(op.package.source_url)
                hash_type, hash = fragment.split("=")
                hash = src_parser.HashModel(**{hash_type: hash})
                source = src_parser.DependencySource(type="url",
                                                     url=op.package.source_url)
            # Choose the most specific distribution for the target
            else:
                link = chooser.choose_for(op.package)
                url = link.url_without_fragment
                hash = src_parser.HashModel(**{link.hash_name: link.hash})

            requirements.append(
                src_parser.LockedDependency(
                    name=op.package.name,
                    version=str(op.package.version),
                    manager="pip",
                    source=source,
                    platform=platform,
                    dependencies={
                        dep.name: str(dep.constraint)
                        for dep in op.package.requires
                    },
                    url=url,
                    hash=hash,
                ))

    # use PyPI names of conda packages to walking the dependency tree and propagate
    # categories from explicit to transitive dependencies
    planned = {
        **{dep.name: dep
           for dep in requirements},
        # prefer conda packages so add them afterwards
    }

    for conda_name, dep in conda_locked.items():
        try:
            pypi_name = conda_name_to_pypi_name(conda_name).lower()
        except KeyError:
            # no conda-name found, assuming conda packages do NOT intersect with the pip package
            continue
        planned[pypi_name] = dep

    src_parser._apply_categories(requested=pip_specs, planned=planned)

    return {dep.name: dep for dep in requirements}
Ejemplo n.º 16
0
    def handle(self):
        from poetry.packages import Dependency
        from poetry.packages import ProjectPackage
        from poetry.puzzle import Solver
        from poetry.repositories.repository import Repository
        from poetry.semver import parse_constraint

        packages = self.argument("package")

        if not packages:
            package = self.poetry.package
        else:
            requirements = self._determine_requirements(packages)
            requirements = self._format_requirements(requirements)

            # validate requirements format
            for constraint in requirements.values():
                parse_constraint(constraint)

            dependencies = []
            for name, constraint in requirements.items():
                dep = Dependency(name, constraint)
                extras = []
                for extra in self.option("extras"):
                    if " " in extra:
                        extras += [e.strip() for e in extra.split(" ")]
                    else:
                        extras.append(extra)

                for ex in extras:
                    dep.extras.append(ex)

                dependencies.append(dep)

            package = ProjectPackage(
                self.poetry.package.name, self.poetry.package.version
            )

            package.python_versions = (
                self.option("python") or self.poetry.package.python_versions
            )
            for dep in dependencies:
                package.requires.append(dep)

        solver = Solver(
            package, self.poetry.pool, Repository(), Repository(), self.output
        )

        ops = solver.solve()

        self.line("")
        self.line("Resolution results:")
        self.line("")

        for op in ops:
            package = op.package
            self.line(
                "  - <info>{}</info> (<comment>{}</comment>)".format(
                    package.name, package.version
                )
            )
            if package.requirements:
                for req_name, req_value in package.requirements.items():
                    self.line("    - {}: {}".format(req_name, req_value))
Ejemplo n.º 17
0
    def _do_install(self, local_repo):
        locked_repository = Repository()
        if self._update:
            if self._locker.is_locked() and self._whitelist:
                # If we update with a lock file present and
                # we have whitelisted packages (the ones we want to update)
                # we get the lock file packages to only update
                # what is strictly needed.
                #
                # Otherwise, the lock file information is irrelevant
                # since we want to update everything.
                locked_repository = self._locker.locked_repository(True)

            # Checking extras
            for extra in self._extras:
                if extra not in self._package.extras:
                    raise ValueError(
                        "Extra [{}] is not specified.".format(extra))

            self._io.writeln("<info>Updating dependencies</>")
            solver = Solver(
                self._package,
                self._pool,
                self._installed_repository,
                locked_repository,
                self._io,
            )

            ops = solver.solve(use_latest=self._whitelist)
        else:
            self._io.writeln("<info>Installing dependencies from lock file</>")

            locked_repository = self._locker.locked_repository(True)

            if not self._locker.is_fresh():
                self._io.writeln(
                    "<warning>"
                    "Warning: The lock file is not up to date with "
                    "the latest changes in pyproject.toml. "
                    "You may be getting outdated dependencies. "
                    "Run update to update them."
                    "</warning>")

            for extra in self._extras:
                if extra not in self._locker.lock_data.get("extras", {}):
                    raise ValueError(
                        "Extra [{}] is not specified.".format(extra))

            # If we are installing from lock
            # Filter the operations by comparing it with what is
            # currently installed
            ops = self._get_operations_from_lock(locked_repository)

        self._populate_local_repo(local_repo, ops, locked_repository)

        # We need to filter operations so that packages
        # not compatible with the current system,
        # or optional and not requested, are dropped
        self._filter_operations(ops, local_repo)

        self._io.new_line()

        # Execute operations
        actual_ops = [op for op in ops if not op.skipped]
        if not actual_ops and (self._execute_operations or self._dry_run):
            self._io.writeln("Nothing to install or update")

        if actual_ops and (self._execute_operations or self._dry_run):
            installs = []
            updates = []
            uninstalls = []
            skipped = []
            for op in ops:
                if op.skipped:
                    skipped.append(op)
                    continue

                if op.job_type == "install":
                    installs.append("{}:{}".format(
                        op.package.pretty_name,
                        op.package.full_pretty_version))
                elif op.job_type == "update":
                    updates.append("{}:{}".format(
                        op.target_package.pretty_name,
                        op.target_package.full_pretty_version,
                    ))
                elif op.job_type == "uninstall":
                    uninstalls.append(op.package.pretty_name)

            self._io.new_line()
            self._io.writeln("Package operations: "
                             "<info>{}</> install{}, "
                             "<info>{}</> update{}, "
                             "<info>{}</> removal{}"
                             "{}".format(
                                 len(installs),
                                 "" if len(installs) == 1 else "s",
                                 len(updates),
                                 "" if len(updates) == 1 else "s",
                                 len(uninstalls),
                                 "" if len(uninstalls) == 1 else "s",
                                 ", <info>{}</> skipped".format(len(skipped))
                                 if skipped and self.is_verbose() else "",
                             ))

        # Writing lock before installing
        if self._update and self._write_lock:
            updated_lock = self._locker.set_lock_data(self._package,
                                                      local_repo.packages)

            if updated_lock:
                self._io.writeln("")
                self._io.writeln("<info>Writing lock file</>")

        self._io.writeln("")
        for op in ops:
            self._execute(op)
Ejemplo n.º 18
0
    def _do_install(self, local_repo: Repository) -> int:
        from poetry.puzzle import Solver

        locked_repository = Repository()
        if self._update:
            if self._locker.is_locked() and not self._lock:
                locked_repository = self._locker.locked_repository(True)

                # If no packages have been whitelisted (The ones we want to update),
                # we whitelist every package in the lock file.
                if not self._whitelist:
                    for pkg in locked_repository.packages:
                        self._whitelist.append(pkg.name)

            # Checking extras
            for extra in self._extras:
                if extra not in self._package.extras:
                    raise ValueError(f"Extra [{extra}] is not specified.")

            self._io.write_line("<info>Updating dependencies</>")
            solver = Solver(
                self._package,
                self._pool,
                self._installed_repository,
                locked_repository,
                self._io,
                remove_untracked=self._remove_untracked,
            )

            ops = solver.solve(use_latest=self._whitelist)
        else:
            self._io.write_line(
                "<info>Installing dependencies from lock file</>")

            locked_repository = self._locker.locked_repository(True)

            if not self._locker.is_fresh():
                self._io.write_line(
                    "<warning>"
                    "Warning: The lock file is not up to date with "
                    "the latest changes in pyproject.toml. "
                    "You may be getting outdated dependencies. "
                    "Run update to update them."
                    "</warning>")

            for extra in self._extras:
                if extra not in self._locker.lock_data.get("extras", {}):
                    raise ValueError(f"Extra [{extra}] is not specified.")

            # If we are installing from lock
            # Filter the operations by comparing it with what is
            # currently installed
            ops = self._get_operations_from_lock(locked_repository)

        self._populate_local_repo(local_repo, ops)

        if self._update:
            self._write_lock_file(local_repo)

            if self._lock:
                # If we are only in lock mode, no need to go any further
                return 0

        if self._without_groups or self._with_groups or self._only_groups:
            if self._with_groups:
                # Default dependencies and opted-in optional dependencies
                root = self._package.with_dependency_groups(self._with_groups)
            elif self._without_groups:
                # Default dependencies without selected groups
                root = self._package.without_dependency_groups(
                    self._without_groups)
            else:
                # Only selected groups
                root = self._package.with_dependency_groups(self._only_groups,
                                                            only=True)
        else:
            root = self._package.without_optional_dependency_groups()

        if self._io.is_verbose():
            self._io.write_line("")
            self._io.write_line(
                "<info>Finding the necessary packages for the current system</>"
            )

        # We resolve again by only using the lock file
        pool = Pool(ignore_repository_names=True)

        # Making a new repo containing the packages
        # newly resolved and the ones from the current lock file
        repo = Repository()
        for package in local_repo.packages + locked_repository.packages:
            if not repo.has_package(package):
                repo.add_package(package)

        pool.add_repository(repo)

        solver = Solver(
            root,
            pool,
            self._installed_repository,
            locked_repository,
            NullIO(),
            remove_untracked=self._remove_untracked,
        )
        # Everything is resolved at this point, so we no longer need
        # to load deferred dependencies (i.e. VCS, URL and path dependencies)
        solver.provider.load_deferred(False)

        with solver.use_environment(self._env):
            ops = solver.solve(use_latest=self._whitelist)

        # We need to filter operations so that packages
        # not compatible with the current system,
        # or optional and not requested, are dropped
        self._filter_operations(ops, local_repo)

        # Execute operations
        return self._execute(ops)
Ejemplo n.º 19
0
    def handle(self) -> Optional[int]:
        from cleo.io.null_io import NullIO

        from poetry.core.packages.project_package import ProjectPackage
        from poetry.factory import Factory
        from poetry.puzzle import Solver
        from poetry.repositories.pool import Pool
        from poetry.repositories.repository import Repository
        from poetry.utils.env import EnvManager

        packages = self.argument("package")

        if not packages:
            package = self.poetry.package
        else:
            # Using current pool for determine_requirements()
            self._pool = self.poetry.pool

            package = ProjectPackage(self.poetry.package.name,
                                     self.poetry.package.version)

            # Silencing output
            verbosity = self.io.output.verbosity
            self.io.output.set_verbosity(Verbosity.QUIET)

            requirements = self._determine_requirements(packages)

            self.io.output.set_verbosity(verbosity)

            for constraint in requirements:
                name = constraint.pop("name")
                extras = []
                for extra in self.option("extras"):
                    if " " in extra:
                        extras += [e.strip() for e in extra.split(" ")]
                    else:
                        extras.append(extra)

                constraint["extras"] = extras

                package.add_dependency(
                    Factory.create_dependency(name, constraint))

        package.python_versions = self.option("python") or (
            self.poetry.package.python_versions)

        pool = self.poetry.pool

        solver = Solver(package, pool, Repository(), Repository(), self._io)

        ops = solver.solve().calculate_operations()

        self.line("")
        self.line("Resolution results:")
        self.line("")

        if self.option("tree"):
            show_command: ShowCommand = self.application.find("show")
            show_command.init_styles(self.io)

            packages = [op.package for op in ops]
            repo = Repository(packages)

            requires = package.all_requires
            for pkg in repo.packages:
                for require in requires:
                    if pkg.name == require.name:
                        show_command.display_package_tree(self.io, pkg, repo)
                        break

            return 0

        table = self.table(style="compact")
        table.style.set_vertical_border_chars("", " ")
        rows = []

        if self.option("install"):
            env = EnvManager(self.poetry).get()
            pool = Pool()
            locked_repository = Repository()
            for op in ops:
                locked_repository.add_package(op.package)

            pool.add_repository(locked_repository)

            solver = Solver(package, pool, Repository(), Repository(),
                            NullIO())
            with solver.use_environment(env):
                ops = solver.solve().calculate_operations()

        for op in ops:
            if self.option("install") and op.skipped:
                continue

            pkg = op.package
            row = [
                "<c1>{}</c1>".format(pkg.complete_name),
                "<b>{}</b>".format(pkg.version),
            ]

            if not pkg.marker.is_any():
                row[2] = str(pkg.marker)

            rows.append(row)

        table.set_rows(rows)
        table.render()

        return None
Ejemplo n.º 20
0
    def _do_install(self, local_repo: Repository) -> int:
        from poetry.puzzle import Solver

        locked_repository = Repository()
        if self._update:
            if self._locker.is_locked() and not self._lock:
                locked_repository = self._locker.locked_repository()

                # If no packages have been whitelisted (The ones we want to update),
                # we whitelist every package in the lock file.
                if not self._whitelist:
                    for pkg in locked_repository.packages:
                        self._whitelist.append(pkg.name)

            # Checking extras
            for extra in self._extras:
                if extra not in self._package.extras:
                    raise ValueError(f"Extra [{extra}] is not specified.")

            self._io.write_line("<info>Updating dependencies</>")
            solver = Solver(
                self._package,
                self._pool,
                self._installed_repository,
                locked_repository,
                self._io,
            )

            with solver.provider.use_source_root(
                source_root=self._env.path.joinpath("src")
            ):
                ops = solver.solve(use_latest=self._whitelist).calculate_operations()
        else:
            self._io.write_line("<info>Installing dependencies from lock file</>")

            locked_repository = self._locker.locked_repository()

            if not self._locker.is_fresh():
                self._io.write_error_line(
                    "<warning>"
                    "Warning: poetry.lock is not consistent with pyproject.toml. "
                    "You may be getting improper dependencies. "
                    "Run `poetry lock [--no-update]` to fix it."
                    "</warning>"
                )

            for extra in self._extras:
                if extra not in self._locker.lock_data.get("extras", {}):
                    raise ValueError(f"Extra [{extra}] is not specified.")

            # If we are installing from lock
            # Filter the operations by comparing it with what is
            # currently installed
            ops = self._get_operations_from_lock(locked_repository)

        self._populate_local_repo(local_repo, ops)

        if self._update:
            self._write_lock_file(local_repo)

            if self._lock:
                # If we are only in lock mode, no need to go any further
                return 0

        if self._groups is not None:
            root = self._package.with_dependency_groups(list(self._groups), only=True)
        else:
            root = self._package.without_optional_dependency_groups()

        if self._io.is_verbose():
            self._io.write_line("")
            self._io.write_line(
                "<info>Finding the necessary packages for the current system</>"
            )

        # We resolve again by only using the lock file
        pool = Pool(ignore_repository_names=True)

        # Making a new repo containing the packages
        # newly resolved and the ones from the current lock file
        repo = Repository()
        for package in local_repo.packages + locked_repository.packages:
            if not repo.has_package(package):
                repo.add_package(package)

        pool.add_repository(repo)

        solver = Solver(
            root, pool, self._installed_repository, locked_repository, NullIO()
        )
        # Everything is resolved at this point, so we no longer need
        # to load deferred dependencies (i.e. VCS, URL and path dependencies)
        solver.provider.load_deferred(False)

        with solver.use_environment(self._env):
            ops = solver.solve(use_latest=self._whitelist).calculate_operations(
                with_uninstalls=self._requires_synchronization,
                synchronize=self._requires_synchronization,
            )

        if not self._requires_synchronization:
            # If no packages synchronisation has been requested we need
            # to calculate the uninstall operations
            from poetry.puzzle.transaction import Transaction

            transaction = Transaction(
                locked_repository.packages,
                [(package, 0) for package in local_repo.packages],
                installed_packages=self._installed_repository.packages,
                root_package=root,
            )

            ops = [
                op
                for op in transaction.calculate_operations(with_uninstalls=True)
                if op.job_type == "uninstall"
            ] + ops

        # We need to filter operations so that packages
        # not compatible with the current system,
        # or optional and not requested, are dropped
        self._filter_operations(ops, local_repo)

        # Execute operations
        return self._execute(ops)
Ejemplo n.º 21
0
    def _do_install(self, local_repo):
        locked_repository = Repository()
        if self._update:
            if self._locker.is_locked():
                locked_repository = self._locker.locked_repository(True)

            # Checking extras
            for extra in self._extras:
                if extra not in self._package.extras:
                    raise ValueError(
                        'Extra [{}] is not specified.'.format(extra))

            self._io.writeln('<info>Updating dependencies</>')
            fixed = []

            # If the whitelist is enabled, packages not in it are fixed
            # to the version specified in the lock
            if self._whitelist:
                # collect packages to fixate from root requirements
                candidates = []
                for package in locked_repository.packages:
                    candidates.append(package)

                # fix them to the version in lock if they are not updateable
                for candidate in candidates:
                    to_fix = True
                    for require in self._whitelist.keys():
                        if require == candidate.name:
                            to_fix = False

                    if to_fix:
                        dependency = Dependency(
                            candidate.name,
                            candidate.version,
                            optional=candidate.optional,
                            category=candidate.category,
                            allows_prereleases=candidate.is_prerelease())
                        fixed.append(dependency)

            solver = Solver(self._package, self._pool,
                            self._installed_repository, locked_repository,
                            self._io)

            request = self._package.requires
            request += self._package.dev_requires

            ops = solver.solve(request, fixed=fixed)
        else:
            self._io.writeln('<info>Installing dependencies from lock file</>')

            locked_repository = self._locker.locked_repository(True)

            if not self._locker.is_fresh():
                self._io.writeln(
                    '<warning>'
                    'Warning: The lock file is not up to date with '
                    'the latest changes in pyproject.toml. '
                    'You may be getting outdated dependencies. '
                    'Run update to update them.'
                    '</warning>')

            for extra in self._extras:
                if extra not in self._locker.lock_data.get('extras', {}):
                    raise ValueError(
                        'Extra [{}] is not specified.'.format(extra))

            # If we are installing from lock
            # Filter the operations by comparing it with what is
            # currently installed
            ops = self._get_operations_from_lock(locked_repository)

        self._populate_local_repo(local_repo, ops, locked_repository)

        # We need to filter operations so that packages
        # not compatible with the current system,
        # or optional and not requested, are dropped
        self._filter_operations(ops, local_repo)

        self._io.new_line()

        # Execute operations
        actual_ops = [op for op in ops if not op.skipped]
        if not actual_ops and (self._execute_operations or self._dry_run):
            self._io.writeln('Nothing to install or update')

        if actual_ops and (self._execute_operations or self._dry_run):
            installs = []
            updates = []
            uninstalls = []
            skipped = []
            for op in ops:
                if op.skipped:
                    skipped.append(op)
                    continue

                if op.job_type == 'install':
                    installs.append('{}:{}'.format(
                        op.package.pretty_name,
                        op.package.full_pretty_version))
                elif op.job_type == 'update':
                    updates.append('{}:{}'.format(
                        op.target_package.pretty_name,
                        op.target_package.full_pretty_version))
                elif op.job_type == 'uninstall':
                    uninstalls.append(op.package.pretty_name)

            self._io.new_line()
            self._io.writeln(
                'Package operations: '
                '<info>{}</> install{}, '
                '<info>{}</> update{}, '
                '<info>{}</> removal{}'
                '{}'.format(
                    len(installs), '' if len(installs) == 1 else 's',
                    len(updates), '' if len(updates) == 1 else 's',
                    len(uninstalls), '' if len(uninstalls) == 1 else 's',
                    ', <info>{}</> skipped'.format(len(skipped))
                    if skipped and self.is_verbose() else ''))

        # Writing lock before installing
        if self._update and self._write_lock:
            updated_lock = self._locker.set_lock_data(self._package,
                                                      local_repo.packages)

            if updated_lock:
                self._io.writeln('')
                self._io.writeln('<info>Writing lock file</>')

        self._io.writeln('')
        for op in ops:
            self._execute(op)
Ejemplo n.º 22
0
    def handle(self):
        from poetry.core.packages.project_package import ProjectPackage
        from poetry.io.null_io import NullIO
        from poetry.puzzle import Solver
        from poetry.repositories.pool import Pool
        from poetry.repositories.repository import Repository
        from poetry.utils.env import EnvManager

        packages = self.argument("package")

        if not packages:
            package = self.poetry.package
        else:
            # Using current pool for determine_requirements()
            self._pool = self.poetry.pool

            package = ProjectPackage(
                self.poetry.package.name, self.poetry.package.version
            )

            # Silencing output
            is_quiet = self.io.output.is_quiet()
            if not is_quiet:
                self.io.output.set_quiet(True)

            requirements = self._determine_requirements(packages)

            if not is_quiet:
                self.io.output.set_quiet(False)

            for constraint in requirements:
                name = constraint.pop("name")
                dep = package.add_dependency(name, constraint)
                extras = []
                for extra in self.option("extras"):
                    if " " in extra:
                        extras += [e.strip() for e in extra.split(" ")]
                    else:
                        extras.append(extra)

                for ex in extras:
                    dep.extras.append(ex)

        package.python_versions = self.option("python") or (
            self.poetry.package.python_versions
        )

        pool = self.poetry.pool

        solver = Solver(package, pool, Repository(), Repository(), self._io)

        ops = solver.solve()

        self.line("")
        self.line("Resolution results:")
        self.line("")

        if self.option("tree"):
            show_command = self.application.find("show")
            show_command.init_styles(self.io)

            packages = [op.package for op in ops]
            repo = Repository(packages)

            requires = package.requires + package.dev_requires
            for pkg in repo.packages:
                for require in requires:
                    if pkg.name == require.name:
                        show_command.display_package_tree(self.io, pkg, repo)
                        break

            return 0

        table = self.table([], style="borderless")
        rows = []

        if self.option("install"):
            env = EnvManager(self.poetry).get()
            pool = Pool()
            locked_repository = Repository()
            for op in ops:
                locked_repository.add_package(op.package)

            pool.add_repository(locked_repository)

            solver = Solver(package, pool, Repository(), Repository(), NullIO())
            with solver.use_environment(env):
                ops = solver.solve()

        for op in ops:
            if self.option("install") and op.skipped:
                continue

            pkg = op.package
            row = [
                "<c1>{}</c1>".format(pkg.name),
                "<b>{}</b>".format(pkg.version),
                "",
            ]

            if not pkg.marker.is_any():
                row[2] = str(pkg.marker)

            rows.append(row)

        table.set_rows(rows)
        table.render(self.io)
Ejemplo n.º 23
0
    def _do_install(self, local_repo):
        locked_repository = Repository()
        if self._update:
            if self._locker.is_locked() and not self._lock:
                locked_repository = self._locker.locked_repository(True)

                # If no packages have been whitelisted (The ones we want to update),
                # we whitelist every package in the lock file.
                if not self._whitelist:
                    for pkg in locked_repository.packages:
                        self._whitelist.append(pkg.name)

            # Checking extras
            for extra in self._extras:
                if extra not in self._package.extras:
                    raise ValueError(
                        "Extra [{}] is not specified.".format(extra))

            self._io.writeln("<info>Updating dependencies</>")
            solver = Solver(
                self._package,
                self._pool,
                self._installed_repository,
                locked_repository,
                self._io,
            )

            ops = solver.solve(use_latest=self._whitelist)
        else:
            self._io.writeln("<info>Installing dependencies from lock file</>")

            locked_repository = self._locker.locked_repository(True)

            if not self._locker.is_fresh():
                self._io.writeln(
                    "<warning>"
                    "Warning: The lock file is not up to date with "
                    "the latest changes in pyproject.toml. "
                    "You may be getting outdated dependencies. "
                    "Run update to update them."
                    "</warning>")

            for extra in self._extras:
                if extra not in self._locker.lock_data.get("extras", {}):
                    raise ValueError(
                        "Extra [{}] is not specified.".format(extra))

            # If we are installing from lock
            # Filter the operations by comparing it with what is
            # currently installed
            ops = self._get_operations_from_lock(locked_repository)

        self._populate_local_repo(local_repo, ops)

        if self._update:
            self._write_lock_file(local_repo)

            if self._lock:
                # If we are only in lock mode, no need to go any further
                return 0

        root = self._package
        if not self.is_dev_mode():
            root = root.clone()
            del root.dev_requires[:]

        with root.with_python_versions(".".join(
            [str(i) for i in self._env.version_info[:3]])):
            # We resolve again by only using the lock file
            pool = Pool()

            # Making a new repo containing the packages
            # newly resolved and the ones from the current lock file
            locked_repository = self._locker.locked_repository(True)
            repo = Repository()
            for package in local_repo.packages + locked_repository.packages:
                if not repo.has_package(package):
                    repo.add_package(package)

            pool.add_repository(repo)

            # We whitelist all packages to be sure
            # that the latest ones are picked up
            whitelist = []
            for pkg in locked_repository.packages:
                whitelist.append(pkg.name)

            solver = Solver(root, pool, self._installed_repository,
                            locked_repository, NullIO())

            ops = solver.solve(use_latest=whitelist)

        # We need to filter operations so that packages
        # not compatible with the current system,
        # or optional and not requested, are dropped
        self._filter_operations(ops, local_repo)

        self._io.new_line()

        # Execute operations
        actual_ops = [op for op in ops if not op.skipped]
        if not actual_ops and (self._execute_operations or self._dry_run):
            self._io.writeln("Nothing to install or update")

        if actual_ops and (self._execute_operations or self._dry_run):
            installs = []
            updates = []
            uninstalls = []
            skipped = []
            for op in ops:
                if op.skipped:
                    skipped.append(op)
                    continue

                if op.job_type == "install":
                    installs.append("{}:{}".format(
                        op.package.pretty_name,
                        op.package.full_pretty_version))
                elif op.job_type == "update":
                    updates.append("{}:{}".format(
                        op.target_package.pretty_name,
                        op.target_package.full_pretty_version,
                    ))
                elif op.job_type == "uninstall":
                    uninstalls.append(op.package.pretty_name)

            self._io.new_line()
            self._io.writeln("Package operations: "
                             "<info>{}</> install{}, "
                             "<info>{}</> update{}, "
                             "<info>{}</> removal{}"
                             "{}".format(
                                 len(installs),
                                 "" if len(installs) == 1 else "s",
                                 len(updates),
                                 "" if len(updates) == 1 else "s",
                                 len(uninstalls),
                                 "" if len(uninstalls) == 1 else "s",
                                 ", <info>{}</> skipped".format(len(skipped))
                                 if skipped and self.is_verbose() else "",
                             ))

        self._io.writeln("")
        for op in ops:
            self._execute(op)
Ejemplo n.º 24
0
    def _do_install(self, local_repo):
        from poetry.puzzle import Solver

        locked_repository = Repository()
        if self._update:
            if self._locker.is_locked() and not self._lock:
                locked_repository = self._locker.locked_repository(True)

                # If no packages have been whitelisted (The ones we want to update),
                # we whitelist every package in the lock file.
                if not self._whitelist:
                    for pkg in locked_repository.packages:
                        self._whitelist.append(pkg.name)

            # Checking extras
            for extra in self._extras:
                if extra not in self._package.extras:
                    raise ValueError(
                        "Extra [{}] is not specified.".format(extra))

            self._io.write_line("<info>Updating dependencies</>")
            solver = Solver(
                self._package,
                self._pool,
                self._installed_repository,
                locked_repository,
                self._io,
                remove_untracked=self._remove_untracked,
            )

            ops = solver.solve(use_latest=self._whitelist)
        else:
            self._io.write_line(
                "<info>Installing dependencies from lock file</>")

            locked_repository = self._locker.locked_repository(True)

            if not self._locker.is_fresh():
                self._io.write_line(
                    "<warning>"
                    "Warning: The lock file is not up to date with "
                    "the latest changes in pyproject.toml. "
                    "You may be getting outdated dependencies. "
                    "Run update to update them."
                    "</warning>")

            for extra in self._extras:
                if extra not in self._locker.lock_data.get("extras", {}):
                    raise ValueError(
                        "Extra [{}] is not specified.".format(extra))

            # If we are installing from lock
            # Filter the operations by comparing it with what is
            # currently installed
            ops = self._get_operations_from_lock(locked_repository)

        self._populate_local_repo(local_repo, ops)

        if self._update:
            self._write_lock_file(local_repo)

            if self._lock:
                # If we are only in lock mode, no need to go any further
                return 0

        root = self._package
        if not self.is_dev_mode():
            root = root.clone()
            del root.dev_requires[:]
        elif self.is_dev_only():
            root = root.clone()
            del root.requires[:]

        if self._io.is_verbose():
            self._io.write_line("")
            self._io.write_line(
                "<info>Finding the necessary packages for the current system</>"
            )

        # We resolve again by only using the lock file
        pool = Pool(ignore_repository_names=True)

        # Making a new repo containing the packages
        # newly resolved and the ones from the current lock file
        repo = Repository()
        for package in local_repo.packages + locked_repository.packages:
            if not repo.has_package(package):
                repo.add_package(package)

        pool.add_repository(repo)

        # We whitelist all packages to be sure
        # that the latest ones are picked up
        whitelist = []
        for pkg in locked_repository.packages:
            whitelist.append(pkg.name)

        solver = Solver(
            root,
            pool,
            self._installed_repository,
            locked_repository,
            NullIO(),
            remove_untracked=self._remove_untracked,
        )

        with solver.use_environment(self._env):
            ops = solver.solve(use_latest=whitelist)

        # We need to filter operations so that packages
        # not compatible with the current system,
        # or optional and not requested, are dropped
        self._filter_operations(ops, local_repo)

        # Execute operations
        return self._execute(ops)
Ejemplo n.º 25
0
    def _do_install(self, local_repo):
        locked_repository = Repository()
        if self._update:
            if self._locker.is_locked():
                locked_repository = self._locker.locked_repository(True)

                # If no packages have been whitelisted (The ones we want to update),
                # we whitelist every package in the lock file.
                if not self._whitelist:
                    for pkg in locked_repository.packages:
                        self._whitelist.append(pkg.name)

            # Checking extras
            for extra in self._extras:
                if extra not in self._package.extras:
                    raise ValueError("Extra [{}] is not specified.".format(extra))

            self._io.writeln("<info>Updating dependencies</>")
            solver = Solver(
                self._package,
                self._pool,
                self._installed_repository,
                locked_repository,
                self._io,
            )

            ops = solver.solve(use_latest=self._whitelist)
        else:
            self._io.writeln("<info>Installing dependencies from lock file</>")

            locked_repository = self._locker.locked_repository(True)

            if not self._locker.is_fresh():
                self._io.writeln(
                    "<warning>"
                    "Warning: The lock file is not up to date with "
                    "the latest changes in pyproject.toml. "
                    "You may be getting outdated dependencies. "
                    "Run update to update them."
                    "</warning>"
                )

            for extra in self._extras:
                if extra not in self._locker.lock_data.get("extras", {}):
                    raise ValueError("Extra [{}] is not specified.".format(extra))

            # If we are installing from lock
            # Filter the operations by comparing it with what is
            # currently installed
            ops = self._get_operations_from_lock(locked_repository)

        self._populate_local_repo(local_repo, ops, locked_repository)

        with self._package.with_python_versions(
            ".".join([str(i) for i in self._venv.version_info[:3]])
        ):
            # We resolve again by only using the lock file
            pool = Pool()

            # Making a new repo containing the packages
            # newly resolved and the ones from the current lock file
            locked_repository = self._locker.locked_repository(True)
            repo = Repository()
            for package in local_repo.packages + locked_repository.packages:
                if not repo.has_package(package):
                    repo.add_package(package)

            pool.add_repository(repo)

            # We whitelist all packages to be sure
            # that the latest ones are picked up
            whitelist = []
            for pkg in locked_repository.packages:
                whitelist.append(pkg.name)

            solver = Solver(
                self._package,
                pool,
                self._installed_repository,
                locked_repository,
                NullIO(),
            )

            ops = solver.solve(use_latest=whitelist)

        # We need to filter operations so that packages
        # not compatible with the current system,
        # or optional and not requested, are dropped
        self._filter_operations(ops, local_repo)

        self._io.new_line()

        # Execute operations
        actual_ops = [op for op in ops if not op.skipped]
        if not actual_ops and (self._execute_operations or self._dry_run):
            self._io.writeln("Nothing to install or update")

        if actual_ops and (self._execute_operations or self._dry_run):
            installs = []
            updates = []
            uninstalls = []
            skipped = []
            for op in ops:
                if op.skipped:
                    skipped.append(op)
                    continue

                if op.job_type == "install":
                    installs.append(
                        "{}:{}".format(
                            op.package.pretty_name, op.package.full_pretty_version
                        )
                    )
                elif op.job_type == "update":
                    updates.append(
                        "{}:{}".format(
                            op.target_package.pretty_name,
                            op.target_package.full_pretty_version,
                        )
                    )
                elif op.job_type == "uninstall":
                    uninstalls.append(op.package.pretty_name)

            self._io.new_line()
            self._io.writeln(
                "Package operations: "
                "<info>{}</> install{}, "
                "<info>{}</> update{}, "
                "<info>{}</> removal{}"
                "{}".format(
                    len(installs),
                    "" if len(installs) == 1 else "s",
                    len(updates),
                    "" if len(updates) == 1 else "s",
                    len(uninstalls),
                    "" if len(uninstalls) == 1 else "s",
                    ", <info>{}</> skipped".format(len(skipped))
                    if skipped and self.is_verbose()
                    else "",
                )
            )

        # Writing lock before installing
        if self._update and self._write_lock:
            updated_lock = self._locker.set_lock_data(
                self._package, local_repo.packages
            )

            if updated_lock:
                self._io.writeln("")
                self._io.writeln("<info>Writing lock file</>")

        self._io.writeln("")
        for op in ops:
            self._execute(op)