Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aacd0fe33c | ||
|
|
26705eef1b | ||
|
|
ff277fd345 | ||
|
|
3d9fef458c | ||
|
|
fac9b13307 | ||
|
|
31a4e3c86b | ||
|
|
bd0aca510c | ||
|
|
93b2ce39f0 | ||
|
|
d696481714 | ||
|
|
42b81ab47f | ||
|
|
c013e0d0e6 | ||
|
|
2fd18793c1 | ||
|
|
200d4af89c | ||
|
|
48d77c7edf | ||
|
|
0b9a3e8afd | ||
|
|
a2a8655c43 | ||
|
|
4b5ac4ecbb | ||
|
|
8a434b1759 | ||
|
|
2a62198b47 | ||
|
|
28de36ea6f | ||
|
|
c3caa5f26f | ||
|
|
6840c9cea1 | ||
|
|
c67da48510 | ||
|
|
9a444b1ab8 | ||
|
|
10585d2882 | ||
|
|
2fbaa36286 | ||
|
|
4433ea4de1 | ||
|
|
5c5d1ef10a | ||
|
|
734dea7526 | ||
|
|
188eaa8a93 | ||
|
|
8e0ee0a4ab | ||
|
|
84446ed1a9 | ||
|
|
a4699f4cc8 | ||
|
|
ac90f2b9ac | ||
|
|
3a984346dd | ||
|
|
b448271640 | ||
|
|
e0dd32dea8 | ||
|
|
fbb4e28b44 | ||
|
|
aafdff7ec7 | ||
|
|
e6e8cb79fc | ||
|
|
a0d67a7a90 | ||
|
|
fd2b5d3270 | ||
|
|
416c6f3a3c | ||
|
|
9df68df525 | ||
|
|
45074a9b3a | ||
|
|
448d6538d7 | ||
|
|
17c83ad78b | ||
|
|
6d6d277ea5 | ||
|
|
d36b2d35c6 | ||
|
|
efa1958023 | ||
|
|
a345008626 | ||
|
|
43abc35259 | ||
|
|
2942c99ce4 | ||
|
|
3c577ab036 | ||
|
|
8ce553b2ea | ||
|
|
48c23b10d0 | ||
|
|
442174157a | ||
|
|
f19c606573 | ||
|
|
ac3523132d | ||
|
|
a7ea9f42cb | ||
|
|
1059249f4d | ||
|
|
516f4b9d7e | ||
|
|
ebf56281ed | ||
|
|
0896566743 | ||
|
|
fd92707823 | ||
|
|
cfec077f05 | ||
|
|
5c4767899d | ||
|
|
a15ccb6ef0 | ||
|
|
ae6d65e62e | ||
|
|
3cd3a9dc77 | ||
|
|
9e40094cfc | ||
|
|
c91d669a90 | ||
|
|
f81c9474d6 | ||
|
|
2610f3220a | ||
|
|
29b0cdb08a | ||
|
|
2b7da3fcbe | ||
|
|
726bcdf372 | ||
|
|
3142806f4b | ||
|
|
e28e43e7f9 | ||
|
|
737ad6b650 | ||
|
|
472eb898ed | ||
|
|
98db24f92c | ||
|
|
29b25a3ab6 | ||
|
|
5a6f35fe76 | ||
|
|
03ae918ec5 | ||
|
|
94dead9440 |
@@ -1,22 +1,6 @@
|
||||
version: 2
|
||||
|
||||
jobs:
|
||||
flake8-mypy:
|
||||
docker:
|
||||
- image: circleci/python:3.6
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
- run:
|
||||
name: Install flake8 & mypy
|
||||
command: sudo python -m pip install flake8 mypy
|
||||
- run:
|
||||
name: flake8
|
||||
command: flake8
|
||||
- run:
|
||||
name: mypy
|
||||
command: mypy
|
||||
|
||||
osx-python3.6:
|
||||
macos:
|
||||
xcode: "9.4.1"
|
||||
@@ -54,6 +38,5 @@ workflows:
|
||||
version: 2
|
||||
all-tests:
|
||||
jobs:
|
||||
- flake8-mypy
|
||||
- osx-python3.6
|
||||
- linux-python3.6
|
||||
|
||||
@@ -7,6 +7,14 @@ on:
|
||||
- 'docs/**'
|
||||
|
||||
jobs:
|
||||
pre-commit:
|
||||
name: Pre-commit checks (mypy, flake8, etc.)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: pre-commit/action@v2.0.0
|
||||
|
||||
test:
|
||||
# skip branch builds on joerick/cibuildwheel, but always build `master` and pull requests
|
||||
if: github.repository != 'joerick/cibuildwheel' || github.ref == 'refs/heads/master' || github.event_name == 'pull_request'
|
||||
@@ -17,6 +25,7 @@ jobs:
|
||||
matrix:
|
||||
os: [ubuntu-18.04, windows-latest, macos-latest]
|
||||
python_version: ['3.7']
|
||||
timeout-minutes: 180
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
linux:
|
||||
image: python:3.8
|
||||
services:
|
||||
- name: docker:dind
|
||||
entrypoint: ["env", "-u", "DOCKER_HOST"]
|
||||
command: ["dockerd-entrypoint.sh"]
|
||||
variables:
|
||||
DOCKER_HOST: tcp://docker:2375/
|
||||
DOCKER_DRIVER: overlay2
|
||||
# See https://github.com/docker-library/docker/pull/166
|
||||
DOCKER_TLS_CERTDIR: ""
|
||||
script:
|
||||
- curl -sSL https://get.docker.com/ | sh
|
||||
- python -m pip install -r requirements-dev.txt
|
||||
- python ./bin/run_tests.py
|
||||
+24
-20
@@ -1,21 +1,25 @@
|
||||
repos:
|
||||
- repo: https://gitlab.com/pycqa/flake8
|
||||
rev: 3.8.1
|
||||
hooks:
|
||||
- id: flake8
|
||||
pass_filenames: true
|
||||
# this seems to need to be here in addition to setup.cfg
|
||||
exclude: cibuildwheel/resources/
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v2.3.0
|
||||
hooks:
|
||||
- id: check-yaml
|
||||
- id: check-merge-conflict
|
||||
- id: end-of-file-fixer
|
||||
exclude: cibuildwheel/resources/pinned_docker_images.cfg
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: '' # Use the sha / tag you want to point at
|
||||
hooks:
|
||||
- id: mypy
|
||||
files: cibuildwheel|test
|
||||
exclude: cibuildwheel/resources
|
||||
- repo: https://gitlab.com/pycqa/flake8
|
||||
rev: 3.8.3
|
||||
hooks:
|
||||
- id: flake8
|
||||
exclude: cibuildwheel/resources/
|
||||
additional_dependencies: [flake8-bugbear]
|
||||
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v3.2.0
|
||||
hooks:
|
||||
- id: check-case-conflict
|
||||
- id: check-merge-conflict
|
||||
- id: check-yaml
|
||||
- id: end-of-file-fixer
|
||||
exclude: cibuildwheel/resources/pinned_docker_images.cfg
|
||||
- id: mixed-line-ending
|
||||
- id: trailing-whitespace
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: v0.782
|
||||
hooks:
|
||||
- id: mypy
|
||||
files: cibuildwheel/|test/
|
||||
pass_filenames: false
|
||||
|
||||
@@ -17,18 +17,18 @@ What does it do?
|
||||
|
||||
| | macOS x86_64 | Windows 64bit | Windows 32bit | manylinux x86_64 | manylinux i686 | manylinux aarch64 | manylinux ppc64le | manylinux s390x |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| CPython 2.7 | ✅ | ✅¹ | ✅¹ | ✅ | ✅ | | | |
|
||||
| CPython 3.5 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅² |
|
||||
| CPython 3.6 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅² |
|
||||
| CPython 3.7 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅² |
|
||||
| CPython 3.8 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅² |
|
||||
| CPython 3.9³ | 🛠 | 🛠 | 🛠 | 🛠 | 🛠 | 🛠 | 🛠 | |
|
||||
| PyPy 2.7 v7.3.0 | ✅ | | ✅ | ✅ | | | | |
|
||||
| PyPy 3.6 v7.3.0 | ✅ | | ✅ | ✅ | | | | |
|
||||
| CPython 2.7 | ✅ | ✅¹ | ✅¹ | ✅ | ✅ | | | |
|
||||
| CPython 3.5 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅² | ✅² | ✅³ |
|
||||
| CPython 3.6 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅² | ✅² | ✅³ |
|
||||
| CPython 3.7 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅² | ✅² | ✅³ |
|
||||
| CPython 3.8 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅² | ✅² | ✅³ |
|
||||
| CPython 3.9 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅² | ✅² | ✅³ |
|
||||
| PyPy 2.7 v7.3.0 | ✅ | | ✅ | ✅ | | | | |
|
||||
| PyPy 3.6 v7.3.0 | ✅ | | ✅ | ✅ | | | | |
|
||||
|
||||
<sup>¹ Not supported on Travis</sup><br>
|
||||
<sup>² Beta support until Travis CI fixes <a href="https://travis-ci.community/t/no-space-left-on-device-for-system-z/5954/11">a bug</a></sup><br>
|
||||
<sup>³ Python 3.9 is not yet ABI stable, so you shouldn't publish wheels with it yet. But if you want to check that your wheels build on Python 3.9, try our [`python3.9` branch](https://github.com/joerick/cibuildwheel/pull/382)!</sup>
|
||||
<sup>² Only supported on Travis</sup><br>
|
||||
<sup>³ Beta support until Travis CI fixes <a href="https://travis-ci.community/t/no-space-left-on-device-for-system-z/5954/11">a bug</a></sup><br>
|
||||
|
||||
- Builds manylinux, macOS and Windows wheels for CPython and PyPy using Azure Pipelines, Travis CI, AppVeyor, and CircleCI
|
||||
- Bundles shared library dependencies on Linux and macOS through [auditwheel](https://github.com/pypa/auditwheel) and [delocate](https://github.com/matthew-brett/delocate)
|
||||
@@ -37,7 +37,7 @@ What does it do?
|
||||
Usage
|
||||
-----
|
||||
|
||||
`cibuildwheel` currently works on **Travis CI**, **Azure Pipelines**, **AppVeyor** and **GitHub Actions** to build wheels for all three supported platforms (Linux, macOS, Windows). On **CircleCI** Linux and macOS wheels can be built.
|
||||
`cibuildwheel` currently works on **Travis CI**, **Azure Pipelines**, **AppVeyor**, **GitHub Actions**, **CircleCI**, and **Gitlab CI**. Check the table below for supported platforms on each service:
|
||||
|
||||
| | Linux | macOS | Windows |
|
||||
|-----------------|-------|-------|---------|
|
||||
@@ -46,8 +46,9 @@ Usage
|
||||
| AppVeyor | ✅ | ✅ | ✅ |
|
||||
| GitHub Actions | ✅ | ✅ | ✅ |
|
||||
| CircleCI | ✅ | ✅ | |
|
||||
| Gitlab CI | ✅ | | |
|
||||
|
||||
`cibuildwheel` is not intended to run on your development machine. Because it uses system Python from Python.org it will try to install packages globally - not what you expect from a build tool! Instead, isolated CI services like Travis CI, CircleCI, Azure Pipelines and AppVeyor are ideal.
|
||||
`cibuildwheel` is not intended to run on your development machine. Because it uses system Python from Python.org it will try to install packages globally - not what you expect from a build tool! Instead, isolated CI services like those mentioned above are ideal.
|
||||
|
||||
<!--intro-end-->
|
||||
|
||||
@@ -72,6 +73,8 @@ jobs:
|
||||
before_install:
|
||||
- choco install python --version 3.8.0
|
||||
- export PATH="/c/Python38:/c/Python38/Scripts:$PATH"
|
||||
# make sure it's on PATH as 'python3'
|
||||
- ln -s /c/Python38/python.exe /c/Python38/python3.exe
|
||||
|
||||
env:
|
||||
global:
|
||||
@@ -79,7 +82,7 @@ env:
|
||||
# Note: TWINE_PASSWORD is set to a PyPI API token in Travis settings
|
||||
|
||||
install:
|
||||
- python3 -m pip install cibuildwheel==1.5.4
|
||||
- python3 -m pip install cibuildwheel==1.6.1
|
||||
|
||||
script:
|
||||
# build the wheels, put them into './wheelhouse'
|
||||
@@ -121,7 +124,7 @@ Working examples
|
||||
|
||||
Here are some repos that use cibuildwheel.
|
||||
|
||||
- [pyinstrument_cext](https://github.com/joerick/pyinstrument_cext)
|
||||
- [pyinstrument_cext](https://github.com/joerick/pyinstrument_cext) - A simple C extension, without external dependencies, built on Travis CI/Appveyor.
|
||||
- [websockets](https://github.com/aaugustin/websockets)
|
||||
- [Parselmouth](https://github.com/YannickJadoul/Parselmouth)
|
||||
- [python-admesh](https://github.com/admesh/python-admesh)
|
||||
@@ -137,8 +140,12 @@ Here are some repos that use cibuildwheel.
|
||||
- [aiortc](https://github.com/aiortc/aiortc)
|
||||
- [aioquic](https://github.com/aiortc/aioquic)
|
||||
- [pikepdf](https://github.com/pikepdf/pikepdf)
|
||||
- [fathon](https://github.com/stfbnc/fathon)
|
||||
- [etebase-py](https://github.com/etesync/etebase-py) - Python bindings to a Rust library using `setuptools-rust`, and `sccache` for improved speed, built on Travis CI.
|
||||
|
||||
> Add your repo here! Send a PR.
|
||||
>
|
||||
> <sup>I'd like to include notes here to indicate why an example might be interesting to cibuildwheel users - the styles/technologies/techniques used in each. Please include that in future additions!</sup>
|
||||
|
||||
Legal note
|
||||
----------
|
||||
@@ -152,6 +159,42 @@ This is similar to static linking, so it might have some licence implications. C
|
||||
Changelog
|
||||
=========
|
||||
|
||||
### 1.6.1
|
||||
|
||||
_20 September 2020_
|
||||
|
||||
- 🛠 Add PPC64LE manylinux image supporting Python 3.9. (#436)
|
||||
- 📚 Add project URLs to PyPI listing (#428)
|
||||
|
||||
### 1.6.0
|
||||
|
||||
_9 September 2020_
|
||||
|
||||
- 🌟 Add Python 3.9 support! This initial support uses release candidate
|
||||
builds. You can start publishing wheels for Python 3.9 now, ahead of
|
||||
the official release. (#382)
|
||||
|
||||
Minor note - if you're building PPC64LE wheels, the manylinux image pinned
|
||||
by this version is
|
||||
[still on Python 3.9b3](https://github.com/pypa/manylinux/issues/758), not a
|
||||
release candidate. We'd advise holding off on distributing 3.9 ppc64le wheels
|
||||
until a subsequent version of cibuildwheel.
|
||||
- 🌟 Add Gitlab CI support. Gitlab CI can now build Linux wheels, using
|
||||
cibuildwheel. (#419)
|
||||
- 🐛 Fix a bug that causes pyproject.toml dependencies to fail to install on
|
||||
Windows (#420)
|
||||
- 📚 Added some information about Windows VC++ runtimes and how they relate
|
||||
to wheels.
|
||||
|
||||
### 1.5.5
|
||||
|
||||
_22 July 2020_
|
||||
|
||||
- 🐛 Fix a bug that would cause command substitutions in CIBW_ENVIRONMENT to
|
||||
produce no output on Linux (#411)
|
||||
- 🐛 Fix regression (introduced in 1.5.3) which caused BEFORE_BUILD and
|
||||
BEFORE_ALL to be executed in the wrong directory (#410)
|
||||
|
||||
### 1.5.4
|
||||
|
||||
_19 June 2020_
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
environment:
|
||||
# workaround an appveyor bug on macos
|
||||
# workaround an appveyor bug on macos
|
||||
# see https://github.com/appveyor/ci/issues/3376#issuecomment-611314299
|
||||
APPVEYOR_CONSOLE_DISABLE_PTY: true
|
||||
matrix:
|
||||
@@ -11,8 +11,8 @@ environment:
|
||||
APPVEYOR_JOB_NAME: "python37-x64-macos-mojave"
|
||||
|
||||
# while pypy libffi dependency is failing the build, allow failures on macos
|
||||
matrix:
|
||||
allow_failures:
|
||||
matrix:
|
||||
allow_failures:
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: macos-mojave
|
||||
|
||||
stack: python 3.7
|
||||
|
||||
@@ -21,6 +21,7 @@ jobs:
|
||||
|
||||
- job: windows_36
|
||||
pool: {vmImage: 'vs2017-win2016'}
|
||||
timeoutInMinutes: 180
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
@@ -33,6 +34,7 @@ jobs:
|
||||
|
||||
- job: windows_38
|
||||
pool: {vmImage: 'vs2017-win2016'}
|
||||
timeoutInMinutes: 180
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
|
||||
Executable
+137
@@ -0,0 +1,137 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
from subprocess import run
|
||||
import sys
|
||||
import textwrap
|
||||
import time
|
||||
import click
|
||||
from collections import namedtuple
|
||||
from urllib.parse import quote
|
||||
|
||||
|
||||
def shell(cmd, **kwargs):
|
||||
return run([cmd], shell=True, **kwargs)
|
||||
|
||||
|
||||
def git_repo_has_changes():
|
||||
unstaged_changes = shell('git diff-index --quiet HEAD --').returncode != 0
|
||||
staged_changes = shell('git diff-index --quiet --cached HEAD --').returncode != 0
|
||||
return unstaged_changes or staged_changes
|
||||
|
||||
|
||||
def generate_basic_project(path):
|
||||
sys.path.insert(0, '')
|
||||
from test.test_projects.c import new_c_project
|
||||
|
||||
project = new_c_project()
|
||||
project.generate(path)
|
||||
|
||||
|
||||
CIService = namedtuple('CIService', 'name src_config_path dst_config_path badge_md')
|
||||
services = [
|
||||
CIService(
|
||||
name='appveyor',
|
||||
src_config_path='examples/appveyor-minimal.yml',
|
||||
dst_config_path='appveyor.yml',
|
||||
badge_md='[](https://ci.appveyor.com/project/joerick/cibuildwheel/branch/{branch})',
|
||||
),
|
||||
CIService(
|
||||
name='azure-pipelines',
|
||||
src_config_path='examples/azure-pipelines-minimal.yml',
|
||||
dst_config_path='azure-pipelines.yml',
|
||||
badge_md='[](https://dev.azure.com/joerick0429/cibuildwheel/_build/latest?definitionId=2&branchName={branch})',
|
||||
),
|
||||
CIService(
|
||||
name='circle-ci',
|
||||
src_config_path='examples/circleci-minimal.yml',
|
||||
dst_config_path='.circleci/config.yml',
|
||||
badge_md='[](https://circleci.com/gh/joerick/cibuildwheel/tree/{branch})',
|
||||
),
|
||||
CIService(
|
||||
name='github',
|
||||
src_config_path='examples/github-minimal.yml',
|
||||
dst_config_path='.github/workflows/example.yml',
|
||||
badge_md='[](https://github.com/joerick/cibuildwheel/actions)',
|
||||
),
|
||||
CIService(
|
||||
name='travis-ci',
|
||||
src_config_path='examples/travis-ci-minimal.yml',
|
||||
dst_config_path='.travis.yml',
|
||||
badge_md='[](https://travis-ci.org/joerick/cibuildwheel)',
|
||||
),
|
||||
CIService(
|
||||
name='gitlab',
|
||||
src_config_path='examples/gitlab-minimal.yml',
|
||||
dst_config_path='.gitlab-ci.yml',
|
||||
badge_md='[](https://gitlab.com/joerick/cibuildwheel/-/commits/{branch})'
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@click.command()
|
||||
def run_example_ci_configs():
|
||||
if git_repo_has_changes():
|
||||
print('Your git repo has uncommitted changes. Commit or stash before continuing.')
|
||||
exit(1)
|
||||
|
||||
previous_branch = shell('git rev-parse --abbrev-ref HEAD',
|
||||
check=True,
|
||||
capture_output=True,
|
||||
encoding='utf8').stdout.strip()
|
||||
|
||||
timestamp = time.strftime('%Y-%m-%dT%H-%M-%S', time.gmtime())
|
||||
branch_name = f'example-config-test---{previous_branch}-{timestamp}'
|
||||
|
||||
try:
|
||||
shell(f'git checkout --orphan {branch_name}', check=True)
|
||||
|
||||
example_project = Path('example_root')
|
||||
generate_basic_project(example_project)
|
||||
|
||||
for service in services:
|
||||
src_config_file = Path(service.src_config_path)
|
||||
dst_config_file = example_project / service.dst_config_path
|
||||
|
||||
dst_config_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
shutil.copyfile(src_config_file, dst_config_file)
|
||||
|
||||
run(['git', 'add', example_project], check=True)
|
||||
run(['git', 'commit', '-m', textwrap.dedent(f'''
|
||||
Test example minimal configs
|
||||
|
||||
Testing files: {[s.src_config_path for s in services]}
|
||||
Generated from branch: {previous_branch}
|
||||
Time: {timestamp}
|
||||
''')], check=True)
|
||||
shell(f'git subtree --prefix={example_project} push origin {branch_name}', check=True)
|
||||
|
||||
print('---')
|
||||
print()
|
||||
print('> **Examples test run**')
|
||||
print('> ')
|
||||
print(f'> Branch: [{branch_name}](https://github.com/joerick/cibuildwheel/tree/{branch_name})')
|
||||
print('> ')
|
||||
print('> | Service | Config | Status |')
|
||||
print('> |---|---|---|')
|
||||
for service in services:
|
||||
badge = service.badge_md.format(branch=branch_name, branch_escaped=quote(branch_name, safe=''))
|
||||
print(f'> | {service.name} | `{service.src_config_path}` | {badge} |')
|
||||
print('> ')
|
||||
print('> Generated by `bin/run_example_ci_config.py`')
|
||||
print()
|
||||
print('---')
|
||||
finally:
|
||||
# remove any local changes
|
||||
shutil.rmtree(example_project, ignore_errors=True)
|
||||
shell('git checkout -- .')
|
||||
shell(f'git checkout {previous_branch}', check=True)
|
||||
shell(f'git branch -D --force {branch_name}', check=True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
os.chdir(os.path.dirname(__file__))
|
||||
os.chdir('..')
|
||||
run_example_ci_configs(standalone_mode=True)
|
||||
@@ -1 +1 @@
|
||||
__version__ = '1.5.4'
|
||||
__version__ = '1.6.1'
|
||||
|
||||
@@ -27,12 +27,14 @@ class DockerContainer:
|
||||
bash_stdin: IO[bytes]
|
||||
bash_stdout: IO[bytes]
|
||||
|
||||
def __init__(self, docker_image: str, simulate_32_bit=False):
|
||||
def __init__(self, docker_image: str, simulate_32_bit: bool = False, cwd: Optional[Union[str, PathLike]] = None):
|
||||
self.docker_image = docker_image
|
||||
self.simulate_32_bit = simulate_32_bit
|
||||
self.cwd = cwd
|
||||
|
||||
def __enter__(self) -> 'DockerContainer':
|
||||
self.name = f'cibuildwheel-{uuid.uuid4()}'
|
||||
cwd_args = ['-w', str(self.cwd)] if self.cwd else []
|
||||
shell_args = ['linux32', '/bin/bash'] if self.simulate_32_bit else ['/bin/bash']
|
||||
subprocess.run(
|
||||
[
|
||||
@@ -41,6 +43,7 @@ class DockerContainer:
|
||||
'--name', self.name,
|
||||
'-i',
|
||||
'-v', '/:/host', # ignored on CircleCI
|
||||
*cwd_args,
|
||||
self.docker_image,
|
||||
*shell_args
|
||||
],
|
||||
@@ -114,11 +117,12 @@ class DockerContainer:
|
||||
|
||||
return [PurePath(p) for p in path_strs]
|
||||
|
||||
def call(self, args: Sequence[Union[str, PathLike]], env: Dict[str, str] = {},
|
||||
def call(self, args: Sequence[Union[str, PathLike]], env: Optional[Dict[str, str]] = None,
|
||||
capture_output=False, cwd: Optional[Union[str, PathLike]] = None) -> str:
|
||||
|
||||
chdir = f'cd {cwd}' if cwd else ''
|
||||
env_assignments = ' '.join(f'{shlex.quote(k)}={shlex.quote(v)}'
|
||||
for k, v in env.items())
|
||||
for k, v in env.items()) if env is not None else ''
|
||||
command = ' '.join(shlex.quote(str(a)) for a in args)
|
||||
end_of_message = str(uuid.uuid4())
|
||||
|
||||
@@ -182,7 +186,7 @@ class DockerContainer:
|
||||
|
||||
def environment_executor(self, command: List[str], environment: Dict[str, str]) -> str:
|
||||
# used as an EnvironmentExecutor to evaluate commands and capture output
|
||||
return self.call(command, env=environment)
|
||||
return self.call(command, env=environment, capture_output=True)
|
||||
|
||||
|
||||
def shell_quote(path: PurePath) -> str:
|
||||
|
||||
+23
-14
@@ -7,7 +7,7 @@ from pathlib import Path, PurePath
|
||||
from typing import List, NamedTuple, Union
|
||||
|
||||
from .docker_container import DockerContainer
|
||||
from .util import (BuildOptions, BuildSelector,
|
||||
from .util import (BuildOptions, BuildSelector, NonPlatformWheelError,
|
||||
get_build_verbosity_extra_flags, prepare_command)
|
||||
|
||||
|
||||
@@ -50,26 +50,31 @@ def get_python_configurations(build_selector: BuildSelector) -> List[PythonConfi
|
||||
PythonConfiguration(version='3.6', identifier='cp36-manylinux_x86_64', path_str='/opt/python/cp36-cp36m'),
|
||||
PythonConfiguration(version='3.7', identifier='cp37-manylinux_x86_64', path_str='/opt/python/cp37-cp37m'),
|
||||
PythonConfiguration(version='3.8', identifier='cp38-manylinux_x86_64', path_str='/opt/python/cp38-cp38'),
|
||||
PythonConfiguration(version='3.9', identifier='cp39-manylinux_x86_64', path_str='/opt/python/cp39-cp39'),
|
||||
PythonConfiguration(version='2.7', identifier='cp27-manylinux_i686', path_str='/opt/python/cp27-cp27m'),
|
||||
PythonConfiguration(version='2.7', identifier='cp27-manylinux_i686', path_str='/opt/python/cp27-cp27mu'),
|
||||
PythonConfiguration(version='3.5', identifier='cp35-manylinux_i686', path_str='/opt/python/cp35-cp35m'),
|
||||
PythonConfiguration(version='3.6', identifier='cp36-manylinux_i686', path_str='/opt/python/cp36-cp36m'),
|
||||
PythonConfiguration(version='3.7', identifier='cp37-manylinux_i686', path_str='/opt/python/cp37-cp37m'),
|
||||
PythonConfiguration(version='3.8', identifier='cp38-manylinux_i686', path_str='/opt/python/cp38-cp38'),
|
||||
PythonConfiguration(version='3.9', identifier='cp39-manylinux_i686', path_str='/opt/python/cp39-cp39'),
|
||||
PythonConfiguration(version='2.7', identifier='pp27-manylinux_x86_64', path_str='/opt/python/pp27-pypy_73'),
|
||||
PythonConfiguration(version='3.6', identifier='pp36-manylinux_x86_64', path_str='/opt/python/pp36-pypy36_pp73'),
|
||||
PythonConfiguration(version='3.5', identifier='cp35-manylinux_aarch64', path_str='/opt/python/cp35-cp35m'),
|
||||
PythonConfiguration(version='3.6', identifier='cp36-manylinux_aarch64', path_str='/opt/python/cp36-cp36m'),
|
||||
PythonConfiguration(version='3.7', identifier='cp37-manylinux_aarch64', path_str='/opt/python/cp37-cp37m'),
|
||||
PythonConfiguration(version='3.8', identifier='cp38-manylinux_aarch64', path_str='/opt/python/cp38-cp38'),
|
||||
PythonConfiguration(version='3.9', identifier='cp39-manylinux_aarch64', path_str='/opt/python/cp39-cp39'),
|
||||
PythonConfiguration(version='3.5', identifier='cp35-manylinux_ppc64le', path_str='/opt/python/cp35-cp35m'),
|
||||
PythonConfiguration(version='3.6', identifier='cp36-manylinux_ppc64le', path_str='/opt/python/cp36-cp36m'),
|
||||
PythonConfiguration(version='3.7', identifier='cp37-manylinux_ppc64le', path_str='/opt/python/cp37-cp37m'),
|
||||
PythonConfiguration(version='3.8', identifier='cp38-manylinux_ppc64le', path_str='/opt/python/cp38-cp38'),
|
||||
PythonConfiguration(version='3.9', identifier='cp39-manylinux_ppc64le', path_str='/opt/python/cp39-cp39'),
|
||||
PythonConfiguration(version='3.5', identifier='cp35-manylinux_s390x', path_str='/opt/python/cp35-cp35m'),
|
||||
PythonConfiguration(version='3.6', identifier='cp36-manylinux_s390x', path_str='/opt/python/cp36-cp36m'),
|
||||
PythonConfiguration(version='3.7', identifier='cp37-manylinux_s390x', path_str='/opt/python/cp37-cp37m'),
|
||||
PythonConfiguration(version='3.8', identifier='cp38-manylinux_s390x', path_str='/opt/python/cp38-cp38'),
|
||||
PythonConfiguration(version='3.9', identifier='cp39-manylinux_s390x', path_str='/opt/python/cp39-cp39'),
|
||||
]
|
||||
# skip builds as required
|
||||
return [c for c in python_configurations if matches_platform(c.identifier) and build_selector(c.identifier)]
|
||||
@@ -101,7 +106,8 @@ def build(options: BuildOptions) -> None:
|
||||
if cwd != abs_package_dir and cwd not in abs_package_dir.parents:
|
||||
raise Exception('package_dir must be inside the working directory')
|
||||
|
||||
container_package_dir = PurePath('/project') / abs_package_dir.relative_to(cwd)
|
||||
container_project_path = PurePath('/project')
|
||||
container_package_dir = container_project_path / abs_package_dir.relative_to(cwd)
|
||||
container_output_dir = PurePath('/output')
|
||||
|
||||
for implementation, platform_tag, docker_image in platforms:
|
||||
@@ -110,15 +116,15 @@ def build(options: BuildOptions) -> None:
|
||||
continue
|
||||
|
||||
try:
|
||||
with DockerContainer(docker_image, simulate_32_bit=platform_tag.endswith('i686')) as docker:
|
||||
docker.copy_into(Path.cwd(), Path('/project'))
|
||||
with DockerContainer(docker_image, simulate_32_bit=platform_tag.endswith('i686'), cwd=container_project_path) as docker:
|
||||
docker.copy_into(Path.cwd(), container_project_path)
|
||||
|
||||
if options.before_all:
|
||||
env = docker.get_environment()
|
||||
env['PATH'] = f'/opt/python/cp38-cp38:{env["PATH"]}'
|
||||
env = options.environment.as_dictionary(env, executor=docker.environment_executor)
|
||||
|
||||
before_all_prepared = prepare_command(options.before_all, project='/project', package=container_package_dir)
|
||||
before_all_prepared = prepare_command(options.before_all, project=container_project_path, package=container_package_dir)
|
||||
docker.call(['sh', '-c', before_all_prepared], env=env)
|
||||
|
||||
for config in platform_configs:
|
||||
@@ -151,7 +157,7 @@ def build(options: BuildOptions) -> None:
|
||||
exit(1)
|
||||
|
||||
if options.before_build:
|
||||
before_build_prepared = prepare_command(options.before_build, project='/project', package=container_package_dir)
|
||||
before_build_prepared = prepare_command(options.before_build, project=container_project_path, package=container_package_dir)
|
||||
docker.call(['sh', '-c', before_build_prepared], env=env)
|
||||
|
||||
temp_dir = PurePath('/tmp/cibuildwheel')
|
||||
@@ -173,11 +179,14 @@ def build(options: BuildOptions) -> None:
|
||||
docker.call(['rm', '-rf', repaired_wheel_dir])
|
||||
docker.call(['mkdir', '-p', repaired_wheel_dir])
|
||||
|
||||
if built_wheel.name.endswith('none-any.whl') or not options.repair_command:
|
||||
docker.call(['mv', built_wheel, repaired_wheel_dir])
|
||||
else:
|
||||
if built_wheel.name.endswith('none-any.whl'):
|
||||
raise NonPlatformWheelError()
|
||||
|
||||
if options.repair_command:
|
||||
repair_command_prepared = prepare_command(options.repair_command, wheel=built_wheel, dest_dir=repaired_wheel_dir)
|
||||
docker.call(['sh', '-c', repair_command_prepared], env=env)
|
||||
else:
|
||||
docker.call(['mv', built_wheel, repaired_wheel_dir])
|
||||
|
||||
repaired_wheels = docker.glob(repaired_wheel_dir, '*.whl')
|
||||
|
||||
@@ -193,7 +202,7 @@ def build(options: BuildOptions) -> None:
|
||||
virtualenv_env['PATH'] = f"{venv_dir / 'bin'}:{virtualenv_env['PATH']}"
|
||||
|
||||
if options.before_test:
|
||||
before_test_prepared = prepare_command(options.before_test, project='/project', package=container_package_dir)
|
||||
before_test_prepared = prepare_command(options.before_test, project=container_project_path, package=container_package_dir)
|
||||
docker.call(['sh', '-c', before_test_prepared], env=virtualenv_env)
|
||||
|
||||
# Install the wheel we just built
|
||||
@@ -210,7 +219,7 @@ def build(options: BuildOptions) -> None:
|
||||
docker.call(['pip', 'install', *options.test_requires], env=virtualenv_env)
|
||||
|
||||
# Run the tests from a different directory
|
||||
test_command_prepared = prepare_command(options.test_command, project='/project', package=container_package_dir)
|
||||
test_command_prepared = prepare_command(options.test_command, project=container_project_path, package=container_package_dir)
|
||||
docker.call(['sh', '-c', test_command_prepared], cwd='/root', env=virtualenv_env)
|
||||
|
||||
# clean up test environment
|
||||
@@ -229,8 +238,8 @@ def build(options: BuildOptions) -> None:
|
||||
|
||||
|
||||
def troubleshoot(package_dir: Path, error: Exception) -> None:
|
||||
if (isinstance(error, subprocess.CalledProcessError) and 'exec' in error.cmd):
|
||||
# the bash script failed
|
||||
if (isinstance(error, subprocess.CalledProcessError) and error.cmd[0:2] == ['pip', 'wheel']):
|
||||
# the 'pip wheel' step failed.
|
||||
print('Checking for common errors...')
|
||||
so_files = list(package_dir.glob('**/*.so'))
|
||||
|
||||
@@ -243,7 +252,7 @@ def troubleshoot(package_dir: Path, error: Exception) -> None:
|
||||
|
||||
If you're using Cython and have previously done an in-place build,
|
||||
remove those build files (*.so and *.c) before starting cibuildwheel.
|
||||
'''))
|
||||
'''), file=sys.stderr)
|
||||
|
||||
print(' Files detected:')
|
||||
print('\n'.join([f' {f}' for f in so_files]))
|
||||
|
||||
+10
-5
@@ -9,7 +9,7 @@ from pathlib import Path
|
||||
from typing import Dict, List, NamedTuple, Optional, Sequence, Union
|
||||
|
||||
from .environment import ParsedEnvironment
|
||||
from .util import (BuildOptions, BuildSelector, download,
|
||||
from .util import (BuildOptions, BuildSelector, NonPlatformWheelError, download,
|
||||
get_build_verbosity_extra_flags, get_pip_script,
|
||||
prepare_command)
|
||||
|
||||
@@ -38,6 +38,7 @@ def get_python_configurations(build_selector: BuildSelector) -> List[PythonConfi
|
||||
PythonConfiguration(version='3.6', identifier='cp36-macosx_x86_64', url='https://www.python.org/ftp/python/3.6.8/python-3.6.8-macosx10.9.pkg'),
|
||||
PythonConfiguration(version='3.7', identifier='cp37-macosx_x86_64', url='https://www.python.org/ftp/python/3.7.8/python-3.7.8-macosx10.9.pkg'),
|
||||
PythonConfiguration(version='3.8', identifier='cp38-macosx_x86_64', url='https://www.python.org/ftp/python/3.8.4/python-3.8.4-macosx10.9.pkg'),
|
||||
PythonConfiguration(version='3.9', identifier='cp39-macosx_x86_64', url='https://www.python.org/ftp/python/3.9.0/python-3.9.0rc1-macosx10.9.pkg'),
|
||||
# PyPy
|
||||
PythonConfiguration(version='2.7', identifier='pp27-macosx_x86_64', url='https://downloads.python.org/pypy/pypy2.7-v7.3.1-osx64.tar.bz2'),
|
||||
PythonConfiguration(version='3.6', identifier='pp36-macosx_x86_64', url='https://downloads.python.org/pypy/pypy3.6-v7.3.1-osx64.tar.bz2'),
|
||||
@@ -215,12 +216,16 @@ def build(options: BuildOptions) -> None:
|
||||
if repaired_wheel_dir.exists():
|
||||
shutil.rmtree(repaired_wheel_dir)
|
||||
repaired_wheel_dir.mkdir(parents=True)
|
||||
if built_wheel.name.endswith('none-any.whl') or not options.repair_command:
|
||||
# pure Python wheel or empty repair command
|
||||
shutil.move(str(built_wheel), repaired_wheel_dir)
|
||||
else:
|
||||
|
||||
if built_wheel.name.endswith('none-any.whl'):
|
||||
raise NonPlatformWheelError()
|
||||
|
||||
if options.repair_command:
|
||||
repair_command_prepared = prepare_command(options.repair_command, wheel=built_wheel, dest_dir=repaired_wheel_dir)
|
||||
call(repair_command_prepared, env=env, shell=True)
|
||||
else:
|
||||
shutil.move(str(built_wheel), repaired_wheel_dir)
|
||||
|
||||
repaired_wheel = next(repaired_wheel_dir.glob('*.whl'))
|
||||
|
||||
if options.test_command:
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
#
|
||||
appdirs==1.4.4 # via virtualenv
|
||||
configparser==4.0.2 # via importlib-metadata
|
||||
contextlib2==0.6.0.post1 # via importlib-metadata, importlib-resources, virtualenv
|
||||
delocate==0.8.0 # via -r cibuildwheel/resources/constraints.in
|
||||
distlib==0.3.0 # via virtualenv
|
||||
contextlib2==0.6.0.post1 # via importlib-metadata, importlib-resources
|
||||
delocate==0.8.2 # via -r cibuildwheel/resources/constraints.in
|
||||
distlib==0.3.1 # via virtualenv
|
||||
filelock==3.0.12 # via virtualenv
|
||||
importlib-metadata==1.6.0 # via importlib-resources, virtualenv
|
||||
importlib-resources==1.5.0 # via virtualenv
|
||||
importlib-metadata==1.7.0 # via virtualenv
|
||||
importlib-resources==3.0.0 # via virtualenv
|
||||
pathlib2==2.3.5 # via importlib-metadata, importlib-resources, virtualenv
|
||||
scandir==1.10.0 # via pathlib2
|
||||
singledispatch==3.4.0.3 # via importlib-resources
|
||||
six==1.15.0 # via pathlib2, virtualenv
|
||||
typing==3.7.4.1 # via importlib-resources
|
||||
virtualenv==20.0.21 # via -r cibuildwheel/resources/constraints.in
|
||||
wheel==0.34.2 # via -r cibuildwheel/resources/constraints.in, delocate
|
||||
typing==3.7.4.3 # via importlib-resources
|
||||
virtualenv==20.0.31 # via -r cibuildwheel/resources/constraints.in
|
||||
wheel==0.35.1 # via -r cibuildwheel/resources/constraints.in, delocate
|
||||
zipp==1.2.0 # via importlib-metadata, importlib-resources
|
||||
|
||||
# The following packages are considered to be unsafe in a requirements file:
|
||||
pip==20.1.1 # via -r cibuildwheel/resources/constraints.in
|
||||
setuptools==44.1.0 # via -r cibuildwheel/resources/constraints.in
|
||||
pip==20.2.2 # via -r cibuildwheel/resources/constraints.in
|
||||
setuptools==44.1.1 # via -r cibuildwheel/resources/constraints.in
|
||||
|
||||
@@ -5,16 +5,16 @@
|
||||
# bin/update_constraints.py
|
||||
#
|
||||
appdirs==1.4.4 # via virtualenv
|
||||
delocate==0.8.0 # via -r cibuildwheel/resources/constraints.in
|
||||
distlib==0.3.0 # via virtualenv
|
||||
delocate==0.8.2 # via -r cibuildwheel/resources/constraints.in
|
||||
distlib==0.3.1 # via virtualenv
|
||||
filelock==3.0.12 # via virtualenv
|
||||
importlib-metadata==1.6.0 # via importlib-resources, virtualenv
|
||||
importlib-resources==1.5.0 # via virtualenv
|
||||
importlib-metadata==1.7.0 # via virtualenv
|
||||
importlib-resources==3.0.0 # via virtualenv
|
||||
six==1.15.0 # via virtualenv
|
||||
virtualenv==20.0.21 # via -r cibuildwheel/resources/constraints.in
|
||||
wheel==0.34.2 # via -r cibuildwheel/resources/constraints.in, delocate
|
||||
virtualenv==20.0.31 # via -r cibuildwheel/resources/constraints.in
|
||||
wheel==0.35.1 # via -r cibuildwheel/resources/constraints.in, delocate
|
||||
zipp==1.2.0 # via importlib-metadata, importlib-resources
|
||||
|
||||
# The following packages are considered to be unsafe in a requirements file:
|
||||
pip==20.1.1 # via -r cibuildwheel/resources/constraints.in
|
||||
setuptools==46.4.0 # via -r cibuildwheel/resources/constraints.in
|
||||
pip==20.2.2 # via -r cibuildwheel/resources/constraints.in
|
||||
setuptools==50.3.0 # via -r cibuildwheel/resources/constraints.in
|
||||
|
||||
@@ -5,16 +5,16 @@
|
||||
# bin/update_constraints.py
|
||||
#
|
||||
appdirs==1.4.4 # via virtualenv
|
||||
delocate==0.8.0 # via -r cibuildwheel/resources/constraints.in
|
||||
distlib==0.3.0 # via virtualenv
|
||||
delocate==0.8.2 # via -r cibuildwheel/resources/constraints.in
|
||||
distlib==0.3.1 # via virtualenv
|
||||
filelock==3.0.12 # via virtualenv
|
||||
importlib-metadata==1.6.0 # via importlib-resources, virtualenv
|
||||
importlib-resources==1.5.0 # via virtualenv
|
||||
importlib-metadata==1.7.0 # via virtualenv
|
||||
importlib-resources==3.0.0 # via virtualenv
|
||||
six==1.15.0 # via virtualenv
|
||||
virtualenv==20.0.21 # via -r cibuildwheel/resources/constraints.in
|
||||
wheel==0.34.2 # via -r cibuildwheel/resources/constraints.in, delocate
|
||||
virtualenv==20.0.31 # via -r cibuildwheel/resources/constraints.in
|
||||
wheel==0.35.1 # via -r cibuildwheel/resources/constraints.in, delocate
|
||||
zipp==3.1.0 # via importlib-metadata, importlib-resources
|
||||
|
||||
# The following packages are considered to be unsafe in a requirements file:
|
||||
pip==20.1.1 # via -r cibuildwheel/resources/constraints.in
|
||||
setuptools==46.4.0 # via -r cibuildwheel/resources/constraints.in
|
||||
pip==20.2.2 # via -r cibuildwheel/resources/constraints.in
|
||||
setuptools==50.3.0 # via -r cibuildwheel/resources/constraints.in
|
||||
|
||||
@@ -5,15 +5,15 @@
|
||||
# bin/update_constraints.py
|
||||
#
|
||||
appdirs==1.4.4 # via virtualenv
|
||||
delocate==0.8.0 # via -r cibuildwheel/resources/constraints.in
|
||||
distlib==0.3.0 # via virtualenv
|
||||
delocate==0.8.2 # via -r cibuildwheel/resources/constraints.in
|
||||
distlib==0.3.1 # via virtualenv
|
||||
filelock==3.0.12 # via virtualenv
|
||||
importlib-metadata==1.6.0 # via virtualenv
|
||||
importlib-metadata==1.7.0 # via virtualenv
|
||||
six==1.15.0 # via virtualenv
|
||||
virtualenv==20.0.21 # via -r cibuildwheel/resources/constraints.in
|
||||
wheel==0.34.2 # via -r cibuildwheel/resources/constraints.in, delocate
|
||||
virtualenv==20.0.31 # via -r cibuildwheel/resources/constraints.in
|
||||
wheel==0.35.1 # via -r cibuildwheel/resources/constraints.in, delocate
|
||||
zipp==3.1.0 # via importlib-metadata
|
||||
|
||||
# The following packages are considered to be unsafe in a requirements file:
|
||||
pip==20.1.1 # via -r cibuildwheel/resources/constraints.in
|
||||
setuptools==46.4.0 # via -r cibuildwheel/resources/constraints.in
|
||||
pip==20.2.2 # via -r cibuildwheel/resources/constraints.in
|
||||
setuptools==50.3.0 # via -r cibuildwheel/resources/constraints.in
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
[x86_64]
|
||||
manylinux1 = quay.io/pypa/manylinux1_x86_64:2020-05-25-b56702d
|
||||
manylinux2010 = quay.io/pypa/manylinux2010_x86_64:2020-05-20-c7bbd11
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2020-05-17-2f8ac3b
|
||||
manylinux1 = quay.io/pypa/manylinux1_x86_64:2020-09-20-9444d5c
|
||||
manylinux2010 = quay.io/pypa/manylinux2010_x86_64:2020-09-20-6131e60
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2020-09-20-fb9af88
|
||||
|
||||
[i686]
|
||||
manylinux1 = quay.io/pypa/manylinux1_i686:2020-05-25-b56702d
|
||||
manylinux2010 = quay.io/pypa/manylinux2010_i686:2020-05-20-c7bbd11
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_i686:2020-05-17-2f8ac3b
|
||||
manylinux1 = quay.io/pypa/manylinux1_i686:2020-09-20-9444d5c
|
||||
manylinux2010 = quay.io/pypa/manylinux2010_i686:2020-09-20-6131e60
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_i686:2020-09-20-fb9af88
|
||||
|
||||
[pypy_x86_64]
|
||||
manylinux2010 = pypywheels/manylinux2010-pypy_x86_64:2020-04-25-eb2cdff
|
||||
manylinux2010 = pypywheels/manylinux2010-pypy_x86_64:2020-07-02-fd8c128
|
||||
|
||||
[aarch64]
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2020-05-17-2f8ac3b
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2020-09-20-fb9af88
|
||||
|
||||
[ppc64le]
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2020-05-17-2f8ac3b
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2020-09-20-fb9af88
|
||||
|
||||
[s390x]
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_s390x:2020-05-17-2f8ac3b
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_s390x:2020-09-20-fb9af88
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import os
|
||||
import textwrap
|
||||
import urllib.request
|
||||
from fnmatch import fnmatch
|
||||
from pathlib import Path
|
||||
@@ -126,3 +127,18 @@ class BuildOptions(NamedTuple):
|
||||
|
||||
resources_dir = Path(__file__).resolve().parent / 'resources'
|
||||
get_pip_script = resources_dir / 'get-pip.py'
|
||||
|
||||
|
||||
class NonPlatformWheelError(Exception):
|
||||
def __init__(self) -> None:
|
||||
message = textwrap.dedent('''
|
||||
cibuildwheel: Build failed because a pure Python wheel was generated.
|
||||
|
||||
If you intend to build a pure-Python wheel, you don't need cibuildwheel - use
|
||||
`pip wheel -w DEST_DIR .` instead.
|
||||
|
||||
If you expected a platform wheel, check your project configuration, or run
|
||||
cibuildwheel with CIBW_BUILD_VERBOSITY=1 to view build logs.
|
||||
''')
|
||||
|
||||
super().__init__(message)
|
||||
|
||||
+18
-6
@@ -10,7 +10,7 @@ from zipfile import ZipFile
|
||||
import toml
|
||||
|
||||
from .environment import ParsedEnvironment
|
||||
from .util import (BuildOptions, BuildSelector, download,
|
||||
from .util import (BuildOptions, BuildSelector, NonPlatformWheelError, download,
|
||||
get_build_verbosity_extra_flags, get_pip_script,
|
||||
prepare_command)
|
||||
|
||||
@@ -58,6 +58,8 @@ def get_python_configurations(build_selector: BuildSelector) -> List[PythonConfi
|
||||
PythonConfiguration(version='3.7.8', arch='64', identifier='cp37-win_amd64', url=None),
|
||||
PythonConfiguration(version='3.8.4', arch='32', identifier='cp38-win32', url=None),
|
||||
PythonConfiguration(version='3.8.4', arch='64', identifier='cp38-win_amd64', url=None),
|
||||
PythonConfiguration(version='3.9.0-rc1', arch='32', identifier='cp39-win32', url=None),
|
||||
PythonConfiguration(version='3.9.0-rc1', arch='64', identifier='cp39-win_amd64', url=None),
|
||||
# PyPy
|
||||
PythonConfiguration(version='2.7', arch='32', identifier='pp27-win32', url='https://downloads.python.org/pypy/pypy2.7-v7.3.1-win32.zip'),
|
||||
PythonConfiguration(version='3.6', arch='32', identifier='pp36-win32', url='https://downloads.python.org/pypy/pypy3.6-v7.3.1-win32.zip'),
|
||||
@@ -177,8 +179,14 @@ def pep_518_cp35_workaround(package_dir: Path, env: Dict[str, str]) -> None:
|
||||
if 'build-system' in data
|
||||
else []
|
||||
)
|
||||
|
||||
if requirements:
|
||||
shell(['pip', 'install'] + requirements, env=env)
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
reqfile = Path(d) / "requirements.txt"
|
||||
with reqfile.open("w") as f:
|
||||
for r in requirements:
|
||||
print(r, file=f)
|
||||
call(['pip', 'install', '-r', reqfile], env=env)
|
||||
|
||||
|
||||
def build(options: BuildOptions) -> None:
|
||||
@@ -236,12 +244,16 @@ def build(options: BuildOptions) -> None:
|
||||
if repaired_wheel_dir.exists():
|
||||
shutil.rmtree(repaired_wheel_dir)
|
||||
repaired_wheel_dir.mkdir(parents=True)
|
||||
if built_wheel.name.endswith('none-any.whl') or not options.repair_command:
|
||||
# pure Python wheel or empty repair command
|
||||
shutil.move(str(built_wheel), repaired_wheel_dir)
|
||||
else:
|
||||
|
||||
if built_wheel.name.endswith('none-any.whl'):
|
||||
raise NonPlatformWheelError()
|
||||
|
||||
if options.repair_command:
|
||||
repair_command_prepared = prepare_command(options.repair_command, wheel=built_wheel, dest_dir=repaired_wheel_dir)
|
||||
shell(repair_command_prepared, env=env)
|
||||
else:
|
||||
shutil.move(str(built_wheel), repaired_wheel_dir)
|
||||
|
||||
repaired_wheel = next(repaired_wheel_dir.glob('*.whl'))
|
||||
|
||||
if options.test_command:
|
||||
|
||||
@@ -28,3 +28,39 @@ cibuildwheel doesn't really do anything itself - it's always deferring to other
|
||||
We're not responsible for errors in those tools, for fixing errors/crashes there. But cibuildwheel's job is providing users with an 'integrated' user experience across those tools. We provide an abstraction. The user says 'build me some wheels', not 'open the docker container, build a wheel with pip, fix up the symbols with auditwheel' etc. However, errors have a habit of breaking abstractions. And this is where users get confused, because the mechanism of cibuildwheel is laid bare, and they must understand a little bit how it works to debug.
|
||||
|
||||
So, if we can, I'd like to improve the experience on errors as well. In [this](https://github.com/joerick/cibuildwheel/issues/139) case, it takes a bit of knowledge to understand that the linux builds are happening in a totally different OS via docker, that the linked symbols won't match, that auditwheel will fail because of this. A problem with how the tools fit together, instead of the tools themselves.
|
||||
|
||||
Maintainer notes
|
||||
----------------
|
||||
|
||||
## Testing minimal configs
|
||||
|
||||
cibuildwheel's _minimal_ example configs can be tested on a simple project on cibuildwheel's existing CI. These should be run whenever the minimal configs change.
|
||||
|
||||
To test minimal configs, make sure you have a clean git repo, then run the script:
|
||||
|
||||
bin/run_example_ci_configs.py
|
||||
|
||||
The script will create an isolated 'orphan' commit containing all the minimal config CI files, and a simple C extension project, and push that to a branch on the `origin` repo. The project's CI is already set up to run on branch push, so will begin testing.
|
||||
|
||||
The script then outputs a Markdown table that can be copy/pasted into a PR to monitor and record the test.
|
||||
|
||||
## Making a release
|
||||
|
||||
Before making a release, ensure pinned dependencies are up-to-date. Run the script:
|
||||
|
||||
bin/make_dependency_update_pr.py
|
||||
|
||||
If updates are needed, this will push a PR with those updates for the CI to test. Once green, merge this PR.
|
||||
|
||||
Then, increment the project version number using:
|
||||
|
||||
bin/bump_version.py
|
||||
|
||||
You'll be prompted to enter the new version number. Update the changelog when prompted. The script will create a 'bump version' commit and version tag.
|
||||
|
||||
Finally, cut the release and upload to PyPI/Github.
|
||||
|
||||
rm -rf dist
|
||||
python setup.py sdist bdist_wheel
|
||||
twine upload dist/*
|
||||
git push && git push --tags
|
||||
|
||||
@@ -9,14 +9,14 @@ After you've built your wheels, you'll probably want to deliver them to PyPI.
|
||||
On your development machine, do the following...
|
||||
|
||||
```bash
|
||||
# Clear out your 'dist' folder.
|
||||
# Clear out your 'dist' folder.
|
||||
rm -rf dist
|
||||
# Make a source distribution
|
||||
python setup.py sdist
|
||||
|
||||
# 🏃🏻
|
||||
# Go and download your wheel files from wherever you put them. e.g. your CI
|
||||
# provider can be configured to store them for you. Put them all into the
|
||||
# provider can be configured to store them for you. Put them all into the
|
||||
# 'dist' folder.
|
||||
|
||||
# Upload using 'twine' (you may need to 'pip install twine')
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ h1, h2, h3, h4, h5, h6 {
|
||||
background-color: #eff1f3;
|
||||
font-size: 85%;
|
||||
font-weight: bold;
|
||||
|
||||
|
||||
border-top-left-radius: 3px;
|
||||
border-top-right-radius: 3px;
|
||||
|
||||
|
||||
+20
@@ -61,3 +61,23 @@ python3 -m cibuildwheel --output-dir wheelhouse
|
||||
python3 -m pip install twine
|
||||
python3 -m twine upload wheelhouse/*.whl
|
||||
```
|
||||
|
||||
### 'ImportError: DLL load failed: The specific module could not be found' error on Windows
|
||||
|
||||
Visual Studio and MSVC link the compiled binary wheels to the Microsoft Visual C++ Runtime. Normally, these are included with Python, but when compiling with a newer version of Visual Studio, it is possible users will run into problems on systems that do not have these runtime libraries installed. The solution is to ask users to download the corresponding Visual C++ Redistributable from the [Microsoft website](https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads) and install it. Since a Python installation normally includes these VC++ Redistributable files for [the version of the MSVC compiler used to compile Python](https://wiki.python.org/moin/WindowsCompilers), this is typically only a problem when compiling a Python 2.7 C extension with a newer compiler, e.g. to support a modern C++ standard (see [the section on modern C++ standards for Python 2.7](cpp_standards.md#windows-and-python-27) for more details).
|
||||
|
||||
Additionally, Visual Studio 2019 started linking to an even newer DLL, `VCRUNTIME140_1.dll`, besides the `VCRUNTIME140.dll` that is included with recent Python versions (starting from Python 3.5; see [here](https://wiki.python.org/moin/WindowsCompilers) for more details on the corresponding Visual Studio & MSVC versions used to compile the different Python versions). To avoid this extra dependency on `VCRUNTIME140_1.dll`, the [`/d2FH4-` flag](https://devblogs.microsoft.com/cppblog/making-cpp-exception-handling-smaller-x64/) can be added to the MSVC invocations (check out [this issue](https://github.com/joerick/cibuildwheel/issues/423) for details and references).
|
||||
|
||||
To add the `/d2FH4-` flag to a standard `setup.py` using `setuptools`, the `extra_compile_args` option can be used:
|
||||
|
||||
```python
|
||||
ext_modules=[
|
||||
Extension(
|
||||
'c_module',
|
||||
sources=['extension.c'],
|
||||
extra_compile_args=['/d2FH4-'] if sys.platform == 'win32' else []
|
||||
)
|
||||
],
|
||||
```
|
||||
|
||||
To investigate the dependencies of a C extension (i.e., the `.pyd` file, a DLL in disguise) on Windows, [Dependency Walker](http://www.dependencywalker.com/) is a great tool.
|
||||
|
||||
+2
-2
@@ -2,9 +2,9 @@
|
||||
title: Home
|
||||
---
|
||||
|
||||
{%
|
||||
{%
|
||||
includemarkdown "../README.md"
|
||||
start="<!--intro-start-->"
|
||||
start="<!--intro-start-->"
|
||||
end="<!--intro-end-->"
|
||||
%}
|
||||
|
||||
|
||||
+14
-1
@@ -48,7 +48,7 @@ Commit this file, enable building of your repo on Travis CI, and push.
|
||||
|
||||
Then setup a deployment method by following the [Travis CI deployment docs](https://docs.travis-ci.com/user/deployment/), or see [Delivering to PyPI](deliver-to-pypi.md). For more info on `.travis.yml`, check out the [docs](https://docs.travis-ci.com/).
|
||||
|
||||
[`examples/travis-deploy.yml`](https://github.com/joerick/cibuildwheel/blob/master/examples/travis-deploy.yml) extends this minimal example with a demonstration of how to automatically upload the built wheels to PyPI.
|
||||
[`examples/travis-ci-deploy.yml`](https://github.com/joerick/cibuildwheel/blob/master/examples/travis-ci-deploy.yml) extends this minimal example with a demonstration of how to automatically upload the built wheels to PyPI.
|
||||
|
||||
# CircleCI [linux/mac] {: #circleci}
|
||||
|
||||
@@ -66,6 +66,19 @@ Commit this file, enable building of your repo on CircleCI, and push.
|
||||
|
||||
CircleCI will store the built wheels for you - you can access them from the project console. Check out the CircleCI [docs](https://circleci.com/docs/2.0/configuration-reference/#section=configuration) for more info on this config file.
|
||||
|
||||
# Gitlab CI [linux] {: #gitlab-ci}
|
||||
|
||||
To build Linux wheels on Gitlab CI, create a `.gitlab-ci.yml` file in your repo,
|
||||
|
||||
> .gitlab-ci.yml
|
||||
```yaml
|
||||
{% include "../examples/gitlab-minimal.yml" %}
|
||||
```
|
||||
|
||||
Commit this file, and push to Gitlab. The pipeline should start automatically.
|
||||
|
||||
Gitlab will store the built wheels for you - you can access them from the Pipelines view. Check out the Gitlab [docs](https://docs.gitlab.com/ee/ci/yaml/) for more info on this config file.
|
||||
|
||||
# AppVeyor [linux/mac/windows] {: #appveyor}
|
||||
|
||||
To build Linux, Mac, and Windows wheels on AppVeyor, create an `appveyor.yml` file in your repo.
|
||||
|
||||
@@ -12,7 +12,7 @@ stack: python 3.7
|
||||
init:
|
||||
- cmd: set PATH=C:\Python37;C:\Python37\Scripts;%PATH%
|
||||
|
||||
install: python -m pip install cibuildwheel==1.5.4
|
||||
install: python -m pip install cibuildwheel==1.6.1
|
||||
|
||||
build_script: python -m cibuildwheel --output-dir wheelhouse
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ jobs:
|
||||
- task: UsePythonVersion@0
|
||||
- bash: |
|
||||
python3 -m pip install --upgrade pip
|
||||
pip3 install cibuildwheel==1.5.4
|
||||
pip3 install cibuildwheel==1.6.1
|
||||
cibuildwheel --output-dir wheelhouse .
|
||||
- task: PublishBuildArtifacts@1
|
||||
inputs: {pathtoPublish: 'wheelhouse'}
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
- task: UsePythonVersion@0
|
||||
- bash: |
|
||||
python3 -m pip install --upgrade pip
|
||||
pip3 install cibuildwheel==1.5.4
|
||||
pip3 install cibuildwheel==1.6.1
|
||||
cibuildwheel --output-dir wheelhouse .
|
||||
- task: PublishBuildArtifacts@1
|
||||
inputs: {pathtoPublish: 'wheelhouse'}
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
displayName: Install Visual C++ for Python 2.7
|
||||
- bash: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install cibuildwheel==1.5.4
|
||||
pip install cibuildwheel==1.6.1
|
||||
cibuildwheel --output-dir wheelhouse .
|
||||
- task: PublishBuildArtifacts@1
|
||||
inputs: {pathtoPublish: 'wheelhouse'}
|
||||
|
||||
@@ -11,7 +11,7 @@ jobs:
|
||||
- run:
|
||||
name: Build the Linux wheels.
|
||||
command: |
|
||||
pip3 install --user cibuildwheel==1.5.4
|
||||
pip3 install --user cibuildwheel==1.6.1
|
||||
cibuildwheel --output-dir wheelhouse
|
||||
- store_artifacts:
|
||||
path: wheelhouse/
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
- run:
|
||||
name: Build the OS X wheels.
|
||||
command: |
|
||||
pip3 install --user cibuildwheel==1.5.4
|
||||
pip3 install cibuildwheel==1.6.1
|
||||
cibuildwheel --output-dir wheelhouse
|
||||
- store_artifacts:
|
||||
path: wheelhouse/
|
||||
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
|
||||
- name: Install cibuildwheel
|
||||
run: |
|
||||
python -m pip install cibuildwheel==1.5.4
|
||||
python -m pip install cibuildwheel==1.6.1
|
||||
|
||||
- name: Install Visual C++ for Python 2.7
|
||||
if: runner.os == 'Windows'
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
|
||||
- name: Install cibuildwheel
|
||||
run: |
|
||||
python -m pip install cibuildwheel==1.5.4
|
||||
python -m pip install cibuildwheel==1.6.1
|
||||
|
||||
- name: Install Visual C++ for Python 2.7
|
||||
if: runner.os == 'Windows'
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
linux:
|
||||
image: python:3.8
|
||||
# make a docker daemon available for cibuildwheel to use
|
||||
services:
|
||||
- name: docker:dind
|
||||
entrypoint: ["env", "-u", "DOCKER_HOST"]
|
||||
command: ["dockerd-entrypoint.sh"]
|
||||
variables:
|
||||
DOCKER_HOST: tcp://docker:2375/
|
||||
DOCKER_DRIVER: overlay2
|
||||
# See https://github.com/docker-library/docker/pull/166
|
||||
DOCKER_TLS_CERTDIR: ""
|
||||
script:
|
||||
- curl -sSL https://get.docker.com/ | sh
|
||||
- python -m pip install cibuildwheel
|
||||
- cibuildwheel --output-dir wheelhouse
|
||||
artifacts:
|
||||
paths:
|
||||
- wheelhouse/
|
||||
@@ -25,7 +25,7 @@ env:
|
||||
# Note: TWINE_PASSWORD is set to a PyPI API token in Travis settings
|
||||
|
||||
install:
|
||||
- python3 -m pip install cibuildwheel==1.5.4
|
||||
- python3 -m pip install cibuildwheel==1.6.1
|
||||
|
||||
script:
|
||||
# build the wheels, put them into './wheelhouse'
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
- ln -s /c/Python38/python.exe /c/Python38/python3.exe
|
||||
|
||||
install:
|
||||
- python3 -m pip install cibuildwheel==1.5.4
|
||||
- python3 -m pip install cibuildwheel==1.6.1
|
||||
|
||||
script:
|
||||
# build the wheels, put them into './wheelhouse'
|
||||
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
- stage: deploy
|
||||
name: Build and deploy Linux wheels
|
||||
services: docker
|
||||
install: python3 -m pip install cibuildwheel==1.5.4
|
||||
install: python3 -m pip install cibuildwheel==1.6.1
|
||||
script: python3 -m cibuildwheel --output-dir wheelhouse
|
||||
after_success: |
|
||||
python3 -m pip install twine
|
||||
@@ -65,7 +65,7 @@ jobs:
|
||||
name: Build and deploy macOS wheels
|
||||
os: osx
|
||||
language: shell
|
||||
install: python3 -m pip install cibuildwheel==1.5.4
|
||||
install: python3 -m pip install cibuildwheel==1.6.1
|
||||
script: python3 -m cibuildwheel --output-dir wheelhouse
|
||||
after_success: |
|
||||
python3 -m pip install twine
|
||||
@@ -75,7 +75,7 @@ jobs:
|
||||
name: Build and deploy Windows wheels
|
||||
os: windows
|
||||
language: shell
|
||||
install: python3 -m pip install cibuildwheel==1.5.4
|
||||
install: python3 -m pip install cibuildwheel==1.6.1
|
||||
script: python3 -m cibuildwheel --output-dir wheelhouse
|
||||
after_success: |
|
||||
python3 -m pip install twine
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
[flake8]
|
||||
ignore = E501,W503,E741,E226
|
||||
ignore = E501,W503,E741,E226,B950
|
||||
select = C,E,F,W,B,B9
|
||||
application-import-names = cibuildwheel
|
||||
exclude =
|
||||
cibuildwheel/resources/,
|
||||
|
||||
@@ -11,7 +11,7 @@ long_description = (this_directory / 'README.md').read_text(encoding='utf-8')
|
||||
|
||||
setup(
|
||||
name='cibuildwheel',
|
||||
version='1.5.4',
|
||||
version='1.6.1',
|
||||
install_requires=['bashlex!=0.13', 'toml'],
|
||||
description="Build Python wheels on CI with minimal configuration.",
|
||||
long_description=long_description,
|
||||
@@ -19,6 +19,10 @@ setup(
|
||||
author="Joe Rickerby",
|
||||
author_email='joerick@mac.com',
|
||||
url='https://github.com/joerick/cibuildwheel',
|
||||
project_urls={
|
||||
'Changelog': 'https://github.com/joerick/cibuildwheel#changelog',
|
||||
'Documentation': 'https://cibuildwheel.readthedocs.io/',
|
||||
},
|
||||
packages=['cibuildwheel', ],
|
||||
license="BSD",
|
||||
zip_safe=False,
|
||||
|
||||
+28
-3
@@ -1,4 +1,5 @@
|
||||
import os
|
||||
import pytest
|
||||
import subprocess
|
||||
import textwrap
|
||||
|
||||
from . import utils
|
||||
@@ -21,7 +22,7 @@ def test(tmp_path):
|
||||
project_dir = tmp_path / 'project'
|
||||
project_with_before_build_asserts.generate(project_dir)
|
||||
|
||||
with open(os.path.join(project_dir, "text_info.txt"), mode='w') as ff:
|
||||
with (project_dir / 'text_info.txt').open(mode='w') as ff:
|
||||
print("dummy text", file=ff)
|
||||
|
||||
# build the wheels
|
||||
@@ -33,6 +34,30 @@ def test(tmp_path):
|
||||
})
|
||||
|
||||
# also check that we got the right wheels
|
||||
os.remove(os.path.join(project_dir, "text_info.txt"))
|
||||
(project_dir / 'text_info.txt').unlink()
|
||||
expected_wheels = utils.expected_wheels('spam', '0.1.0')
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
|
||||
def test_failing_command(tmp_path):
|
||||
project_dir = tmp_path / 'project'
|
||||
test_projects.new_c_project().generate(project_dir)
|
||||
|
||||
with pytest.raises(subprocess.CalledProcessError):
|
||||
utils.cibuildwheel_run(project_dir, add_env={
|
||||
'CIBW_BEFORE_ALL': 'false',
|
||||
'CIBW_BEFORE_ALL_WINDOWS': 'exit /b 1',
|
||||
})
|
||||
|
||||
|
||||
def test_cwd(tmp_path):
|
||||
project_dir = tmp_path / 'project'
|
||||
test_projects.new_c_project().generate(project_dir)
|
||||
|
||||
actual_wheels = utils.cibuildwheel_run(project_dir, add_env={
|
||||
'CIBW_BEFORE_ALL': f'''python -c "import os; assert os.getcwd() == {str(project_dir)!r}"''',
|
||||
'CIBW_BEFORE_ALL_LINUX': '''python -c "import os; assert os.getcwd() == '/project'"''',
|
||||
})
|
||||
|
||||
expected_wheels = utils.expected_wheels('spam', '0.1.0')
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import pytest
|
||||
import subprocess
|
||||
import textwrap
|
||||
|
||||
from . import utils
|
||||
@@ -32,14 +34,41 @@ def test(tmp_path):
|
||||
project_dir = tmp_path / 'project'
|
||||
project_with_before_build_asserts.generate(project_dir)
|
||||
|
||||
before_build = ('''python -c "import sys; open('{output_dir}pythonversion.txt', 'w').write(sys.version)" && '''
|
||||
'''python -c "import sys; open('{output_dir}pythonexecutable.txt', 'w').write(sys.executable)"''')
|
||||
|
||||
# build the wheels
|
||||
actual_wheels = utils.cibuildwheel_run(project_dir, add_env={
|
||||
# write python version information to a temporary file, this is
|
||||
# checked in setup.py
|
||||
'CIBW_BEFORE_BUILD': '''python -c "import sys; open('/tmp/pythonversion.txt', 'w').write(sys.version)" && python -c "import sys; open('/tmp/pythonexecutable.txt', 'w').write(sys.executable)"''',
|
||||
'CIBW_BEFORE_BUILD_WINDOWS': '''python -c "import sys; open('c:\\pythonversion.txt', 'w').write(sys.version)" && python -c "import sys; open('c:\\pythonexecutable.txt', 'w').write(sys.executable)"''',
|
||||
'CIBW_BEFORE_BUILD': before_build.format(output_dir='/tmp/'),
|
||||
'CIBW_BEFORE_BUILD_WINDOWS': before_build.format(output_dir=r'c:\\'),
|
||||
})
|
||||
|
||||
# also check that we got the right wheels
|
||||
expected_wheels = utils.expected_wheels('spam', '0.1.0')
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
|
||||
def test_failing_command(tmp_path):
|
||||
project_dir = tmp_path / 'project'
|
||||
test_projects.new_c_project().generate(project_dir)
|
||||
|
||||
with pytest.raises(subprocess.CalledProcessError):
|
||||
utils.cibuildwheel_run(project_dir, add_env={
|
||||
'CIBW_BEFORE_BUILD': 'false',
|
||||
'CIBW_BEFORE_BUILD_WINDOWS': 'exit /b 1',
|
||||
})
|
||||
|
||||
|
||||
def test_cwd(tmp_path):
|
||||
project_dir = tmp_path / 'project'
|
||||
test_projects.new_c_project().generate(project_dir)
|
||||
|
||||
actual_wheels = utils.cibuildwheel_run(project_dir, add_env={
|
||||
'CIBW_BEFORE_BUILD': f'''python -c "import os; assert os.getcwd() == {str(project_dir)!r}"''',
|
||||
'CIBW_BEFORE_BUILD_LINUX': '''python -c "import os; assert os.getcwd() == '/project'"''',
|
||||
})
|
||||
|
||||
expected_wheels = utils.expected_wheels('spam', '0.1.0')
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
@@ -32,10 +32,10 @@ def test(tmp_path):
|
||||
actual_wheels = utils.cibuildwheel_run(project_dir, add_env={
|
||||
'CIBW_MANYLINUX_X86_64_IMAGE': 'dockcross/manylinux2010-x64',
|
||||
'CIBW_MANYLINUX_I686_IMAGE': 'dockcross/manylinux2010-x86',
|
||||
'CIBW_SKIP': 'pp*',
|
||||
'CIBW_SKIP': 'pp* cp39-*',
|
||||
})
|
||||
|
||||
# also check that we got the right wheels built
|
||||
expected_wheels = [w for w in utils.expected_wheels('spam', '0.1.0')
|
||||
if '-pp' not in w]
|
||||
if '-pp' not in w and '-cp39-' not in w]
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
@@ -13,12 +13,15 @@ project_with_environment_asserts = test_projects.new_c_project(
|
||||
# explode if environment isn't correct, as set in CIBW_ENVIRONMENT
|
||||
CIBW_TEST_VAR = os.environ.get("CIBW_TEST_VAR")
|
||||
CIBW_TEST_VAR_2 = os.environ.get("CIBW_TEST_VAR_2")
|
||||
CIBW_TEST_VAR_3 = os.environ.get("CIBW_TEST_VAR_3")
|
||||
PATH = os.environ.get("PATH")
|
||||
|
||||
if CIBW_TEST_VAR != "a b c":
|
||||
raise Exception('CIBW_TEST_VAR should equal "a b c". It was "%s"' % CIBW_TEST_VAR)
|
||||
if CIBW_TEST_VAR_2 != "1":
|
||||
raise Exception('CIBW_TEST_VAR_2 should equal "1". It was "%s"' % CIBW_TEST_VAR_2)
|
||||
if CIBW_TEST_VAR_3 != "test string 3":
|
||||
raise Exception('CIBW_TEST_VAR_3 should equal "test string 3". It was "%s"' % CIBW_TEST_VAR_3)
|
||||
if "/opt/cibw_test_path" not in PATH:
|
||||
raise Exception('PATH should contain "/opt/cibw_test_path". It was "%s"' % PATH)
|
||||
if "$PATH" in PATH:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import textwrap
|
||||
from . import test_projects
|
||||
from . import utils
|
||||
import os
|
||||
|
||||
basic_project = test_projects.new_c_project(
|
||||
setup_py_add=textwrap.dedent(
|
||||
@@ -27,6 +28,7 @@ basic_project.files[
|
||||
[build-system]
|
||||
requires = [
|
||||
"setuptools >= 42",
|
||||
"setuptools_scm[toml]>=4.1.2",
|
||||
"wheel",
|
||||
"requests==2.22.0; python_version<'3.6'",
|
||||
"requests==2.23.0; python_version>='3.6'"
|
||||
@@ -47,3 +49,10 @@ def test_pep518(tmp_path):
|
||||
# check that the expected wheels are produced
|
||||
expected_wheels = utils.expected_wheels("spam", "0.1.0")
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
# These checks ensure an extra file is not created when using custom
|
||||
# workaround; see https://github.com/joerick/cibuildwheel/issues/421
|
||||
assert not (project_dir / "42").exists()
|
||||
assert not (project_dir / "4.1.2").exists()
|
||||
|
||||
assert len(os.listdir(project_dir)) == len(basic_project.files)
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import subprocess
|
||||
import pytest
|
||||
from test import test_projects
|
||||
from . import utils
|
||||
|
||||
pure_python_project = test_projects.TestProject()
|
||||
pure_python_project.files['setup.py'] = '''
|
||||
from setuptools import Extension, setup
|
||||
|
||||
setup(
|
||||
name="spam",
|
||||
py_modules=['spam'],
|
||||
version="0.1.0",
|
||||
)
|
||||
'''
|
||||
|
||||
pure_python_project.files['spam.py'] = '''
|
||||
def a_function():
|
||||
pass
|
||||
'''
|
||||
|
||||
|
||||
def test(tmp_path, capfd):
|
||||
# this test checks that if a pure wheel is generated, the build should
|
||||
# fail.
|
||||
project_dir = tmp_path / 'project'
|
||||
pure_python_project.generate(project_dir)
|
||||
|
||||
with pytest.raises(subprocess.CalledProcessError):
|
||||
actual_wheels = utils.cibuildwheel_run(project_dir)
|
||||
print('produced wheels:', actual_wheels)
|
||||
|
||||
captured = capfd.readouterr()
|
||||
print('out', captured.out)
|
||||
print('err', captured.err)
|
||||
assert "Build failed because a pure Python wheel was generated" in captured.err
|
||||
@@ -0,0 +1,28 @@
|
||||
import subprocess
|
||||
import pytest
|
||||
from .test_projects import TestProject
|
||||
from . import utils
|
||||
|
||||
so_file_project = TestProject()
|
||||
|
||||
so_file_project.files['libnothing.so'] = ''
|
||||
|
||||
so_file_project.files['setup.py'] = '''
|
||||
raise Exception('this build will fail')
|
||||
'''
|
||||
|
||||
|
||||
def test_failed_project_with_so_files(tmp_path, capfd):
|
||||
if utils.platform != 'linux':
|
||||
pytest.skip('this test is only relevant to the linux build')
|
||||
|
||||
project_dir = tmp_path / 'project'
|
||||
so_file_project.generate(project_dir)
|
||||
|
||||
with pytest.raises(subprocess.CalledProcessError):
|
||||
utils.cibuildwheel_run(project_dir)
|
||||
|
||||
captured = capfd.readouterr()
|
||||
print('out', captured.out)
|
||||
print('err', captured.err)
|
||||
assert "NOTE: Shared object (.so) files found in this project." in captured.err
|
||||
+1
-1
@@ -91,7 +91,7 @@ def expected_wheels(package_name, package_version, manylinux_versions=None,
|
||||
else:
|
||||
manylinux_versions = ['manylinux2014']
|
||||
|
||||
python_abi_tags = ['cp35-cp35m', 'cp36-cp36m', 'cp37-cp37m', 'cp38-cp38']
|
||||
python_abi_tags = ['cp35-cp35m', 'cp36-cp36m', 'cp37-cp37m', 'cp38-cp38', 'cp39-cp39']
|
||||
|
||||
if pm.machine() in ['x86_64', 'AMD64', 'x86']:
|
||||
python_abi_tags += ['cp27-cp27m', 'pp27-pypy_73', 'pp36-pypy36_pp73']
|
||||
|
||||
@@ -8,6 +8,7 @@ from pathlib import Path, PurePath
|
||||
import pytest
|
||||
|
||||
from cibuildwheel.docker_container import DockerContainer
|
||||
from cibuildwheel.environment import EnvironmentAssignment
|
||||
|
||||
# for these tests we use manylinux2014 images, because they're available on
|
||||
# multi architectures and include python3.8
|
||||
@@ -40,6 +41,13 @@ def test_environment():
|
||||
assert container.call(['sh', '-c', 'echo $TEST_VAR'], env={'TEST_VAR': '1'}, capture_output=True) == '1\n'
|
||||
|
||||
|
||||
@pytest.mark.docker
|
||||
def test_cwd():
|
||||
with DockerContainer(DEFAULT_IMAGE, cwd='/cibuildwheel/working_directory') as container:
|
||||
assert container.call(['pwd'], capture_output=True) == '/cibuildwheel/working_directory\n'
|
||||
assert container.call(['pwd'], capture_output=True, cwd='/opt') == '/opt\n'
|
||||
|
||||
|
||||
@pytest.mark.docker
|
||||
def test_container_removed():
|
||||
with DockerContainer(DEFAULT_IMAGE) as container:
|
||||
@@ -145,3 +153,10 @@ def test_dir_operations(tmp_path: Path):
|
||||
container.copy_out(dst_dir, new_test_dir)
|
||||
|
||||
assert test_binary_data == (new_test_dir / 'test.dat').read_bytes()
|
||||
|
||||
|
||||
@pytest.mark.docker
|
||||
def test_environment_executor():
|
||||
with DockerContainer(DEFAULT_IMAGE) as container:
|
||||
assignment = EnvironmentAssignment("TEST=$(echo 42)")
|
||||
assert assignment.evaluated_value({}, container.environment_executor) == "42"
|
||||
|
||||
Reference in New Issue
Block a user