diff --git a/.github/workflows/build-binary.yml b/.github/workflows/build-binary.yml new file mode 100644 index 000000000..aede182da --- /dev/null +++ b/.github/workflows/build-binary.yml @@ -0,0 +1,119 @@ +name: Build binaries + +on: + push: + paths: + - '**.py' + - '**.pyx' + - '**.c' + - '**.h' + - '**.yml' + - '**.toml' + - '**.cfg' + - '**.ini' + - 'requirements.d/*' + - 'scripts/**' + pull_request: + paths: + - '**.py' + - '**.pyx' + - '**.c' + - '**.h' + - '**.yml' + - '**.toml' + - '**.cfg' + - '**.ini' + - 'requirements.d/*' + - 'scripts/**' + workflow_dispatch: + +jobs: + build-binary-macos: + name: Build (macOS ${{ matrix.os }} / ${{ runner.arch }}) + strategy: + fail-fast: false + matrix: + os: [macos-12, macos-14] + runs-on: ${{ matrix.os }} + timeout-minutes: 60 + + env: + # Support both Homebrew locations (Intel and Apple Silicon) + PKG_CONFIG_PATH: "/opt/homebrew/opt/openssl@3.0/lib/pkgconfig:/usr/local/opt/openssl@3.0/lib/pkgconfig:$PKG_CONFIG_PATH" + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + # Just fetching one commit is not enough for setuptools-scm, so we fetch all + fetch-depth: 0 + + - name: Set up Python 3.11 + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Cache pip + uses: actions/cache@v4 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('requirements.d/development.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + ${{ runner.os }}- + + - name: Install macOS packages via Homebrew (see Brewfile) + run: | + brew bundle install + + - name: Install Python requirements + run: | + python -m pip install --upgrade pip setuptools wheel + pip install -r requirements.d/development.txt + + - name: Build Borg to compile extensions + env: + # Set both paths again to be sure nothing overrides them + PKG_CONFIG_PATH: "/opt/homebrew/opt/openssl@3.0/lib/pkgconfig:/usr/local/opt/openssl@3.0/lib/pkgconfig:${{ env.PKG_CONFIG_PATH }}" + run: | + pip install -ve . + + - name: Build PyInstaller single-file binary + run: | + python -m pip install 'pyinstaller==6.7.0' + mkdir -p dist/binary + pyinstaller --clean --distpath=dist/binary scripts/borg.exe.spec + pushd dist/binary + tar -czvf borg.tgz borg-dir + rm -rf borg-dir + popd + + - name: Smoke-test the built binary (borg -V) + run: | + pushd dist/binary + ls -l + # test single-file binary + chmod +x borg.exe + ./borg.exe -V + # test single-dir binary + tar -xzvf borg.tgz + chmod +x borg-dir/borg.exe + ./borg-dir/borg.exe -V + popd + + - name: Prepare artifacts + run: | + mkdir -p artifacts + if [ -f dist/binary/borg.exe ]; then + cp dist/binary/borg.exe artifacts/borg-${{ matrix.os }}-${{ runner.arch }} + fi + if [ -f dist/binary/borg.tgz ]; then + cp dist/binary/borg.tgz artifacts/borg-dir-${{ matrix.os }}-${{ runner.arch }}.tgz + fi + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: borg-macos-${{ matrix.os }}-${{ runner.arch }} + path: artifacts/* + if-no-files-found: error