build miniupnpc wheels in ci (#640)

* add miniupnpc_wheels_yml

* cp --recursive --verbose cloned/miniupnpc source

* --dereference

* reduce legibility to -RLv for macOS

* try qemu for linux aarch64

* use macos-latest for macOS ARM64 and cross build

* only setup qemu for linux

* skip install test for macos arm64 since we are cross building

* force all CIBW_ARCHS

* skip install test for all arm since we are cross building

* copy in actions

* setup for windows exclusion before merge

* add 3.12

* update from upstream

* macos arm runners, supposedly

* checkout before local actions

* cloned/

* _MACOS

* multiple cibuildwheel pins

* more cloned/

* exclude macos arm 3.7-3.9 due to python unavailability from github actions

* yup

* actions/setup-python@v5

* update pip

* maybe actually use qemu for linux arm

* oops

* more explicit in docker

* -m

* hmm

* aarch64

* aarch64 _and_ arm64

* ...

* try calling out os/arch labels for the runner

* Revert "try calling out os/arch labels for the runner"

This reverts commit 51f1f43e6b11b83433eb297a1ba0a15ef9e06702.

* add copyright and license notices

* exclude windows, cleanup
This commit is contained in:
Kyle Altendorf 2024-03-12 20:09:47 -04:00 committed by GitHub
parent 4dda6d8820
commit f9b2857dce
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 474 additions and 0 deletions

View File

@ -0,0 +1,45 @@
# Copyright 2024 Chia Network Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
name: "Activate virtual environment"
description: 'Activate the a virtual environment for future steps.'
inputs:
directories:
description: "A list of directories to attempt to activate, terminates on the first present directory. Uses JSON format."
required: true
default: '["venv/", ".venv/"]'
#outputs:
# virtual-env:
# description: "The VIRTUAL_ENV environment value."
# value:
# virtual-env-bin:
# description: "The path to the virtual environment directory containing the executables."
# value:
runs:
using: "composite"
steps:
- name: Activate virtual environment
shell: sh
env:
INPUT_DIRECTORIES: ${{ inputs.directories }}
run: |
unset PYTHON
for V in 311 3.11 310 3.10 39 3.9 38 3.8 37 3.7 3 ""; do
if command -v python$V >/dev/null; then
PYTHON=python$V
break
fi
done
[ -n "$PYTHON" ] || (echo "Unable to find python" && exit 1)
$PYTHON "${GITHUB_ACTION_PATH}/activate_venv.py"

View File

@ -0,0 +1,47 @@
# Copyright 2024 Chia Network Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import json
import os
import pathlib
import sys
directories = [
pathlib.Path(directory).absolute()
for directory in json.loads(os.environ["INPUT_DIRECTORIES"])
]
github_env = pathlib.Path(os.environ["GITHUB_ENV"])
github_path = pathlib.Path(os.environ["GITHUB_PATH"])
for directory in directories:
if directory.exists():
break
print(f"No environment found at: {os.fspath(directory)}")
else:
print("No environment found")
sys.exit(1)
print(f"Environment found at: {os.fspath(directory)}")
if sys.platform == "win32":
bin_scripts_path = directory.joinpath("Scripts")
else:
bin_scripts_path = directory.joinpath("bin")
with github_path.open("a") as file:
print(os.fspath(bin_scripts_path), file=file)
with github_env.open("a") as file:
print(f"VIRTUAL_ENV={os.fspath(directory)}", file=file)

16
.github/actions/activate-venv/readme.md vendored Normal file
View File

@ -0,0 +1,16 @@
# Activate virtual environment
Provides cross-platform activation of a Python virtual environment.
By default it searches in `venv/` then `.venv/`.
This is configurable via a JSON list passed to the `directories` parameter.
```yaml
- uses: Chia-Network/actions/activate-venv@main
```
```yaml
- uses: Chia-Network/actions/activate-venv@main
directories: '["another_virtualenv/"]'
```
copied from https://github.com/Chia-Network/actions/tree/5851777428fb98585ae9628b7dc49ed9f6487fde/activate-venv

View File

@ -0,0 +1,40 @@
# Copyright 2024 Chia Network Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import pathlib
import sys
reference = pathlib.Path(os.environ["REFERENCE_PATH"]).absolute()
actual = pathlib.Path(sys.executable)
expected_inside = {"true": True, "false": False}[os.environ["EXPECTED_INSIDE"]]
is_inside: bool
try:
actual.relative_to(reference)
except ValueError:
is_inside = False
else:
is_inside = True
correct = expected_inside == is_inside
print(f" reference: {reference}")
print(f" actual: {actual}")
print(f"expected_inside: {expected_inside}")
print(f" is_inside: {is_inside}")
print(f" correct: {'yes' if correct else 'no'}")
if not correct:
sys.exit(1)

43
.github/actions/create-venv/action.yml vendored Normal file
View File

@ -0,0 +1,43 @@
# Copyright 2024 Chia Network Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
name: "Create venv"
description: "Create a temporary venv"
inputs:
python-command:
description: "The Python to use for creating the environment"
required: false
default: "python"
outputs:
venv_path:
description: "The path to the virtual environment directory, not including the bin or scripts directory."
value: ${{ steps.create-venv.outputs.temp-venv-path }}
python_executable:
description: "The path to the Python executable in the virtual environment directory."
value: ${{ steps.create-venv.outputs.temp-python-executable }}
activate-venv-directories:
description: "The JSON serialized array including the path to the temporary env. This is for use with the activate-venv action."
value: ${{ steps.create-venv.outputs.activate-venv-directories }}
runs:
using: "composite"
steps:
- name: Create venv
id: create-venv
shell: sh
run: |
${{ inputs.python-command }} "${GITHUB_ACTION_PATH}/create_temporary_venv.py"
- name: Update pip
shell: sh
run: |
"${{ steps.create-venv.outputs.temp-python-executable }}" -m pip install --upgrade pip

View File

@ -0,0 +1,42 @@
# Copyright 2024 Chia Network Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import json
import os
import pathlib
import sys
import tempfile
import venv
runner_temp = os.environ["RUNNER_TEMP"]
temporary_directory = pathlib.Path(tempfile.mkdtemp(dir=runner_temp))
github_output = pathlib.Path(os.environ["GITHUB_OUTPUT"])
python_executable: pathlib.Path
if sys.platform == "win32":
python_executable = temporary_directory.joinpath("Scripts", "python.exe")
else:
python_executable = temporary_directory.joinpath("bin", "python")
activate_venv_directories = json.dumps([os.fspath(temporary_directory)])
with github_output.open("a") as file:
print(f"temp-venv-path={os.fspath(temporary_directory.as_posix())}", file=file)
print(
f"temp-python-executable={os.fspath(python_executable.as_posix())}",
file=file,
)
print(f"activate-venv-directories={activate_venv_directories}", file=file)
venv.create(env_dir=temporary_directory, with_pip=True)

15
.github/actions/create-venv/readme.md vendored Normal file
View File

@ -0,0 +1,15 @@
# Create venv
Creates a venv in the runner temporary path that will be removed upon completion of the job.
This can be used in combination with the `activate-venv` action such as shown below.
```yaml
- uses: Chia-Network/actions/create-venv@main
id: create-venv
- uses: Chia-Network/actions/activate-venv@main
with:
directories: ${{ steps.create-venv.outputs.activate-venv-directories }}
```
copied from https://github.com/Chia-Network/actions/tree/5851777428fb98585ae9628b7dc49ed9f6487fde/create-venv

226
.github/workflows/miniupnpc_wheels.yml vendored Normal file
View File

@ -0,0 +1,226 @@
# Copyright 2024 Chia Network Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# copied from https://github.com/Chia-Network/build-wheels/blob/52e183920e3ec44017ed767c65e9b204536c0f13/.github/workflows/miniupnpc.yml
name: "build miniupnpc wheels"
on:
push:
branches:
- master
tags:
- '**'
pull_request:
branches:
- '**'
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'workflow_dispatch' && github.event.inputs.version || format('{0}-{1}-{2}', github.ref, github.event_name, github.ref == 'refs/heads/main' && github.sha || '') }}
cancel-in-progress: true
defaults:
run:
shell: bash
permissions:
id-token: write
contents: read
jobs:
build:
name: ${{ matrix.os.emoji }} 📦 Build ${{ matrix.arch.name }} ${{ matrix.python.major-dot-minor }}
runs-on: ${{ matrix.os.runs-on[matrix.arch.matrix] }}
strategy:
fail-fast: false
matrix:
os:
- name: macOS
file-name: macos
matrix: macos
emoji: 🍎
runs-on:
arm: [macos-14]
intel: [macos-latest]
macosx-deployment-target:
arm: 11.0
intel: 10.14
cibw-archs:
# TODO: do we need universal2?
arm: arm64
intel: x86_64
- name: Linux
file-name: linux
matrix: linux
emoji: 🐧
runs-on:
arm: [ubuntu-latest]
intel: [ubuntu-latest]
cibw-archs:
arm: aarch64
intel: x86_64
- name: Windows
file-name: windows
matrix: windows
emoji: 🪟
runs-on:
intel: [windows-latest]
cibw-archs:
intel: x86_64
python:
- major-dot-minor: '3.7'
cibw-build: 'cp37-*'
manylinux:
arm: manylinux2014
intel: manylinux2010
matrix: '3.7'
- major-dot-minor: '3.8'
cibw-build: 'cp38-*'
manylinux:
arm: manylinux2014
intel: manylinux2010
matrix: '3.8'
- major-dot-minor: '3.9'
cibw-build: 'cp39-*'
manylinux:
arm: manylinux2014
intel: manylinux2010
matrix: '3.9'
- major-dot-minor: '3.10'
cibw-build: 'cp310-*'
manylinux:
arm: manylinux2014
intel: manylinux2010
matrix: '3.10'
- major-dot-minor: '3.11'
cibw-build: 'cp311-*'
manylinux:
arm: manylinux2014
intel: manylinux2014
matrix: '3.11'
- major-dot-minor: '3.12'
cibw-build: 'cp312-*'
manylinux:
arm: manylinux2014
intel: manylinux2014
matrix: '3.12'
arch:
- name: ARM
file-name: arm
matrix: arm
cibw: aarch64
- name: Intel
file-name: intel
matrix: intel
cibw: x86_64
exclude:
- os: # excluding windows entirely as that is presently handled in AppVeyor
matrix: windows
- os:
matrix: windows
arch:
matrix: arm
- os:
matrix: macos
arch:
matrix: arm
python:
matrix: '3.7'
- os:
matrix: macos
arch:
matrix: arm
python:
matrix: '3.8'
- os:
matrix: macos
arch:
matrix: arm
python:
matrix: '3.9'
env:
FILE_NAME: ${{ matrix.os.file-name }}-${{ matrix.arch.file-name }}-${{ matrix.python.major-dot-minor }}
CIBW_ARCHS: ${{ matrix.os.cibw-archs[matrix.arch.matrix] }}
CIBW_BUILD: ${{ matrix.python.cibw-build }}
CIBW_ENVIRONMENT_MACOS: MACOSX_DEPLOYMENT_TARGET=${{ matrix.os.macosx-deployment-target[matrix.arch.matrix] }}
CIBW_MANYLINUX_AARCH64_IMAGE: ${{ matrix.python.manylinux['arm'] }}
CIBW_MANYLINUX_X86_64_IMAGE: ${{ matrix.python.manylinux['intel'] }}
CIBW_PRERELEASE_PYTHONS: True
CIBW_SKIP: '*-manylinux_i686 *-win32 *-musllinux_*'
steps:
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python.major-dot-minor }}
- uses: actions/checkout@v4
with:
path: cloned
- uses: ./cloned/.github/actions/create-venv
id: create-venv
- uses: ./cloned/.github/actions/activate-venv
with:
directories: ${{ steps.create-venv.outputs.activate-venv-directories }}
- name: Copy out miniupnpc
run: |
cp -RLv cloned/miniupnpc source
- name: Set up QEMU
if: matrix.os.matrix == 'linux' && matrix.arch.matrix == 'arm'
uses: docker/setup-qemu-action@v3
- name: Build and test
if: matrix.os.matrix != 'windows'
run: |
pip install 'cibuildwheel==2.13.1; python_version < "3.8"' 'cibuildwheel==2.16.5; python_version >= "3.8"'
cibuildwheel source --output-dir dist
- name: Build (Windows)
if: matrix.os.matrix == 'windows'
run: |
cd source
mingw32-make -f Makefile.mingw CC=gcc
python -m pip install setuptools wheel
mingw32-make -f Makefile.mingw pythonmodule PYTHON=python
7z a dist/*.whl miniupnpc.dll
mkdir ../dist
cp dist/*.whl ../dist
- uses: ./cloned/.github/actions/create-venv
id: create-test-venv
- uses: ./cloned/.github/actions/activate-venv
with:
directories: ${{ steps.create-test-venv.outputs.activate-venv-directories }}
- name: Install
if: matrix.arch.matrix != 'arm'
run: |
pip install --no-index --only-binary :all: --find-links dist miniupnpc
- name: Import
if: matrix.arch.matrix != 'arm'
run: |
python -c 'import miniupnpc; print(miniupnpc)'
- uses: actions/upload-artifact@v4
if: always()
with:
name: wheel-${{ env.FILE_NAME }}
path: ./dist
if-no-files-found: error