From e37f40722b52c44d00655afe6722b52e7ebf48d2 Mon Sep 17 00:00:00 2001 From: foefl Date: Fri, 4 Jul 2025 12:30:42 +0200 Subject: [PATCH] add option to overwrite existing installations, related to #9 --- pyproject.toml | 4 ++-- src/pycage/clean.py | 18 +----------------- src/pycage/compile.py | 4 ++-- src/pycage/get.py | 42 ++++++++++++++++++++++++++++++++++++++---- src/pycage/helpers.py | 16 ++++++++++++++++ 5 files changed, 59 insertions(+), 25 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f84c885..776c03f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "pycage" -version = "0.2.6" +version = "0.2.7dev1" description = "tool to handle standalone Python installations from the CLI" authors = [ {name = "Florian Förster", email = "f.foerster@d-opt.com"}, @@ -78,7 +78,7 @@ directory = "reports/coverage" [tool.bumpversion] -current_version = "0.2.6" +current_version = "0.2.7dev1" parse = """(?x) (?P0|[1-9]\\d*)\\. (?P0|[1-9]\\d*)\\. diff --git a/src/pycage/clean.py b/src/pycage/clean.py index cb1f8e5..30582df 100644 --- a/src/pycage/clean.py +++ b/src/pycage/clean.py @@ -1,6 +1,6 @@ import click -from pycage.helpers import get_interpreter, print_error +from pycage.helpers import delete_files, print_error @click.group(help="commands to remove specified files") @@ -8,22 +8,6 @@ def clean() -> None: pass -def delete_files( - glob_pattern: str, -) -> None: - try: - pth_intp = get_interpreter() - except RuntimeError: - click.echo("Base interpreter path could not be found", err=True) - return - - base_folder = pth_intp.parent - assert base_folder.is_dir(), "base folder not a directory" - files_to_delete = base_folder.glob(glob_pattern) - for file in files_to_delete: - file.unlink(missing_ok=True) - - @click.command(help="removes all pre-compiled byte code files in the distribution") def precompiled() -> None: try: diff --git a/src/pycage/compile.py b/src/pycage/compile.py index 13904be..8c3dd0d 100644 --- a/src/pycage/compile.py +++ b/src/pycage/compile.py @@ -4,7 +4,7 @@ import subprocess import click -from pycage import clean +from pycage import helpers from pycage.helpers import get_interpreter, print_error @@ -61,7 +61,7 @@ def compile( if delete_existing: try: - clean.delete_files(r"**/*.pyc") + helpers.delete_files(r"**/*.pyc") except Exception as err: print_error(err) return diff --git a/src/pycage/get.py b/src/pycage/get.py index 0cca9bf..62d5405 100644 --- a/src/pycage/get.py +++ b/src/pycage/get.py @@ -11,7 +11,12 @@ from dopt_basics.io import combine_route from requests.exceptions import HTTPError from pycage import config -from pycage.helpers import delete_folder_recursively, path_verify_existence, print_error +from pycage.helpers import ( + delete_files, + delete_folder_recursively, + path_verify_existence, + print_error, +) from pycage.types import JsonMetadata, RetrievalInfo # cfg_path = Path.cwd() / "../config/config.toml" @@ -113,6 +118,14 @@ def extract_archive( default=None, help="specifiy a different target location, default: current working directory", ) +@click.option( + "-ow", + "--overwrite", + is_flag=True, + show_default=True, + default=False, + help="overwrite installation folder instead of deleting", +) @click.option( "-k", "--keep", @@ -141,6 +154,7 @@ def get( release_tag: str | None, force_reextract: bool, dl_folder: Path | None, + overwrite: bool, keep: bool, ) -> None: url_metadata = cast(str, config.CFG["metadata"]["URL"]) @@ -164,21 +178,30 @@ def get( # destination folder dl_folder = dl_folder if dl_folder is not None else Path.cwd() path_verify_existence(dl_folder) - # folder_extract = prepare_path(dl_folder, None, None, None, create_folder=True) target_folder = dl_folder / "python" folder_extract = dl_folder src_file = dl_folder / filename + _overwrite: bool = False + if target_folder.exists() and overwrite: + if click.confirm("Do you really want to overwrite the existing installation?"): + _overwrite = True + else: + click.echo( + "Overwrite option ignored. Delete existing installation before extraction." + ) try: if not src_file.exists(): click.echo("File not yet available. Download...") load_file_from_url(url=retrieval_info.url, file_save_path=src_file) - delete_folder_recursively(target_folder) + if not _overwrite: + delete_folder_recursively(target_folder) extract_archive(src_file, folder_extract) click.echo("Download and extraction successfully.") elif force_reextract: click.echo("File already downloaded. Re-extract file...") - delete_folder_recursively(target_folder) + if not _overwrite: + delete_folder_recursively(target_folder) extract_archive(src_file, folder_extract) click.echo("Re-extraction successfully.") else: @@ -189,6 +212,17 @@ def get( except Exception as err: print_error(err) + if _overwrite: + click.echo( + "Overwrite option was chosen. Delete any existing pre-compiled " + "files to force recompilation..." + ) + try: + delete_files(r"**/*.pyc") + except Exception as err: + print_error(err) + click.echo("Pre-compiled files were removed successfully.") + if not keep: try: src_file.unlink() diff --git a/src/pycage/helpers.py b/src/pycage/helpers.py index c648c3c..b2b90dd 100644 --- a/src/pycage/helpers.py +++ b/src/pycage/helpers.py @@ -57,3 +57,19 @@ def get_interpreter() -> Path: raise RuntimeError("Base interpreter not found") from err return pth_int + + +def delete_files( + glob_pattern: str, +) -> None: + try: + pth_intp = get_interpreter() + except RuntimeError: + click.echo("Base interpreter path could not be found", err=True) + return + + base_folder = pth_intp.parent + assert base_folder.is_dir(), "base folder not a directory" + files_to_delete = base_folder.glob(glob_pattern) + for file in files_to_delete: + file.unlink(missing_ok=True)