diff --git a/src/pycage/venv.py b/src/pycage/venv.py new file mode 100644 index 0000000..6a35639 --- /dev/null +++ b/src/pycage/venv.py @@ -0,0 +1,151 @@ +from __future__ import annotations + +import subprocess +import sys +from pathlib import Path + +import click + +from pycage.helpers import get_interpreter + + +@click.group(help="manage virtual environment with downloaded standalone images") +def venv() -> None: + pass + + +@click.command(help="upgrade internal seeder packages for virtualenv") +def upgrade_seeders() -> None: + cmd: list[str] = [ + sys.executable, + "-m", + "virtualenv", + "--upgrade-embed-wheels", + ] + subprocess.run(cmd) + + +@click.command(help="create virtual environments") +@click.option("-n", "--name", default=".venv", help="how the VENV folder schould be named") +@click.option( + "--clear", is_flag=True, default=False, help="clear VENV folder before creation" +) +def create( + name: str, + clear: bool, +) -> None: + try: + pth_intp = get_interpreter() + except RuntimeError: + click.echo("Base interpreter path could not be found", err=True) + return + + pth_venv = pth_intp.parent / name + cmd: list[str] = [ + sys.executable, + "-m", + "virtualenv", + str(pth_venv), + "-p", + str(pth_intp), + "--always-copy", + "--no-setuptools", + "--no-periodic-update", + ] + if clear: + cmd.append("--clear") + + subprocess.run(cmd) + + +def add_pkg( + interpreter: Path, + package: str, + index: str | None = None, + extra_index: str | None = None, +) -> None: + cmd: list[str] = [ + str(interpreter), + "-m", + "pip", + "install", + "-U", + package, + ] + if index is not None: + add_opts = ["--index-url", index] + cmd.extend(add_opts) + if extra_index is not None: + add_opts = ["--extra-index-url", extra_index] + cmd.extend(add_opts) + + subprocess.run(cmd) + + +@click.command(help="install packages directly into the virtual environment") +@click.option( + "-e", "--extra-index", default=None, help="extra index to lookup packages at by pip" +) +@click.option("-i", "--index", default=None, help="index to lookup packages at by pip") +@click.argument("package") +def add( + package: str, + index: str | None, + extra_index: str | None, +) -> None: + try: + pth_intp = get_interpreter() + except RuntimeError: + click.echo("Base interpreter path could not be found", err=True) + return + + add_pkg( + interpreter=pth_intp, + package=package, + index=index, + extra_index=extra_index, + ) + + +@click.command(help="upgrades the integrated pip installation") +def upgrade_pip() -> None: + try: + pth_intp = get_interpreter() + except RuntimeError: + click.echo("Base interpreter path could not be found", err=True) + return + + add_pkg( + interpreter=pth_intp, + package="pip", + index=None, + extra_index=None, + ) + + +@click.command(help="uninstall packages directly from the virtual environment") +@click.argument("package") +def remove( + package: str, +) -> None: + try: + pth_intp = get_interpreter() + except RuntimeError: + click.echo("Base interpreter path could not be found", err=True) + return + + cmd: list[str] = [ + str(pth_intp), + "-m", + "pip", + "uninstall", + package, + ] + subprocess.run(cmd) + + +venv.add_command(create) +venv.add_command(add) +venv.add_command(upgrade_pip) +venv.add_command(remove) +venv.add_command(upgrade_seeders)