diff --git a/README.md b/README.md index 058e001..672b770 100644 --- a/README.md +++ b/README.md @@ -271,8 +271,8 @@ jobs: | `python-version` | Python version to use for building | `"3.13"` | `"3.12"` | | `pyinstaller-version` | PyInstaller version to install | `6.11.1` | `""` (use latest) | | `additional-args` | Additional PyInstaller arguments | `""` | `"--hidden-import=module"` | -| `pip-extra-index-url` | Extra pip index URL | `https://dl.espressif.com/pypi` | `""` | -| `install-deps-command` | Command to install project dependencies | `"pip install --user --prefer-binary -e ."` | `"pip install -r requirements.txt"` | +| `pip-extra-index-url` | Extra Python package index URL | `https://dl.espressif.com/pypi` | `""` | +| `install-deps-command` | Command to install project dependencies | `"uv pip install -e ."` | `"uv pip install -r requirements.txt"` | | `additional-arm-packages` | ARMv7 ONLY: Additional system packages | `""` | `"openssl libffi-dev"` | | `test-command-args` | Command arguments to test executables | `"--help"` | `"--version"` | | `certificate` | Certificate to use for signing binaries | `""` | `${{ secrets.CERTIFICATE }}` | diff --git a/action.yml b/action.yml index 28b4fc9..43c24c1 100644 --- a/action.yml +++ b/action.yml @@ -43,14 +43,14 @@ inputs: required: false default: '' pip-extra-index-url: - description: Extra pip index URL + description: Extra Python Package Index URL required: false default: https://dl.espressif.com/pypi install-deps-command: description: Command to install project dependencies. Command will be executed - like `python -m {install-deps-command}` + like `uv pip install {install-deps-command}` required: false - default: pip install --user --prefer-binary -e . + default: uv pip install -e . additional-arm-packages: description: 'ARMv7 ONLY: Additional system packages to install (space-separated). e.g. for cryptography: openssl libffi-dev libffi7 libssl-dev' @@ -134,23 +134,27 @@ runs: --volume "${PWD}/${{ inputs.output-dir }}:/${{ inputs.output-dir }}" --volume "${GITHUB_ACTION_PATH}:/github/action" install: | + export DEBIAN_FRONTEND=noninteractive + export TZ=UTC apt-get update -y - apt-get install -y software-properties-common - add-apt-repository -y ppa:deadsnakes/ppa - apt-get update -y - apt-get install --ignore-missing -y curl python${{ inputs.python-version }} python${{ inputs.python-version }}-dev pkg-config gcc g++ patchelf binutils zlib1g-dev ${{ inputs.additional-arm-packages }} - # Install pip for requested Python version using get-pip.py as ensurepip does not work here - curl -sS https://bootstrap.pypa.io/get-pip.py | python${{ inputs.python-version }} - python${{ inputs.python-version }} -m pip install --upgrade pip setuptools wheel + apt-get install -y curl git build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev pkg-config gcc g++ patchelf binutils ${{ inputs.additional-arm-packages }} run: | adduser --disabled-password --gecos "" builder chmod -R a+rwx /home/runner/work su builder <<'EOF' + curl -LsSf https://astral.sh/uv/install.sh | sh + source $HOME/.local/bin/env + # Install Python version using uv + uv python install ${{ inputs.python-version }} + # Create and activate virtual environment + uv venv + source .venv/bin/activate + # Install UV and upgrade tools + uv pip install --upgrade setuptools wheel export PATH=$PATH:/home/builder/.local/bin # Setup environment using helper script /github/action/setup_environment.sh \ - "python${{ inputs.python-version }}" \ "${{ inputs.pyinstaller-version }}" \ "${{ inputs.pip-extra-index-url }}" \ "${{ inputs.install-deps-command }}" @@ -161,7 +165,6 @@ runs: # Build each file using the script export GITHUB_ACTION_PATH=/github/action /github/action/build_with_pyinstaller.sh \ - "python${{ inputs.python-version }}" \ "${{ inputs.target-platform }}" \ "${{ inputs.output-dir }}" \ "${{ inputs.scripts }}" \ @@ -192,32 +195,51 @@ runs: -w ${GITHUB_WORKSPACE} \ ubuntu:20.04 \ bash -c " + export DEBIAN_FRONTEND=noninteractive && + export TZ=UTC && apt-get update -y && - apt-get install -y software-properties-common curl && - add-apt-repository -y ppa:deadsnakes/ppa && - apt-get update -y && - apt-get install -y python${{ inputs.python-version }} python${{ inputs.python-version }}-dev pkg-config gcc g++ patchelf binutils zlib1g-dev && - curl -sS https://bootstrap.pypa.io/get-pip.py | python${{ inputs.python-version }} && - python${{ inputs.python-version }} -m pip install --upgrade pip setuptools wheel && + apt-get install -y curl git build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev pkg-config gcc g++ patchelf binutils && + curl -LsSf https://astral.sh/uv/install.sh | sh && + source /root/.local/bin/env && + # Install Python version using uv + uv python install ${{ inputs.python-version }} && + # Create and activate virtual environment + uv venv && + source .venv/bin/activate && + # Install UV and upgrade tools + uv pip install --upgrade setuptools wheel && export GITHUB_ACTION_PATH=/github/action && /github/action/setup_environment.sh \ - 'python${{ inputs.python-version }}' \ '${{ inputs.pyinstaller-version }}' \ '${{ inputs.pip-extra-index-url }}' \ '${{ inputs.install-deps-command }}' && # Execute the build script - /github/action/build_with_pyinstaller.sh 'python${{ inputs.python-version }}' '${{ inputs.target-platform }}' '${{ inputs.output-dir }}' '${{ inputs.scripts }}' '${{ inputs.script-name }}' '${{ inputs.icon-file }}' '/github/action/include_data_dirs.json' '${{ steps.setup-platform.outputs.data-separator }}' '${{ inputs.additional-args }}' + /github/action/build_with_pyinstaller.sh '${{ inputs.target-platform }}' '${{ inputs.output-dir }}' '${{ inputs.scripts }}' '${{ inputs.script-name }}' '${{ inputs.icon-file }}' '/github/action/include_data_dirs.json' '${{ steps.setup-platform.outputs.data-separator }}' '${{ inputs.additional-args }}' " + - name: Install UV + if: | + steps.setup-platform.outputs.needs-docker == 'false' && steps.setup-platform.outputs.needs-arm-emulation == 'false' + uses: astral-sh/setup-uv@v6 + with: + enable-cache: true + - name: Setup environment (Native platforms) if: | steps.setup-platform.outputs.needs-docker == 'false' && steps.setup-platform.outputs.needs-arm-emulation == 'false' shell: bash run: | + # Create and activate virtual environment + uv venv + if [ "${{ inputs.target-platform }}" == 'windows-amd64' ]; then + source .venv\\Scripts\\activate + else + source .venv/bin/activate + fi + $GITHUB_ACTION_PATH/setup_environment.sh \ - 'python' \ '${{ inputs.pyinstaller-version }}' \ '${{ inputs.pip-extra-index-url }}' \ '${{ inputs.install-deps-command }}' @@ -228,7 +250,7 @@ runs: id: build shell: bash run: | - $GITHUB_ACTION_PATH/build_with_pyinstaller.sh 'python' '${{ inputs.target-platform }}' '${{ inputs.output-dir }}' '${{ inputs.scripts }}' '${{ inputs.script-name }}' '${{ inputs.icon-file }}' '${{ inputs.include-data-dirs }}' '${{ steps.setup-platform.outputs.data-separator }}' '${{ inputs.additional-args }}' + $GITHUB_ACTION_PATH/build_with_pyinstaller.sh '${{ inputs.target-platform }}' '${{ inputs.output-dir }}' '${{ inputs.scripts }}' '${{ inputs.script-name }}' '${{ inputs.icon-file }}' '${{ inputs.include-data-dirs }}' '${{ steps.setup-platform.outputs.data-separator }}' '${{ inputs.additional-args }}' echo "success=true" >> $GITHUB_OUTPUT diff --git a/build_with_pyinstaller.sh b/build_with_pyinstaller.sh index 71f26cb..dc87047 100755 --- a/build_with_pyinstaller.sh +++ b/build_with_pyinstaller.sh @@ -1,23 +1,21 @@ #!/bin/bash # Build Python scripts with PyInstaller -# Usage: ./build_with_pyinstaller.sh [python_version] [target_platform] [output_dir] [scripts] [script_names] [icon_file] [include_data_dirs] [data_separator] [additional_args] +# Usage: ./build_with_pyinstaller.sh [target_platform] [output_dir] [scripts] [script_names] [icon_file] [include_data_dirs] [data_separator] [additional_args] set -e # Parse arguments -PYTHON_VERSION="${1:-python}" -TARGET_PLATFORM="${2}" -OUTPUT_DIR="${3}" -SCRIPTS="${4}" -SCRIPT_NAMES="${5}" -ICON_FILE="${6}" -INCLUDE_DATA_DIRS="${7}" -DATA_SEPARATOR="${8}" -ADDITIONAL_ARGS="${9}" +TARGET_PLATFORM="${1}" +OUTPUT_DIR="${2}" +SCRIPTS="${3}" +SCRIPT_NAMES="${4}" +ICON_FILE="${5}" +INCLUDE_DATA_DIRS="${6}" +DATA_SEPARATOR="${7}" +ADDITIONAL_ARGS="${8}" echo "Building with PyInstaller..." -echo "Python version: $PYTHON_VERSION" echo "Target platform: $TARGET_PLATFORM" echo "Output directory: $OUTPUT_DIR" echo "Scripts: $SCRIPTS" @@ -32,7 +30,7 @@ for i in "${!PYTHON_FILES[@]}"; do echo "Building $file for $TARGET_PLATFORM..." # Start building the command - cmd="$PYTHON_VERSION -m PyInstaller --onefile --distpath=$OUTPUT_DIR" + cmd="uv run pyinstaller --onefile --distpath=$OUTPUT_DIR" # Add custom name if provided if [ -n "$SCRIPT_NAMES" ] && [ $i -lt ${#SCRIPT_NAMES_ARRAY[@]} ]; then @@ -51,7 +49,7 @@ for i in "${!PYTHON_FILES[@]}"; do # Add include-data-dirs using Python script if [ -n "$INCLUDE_DATA_DIRS" ]; then echo "Processing include-data-dirs for $file..." - include_flags=$($PYTHON_VERSION $GITHUB_ACTION_PATH/process_include_dirs.py "$INCLUDE_DATA_DIRS" "$DATA_SEPARATOR" "$file") + include_flags=$(uv run python $GITHUB_ACTION_PATH/process_include_dirs.py "$INCLUDE_DATA_DIRS" "$DATA_SEPARATOR" "$file") echo "Include flags result: '$include_flags'" if [ -n "$include_flags" ]; then cmd="$cmd $include_flags" diff --git a/setup_environment.sh b/setup_environment.sh index 5c82fb6..5badbfd 100755 --- a/setup_environment.sh +++ b/setup_environment.sh @@ -1,34 +1,33 @@ #!/bin/bash # Setup Python environment for PyInstaller builds -# Usage: ./setup_environment.sh [python_version] [pyinstaller_version] [pip_extra_index_url] [install_deps_command] +# Usage: ./setup_environment.sh [pyinstaller_version] [extra_index_url] [install_deps_command] set -e -PYTHON_VERSION="${1:-python}" -PYINSTALLER_VERSION="${2:-6.11.1}" -PIP_EXTRA_INDEX_URL="${3:-}" -INSTALL_DEPS_COMMAND="${4:-pip install --user --prefer-binary -e .}" +PYINSTALLER_VERSION="${1:-6.11.1}" +EXTRA_INDEX_URL="${2:-}" +INSTALL_DEPS_COMMAND="${3:-uv pip install -e .}" echo "Setting up Python environment..." -echo "Python version: $PYTHON_VERSION" echo "PyInstaller version: $PYINSTALLER_VERSION" -# Set pip extra index if provided -if [ -n "$PIP_EXTRA_INDEX_URL" ]; then - export PIP_EXTRA_INDEX_URL="$PIP_EXTRA_INDEX_URL" - echo "Using extra pip index: $PIP_EXTRA_INDEX_URL" +# Set Python package extra index if provided +if [ -n "$EXTRA_INDEX_URL" ]; then + export UV_INDEX="$EXTRA_INDEX_URL" + export UV_INDEX_STRATEGY="unsafe-best-match" + echo "Using extra Python package index: $EXTRA_INDEX_URL" fi # Install PyInstaller if [ -z "$PYINSTALLER_VERSION" ]; then - $PYTHON_VERSION -m pip install pyinstaller + uv pip install pyinstaller else - $PYTHON_VERSION -m pip install pyinstaller==$PYINSTALLER_VERSION + uv pip install pyinstaller==$PYINSTALLER_VERSION fi # Install dependencies echo "Installing project dependencies..." -$PYTHON_VERSION -m $INSTALL_DEPS_COMMAND +$INSTALL_DEPS_COMMAND echo "Environment setup completed successfully"