|
| 1 | +#!/usr/bin/env bash |
| 2 | +# Build a self-contained flash-worker tarball for process injection. |
| 3 | +# Output: dist/flash-worker-v{VERSION}-py{PYTHON_VERSION}-linux-x86_64.tar.gz |
| 4 | +set -euo pipefail |
| 5 | + |
| 6 | +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" |
| 7 | +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" |
| 8 | + |
| 9 | +# Read version from source |
| 10 | +VERSION=$(python3 -c " |
| 11 | +import re |
| 12 | +text = open('$REPO_ROOT/src/version.py').read() |
| 13 | +print(re.search(r'__version__\\s*=\\s*\"([^\"]+)\"', text).group(1)) |
| 14 | +") |
| 15 | +echo "Building flash-worker tarball v${VERSION}" |
| 16 | + |
| 17 | +# Configuration |
| 18 | +PYTHON_VERSION="${PYTHON_VERSION:-3.11}" |
| 19 | + |
| 20 | +# Validate Python version against project requirement (>=3.10, <3.15) |
| 21 | +PY_MINOR=$(echo "$PYTHON_VERSION" | cut -d. -f2) |
| 22 | +if [ "$PY_MINOR" -lt 10 ] || [ "$PY_MINOR" -ge 15 ]; then |
| 23 | + echo "ERROR: Python ${PYTHON_VERSION} is outside project requirement (>=3.10, <3.15)" |
| 24 | + exit 1 |
| 25 | +fi |
| 26 | + |
| 27 | +UV_VERSION="0.7.19" |
| 28 | +UV_URL="https://github.com/astral-sh/uv/releases/download/${UV_VERSION}/uv-x86_64-unknown-linux-gnu.tar.gz" |
| 29 | + |
| 30 | +# Build in container-local tmpdir to avoid macOS case-insensitive filesystem issues |
| 31 | +BUILD_DIR="/tmp/flash-worker-build" |
| 32 | +TARBALL_ROOT="$BUILD_DIR/flash-worker" |
| 33 | +OUTPUT_DIR="$REPO_ROOT/dist" |
| 34 | +TARBALL_NAME="flash-worker-v${VERSION}-py${PYTHON_VERSION}-linux-x86_64.tar.gz" |
| 35 | + |
| 36 | +# Clean previous build |
| 37 | +rm -rf "$BUILD_DIR" |
| 38 | +mkdir -p "$TARBALL_ROOT" "$OUTPUT_DIR" "$OUTPUT_DIR/.cache" |
| 39 | + |
| 40 | +# 1. Install Python via uv (handles version resolution and caching) |
| 41 | +echo "Installing Python ${PYTHON_VERSION} via uv..." |
| 42 | +uv python install "$PYTHON_VERSION" |
| 43 | +PYTHON_BIN=$(uv python find --python-preference only-managed "$PYTHON_VERSION") |
| 44 | +PYTHON_INSTALL_DIR=$(cd "$(dirname "$PYTHON_BIN")/.." && pwd -P) |
| 45 | +cp -r "$PYTHON_INSTALL_DIR" "$TARBALL_ROOT/python" |
| 46 | + |
| 47 | +# Verify installation |
| 48 | +if [ ! -f "$TARBALL_ROOT/python/bin/python3" ]; then |
| 49 | + echo "ERROR: Python installation failed - python3 binary not found" |
| 50 | + exit 1 |
| 51 | +fi |
| 52 | +PYTHON_FULL_VERSION=$("$TARBALL_ROOT/python/bin/python3" -c "import sys; v=sys.version_info; print(f'{v.major}.{v.minor}.{v.micro}')") |
| 53 | +echo " Python ${PYTHON_FULL_VERSION} installed" |
| 54 | + |
| 55 | +# 2. Download uv static binary |
| 56 | +echo "Downloading uv ${UV_VERSION}..." |
| 57 | +if [ -f "$OUTPUT_DIR/.cache/uv-${UV_VERSION}.tar.gz" ]; then |
| 58 | + echo " Using cached uv download" |
| 59 | + tar xzf "$OUTPUT_DIR/.cache/uv-${UV_VERSION}.tar.gz" -C "$TARBALL_ROOT" --no-same-owner --strip-components=1 "uv-x86_64-unknown-linux-gnu/uv" 2>/dev/null || true |
| 60 | +else |
| 61 | + curl -fsSL "$UV_URL" -o "$OUTPUT_DIR/.cache/uv-${UV_VERSION}.tar.gz" |
| 62 | + tar xzf "$OUTPUT_DIR/.cache/uv-${UV_VERSION}.tar.gz" -C "$TARBALL_ROOT" --no-same-owner --strip-components=1 "uv-x86_64-unknown-linux-gnu/uv" 2>/dev/null || true |
| 63 | +fi |
| 64 | +chmod +x "$TARBALL_ROOT/uv" |
| 65 | + |
| 66 | +# 3. Create venv using portable Python |
| 67 | +echo "Creating virtual environment..." |
| 68 | +"$TARBALL_ROOT/python/bin/python3" -m venv "$TARBALL_ROOT/venv" |
| 69 | + |
| 70 | +# Fix venv symlinks to be relative (python -m venv creates absolute symlinks) |
| 71 | +cd "$TARBALL_ROOT/venv/bin" |
| 72 | +for link in python python3 python3.*; do |
| 73 | + [ -L "$link" ] || continue |
| 74 | + target=$(readlink "$link") |
| 75 | + case "$target" in |
| 76 | + /*) # Absolute path — make relative to ../../python/bin/ |
| 77 | + basename=$(basename "$target") |
| 78 | + ln -sf "../../python/bin/$basename" "$link" |
| 79 | + ;; |
| 80 | + esac |
| 81 | +done |
| 82 | +cd "$REPO_ROOT" |
| 83 | + |
| 84 | +# 4. Export and install production dependencies |
| 85 | +echo "Installing production dependencies..." |
| 86 | +cd "$REPO_ROOT" |
| 87 | +# Use the host uv to export requirements (it reads pyproject.toml/uv.lock) |
| 88 | +uv export --format requirements-txt --no-dev --no-hashes > "$BUILD_DIR/requirements.txt" |
| 89 | + |
| 90 | +# Install into the tarball's venv using the tarball's uv |
| 91 | +"$TARBALL_ROOT/uv" pip install \ |
| 92 | + --python "$TARBALL_ROOT/venv/bin/python" \ |
| 93 | + -r "$BUILD_DIR/requirements.txt" |
| 94 | + |
| 95 | +# 5. Copy source files |
| 96 | +echo "Copying source files..." |
| 97 | +cp -r "$REPO_ROOT/src/"*.py "$TARBALL_ROOT/src/" 2>/dev/null || true |
| 98 | +mkdir -p "$TARBALL_ROOT/src" |
| 99 | +for f in "$REPO_ROOT/src/"*.py; do |
| 100 | + [ -f "$f" ] && cp "$f" "$TARBALL_ROOT/src/" |
| 101 | +done |
| 102 | +# Copy test scripts (used by --test flag) |
| 103 | +for f in "$REPO_ROOT/src/"*.sh; do |
| 104 | + [ -f "$f" ] && cp "$f" "$TARBALL_ROOT/src/" && chmod +x "$TARBALL_ROOT/src/$(basename "$f")" |
| 105 | +done |
| 106 | +# Copy test JSON files |
| 107 | +if [ -d "$REPO_ROOT/src/tests" ]; then |
| 108 | + cp -r "$REPO_ROOT/src/tests" "$TARBALL_ROOT/src/tests" |
| 109 | +fi |
| 110 | + |
| 111 | +# 6. Copy bootstrap script |
| 112 | +cp "$REPO_ROOT/scripts/bootstrap.sh" "$TARBALL_ROOT/bootstrap.sh" |
| 113 | +chmod +x "$TARBALL_ROOT/bootstrap.sh" |
| 114 | + |
| 115 | +# 7. Write version file for cache invalidation |
| 116 | +echo "$VERSION" > "$TARBALL_ROOT/.version" |
| 117 | + |
| 118 | +# 8. Write MANIFEST.json |
| 119 | +# Use sha256sum on Linux, shasum on macOS |
| 120 | +if command -v sha256sum >/dev/null 2>&1; then |
| 121 | + SHA_CMD="sha256sum" |
| 122 | +else |
| 123 | + SHA_CMD="shasum -a 256" |
| 124 | +fi |
| 125 | +CONTENTS_SHA=$(find "$TARBALL_ROOT" -type f -exec $SHA_CMD {} \; | sort | $SHA_CMD | cut -d' ' -f1) |
| 126 | +cat > "$TARBALL_ROOT/MANIFEST.json" <<MANIFEST |
| 127 | +{ |
| 128 | + "version": "${VERSION}", |
| 129 | + "python_version": "${PYTHON_FULL_VERSION}", |
| 130 | + "uv_version": "${UV_VERSION}", |
| 131 | + "platform": "x86_64-unknown-linux-gnu", |
| 132 | + "sha256": "${CONTENTS_SHA}" |
| 133 | +} |
| 134 | +MANIFEST |
| 135 | + |
| 136 | +# 9. Package tarball |
| 137 | +echo "Packaging tarball..." |
| 138 | +cd "$BUILD_DIR" |
| 139 | +tar czf "$OUTPUT_DIR/$TARBALL_NAME" flash-worker/ |
| 140 | + |
| 141 | +# 10. Report |
| 142 | +TARBALL_SIZE=$(du -h "$OUTPUT_DIR/$TARBALL_NAME" | cut -f1) |
| 143 | +echo "" |
| 144 | +echo "Tarball built: $OUTPUT_DIR/$TARBALL_NAME" |
| 145 | +echo "Size: $TARBALL_SIZE" |
| 146 | +echo "Version: $VERSION" |
| 147 | +echo "SHA256: $($SHA_CMD "$OUTPUT_DIR/$TARBALL_NAME" | cut -d' ' -f1)" |
| 148 | + |
| 149 | +# Cleanup build dir (keep cache) |
| 150 | +rm -rf "$BUILD_DIR" |
0 commit comments