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
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)
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