kopia lustrzana https://github.com/jedie/PyInventory
138 wiersze
3.5 KiB
Python
Executable File
138 wiersze
3.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
"""
|
|
bootstrap CLI
|
|
~~~~~~~~~~~~~
|
|
|
|
Just call this file, and the magic happens ;)
|
|
"""
|
|
|
|
import hashlib
|
|
import os
|
|
import shlex
|
|
import signal
|
|
import subprocess
|
|
import sys
|
|
import venv
|
|
from pathlib import Path
|
|
|
|
|
|
def print_no_pip_error():
|
|
print('Error: Pip not available!')
|
|
print('Hint: "apt-get install python3-venv"\n')
|
|
|
|
|
|
try:
|
|
from ensurepip import version
|
|
except ModuleNotFoundError as err:
|
|
print(err)
|
|
print('-' * 100)
|
|
print_no_pip_error()
|
|
raise
|
|
else:
|
|
if not version():
|
|
print_no_pip_error()
|
|
sys.exit(-1)
|
|
|
|
|
|
assert sys.version_info >= (3, 11), f'Python version {sys.version_info} is too old!'
|
|
|
|
|
|
if sys.platform == 'win32': # wtf
|
|
# Files under Windows, e.g.: .../.venv/Scripts/python.exe
|
|
BIN_NAME = 'Scripts'
|
|
FILE_EXT = '.exe'
|
|
else:
|
|
# Files under Linux/Mac and all other than Windows, e.g.: .../.venv/bin/python3
|
|
BIN_NAME = 'bin'
|
|
FILE_EXT = ''
|
|
|
|
BASE_PATH = Path(__file__).parent
|
|
VENV_PATH = BASE_PATH / '.venv'
|
|
BIN_PATH = VENV_PATH / BIN_NAME
|
|
PYTHON_PATH = BIN_PATH / f'python3{FILE_EXT}'
|
|
PIP_PATH = BIN_PATH / f'pip{FILE_EXT}'
|
|
UV_PATH = BIN_PATH / f'uv{FILE_EXT}'
|
|
|
|
DEP_LOCK_PATH = BASE_PATH / 'uv.lock'
|
|
DEP_HASH_PATH = VENV_PATH / '.dep_hash'
|
|
|
|
# script file defined in pyproject.toml as [console_scripts]
|
|
# (Under Windows: ".exe" not added!)
|
|
PROJECT_SHELL_SCRIPT = BIN_PATH / 'inventory_project'
|
|
|
|
|
|
def get_dep_hash():
|
|
"""Get SHA512 hash from lock file content."""
|
|
return hashlib.sha512(DEP_LOCK_PATH.read_bytes()).hexdigest()
|
|
|
|
|
|
def store_dep_hash():
|
|
"""Generate .venv/.dep_hash"""
|
|
DEP_HASH_PATH.write_text(get_dep_hash())
|
|
|
|
|
|
def venv_up2date():
|
|
"""Is existing .venv is up-to-date?"""
|
|
if DEP_HASH_PATH.is_file():
|
|
return DEP_HASH_PATH.read_text() == get_dep_hash()
|
|
return False
|
|
|
|
|
|
def verbose_check_call(*popen_args):
|
|
print(f'\n+ {shlex.join(str(arg) for arg in popen_args)}\n')
|
|
return subprocess.check_call(popen_args)
|
|
|
|
|
|
def noop_sigint_handler(signal_num, frame):
|
|
"""
|
|
Don't exist cmd2 shell on "Interrupt from keyboard"
|
|
e.g.: User stops the dev. server by CONTROL-C
|
|
"""
|
|
|
|
|
|
def main(argv):
|
|
assert DEP_LOCK_PATH.is_file(), f'File not found: "{DEP_LOCK_PATH}" !'
|
|
|
|
# Create virtual env in ".venv/":
|
|
if not PYTHON_PATH.is_file():
|
|
print(f'Create virtual env here: {VENV_PATH.absolute()}')
|
|
builder = venv.EnvBuilder(symlinks=True, upgrade=True, with_pip=True)
|
|
builder.create(env_dir=VENV_PATH)
|
|
|
|
# Set environment variable for uv to use '.venv-app' as project environment:
|
|
os.environ['UV_PROJECT_ENVIRONMENT'] = str(VENV_PATH.absolute())
|
|
|
|
if not PROJECT_SHELL_SCRIPT.is_file() or not venv_up2date():
|
|
# Update pip
|
|
verbose_check_call(PYTHON_PATH, '-m', 'pip', 'install', '-U', 'pip')
|
|
|
|
# Install uv
|
|
verbose_check_call(PYTHON_PATH, '-m', 'pip', 'install', '-U', 'uv')
|
|
|
|
# install requirements
|
|
verbose_check_call(UV_PATH, 'sync', '--frozen')
|
|
|
|
# install project
|
|
verbose_check_call(PIP_PATH, 'install', '--no-deps', '-e', '.')
|
|
|
|
# Activate git pre-commit hooks:
|
|
verbose_check_call(PYTHON_PATH, '-m', 'pre_commit', 'install')
|
|
|
|
store_dep_hash()
|
|
|
|
signal.signal(signal.SIGINT, noop_sigint_handler) # ignore "Interrupt from keyboard" signals
|
|
|
|
# Call our entry point CLI:
|
|
try:
|
|
verbose_check_call(PROJECT_SHELL_SCRIPT, *argv[1:])
|
|
except subprocess.CalledProcessError as err:
|
|
sys.exit(err.returncode)
|
|
except KeyboardInterrupt:
|
|
print('Bye!')
|
|
sys.exit(130)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main(sys.argv)
|