Added --no-cache-dir to pip install commands for pip/setuptools/wheel, requirements file, and extra packages to reduce disk usage and ensure clean installations in CI environments.
148 lines
3.6 KiB
Bash
148 lines
3.6 KiB
Bash
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
REPO_DIR="$(pwd)"
|
|
VENV_DIR=""
|
|
REQUIREMENTS_FILE=""
|
|
SKIP_REQUIREMENTS="false"
|
|
MODE="symlink"
|
|
EXTRA_PACKAGES=""
|
|
CACHE_ROOT="/var/cache/aitbc/python-venvs"
|
|
PIP_CACHE_ROOT="/var/cache/aitbc/pip"
|
|
PYTHON_BIN="${PYTHON_BIN:-python3}"
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--repo-dir)
|
|
REPO_DIR="$2"
|
|
shift 2
|
|
;;
|
|
--venv-dir)
|
|
VENV_DIR="$2"
|
|
shift 2
|
|
;;
|
|
--requirements-file)
|
|
REQUIREMENTS_FILE="$2"
|
|
shift 2
|
|
;;
|
|
--skip-requirements)
|
|
SKIP_REQUIREMENTS="true"
|
|
shift
|
|
;;
|
|
--mode)
|
|
MODE="$2"
|
|
shift 2
|
|
;;
|
|
--extra-packages)
|
|
EXTRA_PACKAGES="$2"
|
|
shift 2
|
|
;;
|
|
--cache-root)
|
|
CACHE_ROOT="$2"
|
|
shift 2
|
|
;;
|
|
--python-bin)
|
|
PYTHON_BIN="$2"
|
|
shift 2
|
|
;;
|
|
*)
|
|
echo "Unknown argument: $1" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
VENV_DIR="${VENV_DIR:-$REPO_DIR/venv}"
|
|
REQUIREMENTS_FILE="${REQUIREMENTS_FILE:-$REPO_DIR/requirements.txt}"
|
|
|
|
if [[ "$SKIP_REQUIREMENTS" == "true" ]]; then
|
|
REQUIREMENTS_FILE=""
|
|
fi
|
|
|
|
if [[ "$MODE" != "symlink" && "$MODE" != "copy" ]]; then
|
|
echo "Invalid mode: $MODE" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ! -d "$REPO_DIR" ]]; then
|
|
echo "Repository directory not found: $REPO_DIR" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! command -v "$PYTHON_BIN" >/dev/null 2>&1; then
|
|
echo "Python binary not found: $PYTHON_BIN" >&2
|
|
exit 1
|
|
fi
|
|
|
|
export PIP_DISABLE_PIP_VERSION_CHECK=1
|
|
export PIP_NO_INPUT=1
|
|
export PIP_PROGRESS_BAR=off
|
|
export PIP_CACHE_DIR="$PIP_CACHE_ROOT"
|
|
|
|
mkdir -p "$CACHE_ROOT" "$PIP_CACHE_ROOT"
|
|
|
|
PYTHON_VERSION="$($PYTHON_BIN -c 'import sys; print(".".join(map(str, sys.version_info[:3])))')"
|
|
if [[ -n "$REQUIREMENTS_FILE" && -f "$REQUIREMENTS_FILE" ]]; then
|
|
REQUIREMENTS_HASH="$(sha256sum "$REQUIREMENTS_FILE" | awk '{print $1}' | cut -c1-16)"
|
|
else
|
|
REQUIREMENTS_HASH="no-req"
|
|
fi
|
|
EXTRA_HASH="$(printf '%s' "$EXTRA_PACKAGES" | sha256sum | awk '{print $1}' | cut -c1-16)"
|
|
CACHE_KEY="py${PYTHON_VERSION}-req${REQUIREMENTS_HASH}-extra${EXTRA_HASH}"
|
|
CACHE_VENV_DIR="$CACHE_ROOT/$CACHE_KEY"
|
|
LOCK_FILE="$CACHE_ROOT/$CACHE_KEY.lock"
|
|
|
|
build_cached_environment() {
|
|
local temp_dir
|
|
temp_dir="${CACHE_VENV_DIR}.tmp.$$"
|
|
|
|
rm -rf "$temp_dir"
|
|
"$PYTHON_BIN" -m venv "$temp_dir"
|
|
source "$temp_dir/bin/activate"
|
|
|
|
python -m pip install -q --upgrade pip setuptools wheel --no-cache-dir
|
|
|
|
if [[ -n "$REQUIREMENTS_FILE" && -f "$REQUIREMENTS_FILE" ]]; then
|
|
python -m pip install -q -r "$REQUIREMENTS_FILE" --no-cache-dir
|
|
fi
|
|
|
|
if [[ -n "$EXTRA_PACKAGES" ]]; then
|
|
read -r -a extra_array <<< "$EXTRA_PACKAGES"
|
|
python -m pip install -q "${extra_array[@]}" --no-cache-dir
|
|
fi
|
|
|
|
deactivate || true
|
|
mv "$temp_dir" "$CACHE_VENV_DIR"
|
|
}
|
|
|
|
if command -v flock >/dev/null 2>&1; then
|
|
exec 9>"$LOCK_FILE"
|
|
flock 9
|
|
fi
|
|
|
|
if [[ -x "$CACHE_VENV_DIR/bin/python" ]]; then
|
|
echo "✅ Reusing cached Python environment: $CACHE_KEY"
|
|
else
|
|
echo "📦 Building cached Python environment: $CACHE_KEY"
|
|
build_cached_environment
|
|
fi
|
|
|
|
rm -rf "$VENV_DIR"
|
|
|
|
case "$MODE" in
|
|
symlink)
|
|
ln -s "$CACHE_VENV_DIR" "$VENV_DIR"
|
|
;;
|
|
copy)
|
|
mkdir -p "$VENV_DIR"
|
|
if command -v rsync >/dev/null 2>&1; then
|
|
rsync -a --delete "$CACHE_VENV_DIR/" "$VENV_DIR/"
|
|
else
|
|
cp -a "$CACHE_VENV_DIR/." "$VENV_DIR/"
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
source "$VENV_DIR/bin/activate"
|
|
echo "✅ Python environment ready from cache: $CACHE_KEY"
|