Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}` |
Expand Down
66 changes: 44 additions & 22 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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 }}"
Expand All @@ -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 }}" \
Expand Down Expand Up @@ -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 }}'
Expand All @@ -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

Expand Down
24 changes: 11 additions & 13 deletions build_with_pyinstaller.sh
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -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
Expand All @@ -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"
Expand Down
25 changes: 12 additions & 13 deletions setup_environment.sh
Original file line number Diff line number Diff line change
@@ -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"