Compare commits

..
96 Commits
Author SHA1 Message Date
Joe Rickerby 0fb2ead6fb Bump version: v1.7.0 2020-11-26 23:29:34 +00:00
Joe Rickerby dcf703c67e Show the PR link before asking for new version number 2020-11-26 23:26:17 +00:00
Joe Rickerby edbbdb6861 Merge pull request #467 from joerick/update-constraints-2020-11-26T18-06-10
Update dependencies
2020-11-26 23:23:30 +00:00
Joe Rickerby 54877b96e3 Update dependencies 2020-11-26 18:06:44 +00:00
Joe Rickerby e0f2f8fdac Merge pull request #458 from joerick/logger
Improve CI logs using fold groups
2020-11-26 17:44:49 +00:00
Joe Rickerby c065e3ce2d Scrap the stderr->stdout redirect (we don't seem to need it)
Let's keep an eye on this and if we see output outside of the fold
groups we can add it back
2020-11-24 19:04:27 +00:00
Joe Rickerby 27bda4fa64 Hide some errant output 2020-11-24 19:02:50 +00:00
Joe Rickerby 5665b61cbf Double-check this 2020-11-24 18:53:43 +00:00
Joe Rickerby 4c035a441b Try using an Unbuffered sys.stderr 2020-11-24 18:48:27 +00:00
Joe Rickerby ba01ec546e Update pr-labels-action 2020-11-24 09:05:14 +00:00
Joe Rickerby b9cf466cd8 Merge pull request #445 from jbarlow83/patch-3
README: Mention which CIs support ARM builds
2020-11-24 09:00:56 +00:00
Joe Rickerby 6413732187 Merge pull request #464 from YannickJadoul/manylinux-python-version
Ensure modern version of Python in CIBW_BEFORE_ALL on manylinux
2020-11-24 08:58:51 +00:00
jbarlow83andHenry Schreiner 10c244d827 Update README.md
Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
2020-11-23 16:42:58 -08:00
Joe Rickerby bfd9bb482b Fix unit test 2020-11-23 21:21:40 +00:00
Joe Rickerby c2a7cdf98a Fix flake8 errors 2020-11-23 21:06:36 +00:00
Joe Rickerby f8a4fbe42d Share CI platform detection 2020-11-23 21:00:22 +00:00
Joe Rickerby 95fecc2d58 Remove debug code 2020-11-23 20:56:24 +00:00
Joe Rickerby ece358f29d lowercase for command line argument 2020-11-23 20:24:08 +00:00
Yannick Jadoul 6f3fcf8b12 Fix PATH of CPython 3.8 binary for CIBW_BEFORE_ALL 2020-11-23 00:49:32 +01:00
Yannick Jadoul c67de74e28 Demonstrate old version of Python in CIBW_BEFORE_ALL on manylinux 2020-11-23 00:41:52 +01:00
Yannick Jadoul 2f4ed1fafc Update to PyPy 7.3.3 (#460)
* Test PyPy 7.3.3rc1

* Revert "Update Travis CI and CircleCI to use macOS 10.14 " and "Change examples to use macOS >= 10.14"

This reverts commits 870bf3f740 and cd53552b4b.

* PyPy 7.3.3rc2

* PyPy 7.3.3 released

* Revert to using pypywheels docker images
2020-11-22 14:55:04 +01:00
Joe Rickerby 05d7c142e9 Subprocess stderr goes to stdout on Mac and Windows too 2020-11-22 10:35:40 +00:00
Joe Rickerby e84c6b2de0 Remove old sample build workflow 2020-11-22 01:20:14 +00:00
Joe Rickerby a93cee1a30 Run a sample build before tests on PRs with this label 2020-11-22 01:15:44 +00:00
Joe Rickerby d3f57bbb22 Merge pull request #461 from joerick/azure-errexit
Use set -o errexit in the Azure example
2020-11-20 10:07:43 +00:00
Henry Schreiner a50be4d820 Update README.md 2020-11-19 10:23:37 -05:00
Henry Schreiner b8a41130c3 Update README.md 2020-11-19 10:22:55 -05:00
Joe Rickerby 9d731cd440 Make the sample build only happen from a manual trigger 2020-11-14 14:52:20 +00:00
Joe Rickerby 309222cca3 Merge remote-tracking branch 'origin/master' into logger 2020-11-14 14:51:18 +00:00
Joe Rickerby fe6eadc1f2 Merge remote-tracking branch 'origin/master' into logger 2020-11-14 14:50:52 +00:00
Joe Rickerby 91906b2aea Skip the example output test 2020-11-14 14:50:29 +00:00
Joe Rickerby 0760c330cf Merge pull request #462 from joerick/github-triggers
Improve Github triggers to prevent multiple runs on origin branches
2020-11-14 14:46:30 +00:00
Joe Rickerby d054b45ecf Perhaps displayName must come second 2020-11-14 14:33:58 +00:00
Joe Rickerby 8606c4771e Add explicit sample build test to keep the first test simple 2020-11-14 14:28:47 +00:00
Joe Rickerby 4c94e7ef20 Add back newline after stage header. Also flush stdout to help with ordering 2020-11-14 14:28:17 +00:00
Joe Rickerby c56448eba7 Named steps and set -o errexit 2020-11-13 19:20:16 +00:00
Joe Rickerby ebe632eff0 Limit push to master instead 2020-11-13 19:15:17 +00:00
Joe Rickerby a732525084 Move encoding switch to before the unicode decision is made 2020-11-13 19:04:02 +00:00
Joe Rickerby e8aef6962a Set output to UTF8 on windows (on Python >= 3.7) 2020-11-13 18:57:07 +00:00
Joe Rickerby fba3248163 Remove encoding debug code 2020-11-13 18:46:41 +00:00
Joe Rickerby 113350b7fb Remove unicode test 2020-11-13 18:37:48 +00:00
Joe Rickerby 54858bbd64 Support non-unicode stdout 2020-11-13 18:37:30 +00:00
Joe Rickerby 0227b9d941 Improve debug code 2020-11-13 17:44:13 +00:00
Joe Rickerby df71e028a9 grumble 2020-11-13 17:41:43 +00:00
Joe Rickerby 8e2381bfb1 add some encoding debug code 2020-11-13 17:40:07 +00:00
Joe Rickerby 3d59c56584 Ensure sample build shell is bash on Windows 2020-11-13 17:32:49 +00:00
Joe Rickerby 57d38efd4d Add mac/windows sample builds 2020-11-13 17:21:14 +00:00
Joe Rickerby 1f830a3626 Improve Github triggers to prevent multiple runs on origin branches 2020-11-13 17:08:20 +00:00
Joe Rickerby 1ab1130fe1 Move initialization of the global logger to the end of the file 2020-11-13 16:51:26 +00:00
Joe Rickerby 931f8e106e Shorten the travis IDs 2020-11-13 16:46:58 +00:00
Joe Rickerby 8b8d6d749c Prevent double-builds of the sample 2020-11-13 16:33:59 +00:00
Joe Rickerby 38297e6663 Add log steps to macOS/Windows 2020-11-13 16:30:35 +00:00
Joe RickerbyandHenry Schreiner 246aa0848e Update cibuildwheel/util.py
Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
2020-11-13 15:38:34 +00:00
Joe Rickerby 7914432a68 fix appearance on Travis with headers and identifiers 2020-11-13 15:26:06 +00:00
Joe Rickerby 5e99d962f5 Wrap the sample build output in a fold group 2020-11-13 15:22:43 +00:00
Joe Rickerby df04fa5ac3 Use set -o errexit in the Azure example 2020-11-13 14:57:09 +00:00
Joe Rickerby 8e38132000 Merge pull request #454 from nsoranzo/patch-1
Update repos using cibuildwheel
2020-11-13 09:31:26 +00:00
Joe Rickerby 8108deacfe Don't capture the output of the first test 2020-11-05 23:10:25 +00:00
Joe Rickerby c9ea0251fe Sample build uses a testcase failure project 2020-11-04 16:08:40 +00:00
Joe Rickerby fbbc295901 Starting a build implicitly closes a log step 2020-11-04 16:08:24 +00:00
Joe Rickerby 888da8274c GHA build tweak 2020-11-04 15:43:27 +00:00
Joe Rickerby 06b6823637 Remove some unnecessary step_end calls 2020-11-04 11:48:12 +00:00
Joe Rickerby 2f9ee793f0 Adjust sample build to show passing/failing test
Drop the 'allow fail' approach, it shows up as red in PR/commit status
2020-11-04 11:38:03 +00:00
Joe Rickerby 75c6e6a0a4 Improvements from code review 2020-11-04 11:11:42 +00:00
Joe Rickerby c5bbfb3cc6 ...and make that step fail 2020-11-03 09:15:22 +00:00
Joe Rickerby 53ee55bad7 and again 2020-11-03 09:13:42 +00:00
Joe Rickerby 225342c777 fix syntax 2020-11-03 09:12:19 +00:00
Joe Rickerby 8808add708 Try allow failure Github job 2020-11-03 08:51:45 +00:00
Joe Rickerby fa4a0cbd33 Improve error output 2020-11-01 21:36:44 +00:00
Joe Rickerby 4a736cdcb1 Improve options output 2020-11-01 21:17:25 +00:00
Joe Rickerby 4b402e0593 Experiment 2020-11-01 20:44:38 +00:00
Joe Rickerby 4eff3bc7a8 Add a failure example build 2020-11-01 17:06:55 +00:00
Joe Rickerby 0a32e3bc0e Improve appearance outside CI 2020-11-01 16:57:22 +00:00
Joe Rickerby b22001b26d Add build end message 2020-11-01 15:19:42 +00:00
Joe Rickerby 39b94b7dec Tidy up log output 2020-11-01 15:19:25 +00:00
Joe Rickerby 152483bcb4 Try putting all build output on stdout 2020-11-01 15:16:28 +00:00
Joe Rickerby f51c8dc1e3 More tweaks 2020-11-01 12:33:14 +00:00
Joe Rickerby 45c723cdea Fix folding 2020-11-01 12:03:21 +00:00
Joe Rickerby dac4006083 More formatting tweaks 2020-11-01 12:00:59 +00:00
Joe Rickerby f48a84d92f Improve some formatting 2020-11-01 11:43:28 +00:00
Joe Rickerby 38e7b5a91d Change to an imperative-style API 2020-11-01 11:34:02 +00:00
Yannick Jadoul beda0e5ce8 Add description to Parselmouth in README.md 2020-10-31 20:57:45 +01:00
Nicola SoranzoandJoe Rickerby 957a4fb8e1 Add context to repos
Co-authored-by: Joe Rickerby <joerick@mac.com>
2020-10-31 20:57:45 +01:00
Nicola Soranzo 7e4b44b6ee Add Matplotlib, twisted-iocpsupport and bx-python 2020-10-31 20:57:45 +01:00
Nicola Soranzo a494f9bbe5 twisted not using cibuildwheel any more 2020-10-31 20:57:45 +01:00
Joe Rickerby 946306b21d Fix sample project gen command 2020-10-31 18:19:02 +00:00
Joe Rickerby 0191496fc9 Install dependencies in sample build 2020-10-31 18:17:36 +00:00
Joe Rickerby 4ec28cb37e Fix flake8 2020-10-31 18:16:23 +00:00
Joe Rickerby 136adebf09 Add a github action to run a sample build to check output 2020-10-31 18:13:31 +00:00
Joe Rickerby 461aa35f99 Initial commit of logger functionality 2020-10-31 17:48:34 +00:00
Joe Rickerby d12e54af41 Bump version: v1.6.4 2020-10-31 15:56:43 +00:00
Matthieu DarboisandJoe Rickerby 336c80b694 Use certifi provided certificates when downloading files (#455)
* Use certifi provided certificates when downloading files

* fix typo

* Add comment about certifi usage

Co-authored-by: Joe Rickerby <joerick@mac.com>

Co-authored-by: Joe Rickerby <joerick@mac.com>
2020-10-31 10:06:14 +01:00
Joe Rickerby 7dcd6826a4 Merge pull request #439 from dimitern/dimitern-xmlstarlet-example-readme
Add xmlstarlet to Working examples.
2020-10-30 22:20:35 +00:00
jbarlow83 c89b74604d README: Mention which CIs support ARM builds 2020-10-08 01:35:22 -07:00
Dimiter Naydenov 3e7a665b11 Updated description 2020-10-07 19:26:32 +03:00
Dimiter Naydenov 734377b5f5 Add xmlstarlet to Working examples.
Building binary wheels for Python 3.6+ and Linux, MacOS, and Windows.
The easiest way to install and use the tool on Windows (from Python), also builds a truly native MSVC win_amd64 binary (not MinGW64).
I couldn't find a good example of a usable CFFI cross-platform binary wheel build setup (esp. when the original C sources only build under MinGW32).
2020-10-04 20:45:46 +03:00
36 changed files with 819 additions and 327 deletions
+1 -1
View File
@@ -3,7 +3,7 @@ version: 2
jobs:
osx-python3.6:
macos:
xcode: 10.2.1
xcode: 9.4.1
environment:
PYTHON: python3
steps:
+16 -4
View File
@@ -1,10 +1,14 @@
name: Test
on:
push: {}
push:
branches:
- master
pull_request:
paths-ignore:
- 'docs/**'
workflow_dispatch:
# allow manual runs on branches without a PR
jobs:
pre-commit:
@@ -16,9 +20,6 @@ jobs:
- 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'
name: Test cibuildwheel on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
@@ -36,10 +37,21 @@ jobs:
- name: Install dependencies
run: |
python -m pip install -r requirements-dev.txt
- name: Install Visual C++ for Python 2.7
if: runner.os == 'Windows'
run: |
choco install vcpython27 -f -y
- name: Get PR labels
id: pr-labels
uses: joerick/pr-labels-action@v1.0.6
- name: Sample build
if: contains(steps.pr-labels.outputs.labels, ' ci-sample-build ')
run: |
python bin/sample_build.py
- name: Test cibuildwheel
run: |
python ./bin/run_tests.py
-1
View File
@@ -28,7 +28,6 @@ jobs:
- name: macOS | x86_64 | Python 3.x
os: osx
osx_image: xcode10.2
env:
- PYTHON=python3
- PYTEST_ADDOPTS='-k "unit_test or test_0_basic" --suppress-no-test-exit-code'
+36 -16
View File
@@ -23,9 +23,9 @@ What does it do?
| CPython 3.7 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅² | ✅² | ✅³ |
| CPython 3.8 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅² | ✅² | ✅³ |
| CPython 3.9 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅² | ✅² | ✅³ |
| PyPy 2.7 v7.3.2 | ✅ | | ✅ | ✅ | | | | |
| PyPy 3.6 v7.3.2 | ✅ | | ✅ | ✅ | | | | |
| PyPy 3.7 (alpha) v7.3.2 | ✅ | | ✅ | ✅ | | | | |
| PyPy 2.7 v7.3.3 | ✅ | | ✅ | ✅ | | | | |
| PyPy 3.6 v7.3.3 | ✅ | | ✅ | ✅ | | | | |
| PyPy 3.7 (beta) v7.3.3 | ✅ | | ✅ | ✅ | | | | |
<sup>¹ Not supported on Travis</sup><br>
<sup>² Only supported on Travis</sup><br>
@@ -40,14 +40,16 @@ Usage
`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 |
|-----------------|-------|-------|---------|
| Azure Pipelines | ✅ | ✅ | ✅ |
| Travis CI | ✅ | ✅ | ✅ |
| AppVeyor | ✅ | ✅ | ✅ |
| GitHub Actions | ✅ | ✅ | ✅ |
| CircleCI | ✅ | ✅ | |
| Gitlab CI | ✅ | | |
| | Linux | macOS | Windows | Linux ARM |
|-----------------|-------|-------|---------|--------------|
| Azure Pipelines | ✅ | ✅ | ✅ | ✴️¹ |
| Travis CI | ✅ | ✅ | ✅ | ✅ |
| AppVeyor | ✅ | ✅ | ✅ | |
| GitHub Actions | ✅ | ✅ | ✅ | ✴️¹ |
| CircleCI | ✅ | ✅ | | |
| Gitlab CI | ✅ | | | |
<sup>¹ Requires a "third-party build host"; expected to work with cibuildwheel but not directly tested by our CI.</sup><br>
`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.
@@ -67,8 +69,6 @@ jobs:
- services: docker
# and a mac build
- os: osx
# PyPy 7.3.2 needs macOS >= 10.14
osx_image: xcode10.2
language: shell
# and a windows build
- os: windows
@@ -85,7 +85,7 @@ env:
# Note: TWINE_PASSWORD is set to a PyPI API token in Travis settings
install:
- python3 -m pip install cibuildwheel==1.6.3
- python3 -m pip install cibuildwheel==1.7.0
script:
# build the wheels, put them into './wheelhouse'
@@ -127,16 +127,17 @@ Working examples
Here are some repos that use cibuildwheel.
- [Matplotlib](https://github.com/matplotlib/matplotlib) - The venerable Matplotlib, a Python library with C++ portions, built for Linux, Mac, and Windows on Github Actions.
- [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)
- [Parselmouth](https://github.com/YannickJadoul/Parselmouth) - A Python interface to the Praat software package, using pybind11, C++17 and CMake, with the core Praat static library built only once and shared between wheels; all platforms built on Github Actions.
- [python-admesh](https://github.com/admesh/python-admesh)
- [pybase64](https://github.com/mayeut/pybase64)
- [KDEpy](https://github.com/tommyod/KDEpy)
- [AutoPy](https://github.com/autopilot-rs/autopy)
- [apriltags2-ethz](https://github.com/safijari/apriltags2_ethz)
- [TgCrypto](https://github.com/pyrogram/tgcrypto)
- [Twisted](https://github.com/twisted/twisted)
- [twisted-iocpsupport](https://github.com/twisted/twisted-iocpsupport) - A submodule of Twisted that hooks into native C APIs using Cython. Built on Github CI for Windows.
- [gmic-py](https://github.com/dtschump/gmic-py)
- [creme](https://github.com/creme-ml/creme)
- [PyAV](https://github.com/PyAV-Org/PyAV)
@@ -145,6 +146,8 @@ Here are some repos that use cibuildwheel.
- [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.
- [xmlstarlet](https://github.com/dimitern/xmlstarlet) - Python 3.6+ CFFI bindings with true MSVC build and GitHub Actions.
- [bx-python](https://github.com/bxlab/bx-python) - A library that includes Cython extensions, built on Travis CI for Mac and Linux.
> Add your repo here! Send a PR.
>
@@ -162,6 +165,23 @@ This is similar to static linking, so it might have some licence implications. C
Changelog
=========
### 1.7.0
_26 November 2020_
- ✨ New logging format, that uses 'fold groups' in CI services that support
it. (#458)
- 🛠 Update PyPy to 7.3.3 (#460)
- 🐛 Fix a bug where CIBW_BEFORE_ALL runs with a very old version of Python on
Linux. (#464)
### 1.6.4
_31 October 2020_
- 🐛 Fix crash on Appveyor during nuget install due to old system CA
certificates. We now use certifi's CA certs to download files. (#455)
### 1.6.3
_12 October 2020_
+19 -18
View File
@@ -20,6 +20,25 @@ config = [
@click.command()
def bump_version():
current_version = cibuildwheel.__version__
try:
commit_date_str = subprocess.run([
'git',
'show', '-s', '--pretty=format:%ci',
f'v{current_version}^{{commit}}'
], check=True, capture_output=True, encoding='utf8').stdout
commit_date_parts = commit_date_str.split(' ')
url = 'https://github.com/joerick/cibuildwheel/pulls?' + urllib.parse.urlencode({
'q': f'is:pr merged:>{commit_date_parts[0]}T{commit_date_parts[1]}{commit_date_parts[2]}',
})
print(f'PRs merged since last release:\n {url}')
print()
except subprocess.CalledProcessError as e:
print(e)
print('Failed to get previous version tag information.')
git_changes_result = subprocess.run(['git diff-index --quiet HEAD --'], shell=True)
repo_has_uncommitted_changes = git_changes_result.returncode != 0
@@ -27,7 +46,6 @@ def bump_version():
print('error: Uncommitted changes detected.')
exit(1)
current_version = cibuildwheel.__version__
print( 'Current version:', current_version) # noqa
new_version = input(' New version: ').strip()
@@ -90,23 +108,6 @@ def bump_version():
print('commit, do that now.')
print()
try:
commit_date_str = subprocess.run([
'git',
'show', '-s', '--pretty=format:%ci',
f'v{current_version}^{{commit}}'
], check=True, capture_output=True, encoding='utf8').stdout
commit_date_parts = commit_date_str.split(' ')
url = 'https://github.com/joerick/cibuildwheel/pulls?' + urllib.parse.urlencode({
'q': f'is:pr merged:>{commit_date_parts[0]}T{commit_date_parts[1]}{commit_date_parts[2]}',
})
print(f'PRs merged since last release:\n {url}')
print()
except subprocess.CalledProcessError as e:
print(e)
print('Failed to get previous version tag information.')
while input('Type "done" to continue: ').strip().lower() != 'done':
pass
+25
View File
@@ -0,0 +1,25 @@
#!/usr/bin/env python3
import os
import subprocess
import sys
import argparse
import tempfile
from pathlib import Path
if __name__ == '__main__':
# move cwd to the project root
os.chdir(Path(__file__).resolve().parents[1])
parser = argparse.ArgumentParser(description='Runs a sample build')
parser.add_argument('project_python_path', nargs='?', default='test.test_0_basic.basic_project')
options = parser.parse_args()
project_dir = tempfile.mkdtemp()
subprocess.run([
sys.executable, '-m', 'test.test_projects',
options.project_python_path, project_dir
], check=True)
exit(subprocess.run(['cibuildwheel'], cwd=project_dir).returncode)
+1 -1
View File
@@ -1 +1 @@
__version__ = '1.6.3'
__version__ = '1.7.0'
+9 -13
View File
@@ -21,6 +21,7 @@ from cibuildwheel.util import (
BuildSelector,
DependencyConstraints,
Unbuffered,
detect_ci_provider,
resources_dir,
)
@@ -47,12 +48,6 @@ def get_option_from_environment(option_name: str, platform: Optional[str] = None
return os.environ.get(option_name, default)
def strtobool(val: str) -> bool:
if val.lower() in ('y', 'yes', 't', 'true', 'on', '1'):
return True
return False
def main() -> None:
parser = argparse.ArgumentParser(
description='Build wheels for all the platforms.',
@@ -96,13 +91,14 @@ def main() -> None:
if args.platform != 'auto':
platform = args.platform
else:
ci = strtobool(os.environ.get('CI', 'false')) or 'BITRISE_BUILD_NUMBER' in os.environ or 'AZURE_HTTP_USER_AGENT' in os.environ or 'GITHUB_WORKFLOW' in os.environ
if not ci:
print('cibuildwheel: Unable to detect platform. cibuildwheel should run on your CI server, '
'Travis CI, AppVeyor, Azure Pipelines, GitHub Actions and CircleCI are supported. You '
'can run on your development machine or other CI providers using the --platform argument. '
'Check --help output for more information.',
file=sys.stderr)
ci_provider = detect_ci_provider()
if ci_provider is None:
print(textwrap.dedent('''
cibuildwheel: Unable to detect platform. cibuildwheel should run on your CI server;
Travis CI, AppVeyor, Azure Pipelines, GitHub Actions, CircleCI, and Gitlab are
supported. You can run on your development machine or other CI providers using the
--platform argument. Check --help output for more information.
'''), file=sys.stderr)
exit(2)
if sys.platform.startswith('linux'):
platform = 'linux'
+1 -1
View File
@@ -73,7 +73,7 @@ class DockerContainer:
self.process.terminate()
self.process.wait()
subprocess.run(['docker', 'rm', '--force', '-v', self.name])
subprocess.run(['docker', 'rm', '--force', '-v', self.name], stdout=subprocess.DEVNULL)
self.name = None
def copy_into(self, from_path: Path, to_path: PurePath) -> None:
+23 -3
View File
@@ -7,6 +7,7 @@ from pathlib import Path, PurePath
from typing import List, NamedTuple, Union
from .docker_container import DockerContainer
from .logger import log
from .util import (BuildOptions, BuildSelector, NonPlatformWheelError,
get_build_verbosity_extra_flags, prepare_command)
@@ -83,7 +84,7 @@ def get_python_configurations(build_selector: BuildSelector) -> List[PythonConfi
def build(options: BuildOptions) -> None:
try:
subprocess.check_call(['docker', '--version'])
subprocess.check_output(['docker', '--version'])
except Exception:
print('cibuildwheel: Docker not found. Docker is required to run Linux builds. '
'If you\'re building on Travis CI, add `services: [docker]` to your .travis.yml.'
@@ -117,18 +118,25 @@ def build(options: BuildOptions) -> None:
continue
try:
log.step(f'Starting Docker image {docker_image}...')
with DockerContainer(docker_image, simulate_32_bit=platform_tag.endswith('i686'), cwd=container_project_path) as docker:
log.step('Copying project into Docker...')
docker.copy_into(Path.cwd(), container_project_path)
if options.before_all:
log.step('Running before_all...')
env = docker.get_environment()
env['PATH'] = f'/opt/python/cp38-cp38:{env["PATH"]}'
env['PATH'] = f'/opt/python/cp38-cp38/bin:{env["PATH"]}'
env = options.environment.as_dictionary(env, executor=docker.environment_executor)
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:
log.build_start(config.identifier)
dependency_constraint_flags: List[Union[str, PathLike]] = []
if options.dependency_constraints:
@@ -138,6 +146,8 @@ def build(options: BuildOptions) -> None:
docker.copy_into(constraints_file, container_constraints_file)
dependency_constraint_flags = ['-c', container_constraints_file]
log.step('Setting up build environment...')
env = docker.get_environment()
# put this config's python top of the list
@@ -158,9 +168,12 @@ def build(options: BuildOptions) -> None:
exit(1)
if options.before_build:
log.step('Running before_build...')
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)
log.step('Building wheel...')
temp_dir = PurePath('/tmp/cibuildwheel')
built_wheel_dir = temp_dir / 'built_wheel'
docker.call(['rm', '-rf', built_wheel_dir])
@@ -184,6 +197,7 @@ def build(options: BuildOptions) -> None:
raise NonPlatformWheelError()
if options.repair_command:
log.step('Repairing wheel...')
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:
@@ -192,6 +206,8 @@ def build(options: BuildOptions) -> None:
repaired_wheels = docker.glob(repaired_wheel_dir, '*.whl')
if options.test_command:
log.step('Testing wheel...')
# set up a virtual environment to install and test from, to make sure
# there are no dependencies that were pulled in at build time.
docker.call(['pip', 'install', 'virtualenv', *dependency_constraint_flags], env=env)
@@ -230,10 +246,14 @@ def build(options: BuildOptions) -> None:
docker.call(['mkdir', '-p', container_output_dir])
docker.call(['mv', *repaired_wheels, container_output_dir])
log.build_end()
log.step('Copying wheels back to host...')
# copy the output back into the host
docker.copy_out(container_output_dir, options.output_dir)
log.step_end()
except subprocess.CalledProcessError as error:
print(f'Command {error.cmd} failed with code {error.returncode}. {error.stdout}')
log.error(f'Command {error.cmd} failed with code {error.returncode}. {error.stdout}')
troubleshoot(options.package_dir, error)
exit(1)
+263
View File
@@ -0,0 +1,263 @@
import codecs
import os
import re
import sys
import time
from typing import Optional, Union
from cibuildwheel.util import CIProvider, detect_ci_provider
DEFAULT_FOLD_PATTERN = ('{name}', '')
FOLD_PATTERNS = {
'azure': ('##[group]{name}', '##[endgroup]'),
'travis': ('travis_fold:start:{identifier}\n{name}', 'travis_fold:end:{identifier}'),
'github': ('::group::{name}', '::endgroup::{name}'),
}
PLATFORM_IDENTIFIER_DESCIPTIONS = {
'manylinux_x86_64': 'manylinux x86_64',
'manylinux_i686': 'manylinux i686',
'manylinux_aarch64': 'manylinux aarch64',
'manylinux_ppc64le': 'manylinux ppc64le',
'manylinux_s390x': 'manylinux s390x',
'win32': 'Windows 32bit',
'win_amd64': 'Windows 64bit',
'macosx_x86_64': 'macOS x86_64',
}
class Logger:
fold_mode: str
colors_enabled: bool
unicode_enabled: bool
active_build_identifier: Optional[str] = None
build_start_time: Optional[float] = None
step_start_time: Optional[float] = None
active_fold_group_name: Optional[str] = None
def __init__(self):
if sys.platform == 'win32' and hasattr(sys.stdout, 'reconfigure'):
# the encoding on Windows can be a 1-byte charmap, but all CIs
# support utf8, so we hardcode that
sys.stdout.reconfigure(encoding='utf8')
self.unicode_enabled = file_supports_unicode(sys.stdout)
ci_provider = detect_ci_provider()
if ci_provider == CIProvider.azure_pipelines:
self.fold_mode = 'azure'
self.colors_enabled = True
elif ci_provider == CIProvider.github_actions:
self.fold_mode = 'github'
self.colors_enabled = True
elif ci_provider == CIProvider.travis_ci:
self.fold_mode = 'travis'
self.colors_enabled = True
elif ci_provider == CIProvider.appveyor:
self.fold_mode = 'disabled'
self.colors_enabled = True
else:
self.fold_mode = 'disabled'
self.colors_enabled = file_supports_color(sys.stdout)
def build_start(self, identifier: str):
self.step_end()
c = self.colors
description = build_description_from_identifier(identifier)
print()
print(f'{c.bold}{c.blue}Building {identifier} wheel{c.end}')
print(f'{description}')
print()
self.build_start_time = time.time()
self.active_build_identifier = identifier
def build_end(self):
assert self.build_start_time is not None
assert self.active_build_identifier is not None
self.step_end()
c = self.colors
s = self.symbols
duration = time.time() - self.build_start_time
print()
print(f'{c.green}{s.done} {c.end}{self.active_build_identifier} finished in {duration:.2f}s')
self.build_start_time = None
self.active_build_identifier = None
def step(self, step_description: str):
self.step_end()
self.step_start_time = time.time()
self._start_fold_group(step_description)
def step_end(self, success=True):
if self.step_start_time is not None:
self._end_fold_group()
c = self.colors
s = self.symbols
duration = time.time() - self.step_start_time
if success:
print(f'{c.green}{s.done} {c.end}{duration:.2f}s'.rjust(78))
else:
print(f'{c.red}{s.error} {c.end}{duration:.2f}s'.rjust(78))
self.step_start_time = None
def error(self, error: Union[Exception, str]):
self.step_end(success=False)
print()
if self.fold_mode == 'github':
print(f'::error::{error}')
else:
c = self.colors
print(f'{c.bright_red}Error{c.end} {error}')
def _start_fold_group(self, name: str):
self._end_fold_group()
self.active_fold_group_name = name
fold_start_pattern = FOLD_PATTERNS.get(self.fold_mode, DEFAULT_FOLD_PATTERN)[0]
identifier = self._fold_group_identifier(name)
print(fold_start_pattern.format(name=self.active_fold_group_name, identifier=identifier))
print()
sys.stdout.flush()
def _end_fold_group(self):
if self.active_fold_group_name:
fold_start_pattern = FOLD_PATTERNS.get(self.fold_mode, DEFAULT_FOLD_PATTERN)[1]
identifier = self._fold_group_identifier(self.active_fold_group_name)
print(fold_start_pattern.format(name=self.active_fold_group_name, identifier=identifier))
sys.stdout.flush()
self.active_fold_group_name = None
def _fold_group_identifier(self, name: str):
'''
Travis doesn't like fold groups identifiers that have spaces in. This
method converts them to ascii identifiers
'''
# whitespace to underscores
identifier = re.sub(r'\s+', '_', name)
# remove non-alphanum
identifier = re.sub(r'[^A-Za-z\d_]+', '', identifier)
# trim underscores
identifier = identifier.strip('_')
# lowercase, shorten
return identifier.lower()[:20]
@property
def colors(self):
if self.colors_enabled:
return Colors.enabled
else:
return Colors.disabled
@property
def symbols(self):
if self.unicode_enabled:
return Symbols.unicode
else:
return Symbols.ascii
def build_description_from_identifier(identifier: str):
python_identifier, _, platform_identifier = identifier.partition('-')
build_description = ''
python_interpreter = python_identifier[0:2]
python_version = python_identifier[2:4]
if python_interpreter == 'cp':
build_description += 'CPython'
elif python_interpreter == 'pp':
build_description += 'PyPy'
else:
raise Exception('unknown python')
build_description += f' {python_version[0]}.{python_version[1]} '
try:
build_description += PLATFORM_IDENTIFIER_DESCIPTIONS[platform_identifier]
except KeyError as e:
raise Exception('unknown platform') from e
return build_description
class Colors:
class Enabled:
red = '\033[31m'
green = '\033[32m'
yellow = '\033[33m'
blue = '\033[34m'
cyan = '\033[36m'
bright_red = '\033[91m'
bright_green = '\033[92m'
white = '\033[37m\033[97m'
bg_grey = '\033[48;5;235m'
bold = '\033[1m'
faint = '\033[2m'
end = '\033[0m'
class Disabled:
def __getattr__(self, attr: str) -> str:
return ''
enabled = Enabled()
disabled = Disabled()
class Symbols:
class Unicode:
done = ''
error = ''
class Ascii:
done = 'done'
error = 'failed'
unicode = Unicode()
ascii = Ascii()
def file_supports_color(file_obj):
"""
Returns True if the running system's terminal supports color.
"""
plat = sys.platform
supported_platform = (plat != 'win32' or 'ANSICON' in os.environ)
is_a_tty = file_is_a_tty(file_obj)
return (supported_platform and is_a_tty)
def file_is_a_tty(file_obj):
return hasattr(file_obj, 'isatty') and file_obj.isatty()
def file_supports_unicode(file_obj):
encoding = getattr(file_obj, 'encoding', None)
if not encoding:
return False
codec_info = codecs.lookup(encoding)
return ('utf' in codec_info.name)
'''
Global instance of the Logger.
'''
# (there's only one stdout per-process, so a global instance is justified)
log = Logger()
+104 -87
View File
@@ -9,9 +9,10 @@ from pathlib import Path
from typing import Dict, List, NamedTuple, Optional, Sequence, Union
from .environment import ParsedEnvironment
from .util import (BuildOptions, BuildSelector, NonPlatformWheelError, download,
get_build_verbosity_extra_flags, get_pip_script,
prepare_command, install_certifi_script)
from .logger import log
from .util import (BuildOptions, BuildSelector, NonPlatformWheelError,
download, get_build_verbosity_extra_flags, get_pip_script,
install_certifi_script, prepare_command)
def call(args: Union[str, Sequence[Union[str, PathLike]]], env: Optional[Dict[str, str]] = None, cwd: Optional[str] = None, shell: bool = False) -> int:
@@ -40,9 +41,9 @@ def get_python_configurations(build_selector: BuildSelector) -> List[PythonConfi
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.0-macosx10.9.pkg'),
# PyPy
PythonConfiguration(version='2.7', identifier='pp27-macosx_x86_64', url='https://downloads.python.org/pypy/pypy2.7-v7.3.2-osx64.tar.bz2'),
PythonConfiguration(version='3.6', identifier='pp36-macosx_x86_64', url='https://downloads.python.org/pypy/pypy3.6-v7.3.2-osx64.tar.bz2'),
PythonConfiguration(version='3.7', identifier='pp37-macosx_x86_64', url='https://downloads.python.org/pypy/pypy3.7-v7.3.2-osx64.tar.bz2'),
PythonConfiguration(version='2.7', identifier='pp27-macosx_x86_64', url='https://downloads.python.org/pypy/pypy2.7-v7.3.3-osx64.tar.bz2'),
PythonConfiguration(version='3.6', identifier='pp36-macosx_x86_64', url='https://downloads.python.org/pypy/pypy3.6-v7.3.3-osx64.tar.bz2'),
PythonConfiguration(version='3.7', identifier='pp37-macosx_x86_64', url='https://downloads.python.org/pypy/pypy3.7-v7.3.3-osx64.tar.bz2'),
]
# skip builds as required
@@ -116,13 +117,18 @@ def install_pypy(version: str, url: str) -> Path:
def setup_python(python_configuration: PythonConfiguration,
dependency_constraint_flags: Sequence[Union[str, PathLike]],
environment: ParsedEnvironment) -> Dict[str, str]:
if python_configuration.identifier.startswith('cp'):
implementation_id = python_configuration.identifier.split("-")[0]
log.step(f'Installing Python {implementation_id}...')
if implementation_id.startswith('cp'):
installation_bin_path = install_cpython(python_configuration.version, python_configuration.url)
elif python_configuration.identifier.startswith('pp'):
elif implementation_id.startswith('pp'):
installation_bin_path = install_pypy(python_configuration.version, python_configuration.url)
else:
raise ValueError("Unknown Python implementation")
log.step('Setting up build environment...')
env = os.environ.copy()
env['PATH'] = os.pathsep.join([
str(SYMLINKS_DIR),
@@ -156,7 +162,6 @@ def setup_python(python_configuration: PythonConfiguration,
if which_pip != '/tmp/cibw_bin/pip':
print("cibuildwheel: pip available on PATH doesn't match our installed instance. If you have modified PATH, ensure that you don't overwrite cibuildwheel's entry or insert pip above it.", file=sys.stderr)
exit(1)
call(['pip', 'install', '--upgrade', 'setuptools', 'wheel', 'delocate', *dependency_constraint_flags], env=env)
# Set MACOSX_DEPLOYMENT_TARGET to 10.9, if the user didn't set it.
# CPython 3.5 defaults to 10.6, and pypy defaults to 10.7, causing
@@ -170,6 +175,9 @@ def setup_python(python_configuration: PythonConfiguration,
# https://github.com/python/cpython/blob/a5ed2fe0eedefa1649aa93ee74a0bafc8e628a10/Lib/_osx_support.py#L260
env.setdefault('ARCHFLAGS', '-arch x86_64')
log.step('Installing build tools...')
call(['pip', 'install', '--upgrade', 'setuptools', 'wheel', 'delocate', *dependency_constraint_flags], env=env)
return env
@@ -178,102 +186,111 @@ def build(options: BuildOptions) -> None:
built_wheel_dir = temp_dir / 'built_wheel'
repaired_wheel_dir = temp_dir / 'repaired_wheel'
if options.before_all:
env = options.environment.as_dictionary(prev_environment=os.environ)
before_all_prepared = prepare_command(options.before_all, project='.', package=options.package_dir)
call([before_all_prepared], shell=True, env=env)
try:
if options.before_all:
log.step('Running before_all...')
env = options.environment.as_dictionary(prev_environment=os.environ)
before_all_prepared = prepare_command(options.before_all, project='.', package=options.package_dir)
call([before_all_prepared], shell=True, env=env)
python_configurations = get_python_configurations(options.build_selector)
python_configurations = get_python_configurations(options.build_selector)
for config in python_configurations:
dependency_constraint_flags: Sequence[Union[str, PathLike]] = []
if options.dependency_constraints:
dependency_constraint_flags = [
'-c', options.dependency_constraints.get_for_python_version(config.version)
]
for config in python_configurations:
log.build_start(config.identifier)
env = setup_python(config, dependency_constraint_flags, options.environment)
dependency_constraint_flags: Sequence[Union[str, PathLike]] = []
if options.dependency_constraints:
dependency_constraint_flags = [
'-c', options.dependency_constraints.get_for_python_version(config.version)
]
# run the before_build command
if options.before_build:
before_build_prepared = prepare_command(options.before_build, project='.', package=options.package_dir)
call(before_build_prepared, env=env, shell=True)
env = setup_python(config, dependency_constraint_flags, options.environment)
# build the wheel
if built_wheel_dir.exists():
shutil.rmtree(built_wheel_dir)
built_wheel_dir.mkdir(parents=True)
if options.before_build:
log.step('Running before_build...')
before_build_prepared = prepare_command(options.before_build, project='.', package=options.package_dir)
call(before_build_prepared, env=env, shell=True)
# Path.resolve() is needed. Without it pip wheel may try to fetch package from pypi.org
# see https://github.com/joerick/cibuildwheel/pull/369
call([
'pip', 'wheel',
options.package_dir.resolve(),
'-w', built_wheel_dir,
'--no-deps',
*get_build_verbosity_extra_flags(options.build_verbosity)
], env=env)
log.step('Building wheel...')
if built_wheel_dir.exists():
shutil.rmtree(built_wheel_dir)
built_wheel_dir.mkdir(parents=True)
built_wheel = next(built_wheel_dir.glob('*.whl'))
# Path.resolve() is needed. Without it pip wheel may try to fetch package from pypi.org
# see https://github.com/joerick/cibuildwheel/pull/369
call([
'pip', 'wheel',
options.package_dir.resolve(),
'-w', built_wheel_dir,
'--no-deps',
*get_build_verbosity_extra_flags(options.build_verbosity)
], env=env)
# repair the wheel
if repaired_wheel_dir.exists():
shutil.rmtree(repaired_wheel_dir)
repaired_wheel_dir.mkdir(parents=True)
built_wheel = next(built_wheel_dir.glob('*.whl'))
if built_wheel.name.endswith('none-any.whl'):
raise NonPlatformWheelError()
if repaired_wheel_dir.exists():
shutil.rmtree(repaired_wheel_dir)
repaired_wheel_dir.mkdir(parents=True)
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)
if built_wheel.name.endswith('none-any.whl'):
raise NonPlatformWheelError()
repaired_wheel = next(repaired_wheel_dir.glob('*.whl'))
if options.repair_command:
log.step('Repairing wheel...')
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)
if options.test_command:
# set up a virtual environment to install and test from, to make sure
# there are no dependencies that were pulled in at build time.
call(['pip', 'install', 'virtualenv', *dependency_constraint_flags], env=env)
venv_dir = Path(tempfile.mkdtemp())
repaired_wheel = next(repaired_wheel_dir.glob('*.whl'))
# Use --no-download to ensure determinism by using seed libraries
# built into virtualenv
call(['python', '-m', 'virtualenv', '--no-download', venv_dir], env=env)
if options.test_command:
log.step('Testing wheel...')
# set up a virtual environment to install and test from, to make sure
# there are no dependencies that were pulled in at build time.
call(['pip', 'install', 'virtualenv', *dependency_constraint_flags], env=env)
venv_dir = Path(tempfile.mkdtemp())
virtualenv_env = env.copy()
virtualenv_env['PATH'] = os.pathsep.join([
str(venv_dir / 'bin'),
virtualenv_env['PATH'],
])
# Use --no-download to ensure determinism by using seed libraries
# built into virtualenv
call(['python', '-m', 'virtualenv', '--no-download', venv_dir], env=env)
# check that we are using the Python from the virtual environment
call(['which', 'python'], env=virtualenv_env)
virtualenv_env = env.copy()
virtualenv_env['PATH'] = os.pathsep.join([
str(venv_dir / 'bin'),
virtualenv_env['PATH'],
])
if options.before_test:
before_test_prepared = prepare_command(options.before_test, project='.', package=options.package_dir)
call(before_test_prepared, env=virtualenv_env, shell=True)
# check that we are using the Python from the virtual environment
call(['which', 'python'], env=virtualenv_env)
# install the wheel
call(['pip', 'install', str(repaired_wheel) + options.test_extras], env=virtualenv_env)
if options.before_test:
before_test_prepared = prepare_command(options.before_test, project='.', package=options.package_dir)
call(before_test_prepared, env=virtualenv_env, shell=True)
# test the wheel
if options.test_requires:
call(['pip', 'install'] + options.test_requires, env=virtualenv_env)
# install the wheel
call(['pip', 'install', str(repaired_wheel) + options.test_extras], env=virtualenv_env)
# run the tests from $HOME, with an absolute path in the command
# (this ensures that Python runs the tests against the installed wheel
# and not the repo code)
test_command_prepared = prepare_command(
options.test_command,
project=Path('.').resolve(),
package=options.package_dir.resolve()
)
call(test_command_prepared, cwd=os.environ['HOME'], env=virtualenv_env, shell=True)
# test the wheel
if options.test_requires:
call(['pip', 'install'] + options.test_requires, env=virtualenv_env)
# clean up
shutil.rmtree(venv_dir)
# run the tests from $HOME, with an absolute path in the command
# (this ensures that Python runs the tests against the installed wheel
# and not the repo code)
test_command_prepared = prepare_command(
options.test_command,
project=Path('.').resolve(),
package=options.package_dir.resolve()
)
call(test_command_prepared, cwd=os.environ['HOME'], env=virtualenv_env, shell=True)
# we're all done here; move it to output (overwrite existing)
shutil.move(str(repaired_wheel), options.output_dir)
# clean up
shutil.rmtree(venv_dir)
# we're all done here; move it to output (overwrite existing)
shutil.move(str(repaired_wheel), options.output_dir)
log.build_end()
except subprocess.CalledProcessError as error:
log.error(f'Command {error.cmd} failed with code {error.returncode}. {error.stdout}')
exit(1)
@@ -10,17 +10,17 @@ 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==2.0.0 # via virtualenv
importlib-resources==3.0.0 # via virtualenv
importlib-metadata==2.1.0 # via virtualenv
importlib-resources==3.3.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.3 # via importlib-resources
virtualenv==20.0.33 # via -r cibuildwheel/resources/constraints.in
virtualenv==20.2.1 # 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.2.3 # via -r cibuildwheel/resources/constraints.in
pip==20.2.4 # via -r cibuildwheel/resources/constraints.in
setuptools==44.1.1 # via -r cibuildwheel/resources/constraints.in
@@ -8,13 +8,13 @@ appdirs==1.4.4 # 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==2.0.0 # via virtualenv
importlib-resources==3.0.0 # via virtualenv
importlib-metadata==2.1.0 # via virtualenv
importlib-resources==3.2.1 # via virtualenv
six==1.15.0 # via virtualenv
virtualenv==20.0.33 # via -r cibuildwheel/resources/constraints.in
virtualenv==20.2.1 # 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.2.3 # via -r cibuildwheel/resources/constraints.in
setuptools==50.3.0 # via -r cibuildwheel/resources/constraints.in
pip==20.2.4 # via -r cibuildwheel/resources/constraints.in
setuptools==50.3.2 # via -r cibuildwheel/resources/constraints.in
@@ -8,13 +8,13 @@ appdirs==1.4.4 # 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==2.0.0 # via virtualenv
importlib-resources==3.0.0 # via virtualenv
importlib-metadata==3.1.0 # via virtualenv
importlib-resources==3.3.0 # via virtualenv
six==1.15.0 # via virtualenv
virtualenv==20.0.33 # via -r cibuildwheel/resources/constraints.in
virtualenv==20.2.1 # via -r cibuildwheel/resources/constraints.in
wheel==0.35.1 # via -r cibuildwheel/resources/constraints.in, delocate
zipp==3.3.0 # via importlib-metadata, importlib-resources
zipp==3.4.0 # via importlib-metadata, importlib-resources
# The following packages are considered to be unsafe in a requirements file:
pip==20.2.3 # via -r cibuildwheel/resources/constraints.in
setuptools==50.3.0 # via -r cibuildwheel/resources/constraints.in
pip==20.2.4 # via -r cibuildwheel/resources/constraints.in
setuptools==50.3.2 # via -r cibuildwheel/resources/constraints.in
@@ -8,12 +8,12 @@ appdirs==1.4.4 # 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==2.0.0 # via virtualenv
importlib-metadata==3.1.0 # via virtualenv
six==1.15.0 # via virtualenv
virtualenv==20.0.33 # via -r cibuildwheel/resources/constraints.in
virtualenv==20.2.1 # via -r cibuildwheel/resources/constraints.in
wheel==0.35.1 # via -r cibuildwheel/resources/constraints.in, delocate
zipp==3.3.0 # via importlib-metadata
zipp==3.4.0 # via importlib-metadata
# The following packages are considered to be unsafe in a requirements file:
pip==20.2.3 # via -r cibuildwheel/resources/constraints.in
setuptools==50.3.0 # via -r cibuildwheel/resources/constraints.in
pip==20.2.4 # via -r cibuildwheel/resources/constraints.in
setuptools==50.3.2 # via -r cibuildwheel/resources/constraints.in
+3 -3
View File
@@ -9,9 +9,9 @@ delocate==0.8.2 # via -r cibuildwheel/resources/constraints.in
distlib==0.3.1 # via virtualenv
filelock==3.0.12 # via virtualenv
six==1.15.0 # via virtualenv
virtualenv==20.0.33 # via -r cibuildwheel/resources/constraints.in
virtualenv==20.2.1 # via -r cibuildwheel/resources/constraints.in
wheel==0.35.1 # via -r cibuildwheel/resources/constraints.in, delocate
# The following packages are considered to be unsafe in a requirements file:
pip==20.2.3 # via -r cibuildwheel/resources/constraints.in
setuptools==50.3.0 # via -r cibuildwheel/resources/constraints.in
pip==20.2.4 # via -r cibuildwheel/resources/constraints.in
setuptools==50.3.2 # via -r cibuildwheel/resources/constraints.in
+11 -10
View File
@@ -1,21 +1,22 @@
[x86_64]
manylinux1 = quay.io/pypa/manylinux1_x86_64:2020-10-06-c4a4a7c
manylinux2010 = quay.io/pypa/manylinux2010_x86_64:2020-10-06-786a931
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2020-10-06-b2ca7a1
manylinux1 = quay.io/pypa/manylinux1_x86_64:2020-11-11-0f1f128
manylinux2010 = quay.io/pypa/manylinux2010_x86_64:2020-11-11-201fb79
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2020-11-11-bc8ce45
[i686]
manylinux1 = quay.io/pypa/manylinux1_i686:2020-10-06-c4a4a7c
manylinux2010 = quay.io/pypa/manylinux2010_i686:2020-10-06-786a931
manylinux2014 = quay.io/pypa/manylinux2014_i686:2020-10-06-b2ca7a1
manylinux1 = quay.io/pypa/manylinux1_i686:2020-11-11-0f1f128
manylinux2010 = quay.io/pypa/manylinux2010_i686:2020-11-11-201fb79
manylinux2014 = quay.io/pypa/manylinux2014_i686:2020-11-11-bc8ce45
[pypy_x86_64]
manylinux2010 = pypywheels/manylinux2010-pypy_x86_64:2020-09-26-8f210b5
manylinux2010 = pypywheels/manylinux2010-pypy_x86_64:2020-11-21-a03b9e9
[aarch64]
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2020-10-06-b2ca7a1
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2020-11-11-bc8ce45
[ppc64le]
manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2020-10-06-b2ca7a1
manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2020-11-11-bc8ce45
[s390x]
manylinux2014 = quay.io/pypa/manylinux2014_s390x:2020-10-06-b2ca7a1
manylinux2014 = quay.io/pypa/manylinux2014_s390x:2020-11-11-bc8ce45
+50 -5
View File
@@ -1,12 +1,15 @@
import os
import ssl
import textwrap
import urllib.request
from enum import Enum
from fnmatch import fnmatch
from pathlib import Path
from time import sleep
from typing import Dict, List, NamedTuple, Optional, Union
import certifi
from .environment import ParsedEnvironment
@@ -40,7 +43,10 @@ class BuildSelector:
return match_any(self.build_patterns) and not match_any(self.skip_patterns)
def __repr__(self) -> str:
return f'BuildSelector({" ".join(self.build_patterns)!r} - {" ".join(self.skip_patterns)!r})'
if not self.skip_patterns:
return f'BuildSelector({" ".join(self.build_patterns)!r})'
else:
return f'BuildSelector({" ".join(self.build_patterns)!r} - {" ".join(self.skip_patterns)!r})'
# Taken from https://stackoverflow.com/a/107717
@@ -66,10 +72,14 @@ def download(url: str, dest: Path) -> None:
if not dest_dir.exists():
dest_dir.mkdir(parents=True)
# we've had issues when relying on the host OS' CA certificates on Windows,
# so we use certifi (this sounds odd but requests also does this by default)
cafile = os.environ.get('SSL_CERT_FILE', certifi.where())
context = ssl.create_default_context(cafile=cafile)
repeat_num = 3
for i in range(repeat_num):
try:
response = urllib.request.urlopen(url)
response = urllib.request.urlopen(url, context=context)
except Exception:
if i == repeat_num - 1:
raise
@@ -107,8 +117,8 @@ class DependencyConstraints:
else:
return self.base_file_path
def __str__(self):
return f"File '{self.base_file_path}'"
def __repr__(self):
return f'{self.__class__.__name__}{self.base_file_path!r})'
class BuildOptions(NamedTuple):
@@ -146,3 +156,38 @@ class NonPlatformWheelError(Exception):
''')
super().__init__(message)
def strtobool(val: str) -> bool:
if val.lower() in ('y', 'yes', 't', 'true', 'on', '1'):
return True
return False
class CIProvider(str, Enum):
travis_ci = 'travis'
appveyor = 'appveyor'
circle_ci = 'circle_ci'
azure_pipelines = 'azure_pipelines'
github_actions = 'github_actions'
gitlab = 'gitlab'
other = 'other'
def detect_ci_provider() -> Optional[CIProvider]:
if 'TRAVIS' in os.environ:
return CIProvider.travis_ci
elif 'APPVEYOR' in os.environ:
return CIProvider.appveyor
elif 'CIRCLECI' in os.environ:
return CIProvider.circle_ci
elif 'AZURE_HTTP_USER_AGENT' in os.environ:
return CIProvider.azure_pipelines
elif 'GITHUB_ACTIONS' in os.environ:
return CIProvider.github_actions
elif 'GITLAB_CI' in os.environ:
return CIProvider.gitlab
elif strtobool(os.environ.get('CI', 'false')):
return CIProvider.other
else:
return None
+118 -100
View File
@@ -7,11 +7,13 @@ from os import PathLike
from pathlib import Path
from typing import Dict, List, NamedTuple, Optional, Sequence, Union
from zipfile import ZipFile
import toml
from .environment import ParsedEnvironment
from .util import (BuildOptions, BuildSelector, NonPlatformWheelError, download,
get_build_verbosity_extra_flags, get_pip_script,
from .logger import log
from .util import (BuildOptions, BuildSelector, NonPlatformWheelError,
download, get_build_verbosity_extra_flags, get_pip_script,
prepare_command)
IS_RUNNING_ON_AZURE = Path('C:\\hostedtoolcache').exists()
@@ -61,9 +63,9 @@ def get_python_configurations(build_selector: BuildSelector) -> List[PythonConfi
PythonConfiguration(version='3.9.0', arch='32', identifier='cp39-win32', url=None),
PythonConfiguration(version='3.9.0', 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.2-win32.zip'),
PythonConfiguration(version='3.6', arch='32', identifier='pp36-win32', url='https://downloads.python.org/pypy/pypy3.6-v7.3.2-win32.zip'),
PythonConfiguration(version='3.7', arch='32', identifier='pp37-win32', url='https://downloads.python.org/pypy/pypy3.7-v7.3.2-win32.zip'),
PythonConfiguration(version='2.7', arch='32', identifier='pp27-win32', url='https://downloads.python.org/pypy/pypy2.7-v7.3.3-win32.zip'),
PythonConfiguration(version='3.6', arch='32', identifier='pp36-win32', url='https://downloads.python.org/pypy/pypy3.6-v7.3.3-win32.zip'),
PythonConfiguration(version='3.7', arch='32', identifier='pp37-win32', url='https://downloads.python.org/pypy/pypy3.7-v7.3.3-win32.zip'),
]
if IS_RUNNING_ON_TRAVIS:
@@ -109,11 +111,15 @@ def install_pypy(version: str, arch: str, url: str) -> Path:
def setup_python(python_configuration: PythonConfiguration, dependency_constraint_flags: Sequence[Union[str, PathLike]], environment: ParsedEnvironment) -> Dict[str, str]:
nuget = Path('C:\\cibw\\nuget.exe')
if not nuget.exists():
log.step('Downloading nuget...')
download('https://dist.nuget.org/win-x86-commandline/latest/nuget.exe', nuget)
if python_configuration.identifier.startswith('cp'):
implementation_id = python_configuration.identifier.split("-")[0]
log.step(f'Installing Python {implementation_id}...')
if implementation_id.startswith('cp'):
installation_path = install_cpython(python_configuration.version, python_configuration.arch, nuget)
elif python_configuration.identifier.startswith('pp'):
elif implementation_id.startswith('pp'):
assert python_configuration.url is not None
installation_path = install_pypy(python_configuration.version, python_configuration.arch, python_configuration.url)
else:
@@ -121,6 +127,8 @@ def setup_python(python_configuration: PythonConfiguration, dependency_constrain
assert (installation_path / 'python.exe').exists()
log.step('Setting up build environment...')
# set up PATH and environment variables for run_with_env
env = os.environ.copy()
env['PYTHON_VERSION'] = python_configuration.version
@@ -151,7 +159,8 @@ def setup_python(python_configuration: PythonConfiguration, dependency_constrain
print("cibuildwheel: pip available on PATH doesn't match our installed instance. If you have modified PATH, ensure that you don't overwrite cibuildwheel's entry or insert pip above it.", file=sys.stderr)
exit(1)
# prepare the Python environment
log.step('Installing build tools...')
call(['python', '-m', 'pip', 'install', '--upgrade', 'pip', *dependency_constraint_flags], env=env)
call(['pip', '--version'], env=env)
call(['pip', 'install', '--upgrade', 'setuptools', 'wheel', *dependency_constraint_flags], env=env)
@@ -182,6 +191,7 @@ def pep_518_cp35_workaround(package_dir: Path, env: Dict[str, str]) -> None:
)
if requirements:
log.step('Performing PEP518 workaround...')
with tempfile.TemporaryDirectory() as d:
reqfile = Path(d) / "requirements.txt"
with reqfile.open("w") as f:
@@ -195,114 +205,122 @@ def build(options: BuildOptions) -> None:
built_wheel_dir = temp_dir / 'built_wheel'
repaired_wheel_dir = temp_dir / 'repaired_wheel'
# install nuget as best way to provide python
nuget = Path('C:\\cibw\\nuget.exe')
download('https://dist.nuget.org/win-x86-commandline/latest/nuget.exe', nuget)
try:
if options.before_all:
log.step('Running before_all...')
env = options.environment.as_dictionary(prev_environment=os.environ)
before_all_prepared = prepare_command(options.before_all, project='.', package=options.package_dir)
shell(before_all_prepared, env=env)
if options.before_all:
env = options.environment.as_dictionary(prev_environment=os.environ)
before_all_prepared = prepare_command(options.before_all, project='.', package=options.package_dir)
shell(before_all_prepared, env=env)
python_configurations = get_python_configurations(options.build_selector)
python_configurations = get_python_configurations(options.build_selector)
for config in python_configurations:
dependency_constraint_flags: Sequence[Union[str, PathLike]] = []
if options.dependency_constraints:
dependency_constraint_flags = [
'-c', options.dependency_constraints.get_for_python_version(config.version)
]
for config in python_configurations:
log.build_start(config.identifier)
# install Python
env = setup_python(config, dependency_constraint_flags, options.environment)
dependency_constraint_flags: Sequence[Union[str, PathLike]] = []
if options.dependency_constraints:
dependency_constraint_flags = [
'-c', options.dependency_constraints.get_for_python_version(config.version)
]
# run the before_build command
if options.before_build:
before_build_prepared = prepare_command(options.before_build, project='.', package=options.package_dir)
shell(before_build_prepared, env=env)
# install Python
env = setup_python(config, dependency_constraint_flags, options.environment)
# activate the PEP 518 patch if on Windows Python 3.5
# (will only have an effect if PEP 517 builds are used):
if config.version.startswith('3.5'):
pep_518_cp35_workaround(options.package_dir, env)
# run the before_build command
if options.before_build:
log.step('Running before_build...')
before_build_prepared = prepare_command(options.before_build, project='.', package=options.package_dir)
shell(before_build_prepared, env=env)
# build the wheel
if built_wheel_dir.exists():
shutil.rmtree(built_wheel_dir)
built_wheel_dir.mkdir(parents=True)
# Path.resolve() is needed. Without it pip wheel may try to fetch package from pypi.org
# see https://github.com/joerick/cibuildwheel/pull/369
call([
'pip', 'wheel',
options.package_dir.resolve(),
'-w', built_wheel_dir,
'--no-deps',
*get_build_verbosity_extra_flags(options.build_verbosity)
], env=env)
# activate the PEP 518 patch if on Windows Python 3.5
# (will only have an effect if PEP 517 builds are used):
if config.version.startswith('3.5'):
pep_518_cp35_workaround(options.package_dir, env)
built_wheel = next(built_wheel_dir.glob('*.whl'))
log.step('Building wheel...')
if built_wheel_dir.exists():
shutil.rmtree(built_wheel_dir)
built_wheel_dir.mkdir(parents=True)
# Path.resolve() is needed. Without it pip wheel may try to fetch package from pypi.org
# see https://github.com/joerick/cibuildwheel/pull/369
call([
'pip', 'wheel',
options.package_dir.resolve(),
'-w', built_wheel_dir,
'--no-deps',
*get_build_verbosity_extra_flags(options.build_verbosity)
], env=env)
# repair the wheel
if repaired_wheel_dir.exists():
shutil.rmtree(repaired_wheel_dir)
repaired_wheel_dir.mkdir(parents=True)
built_wheel = next(built_wheel_dir.glob('*.whl'))
if built_wheel.name.endswith('none-any.whl'):
raise NonPlatformWheelError()
# repair the wheel
if repaired_wheel_dir.exists():
shutil.rmtree(repaired_wheel_dir)
repaired_wheel_dir.mkdir(parents=True)
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)
if built_wheel.name.endswith('none-any.whl'):
raise NonPlatformWheelError()
repaired_wheel = next(repaired_wheel_dir.glob('*.whl'))
if options.repair_command:
log.step('Repairing wheel...')
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)
if options.test_command:
# set up a virtual environment to install and test from, to make sure
# there are no dependencies that were pulled in at build time.
call(['pip', 'install', 'virtualenv', *dependency_constraint_flags], env=env)
venv_dir = Path(tempfile.mkdtemp())
repaired_wheel = next(repaired_wheel_dir.glob('*.whl'))
# Use --no-download to ensure determinism by using seed libraries
# built into virtualenv
call(['python', '-m', 'virtualenv', '--no-download', venv_dir], env=env)
if options.test_command:
log.step('Testing wheel...')
# set up a virtual environment to install and test from, to make sure
# there are no dependencies that were pulled in at build time.
call(['pip', 'install', 'virtualenv', *dependency_constraint_flags], env=env)
venv_dir = Path(tempfile.mkdtemp())
virtualenv_env = env.copy()
virtualenv_env['PATH'] = os.pathsep.join([
str(venv_dir / 'Scripts'),
virtualenv_env['PATH'],
])
# Use --no-download to ensure determinism by using seed libraries
# built into virtualenv
call(['python', '-m', 'virtualenv', '--no-download', venv_dir], env=env)
# check that we are using the Python from the virtual environment
call(['which', 'python'], env=virtualenv_env)
virtualenv_env = env.copy()
virtualenv_env['PATH'] = os.pathsep.join([
str(venv_dir / 'Scripts'),
virtualenv_env['PATH'],
])
if options.before_test:
before_test_prepared = prepare_command(
options.before_test,
project='.',
package=options.package_dir
# check that we are using the Python from the virtual environment
call(['which', 'python'], env=virtualenv_env)
if options.before_test:
before_test_prepared = prepare_command(
options.before_test,
project='.',
package=options.package_dir
)
shell(before_test_prepared, env=virtualenv_env)
# install the wheel
call(['pip', 'install', str(repaired_wheel) + options.test_extras], env=virtualenv_env)
# test the wheel
if options.test_requires:
call(['pip', 'install'] + options.test_requires, env=virtualenv_env)
# run the tests from c:\, with an absolute path in the command
# (this ensures that Python runs the tests against the installed wheel
# and not the repo code)
test_command_prepared = prepare_command(
options.test_command,
project=Path('.').resolve(),
package=options.package_dir.resolve()
)
shell(before_test_prepared, env=virtualenv_env)
shell(test_command_prepared, cwd='c:\\', env=virtualenv_env)
# install the wheel
call(['pip', 'install', str(repaired_wheel) + options.test_extras], env=virtualenv_env)
# clean up
shutil.rmtree(venv_dir)
# test the wheel
if options.test_requires:
call(['pip', 'install'] + options.test_requires, env=virtualenv_env)
# run the tests from c:\, with an absolute path in the command
# (this ensures that Python runs the tests against the installed wheel
# and not the repo code)
test_command_prepared = prepare_command(
options.test_command,
project=Path('.').resolve(),
package=options.package_dir.resolve()
)
shell(test_command_prepared, cwd='c:\\', env=virtualenv_env)
# clean up
shutil.rmtree(venv_dir)
# we're all done here; move it to output (remove if already exists)
shutil.move(str(repaired_wheel), options.output_dir)
# we're all done here; move it to output (remove if already exists)
shutil.move(str(repaired_wheel), options.output_dir)
log.build_end()
except subprocess.CalledProcessError as error:
log.error(f'Command {error.cmd} failed with code {error.returncode}. {error.stdout}')
exit(1)
+3 -3
View File
@@ -87,9 +87,9 @@ When setting the options, you can use shell-style globbing syntax (as per [`fnma
| Python 3.7 | cp37-macosx_x86_64 | cp37-manylinux_x86_64 | cp37-manylinux_i686 | cp37-win_amd64 | cp37-win32 | cp37-manylinux_aarch64 | cp37-manylinux_ppc64le | cp37-manylinux_s390x |
| Python 3.8 | cp38-macosx_x86_64 | cp38-manylinux_x86_64 | cp38-manylinux_i686 | cp38-win_amd64 | cp38-win32 | cp38-manylinux_aarch64 | cp38-manylinux_ppc64le | cp38-manylinux_s390x |
| Python 3.9 | cp39-macosx_x86_64 | cp39-manylinux_x86_64 | cp39-manylinux_i686 | cp39-win_amd64 | cp39-win32 | cp39-manylinux_aarch64 | cp39-manylinux_ppc64le | cp39-manylinux_s390x |
| PyPy 2.7 v7.3.2 | pp27-macosx_x86_64 | pp27-manylinux_x86_64 | | | pp27-win32 | | | |
| PyPy 3.6 v7.3.2 | pp36-macosx_x86_64 | pp36-manylinux_x86_64 | | | pp36-win32 | | | |
| PyPy 3.7 (alpha) v7.3.2 | pp37-macosx_x86_64 | pp37-manylinux_x86_64 | | | pp37-win32 | | | |
| PyPy 2.7 v7.3.3 | pp27-macosx_x86_64 | pp27-manylinux_x86_64 | | | pp27-win32 | | | |
| PyPy 3.6 v7.3.3 | pp36-macosx_x86_64 | pp36-manylinux_x86_64 | | | pp36-win32 | | | |
| PyPy 3.7 (beta) v7.3.3 | pp37-macosx_x86_64 | pp37-manylinux_x86_64 | | | pp37-win32 | | | |
The list of supported and currently selected build identifiers can also be retrieved by passing the `--print-build-identifiers` flag to `cibuildwheel`.
+1 -1
View File
@@ -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.6.3
install: python -m pip install cibuildwheel==1.7.0
build_script: python -m cibuildwheel --output-dir wheelhouse
+16 -7
View File
@@ -4,9 +4,12 @@ jobs:
steps:
- task: UsePythonVersion@0
- bash: |
set -o errexit
python3 -m pip install --upgrade pip
pip3 install cibuildwheel==1.6.3
cibuildwheel --output-dir wheelhouse .
pip3 install cibuildwheel==1.7.0
displayName: Install dependencies
- bash: cibuildwheel --output-dir wheelhouse .
displayName: Build wheels
- task: PublishBuildArtifacts@1
inputs: {pathtoPublish: 'wheelhouse'}
@@ -15,11 +18,14 @@ jobs:
steps:
- task: UsePythonVersion@0
- bash: |
set -o errexit
python3 -m pip install --upgrade pip
pip3 install cibuildwheel==1.6.3
cibuildwheel --output-dir wheelhouse .
python3 -m pip install cibuildwheel==1.7.0
displayName: Install dependencies
- bash: cibuildwheel --output-dir wheelhouse .
displayName: Build wheels
- task: PublishBuildArtifacts@1
inputs: {pathtoPublish: 'wheelhouse'}
inputs: {pathtoPublish: wheelhouse}
- job: windows
pool: {vmImage: 'vs2017-win2016'}
@@ -28,8 +34,11 @@ jobs:
- script: choco install vcpython27 -f -y
displayName: Install Visual C++ for Python 2.7
- bash: |
set -o errexit
python -m pip install --upgrade pip
pip install cibuildwheel==1.6.3
cibuildwheel --output-dir wheelhouse .
pip install cibuildwheel==1.7.0
displayName: Install dependencies
- bash: cibuildwheel --output-dir wheelhouse .
displayName: Build wheels
- task: PublishBuildArtifacts@1
inputs: {pathtoPublish: 'wheelhouse'}
+3 -4
View File
@@ -11,7 +11,7 @@ jobs:
- run:
name: Build the Linux wheels.
command: |
pip3 install --user cibuildwheel==1.6.3
pip3 install --user cibuildwheel==1.7.0
cibuildwheel --output-dir wheelhouse
- store_artifacts:
path: wheelhouse/
@@ -19,14 +19,13 @@ jobs:
osx-wheels:
working_directory: ~/osx-wheels
macos:
# PyPy 7.3.2 needs macOS >= 10.14
xcode: 10.2.1
xcode: 10.0.0
steps:
- checkout
- run:
name: Build the OS X wheels.
command: |
pip3 install cibuildwheel==1.6.3
pip3 install cibuildwheel==1.7.0
cibuildwheel --output-dir wheelhouse
- store_artifacts:
path: wheelhouse/
+1 -1
View File
@@ -28,7 +28,7 @@ jobs:
- name: Install cibuildwheel
run: |
python -m pip install cibuildwheel==1.6.3
python -m pip install cibuildwheel==1.7.0
- name: Install Visual C++ for Python 2.7
if: runner.os == 'Windows'
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
- name: Install cibuildwheel
run: |
python -m pip install cibuildwheel==1.6.3
python -m pip install cibuildwheel==1.7.0
- name: Install Visual C++ for Python 2.7
if: runner.os == 'Windows'
+1 -3
View File
@@ -9,8 +9,6 @@ jobs:
- services: docker
# and a mac build
- os: osx
# PyPy 7.3.2 needs macOS >= 10.14
osx_image: xcode10.2
language: shell
# and a windows build
- os: windows
@@ -27,7 +25,7 @@ env:
# Note: TWINE_PASSWORD is set to a PyPI API token in Travis settings
install:
- python3 -m pip install cibuildwheel==1.6.3
- python3 -m pip install cibuildwheel==1.7.0
script:
# build the wheels, put them into './wheelhouse'
+1 -3
View File
@@ -15,8 +15,6 @@ jobs:
arch: s390x
# and a mac build
- os: osx
# PyPy 7.3.2 needs macOS >= 10.14
osx_image: xcode10.2
language: shell
# and a windows build
- os: windows
@@ -28,7 +26,7 @@ jobs:
- ln -s /c/Python38/python.exe /c/Python38/python3.exe
install:
- python3 -m pip install cibuildwheel==1.6.3
- python3 -m pip install cibuildwheel==1.7.0
script:
# build the wheels, put them into './wheelhouse'
+3 -5
View File
@@ -55,7 +55,7 @@ jobs:
- stage: deploy
name: Build and deploy Linux wheels
services: docker
install: python3 -m pip install cibuildwheel==1.6.3
install: python3 -m pip install cibuildwheel==1.7.0
script: python3 -m cibuildwheel --output-dir wheelhouse
after_success: |
python3 -m pip install twine
@@ -64,10 +64,8 @@ jobs:
- stage: deploy
name: Build and deploy macOS wheels
os: osx
# PyPy 7.3.2 needs macOS >= 10.14
osx_image: xcode10.2
language: shell
install: python3 -m pip install cibuildwheel==1.6.3
install: python3 -m pip install cibuildwheel==1.7.0
script: python3 -m cibuildwheel --output-dir wheelhouse
after_success: |
python3 -m pip install twine
@@ -77,7 +75,7 @@ jobs:
name: Build and deploy Windows wheels
os: windows
language: shell
install: python3 -m pip install cibuildwheel==1.6.3
install: python3 -m pip install cibuildwheel==1.7.0
script: python3 -m cibuildwheel --output-dir wheelhouse
after_success: |
python3 -m pip install twine
+2 -2
View File
@@ -11,8 +11,8 @@ long_description = (this_directory / 'README.md').read_text(encoding='utf-8')
setup(
name='cibuildwheel',
version='1.6.3',
install_requires=['bashlex!=0.13', 'toml'],
version='1.7.0',
install_requires=['bashlex!=0.13', 'toml', 'certifi'],
description="Build Python wheels on CI with minimal configuration.",
long_description=long_description,
long_description_content_type='text/markdown',
+21 -3
View File
@@ -1,7 +1,9 @@
import textwrap
import platform
from . import test_projects
from . import utils
import textwrap
import pytest
from cibuildwheel.logger import Logger
from . import test_projects, utils
basic_project = test_projects.new_c_project(
setup_py_add=textwrap.dedent('''
@@ -25,6 +27,22 @@ def test(tmp_path):
assert set(actual_wheels) == set(expected_wheels)
@pytest.mark.skip(reason='to keep test output clean')
def test_sample_build(tmp_path, capfd):
project_dir = tmp_path / 'project'
basic_project.generate(project_dir)
# build the wheels, and let the output passthrough to the caller, so
# we can see how it looks
with capfd.disabled():
logger = Logger()
logger.step('test_sample_build')
try:
utils.cibuildwheel_run(project_dir)
finally:
logger.step_end()
def test_build_identifiers(tmp_path):
project_dir = tmp_path / 'project'
basic_project.generate(project_dir)
+3 -1
View File
@@ -26,10 +26,12 @@ def test(tmp_path):
print("dummy text", file=ff)
# build the wheels
before_all_command = '''python -c "import os;open('{project}/text_info.txt', 'w').write('sample text '+os.environ.get('TEST_VAL', ''))"'''
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_ALL': '''python -c "import os;open('{project}/text_info.txt', 'w').write('sample text '+os.environ.get('TEST_VAL', ''))"''',
'CIBW_BEFORE_ALL': before_all_command,
'CIBW_BEFORE_ALL_LINUX': before_all_command + ''' && python -c "import sys; assert sys.version_info >= (3, 6)"''',
'CIBW_ENVIRONMENT': "TEST_VAL='123'"
})
+14 -7
View File
@@ -11,27 +11,34 @@ def main():
prog="python -m test.test_projects",
description='Generate a test project to check it out'
)
parser.add_argument('--open', action='store_true', help='''
Open the generated project in a file explorer
''')
parser.add_argument('PROJECT', help='''
Python path to a project object. E.g. test.test_0_basic.basic_project
''')
parser.add_argument('OUTPUT', nargs='?', help='''
Path to output dir. If no dir is passed, a tempdir will be generated.
''')
options = parser.parse_args()
module, _, name = options.PROJECT.rpartition('.')
project = getattr(importlib.import_module(module), name)
project_dir = Path(tempfile.mkdtemp())
project_dir = Path(options.OUTPUT or tempfile.mkdtemp())
project.generate(project_dir)
print('Project generated at', project_dir)
print()
if sys.platform == 'darwin':
subprocess.check_call(['open', '--', project_dir])
elif sys.platform == 'linux2':
subprocess.check_call(['xdg-open', '--', project_dir])
elif sys.platform == 'win32':
subprocess.check_call(['explorer', project_dir])
if options.open:
if sys.platform == 'darwin':
subprocess.check_call(['open', '--', project_dir])
elif sys.platform == 'linux2':
subprocess.check_call(['xdg-open', '--', project_dir])
elif sys.platform == 'win32':
subprocess.check_call(['explorer', project_dir])
if __name__ == '__main__':
+13 -2
View File
@@ -103,15 +103,26 @@ def test_extras_require(tmp_path):
assert set(actual_wheels) == set(expected_wheels)
project_with_a_failing_test = test_projects.new_c_project()
project_with_a_failing_test.files['test/spam_test.py'] = r'''
from unittest import TestCase
class TestSpam(TestCase):
def test_something(self):
self.fail('this test is supposed to fail')
'''
def test_failing_test(tmp_path):
"""Ensure a failing test causes cibuildwheel to error out and exit"""
project_dir = tmp_path / 'project'
output_dir = tmp_path / 'output'
project_with_a_test.generate(project_dir)
project_with_a_failing_test.generate(project_dir)
with pytest.raises(subprocess.CalledProcessError):
utils.cibuildwheel_run(project_dir, output_dir=output_dir, add_env={
'CIBW_TEST_COMMAND': 'false',
'CIBW_TEST_REQUIRES': 'nose',
'CIBW_TEST_COMMAND': 'nosetests {project}/test',
# manylinux1 has a version of bash that's been shown to have
# problems with this, so let's check that.
'CIBW_MANYLINUX_I686_IMAGE': 'manylinux1',
+31
View File
@@ -0,0 +1,31 @@
import certifi
import pytest
import ssl
from cibuildwheel.util import download
DOWNLOAD_URL = 'https://raw.githubusercontent.com/joerick/cibuildwheel/v1.6.3/requirements-dev.txt'
def test_download(monkeypatch, tmp_path):
monkeypatch.delenv('SSL_CERT_FILE', raising=False)
dest = tmp_path / 'file.txt'
download(DOWNLOAD_URL, dest)
assert len(dest.read_bytes()) == 134
def test_download_good_ssl_cert_file(monkeypatch, tmp_path):
monkeypatch.setenv('SSL_CERT_FILE', certifi.where())
dest = tmp_path / 'file.txt'
download(DOWNLOAD_URL, dest)
assert len(dest.read_bytes()) == 134
def test_download_bad_ssl_cert_file(monkeypatch, tmp_path):
bad_cafile = tmp_path / 'ca.pem'
bad_cafile.write_text('bad certificates')
monkeypatch.setenv('SSL_CERT_FILE', str(bad_cafile))
dest = tmp_path / 'file.txt'
with pytest.raises(ssl.SSLError):
download(DOWNLOAD_URL, dest)
+5 -1
View File
@@ -11,7 +11,11 @@ def test_unknown_platform_non_ci(monkeypatch, capsys):
monkeypatch.delenv('CI', raising=False)
monkeypatch.delenv('BITRISE_BUILD_NUMBER', raising=False)
monkeypatch.delenv('AZURE_HTTP_USER_AGENT', raising=False)
monkeypatch.delenv('GITHUB_WORKFLOW', raising=False)
monkeypatch.delenv('TRAVIS', raising=False)
monkeypatch.delenv('APPVEYOR', raising=False)
monkeypatch.delenv('GITHUB_ACTIONS', raising=False)
monkeypatch.delenv('GITLAB_CI', raising=False)
monkeypatch.delenv('CIRCLECI', raising=False)
monkeypatch.delenv('CIBW_PLATFORM', raising=False)
with pytest.raises(SystemExit) as exit: