Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a517ca0ad6 | |||
| b54c4e934a | |||
| d9b8a48495 | |||
| 6061294b28 | |||
| 54bd6026c9 | |||
| e37f40722b | |||
| 64d9a094eb | |||
| a5bb7ee3bf | |||
| a584b285c9 | |||
| e9b259d4b9 | |||
| 1addbeffda |
@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "pycage"
|
||||
version = "0.2.5"
|
||||
version = "0.2.8"
|
||||
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.5"
|
||||
current_version = "0.2.8"
|
||||
parse = """(?x)
|
||||
(?P<major>0|[1-9]\\d*)\\.
|
||||
(?P<minor>0|[1-9]\\d*)\\.
|
||||
|
||||
@ -1 +1 @@
|
||||
pdm build -d build/
|
||||
pdm build -d build/ --no-sdist
|
||||
BIN
src/pycage/_files/msvc-redist/Microsoft.VC143.CRT/concrt140.dll
Normal file
BIN
src/pycage/_files/msvc-redist/Microsoft.VC143.CRT/concrt140.dll
Normal file
Binary file not shown.
BIN
src/pycage/_files/msvc-redist/Microsoft.VC143.CRT/msvcp140.dll
Normal file
BIN
src/pycage/_files/msvc-redist/Microsoft.VC143.CRT/msvcp140.dll
Normal file
Binary file not shown.
BIN
src/pycage/_files/msvc-redist/Microsoft.VC143.CRT/msvcp140_1.dll
Normal file
BIN
src/pycage/_files/msvc-redist/Microsoft.VC143.CRT/msvcp140_1.dll
Normal file
Binary file not shown.
BIN
src/pycage/_files/msvc-redist/Microsoft.VC143.CRT/msvcp140_2.dll
Normal file
BIN
src/pycage/_files/msvc-redist/Microsoft.VC143.CRT/msvcp140_2.dll
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,8 +1,6 @@
|
||||
from pathlib import Path
|
||||
|
||||
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")
|
||||
@ -10,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"
|
||||
precomp_files = base_folder.glob(glob_pattern)
|
||||
for file in precomp_files:
|
||||
file.unlink(missing_ok=True)
|
||||
|
||||
|
||||
@click.command(help="removes all pre-compiled byte code files in the distribution")
|
||||
def precompiled() -> None:
|
||||
try:
|
||||
|
||||
@ -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
|
||||
|
||||
17
src/pycage/constants.py
Normal file
17
src/pycage/constants.py
Normal file
@ -0,0 +1,17 @@
|
||||
from pathlib import Path
|
||||
from typing import Final, TypeAlias
|
||||
|
||||
LIB_ROOT_FOLDER: Final[Path] = Path(__file__).parent
|
||||
if not LIB_ROOT_FOLDER.exists():
|
||||
raise FileNotFoundError(f"Lib root folder not found under: >{LIB_ROOT_FOLDER}<")
|
||||
|
||||
MSVC_FOLDER: Final[Path] = LIB_ROOT_FOLDER / "_files/msvc-redist"
|
||||
if not MSVC_FOLDER.exists():
|
||||
raise FileNotFoundError(f"Folder for MSVC Redist files not found under: >{MSVC_FOLDER}<")
|
||||
|
||||
PyVersionToReleaseTag: TypeAlias = tuple[str, str]
|
||||
PY_VERSION_TO_RELEASE_TAG_PAIRS: Final[tuple[PyVersionToReleaseTag, ...]] = (
|
||||
("3.11.12", "20250409"),
|
||||
("3.11.13", "20250702"),
|
||||
("3.11.14", "20251014"),
|
||||
)
|
||||
@ -11,7 +11,13 @@ 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.constants import PY_VERSION_TO_RELEASE_TAG_PAIRS
|
||||
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 +119,20 @@ 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 with specified Python bundle instead of deleting it, any "
|
||||
"pre-compiled files are deleted to force the re-comilation of the code by the new "
|
||||
"Python interpreter. CAUTION: No compatibility checks for the installed packages is "
|
||||
"done. Therefore, it is not guaranteed that the new installation will work. This "
|
||||
"option is primarily intented for patch versions of Python."
|
||||
),
|
||||
)
|
||||
@click.option(
|
||||
"-k",
|
||||
"--keep",
|
||||
@ -141,6 +161,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,20 +185,29 @@ 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)
|
||||
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...")
|
||||
if not _overwrite:
|
||||
delete_folder_recursively(target_folder)
|
||||
extract_archive(src_file, folder_extract)
|
||||
click.echo("Re-extraction successfully.")
|
||||
@ -189,6 +219,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()
|
||||
@ -197,3 +238,17 @@ def get(
|
||||
"The archive file could not be deleted because of following exception..."
|
||||
)
|
||||
print_error(err)
|
||||
|
||||
|
||||
@click.command(
|
||||
help=(
|
||||
"show supported Python version and corresponding release tags from the"
|
||||
"standalone repository to have a quick lookup which version can be downloaded "
|
||||
"with which release tag, information can be used with the 'get' command"
|
||||
)
|
||||
)
|
||||
def show_version_release_tag() -> None:
|
||||
click.echo("Known version and release tag pairs are...")
|
||||
click.echo("Python Version --> Release Tag")
|
||||
for pair in PY_VERSION_TO_RELEASE_TAG_PAIRS:
|
||||
click.echo(f"{pair[0]:<8} --> {pair[1]:>9}")
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -15,6 +15,7 @@ def cli():
|
||||
|
||||
|
||||
cli.add_command(pycage.get.get)
|
||||
cli.add_command(pycage.get.show_version_release_tag)
|
||||
cli.add_command(pycage.venv.venv)
|
||||
cli.add_command(pycage.files.copy)
|
||||
cli.add_command(pycage.compile.compile)
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import click
|
||||
|
||||
from pycage.helpers import get_interpreter
|
||||
from pycage.constants import MSVC_FOLDER
|
||||
from pycage.helpers import get_interpreter, path_verify_directory, path_verify_existence
|
||||
|
||||
|
||||
@click.group(help="manage virtual environment with downloaded standalone images")
|
||||
@ -159,8 +161,41 @@ def remove(
|
||||
subprocess.run(cmd)
|
||||
|
||||
|
||||
@click.command(
|
||||
help="add MSVC Redistributable runtime dependencies to the root path of the environment"
|
||||
)
|
||||
def add_msvc_redist() -> None:
|
||||
try:
|
||||
pth_intp = get_interpreter()
|
||||
except RuntimeError:
|
||||
click.echo("Base interpreter path could not be found", err=True)
|
||||
return
|
||||
|
||||
target_path = pth_intp.parent
|
||||
try:
|
||||
path_verify_directory(target_path)
|
||||
except ValueError:
|
||||
click.echo(f"Target path >{target_path}< does not seem to be a directory", err=True)
|
||||
return
|
||||
try:
|
||||
path_verify_existence(target_path)
|
||||
except FileNotFoundError:
|
||||
click.echo(f"Target path >{target_path}< does not seem to exist", err=True)
|
||||
return
|
||||
|
||||
dll_files = MSVC_FOLDER.glob("**/*.dll")
|
||||
|
||||
click.echo("Start copying files...")
|
||||
for dll_src in dll_files:
|
||||
click.echo(f"Copy file >{dll_src.name}<")
|
||||
shutil.copy2(dll_src, target_path)
|
||||
|
||||
click.echo("Copied files successfully.")
|
||||
|
||||
|
||||
venv.add_command(create)
|
||||
venv.add_command(add)
|
||||
venv.add_command(upgrade_pip)
|
||||
venv.add_command(remove)
|
||||
venv.add_command(upgrade_seeders)
|
||||
venv.add_command(add_msvc_redist)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user