214 lines
7.5 KiB
Python
214 lines
7.5 KiB
Python
import shutil
|
|
import sys
|
|
|
|
from pipenv import exceptions
|
|
from pipenv.patched.pip._internal.build_env import get_runnable_pip
|
|
from pipenv.routines.lock import do_lock
|
|
from pipenv.utils.dependencies import (
|
|
expansive_install_req_from_line,
|
|
get_lockfile_section_using_pipfile_category,
|
|
get_pipfile_category_using_lockfile_section,
|
|
pep423_name,
|
|
)
|
|
from pipenv.utils.processes import run_command, subprocess_run
|
|
from pipenv.utils.requirements import BAD_PACKAGES
|
|
from pipenv.utils.resolver import venv_resolve_deps
|
|
from pipenv.utils.shell import cmd_list_to_shell, project_python
|
|
from pipenv.vendor import click
|
|
|
|
|
|
def _uninstall_from_environment(project, package, system=False):
|
|
# Execute the uninstall command for the package
|
|
click.secho(f"Uninstalling {package}...", fg="green", bold=True)
|
|
with project.environment.activated():
|
|
cmd = [
|
|
project_python(project, system=system),
|
|
get_runnable_pip(),
|
|
"uninstall",
|
|
package,
|
|
"-y",
|
|
]
|
|
c = run_command(cmd, is_verbose=project.s.is_verbose())
|
|
click.secho(c.stdout, fg="cyan")
|
|
if c.returncode != 0:
|
|
click.echo(f"Error occurred while uninstalling package {package}.")
|
|
return False
|
|
return True
|
|
|
|
|
|
def do_uninstall(
|
|
project,
|
|
packages=None,
|
|
editable_packages=None,
|
|
python=False,
|
|
system=False,
|
|
lock=False,
|
|
all_dev=False,
|
|
all=False,
|
|
pre=False,
|
|
pypi_mirror=None,
|
|
ctx=None,
|
|
categories=None,
|
|
):
|
|
# Initialization similar to the upgrade function
|
|
if not any([packages, editable_packages, all_dev, all]):
|
|
raise exceptions.PipenvUsageError("No package provided!", ctx=ctx)
|
|
|
|
if not categories:
|
|
categories = ["default"]
|
|
|
|
lockfile_content = project.lockfile_content
|
|
|
|
if all_dev:
|
|
click.secho(
|
|
click.style(
|
|
"Un-installing all {}...".format(
|
|
click.style("[dev-packages]", fg="yellow")
|
|
),
|
|
bold=True,
|
|
)
|
|
)
|
|
# Uninstall all dev-packages from environment
|
|
for package in project.get_pipfile_section("dev-packages"):
|
|
_uninstall_from_environment(project, package, system=system)
|
|
# Remove the package from the Pipfile
|
|
if project.reset_category_in_pipfile(category="dev-packages"):
|
|
click.echo("Removed [dev-packages] from Pipfile.")
|
|
# Finalize changes to lockfile
|
|
lockfile_content["develop"] = {}
|
|
lockfile_content.update({"_meta": project.get_lockfile_meta()})
|
|
project.write_lockfile(lockfile_content)
|
|
|
|
if all:
|
|
click.secho(
|
|
click.style(
|
|
"Un-installing all {}...".format(click.style("[packages]", fg="yellow")),
|
|
bold=True,
|
|
)
|
|
)
|
|
# Uninstall all dev-packages from environment
|
|
for package in project.get_pipfile_section("packages"):
|
|
_uninstall_from_environment(project, package, system=system)
|
|
# Remove the package from the Pipfile
|
|
if project.reset_category_in_pipfile(category="packages"):
|
|
click.echo("Removed [packages] from Pipfile.")
|
|
|
|
# Finalize changes to lockfile
|
|
lockfile_content["default"] = {}
|
|
lockfile_content.update({"_meta": project.get_lockfile_meta()})
|
|
project.write_lockfile(lockfile_content)
|
|
|
|
package_args = list(packages) + [f"-e {pkg}" for pkg in editable_packages]
|
|
|
|
# Determine packages and their dependencies for removal
|
|
for category in categories:
|
|
category = get_lockfile_section_using_pipfile_category(
|
|
category
|
|
) # In case they passed pipfile category
|
|
pipfile_category = get_pipfile_category_using_lockfile_section(category)
|
|
|
|
for package in package_args[:]:
|
|
install_req, _ = expansive_install_req_from_line(package, expand_env=True)
|
|
name, normalized_name, pipfile_entry = project.generate_package_pipfile_entry(
|
|
install_req, package, category=pipfile_category
|
|
)
|
|
|
|
# Remove the package from the Pipfile
|
|
if project.remove_package_from_pipfile(
|
|
normalized_name, category=pipfile_category
|
|
):
|
|
click.echo(f"Removed {normalized_name} from Pipfile.")
|
|
|
|
# Rebuild the dependencies for resolution from the updated Pipfile
|
|
updated_packages = project.get_pipfile_section(pipfile_category)
|
|
|
|
# Resolve dependencies with the package removed
|
|
resolved_lock_data = venv_resolve_deps(
|
|
updated_packages,
|
|
which=project._which,
|
|
project=project,
|
|
lockfile={},
|
|
category=pipfile_category,
|
|
pre=pre,
|
|
allow_global=system,
|
|
pypi_mirror=pypi_mirror,
|
|
)
|
|
|
|
# Determine which dependencies are no longer needed
|
|
try:
|
|
current_lock_data = lockfile_content[category]
|
|
if current_lock_data:
|
|
deps_to_remove = [
|
|
dep for dep in current_lock_data if dep not in resolved_lock_data
|
|
]
|
|
# Remove unnecessary dependencies from Pipfile and lockfile
|
|
for dep in deps_to_remove:
|
|
if (
|
|
category in lockfile_content
|
|
and dep in lockfile_content[category]
|
|
):
|
|
del lockfile_content[category][dep]
|
|
except KeyError:
|
|
pass # No lockfile data for this category
|
|
|
|
# Finalize changes to lockfile
|
|
lockfile_content.update({"_meta": project.get_lockfile_meta()})
|
|
project.write_lockfile(lockfile_content)
|
|
|
|
# Perform uninstallation of packages and dependencies
|
|
failure = False
|
|
for package in package_args:
|
|
_uninstall_from_environment(project, package, system=system)
|
|
|
|
if lock:
|
|
do_lock(project, system=system, pypi_mirror=pypi_mirror)
|
|
|
|
sys.exit(int(failure))
|
|
|
|
|
|
def do_purge(project, bare=False, downloads=False, allow_global=False):
|
|
"""Executes the purge functionality."""
|
|
|
|
if downloads:
|
|
if not bare:
|
|
click.secho("Clearing out downloads directory...", bold=True)
|
|
shutil.rmtree(project.download_location)
|
|
return
|
|
|
|
# Remove comments from the output, if any.
|
|
installed = {
|
|
pep423_name(pkg.project_name)
|
|
for pkg in project.environment.get_installed_packages()
|
|
}
|
|
bad_pkgs = {pep423_name(pkg) for pkg in BAD_PACKAGES}
|
|
# Remove setuptools, pip, etc from targets for removal
|
|
to_remove = installed - bad_pkgs
|
|
|
|
# Skip purging if there is no packages which needs to be removed
|
|
if not to_remove:
|
|
if not bare:
|
|
click.echo("Found 0 installed package, skip purging.")
|
|
click.secho("Environment now purged and fresh!", fg="green")
|
|
return installed
|
|
|
|
if not bare:
|
|
click.echo(f"Found {len(to_remove)} installed package(s), purging...")
|
|
|
|
command = [
|
|
project_python(project, system=allow_global),
|
|
get_runnable_pip(),
|
|
"uninstall",
|
|
"-y",
|
|
] + list(to_remove)
|
|
if project.s.is_verbose():
|
|
click.echo(f"$ {cmd_list_to_shell(command)}")
|
|
c = subprocess_run(command)
|
|
if c.returncode != 0:
|
|
raise exceptions.UninstallError(
|
|
installed, cmd_list_to_shell(command), c.stdout + c.stderr, c.returncode
|
|
)
|
|
if not bare:
|
|
click.secho(c.stdout, fg="cyan")
|
|
click.secho("Environment now purged and fresh!", fg="green")
|
|
return installed
|