Esempio n. 1
0
    def handle(self) -> Optional[int]:
        from cleo.io.null_io import NullIO
        from cleo.terminal import Terminal

        from poetry.puzzle.solver import Solver
        from poetry.repositories.installed_repository import InstalledRepository
        from poetry.repositories.pool import Pool
        from poetry.repositories.repository import Repository
        from poetry.utils.helpers import get_package_version_display_string

        package = self.argument("package")

        if self.option("tree"):
            self.init_styles(self.io)

        if self.option("outdated"):
            self._io.input.set_option("latest", True)

        excluded_groups = []
        included_groups = []
        only_groups = []
        if self.option("no-dev"):
            self.line_error(
                "<warning>The `<fg=yellow;options=bold>--no-dev</>` option is"
                " deprecated, use the `<fg=yellow;options=bold>--without dev</>`"
                " notation instead.</warning>"
            )
            excluded_groups.append("dev")

        excluded_groups.extend(
            [
                group.strip()
                for groups in self.option("without")
                for group in groups.split(",")
            ]
        )
        included_groups.extend(
            [
                group.strip()
                for groups in self.option("with")
                for group in groups.split(",")
            ]
        )
        only_groups.extend(
            [
                group.strip()
                for groups in self.option("only")
                for group in groups.split(",")
            ]
        )

        if self.option("default"):
            only_groups.append("default")

        locked_repo = self.poetry.locker.locked_repository(True)

        if only_groups:
            root = self.poetry.package.with_dependency_groups(only_groups, only=True)
        else:
            root = self.poetry.package.with_dependency_groups(
                included_groups
            ).without_dependency_groups(excluded_groups)

        # Show tree view if requested
        if self.option("tree") and not package:
            requires = root.all_requires
            packages = locked_repo.packages
            for pkg in packages:
                for require in requires:
                    if pkg.name == require.name:
                        self.display_package_tree(self._io, pkg, locked_repo)
                        break

            return 0

        table = self.table(style="compact")
        locked_packages = locked_repo.packages
        pool = Pool(ignore_repository_names=True)
        pool.add_repository(locked_repo)
        solver = Solver(
            root,
            pool=pool,
            installed=Repository(),
            locked=locked_repo,
            io=NullIO(),
        )
        solver.provider.load_deferred(False)
        with solver.use_environment(self.env):
            ops = solver.solve().calculate_operations()

        required_locked_packages = {op.package for op in ops if not op.skipped}

        if package:
            pkg = None
            for locked in locked_packages:
                if package.lower() == locked.name:
                    pkg = locked
                    break

            if not pkg:
                raise ValueError(f"Package {package} not found")

            if self.option("tree"):
                self.display_package_tree(self.io, pkg, locked_repo)

                return 0

            required_by = {}
            for locked in locked_packages:
                dependencies = {d.name: d.pretty_constraint for d in locked.requires}

                if pkg.name in dependencies:
                    required_by[locked.pretty_name] = dependencies[pkg.name]

            rows = [
                ["<info>name</>", f" : <c1>{pkg.pretty_name}</>"],
                ["<info>version</>", f" : <b>{pkg.pretty_version}</b>"],
                ["<info>description</>", f" : {pkg.description}"],
            ]

            table.add_rows(rows)
            table.render()

            if pkg.requires:
                self.line("")
                self.line("<info>dependencies</info>")
                for dependency in pkg.requires:
                    self.line(
                        f" - <c1>{dependency.pretty_name}</c1>"
                        f" <b>{dependency.pretty_constraint}</b>"
                    )

            if required_by:
                self.line("")
                self.line("<info>required by</info>")
                for parent, requires_version in required_by.items():
                    self.line(f" - <c1>{parent}</c1> <b>{requires_version}</b>")

            return 0

        show_latest = self.option("latest")
        show_all = self.option("all")
        terminal = Terminal()
        width = terminal.width
        name_length = version_length = latest_length = 0
        latest_packages = {}
        latest_statuses = {}
        installed_repo = InstalledRepository.load(self.env)

        # Computing widths
        for locked in locked_packages:
            if locked not in required_locked_packages and not show_all:
                continue

            current_length = len(locked.pretty_name)
            if not self._io.output.is_decorated():
                installed_status = self.get_installed_status(locked, installed_repo)

                if installed_status == "not-installed":
                    current_length += 4

            if show_latest:
                latest = self.find_latest_package(locked, root)
                if not latest:
                    latest = locked

                latest_packages[locked.pretty_name] = latest
                update_status = latest_statuses[
                    locked.pretty_name
                ] = self.get_update_status(latest, locked)

                if not self.option("outdated") or update_status != "up-to-date":
                    name_length = max(name_length, current_length)
                    version_length = max(
                        version_length,
                        len(
                            get_package_version_display_string(
                                locked, root=self.poetry.file.parent
                            )
                        ),
                    )
                    latest_length = max(
                        latest_length,
                        len(
                            get_package_version_display_string(
                                latest, root=self.poetry.file.parent
                            )
                        ),
                    )
            else:
                name_length = max(name_length, current_length)
                version_length = max(
                    version_length,
                    len(
                        get_package_version_display_string(
                            locked, root=self.poetry.file.parent
                        )
                    ),
                )

        write_version = name_length + version_length + 3 <= width
        write_latest = name_length + version_length + latest_length + 3 <= width
        write_description = name_length + version_length + latest_length + 24 <= width

        for locked in locked_packages:
            color = "cyan"
            name = locked.pretty_name
            install_marker = ""
            if locked not in required_locked_packages:
                if not show_all:
                    continue

                color = "black;options=bold"
            else:
                installed_status = self.get_installed_status(locked, installed_repo)
                if installed_status == "not-installed":
                    color = "red"

                    if not self._io.output.is_decorated():
                        # Non installed in non decorated mode
                        install_marker = " (!)"

            if (
                show_latest
                and self.option("outdated")
                and latest_statuses[locked.pretty_name] == "up-to-date"
            ):
                continue

            line = (
                f"<fg={color}>"
                f"{name:{name_length - len(install_marker)}}{install_marker}</>"
            )
            if write_version:
                version = get_package_version_display_string(
                    locked, root=self.poetry.file.parent
                )
                line += f" <b>{version:{version_length}}</b>"
            if show_latest:
                latest = latest_packages[locked.pretty_name]
                update_status = latest_statuses[locked.pretty_name]

                if write_latest:
                    color = "green"
                    if update_status == "semver-safe-update":
                        color = "red"
                    elif update_status == "update-possible":
                        color = "yellow"

                    version = get_package_version_display_string(
                        latest, root=self.poetry.file.parent
                    )
                    line += f" <fg={color}>{version:{latest_length}}</>"

            if write_description:
                description = locked.description
                remaining = width - name_length - version_length - 4
                if show_latest:
                    remaining -= latest_length

                if len(locked.description) > remaining:
                    description = description[: remaining - 3] + "..."

                line += " " + description

            self.line(line)
        return None
Esempio n. 2
0
    def handle(self):
        from clikit.utils.terminal import Terminal

        from poetry.io.null_io import NullIO
        from poetry.puzzle.solver import Solver
        from poetry.repositories.installed_repository import InstalledRepository
        from poetry.repositories.pool import Pool
        from poetry.repositories.repository import Repository
        from poetry.utils.helpers import get_package_version_display_string

        package = self.argument("package")

        if self.option("tree"):
            self.init_styles(self.io)

        if self.option("outdated"):
            self._args.set_option("latest", True)

        include_dev = not self.option("no-dev")
        locked_repo = self.poetry.locker.locked_repository(True)

        # Show tree view if requested
        if self.option("tree") and not package:
            requires = self.poetry.package.requires + self.poetry.package.dev_requires
            packages = locked_repo.packages
            for package in packages:
                for require in requires:
                    if package.name == require.name:
                        self.display_package_tree(self._io, package,
                                                  locked_repo)
                        break

            return 0

        table = self.table(style="compact")
        # table.style.line_vc_char = ""
        locked_packages = locked_repo.packages
        pool = Pool(ignore_repository_names=True)
        pool.add_repository(locked_repo)
        solver = Solver(
            self.poetry.package,
            pool=pool,
            installed=Repository(),
            locked=locked_repo,
            io=NullIO(),
        )
        solver.provider.load_deferred(False)
        with solver.use_environment(self.env):
            ops = solver.solve()

        required_locked_packages = set(
            [op.package for op in ops if not op.skipped])

        if self.option("no-dev"):
            required_locked_packages = [
                p for p in locked_packages if p.category == "main"
            ]

        if package:
            pkg = None
            for locked in locked_packages:
                if package.lower() == locked.name:
                    pkg = locked
                    break

            if not pkg:
                raise ValueError("Package {} not found".format(package))

            if self.option("tree"):
                self.display_package_tree(self.io, pkg, locked_repo)

                return 0

            rows = [
                ["<info>name</>", " : <c1>{}</>".format(pkg.pretty_name)],
                [
                    "<info>version</>",
                    " : <b>{}</b>".format(pkg.pretty_version)
                ],
                ["<info>description</>", " : {}".format(pkg.description)],
            ]

            table.add_rows(rows)
            table.render(self.io)

            if pkg.requires:
                self.line("")
                self.line("<info>dependencies</info>")
                for dependency in pkg.requires:
                    self.line(" - <c1>{}</c1> <b>{}</b>".format(
                        dependency.pretty_name, dependency.pretty_constraint))

            return 0

        show_latest = self.option("latest")
        show_all = self.option("all")
        terminal = Terminal()
        width = terminal.width
        name_length = version_length = latest_length = 0
        latest_packages = {}
        latest_statuses = {}
        installed_repo = InstalledRepository.load(self.env)

        # Computing widths
        for locked in locked_packages:
            if locked not in required_locked_packages and not show_all:
                continue

            current_length = len(locked.pretty_name)
            if not self._io.output.supports_ansi():
                installed_status = self.get_installed_status(
                    locked, installed_repo)

                if installed_status == "not-installed":
                    current_length += 4

            if show_latest:
                latest = self.find_latest_package(locked, include_dev)
                if not latest:
                    latest = locked

                latest_packages[locked.pretty_name] = latest
                update_status = latest_statuses[
                    locked.pretty_name] = self.get_update_status(
                        latest, locked)

                if not self.option(
                        "outdated") or update_status != "up-to-date":
                    name_length = max(name_length, current_length)
                    version_length = max(
                        version_length,
                        len(
                            get_package_version_display_string(
                                locked, root=self.poetry.file.parent)),
                    )
                    latest_length = max(
                        latest_length,
                        len(
                            get_package_version_display_string(
                                latest, root=self.poetry.file.parent)),
                    )
            else:
                name_length = max(name_length, current_length)
                version_length = max(
                    version_length,
                    len(
                        get_package_version_display_string(
                            locked, root=self.poetry.file.parent)),
                )

        write_version = name_length + version_length + 3 <= width
        write_latest = name_length + version_length + latest_length + 3 <= width
        write_description = name_length + version_length + latest_length + 24 <= width

        for locked in locked_packages:
            color = "cyan"
            name = locked.pretty_name
            install_marker = ""
            if locked not in required_locked_packages:
                if not show_all:
                    continue

                color = "black;options=bold"
            else:
                installed_status = self.get_installed_status(
                    locked, installed_repo)
                if installed_status == "not-installed":
                    color = "red"

                    if not self._io.output.supports_ansi():
                        # Non installed in non decorated mode
                        install_marker = " (!)"

            if (show_latest and self.option("outdated")
                    and latest_statuses[locked.pretty_name] == "up-to-date"):
                continue

            line = "<fg={}>{:{}}{}</>".format(
                color, name, name_length - len(install_marker), install_marker)
            if write_version:
                line += " <b>{:{}}</b>".format(
                    get_package_version_display_string(
                        locked, root=self.poetry.file.parent),
                    version_length,
                )
            if show_latest:
                latest = latest_packages[locked.pretty_name]
                update_status = latest_statuses[locked.pretty_name]

                if write_latest:
                    color = "green"
                    if update_status == "semver-safe-update":
                        color = "red"
                    elif update_status == "update-possible":
                        color = "yellow"

                    line += " <fg={}>{:{}}</>".format(
                        color,
                        get_package_version_display_string(
                            latest, root=self.poetry.file.parent),
                        latest_length,
                    )

            if write_description:
                description = locked.description
                remaining = width - name_length - version_length - 4
                if show_latest:
                    remaining -= latest_length

                if len(locked.description) > remaining:
                    description = description[:remaining - 3] + "..."

                line += " " + description

            self.line(line)
Esempio n. 3
0
    def handle(self) -> int:
        from cleo.io.null_io import NullIO
        from cleo.terminal import Terminal

        from poetry.puzzle.solver import Solver
        from poetry.repositories.installed_repository import InstalledRepository
        from poetry.repositories.pool import Pool
        from poetry.utils.helpers import get_package_version_display_string

        package = self.argument("package")

        if self.option("tree"):
            self.init_styles(self.io)

        if self.option("why"):
            if self.option("tree") and package is None:
                self.line_error(
                    "<error>Error: --why requires a package when combined with"
                    " --tree.</error>")

                return 1

            if not self.option("tree") and package:
                self.line_error(
                    "<error>Error: --why cannot be used without --tree when displaying"
                    " a single package.</error>")

                return 1

        if self.option("outdated"):
            self.io.input.set_option("latest", True)

        if not self.poetry.locker.is_locked():
            self.line_error(
                "<error>Error: poetry.lock not found. Run `poetry lock` to create"
                " it.</error>")
            return 1

        locked_repo = self.poetry.locker.locked_repository()
        root = self.project_with_activated_groups_only()

        # Show tree view if requested
        if self.option("tree") and package is None:
            requires = root.all_requires
            packages = locked_repo.packages
            for p in packages:
                for require in requires:
                    if p.name == require.name:
                        self.display_package_tree(self.io, p, packages)
                        break

            return 0

        table = self.table(style="compact")
        locked_packages = locked_repo.packages
        pool = Pool(ignore_repository_names=True)
        pool.add_repository(locked_repo)
        solver = Solver(
            root,
            pool=pool,
            installed=[],
            locked=locked_packages,
            io=NullIO(),
        )
        solver.provider.load_deferred(False)
        with solver.use_environment(self.env):
            ops = solver.solve().calculate_operations()

        required_locked_packages = {op.package for op in ops if not op.skipped}

        if package:
            pkg = None
            for locked in locked_packages:
                if canonicalize_name(package) == locked.name:
                    pkg = locked
                    break

            if not pkg:
                raise ValueError(f"Package {package} not found")

            required_by = reverse_deps(pkg, locked_repo)

            if self.option("tree"):
                if self.option("why"):
                    # The default case if there's no reverse dependencies is to query
                    # the subtree for pkg but if any rev-deps exist we'll query for each
                    # of them in turn
                    packages = [pkg]
                    if required_by:
                        packages = [
                            p for p in locked_packages
                            for r in required_by.keys() if p.name == r
                        ]
                    else:
                        # if no rev-deps exist we'll make this clear as it can otherwise
                        # look very odd for packages that also have no or few direct
                        # dependencies
                        self.io.write_line(
                            f"Package {package} is a direct dependency.")

                    for p in packages:
                        self.display_package_tree(self.io,
                                                  p,
                                                  locked_packages,
                                                  why_package=pkg)

                else:
                    self.display_package_tree(self.io, pkg, locked_packages)

                return 0

            rows = [
                ["<info>name</>", f" : <c1>{pkg.pretty_name}</>"],
                ["<info>version</>", f" : <b>{pkg.pretty_version}</b>"],
                ["<info>description</>", f" : {pkg.description}"],
            ]

            table.add_rows(rows)
            table.render()

            if pkg.requires:
                self.line("")
                self.line("<info>dependencies</info>")
                for dependency in pkg.requires:
                    self.line(f" - <c1>{dependency.pretty_name}</c1>"
                              f" <b>{dependency.pretty_constraint}</b>")

            if required_by:
                self.line("")
                self.line("<info>required by</info>")
                for parent, requires_version in required_by.items():
                    self.line(
                        f" - <c1>{parent}</c1> <b>{requires_version}</b>")

            return 0

        show_latest = self.option("latest")
        show_all = self.option("all")
        terminal = Terminal()
        width = terminal.width
        name_length = version_length = latest_length = required_by_length = 0
        latest_packages = {}
        latest_statuses = {}
        installed_repo = InstalledRepository.load(self.env)

        # Computing widths
        for locked in locked_packages:
            if locked not in required_locked_packages and not show_all:
                continue

            current_length = len(locked.pretty_name)
            if not self.io.output.is_decorated():
                installed_status = self.get_installed_status(
                    locked, installed_repo.packages)

                if installed_status == "not-installed":
                    current_length += 4

            if show_latest:
                latest = self.find_latest_package(locked, root)
                if not latest:
                    latest = locked

                latest_packages[locked.pretty_name] = latest
                update_status = latest_statuses[
                    locked.pretty_name] = self.get_update_status(
                        latest, locked)

                if not self.option(
                        "outdated") or update_status != "up-to-date":
                    name_length = max(name_length, current_length)
                    version_length = max(
                        version_length,
                        len(
                            get_package_version_display_string(
                                locked, root=self.poetry.file.parent)),
                    )
                    latest_length = max(
                        latest_length,
                        len(
                            get_package_version_display_string(
                                latest, root=self.poetry.file.parent)),
                    )

                    if self.option("why"):
                        required_by = reverse_deps(locked, locked_repo)
                        required_by_length = max(
                            required_by_length,
                            len(" from " + ",".join(required_by.keys())),
                        )
            else:
                name_length = max(name_length, current_length)
                version_length = max(
                    version_length,
                    len(
                        get_package_version_display_string(
                            locked, root=self.poetry.file.parent)),
                )

                if self.option("why"):
                    required_by = reverse_deps(locked, locked_repo)
                    required_by_length = max(
                        required_by_length,
                        len(" from " + ",".join(required_by.keys())))

        write_version = name_length + version_length + 3 <= width
        write_latest = name_length + version_length + latest_length + 3 <= width

        why_end_column = (name_length + version_length + latest_length +
                          required_by_length)
        write_why = self.option("why") and (why_end_column + 3) <= width
        write_description = (why_end_column + 24) <= width

        for locked in locked_packages:
            color = "cyan"
            name = locked.pretty_name
            install_marker = ""
            if locked not in required_locked_packages:
                if not show_all:
                    continue

                color = "black;options=bold"
            else:
                installed_status = self.get_installed_status(
                    locked, installed_repo.packages)
                if installed_status == "not-installed":
                    color = "red"

                    if not self.io.output.is_decorated():
                        # Non installed in non decorated mode
                        install_marker = " (!)"

            if (show_latest and self.option("outdated")
                    and latest_statuses[locked.pretty_name] == "up-to-date"):
                continue

            line = (
                f"<fg={color}>"
                f"{name:{name_length - len(install_marker)}}{install_marker}</>"
            )
            if write_version:
                version = get_package_version_display_string(
                    locked, root=self.poetry.file.parent)
                line += f" <b>{version:{version_length}}</b>"
            if show_latest:
                latest = latest_packages[locked.pretty_name]
                update_status = latest_statuses[locked.pretty_name]

                if write_latest:
                    color = "green"
                    if update_status == "semver-safe-update":
                        color = "red"
                    elif update_status == "update-possible":
                        color = "yellow"

                    version = get_package_version_display_string(
                        latest, root=self.poetry.file.parent)
                    line += f" <fg={color}>{version:{latest_length}}</>"

            if write_why:
                required_by = reverse_deps(locked, locked_repo)
                if required_by:
                    content = ",".join(required_by.keys())
                    # subtract 6 for ' from '
                    line += f" from {content:{required_by_length - 6}}"
                else:
                    line += " " * required_by_length

            if write_description:
                description = locked.description
                remaining = (width - name_length - version_length -
                             required_by_length - 4)

                if show_latest:
                    remaining -= latest_length

                if len(locked.description) > remaining:
                    description = description[:remaining - 3] + "..."

                line += " " + description

            self.line(line)

        return 0