96 lines
3.8 KiB
Python
96 lines
3.8 KiB
Python
|
import sys
|
||
|
from collections import namedtuple
|
||
|
from collections.abc import Mapping
|
||
|
|
||
|
from pipenv.patched.pip._vendor.packaging.utils import canonicalize_name
|
||
|
from pipenv.patched.pip._vendor.packaging.version import parse as parse_version
|
||
|
from pipenv.routines.lock import do_lock
|
||
|
from pipenv.utils.dependencies import (
|
||
|
as_pipfile,
|
||
|
expansive_install_req_from_line,
|
||
|
get_version,
|
||
|
pep423_name,
|
||
|
)
|
||
|
from pipenv.vendor import click
|
||
|
|
||
|
|
||
|
def do_outdated(project, pypi_mirror=None, pre=False, clear=False):
|
||
|
packages = {}
|
||
|
package_info = namedtuple("PackageInfo", ["name", "installed", "available"])
|
||
|
|
||
|
installed_packages = project.environment.get_installed_packages()
|
||
|
outdated_packages = {
|
||
|
canonicalize_name(pkg.name): package_info(
|
||
|
pkg.name, parse_version(pkg.version), pkg.latest_version
|
||
|
)
|
||
|
for pkg in project.environment.get_outdated_packages()
|
||
|
}
|
||
|
reverse_deps = {
|
||
|
canonicalize_name(name): deps
|
||
|
for name, deps in project.environment.reverse_dependencies().items()
|
||
|
}
|
||
|
for result in installed_packages:
|
||
|
dep, _ = expansive_install_req_from_line(f"{result.name}=={result.version}")
|
||
|
packages.update(as_pipfile(dep))
|
||
|
|
||
|
updated_packages = {}
|
||
|
lockfile = do_lock(
|
||
|
project, clear=clear, pre=pre, write=False, pypi_mirror=pypi_mirror
|
||
|
)
|
||
|
for category in project.get_package_categories(for_lockfile=True):
|
||
|
for package in lockfile.get(category, []):
|
||
|
try:
|
||
|
updated_packages[package] = parse_version(
|
||
|
lockfile[category][package]["version"]
|
||
|
)
|
||
|
except KeyError: # noqa: PERF203
|
||
|
pass
|
||
|
outdated = []
|
||
|
skipped = []
|
||
|
for package in packages:
|
||
|
norm_name = pep423_name(package)
|
||
|
if norm_name in updated_packages:
|
||
|
version = packages[package]
|
||
|
if isinstance(version, Mapping):
|
||
|
version = parse_version(version.get("version"))
|
||
|
else:
|
||
|
version = parse_version(version)
|
||
|
if updated_packages[norm_name] != version:
|
||
|
outdated.append(
|
||
|
package_info(package, str(version), str(updated_packages[norm_name]))
|
||
|
)
|
||
|
elif canonicalize_name(package) in outdated_packages:
|
||
|
skipped.append(outdated_packages[canonicalize_name(package)])
|
||
|
for package, old_version, new_version in skipped:
|
||
|
for category in project.get_package_categories():
|
||
|
name_in_pipfile = project.get_package_name_in_pipfile(
|
||
|
package, category=category
|
||
|
)
|
||
|
if name_in_pipfile:
|
||
|
required = ""
|
||
|
version = get_version(
|
||
|
project.get_pipfile_section(category)[name_in_pipfile]
|
||
|
)
|
||
|
rdeps = reverse_deps.get(canonicalize_name(package))
|
||
|
if isinstance(rdeps, Mapping) and "required" in rdeps:
|
||
|
required = " {rdeps['required']} required"
|
||
|
if version:
|
||
|
pipfile_version_text = f" ({version} set in Pipfile)"
|
||
|
else:
|
||
|
pipfile_version_text = " (Unpinned in Pipfile)"
|
||
|
click.secho(
|
||
|
f"Skipped Update of Package {package!s}:"
|
||
|
f" {old_version!s} installed,{required!s}{pipfile_version_text!s}, "
|
||
|
f"{new_version!s} available.",
|
||
|
fg="yellow",
|
||
|
err=True,
|
||
|
)
|
||
|
if not outdated:
|
||
|
click.echo(click.style("All packages are up to date!", fg="green", bold=True))
|
||
|
sys.exit(0)
|
||
|
for package, new_version, old_version in outdated:
|
||
|
click.echo(
|
||
|
f"Package {package!r} out-of-date: {old_version!r} installed, {new_version!r} available."
|
||
|
)
|
||
|
sys.exit(bool(outdated))
|