Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d93547d8be | ||
|
|
a863e21b14 | ||
|
|
b4c0150d43 | ||
|
|
c8019dac1d | ||
|
|
e6fa70a910 | ||
|
|
b19e8b76f3 | ||
|
|
23ab1f780e | ||
|
|
eedcd62753 | ||
|
|
3a4d611da1 | ||
|
|
8877990ec6 | ||
|
|
0cc41fabba | ||
|
|
8d9d970874 | ||
|
|
c563bca054 | ||
|
|
71503b7143 | ||
|
|
e33b6bed77 | ||
|
|
99469087ed | ||
|
|
3b847ab0aa | ||
|
|
7f51b1d8e7 | ||
|
|
7f77aa86b1 | ||
|
|
47873a9175 | ||
|
|
c38a33381d | ||
|
|
121f7cc678 | ||
|
|
d6361c0e31 | ||
|
|
ffb48a61cb | ||
|
|
d16c63ad95 | ||
|
|
d16d81e207 | ||
|
|
e5c7bb416d | ||
|
|
a85b535d83 | ||
|
|
9013a7783f | ||
|
|
08194a1db9 | ||
|
|
a9e05a596a | ||
|
|
e40f9b2345 | ||
|
|
65dccc46b2 | ||
|
|
d247743713 | ||
|
|
4e0b3c0f31 | ||
|
|
6bbef964c9 | ||
|
|
ede818944e | ||
|
|
9c73dd2ac7 | ||
|
|
5f7c019392 | ||
|
|
cd9eeb72e5 | ||
|
|
d075c731b6 | ||
|
|
8fa41df67d | ||
|
|
0e849c2bcf | ||
|
|
212fa34d9d | ||
|
|
cb73b18bce | ||
|
|
1730d6fd0b | ||
|
|
1e9067272d | ||
|
|
b0afaf33c2 | ||
|
|
d0e5a4bb3c | ||
|
|
4dc8bf447f | ||
|
|
9a6a7d3375 | ||
|
|
719ad30d05 | ||
|
|
d549a1301f | ||
|
|
adef5445f7 | ||
|
|
666c10465a | ||
|
|
e486a6551d | ||
|
|
53b4ea5125 | ||
|
|
a7f81b3c58 | ||
|
|
52dba1cc83 | ||
|
|
986d56279e | ||
|
|
e413863531 | ||
|
|
f4eafa901b | ||
|
|
0cd8228db1 | ||
|
|
510a6ce84a | ||
|
|
7420e2a924 | ||
|
|
1cd65ccbb6 | ||
|
|
857644e391 | ||
|
|
4922c8c4ec | ||
|
|
267e566c43 | ||
|
|
92304597bd | ||
|
|
6abacb46e4 | ||
|
|
f07979ec23 | ||
|
|
e66ab50909 | ||
|
|
037cda5ef3 |
@@ -85,7 +85,10 @@ celerybeat-schedule
|
||||
# virtualenv
|
||||
.venv
|
||||
venv/
|
||||
venv3/
|
||||
ENV/
|
||||
env/
|
||||
env3/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
|
||||
+33
-4
@@ -1,17 +1,46 @@
|
||||
language: generic
|
||||
|
||||
matrix:
|
||||
include:
|
||||
# Linux Python 2
|
||||
- sudo: required
|
||||
language: python
|
||||
services:
|
||||
- docker
|
||||
env:
|
||||
- "PYTHON=python2"
|
||||
|
||||
# Linux Python 3
|
||||
- sudo: required
|
||||
language: python
|
||||
services:
|
||||
- docker
|
||||
env:
|
||||
- "PYTHON=python3"
|
||||
before_install:
|
||||
- sudo apt-get -qq update
|
||||
- sudo apt-get install -y python3-pip
|
||||
|
||||
# macOS Python 2
|
||||
- os: osx
|
||||
env:
|
||||
- "PYTHON=python2"
|
||||
|
||||
# macOS Python 3
|
||||
- os: osx
|
||||
env:
|
||||
- "PYTHON=python3"
|
||||
before_install:
|
||||
- brew update
|
||||
- brew outdated python || brew upgrade python
|
||||
|
||||
script:
|
||||
- |
|
||||
if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
|
||||
pip install -r requirements-dev.txt
|
||||
python ./bin/run_tests.py
|
||||
$PYTHON -m pip install -r requirements-dev.txt
|
||||
$PYTHON ./bin/run_tests.py
|
||||
else
|
||||
# linux test requires root to clean up the wheelhouse (docker runs as root)
|
||||
sudo pip install -r requirements-dev.txt
|
||||
sudo python ./bin/run_tests.py
|
||||
sudo $PYTHON -m pip install -r requirements-dev.txt
|
||||
sudo $PYTHON ./bin/run_tests.py
|
||||
fi
|
||||
|
||||
@@ -15,7 +15,7 @@ What does it do?
|
||||
| | macOS 10.6+ | manylinux i686 | manylinux x86_64 | Windows 32bit | Windows 64bit |
|
||||
|---|---|---|---|---|---|
|
||||
| Python 2.7 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| Python 3.3 | | ✅ | ✅ | ✅ | ✅ |
|
||||
| Python 3.3 | | | | ✅ | ✅ |
|
||||
| Python 3.4 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| Python 3.5 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| Python 3.6 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
@@ -36,15 +36,20 @@ Usage
|
||||
- Create a `.travis.yml` file in your repo.
|
||||
|
||||
```
|
||||
language: python
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- sudo: required
|
||||
services:
|
||||
- docker
|
||||
env: PIP=pip
|
||||
- os: osx
|
||||
language: generic
|
||||
env: PIP=pip2
|
||||
|
||||
script:
|
||||
- pip install cibuildwheel==0.5.0
|
||||
- $PIP install cibuildwheel==0.8.0
|
||||
- cibuildwheel --output-dir wheelhouse
|
||||
```
|
||||
|
||||
@@ -54,7 +59,7 @@ Usage
|
||||
|
||||
```
|
||||
build_script:
|
||||
- pip install cibuildwheel==0.5.0
|
||||
- pip install cibuildwheel==0.8.0
|
||||
- cibuildwheel --output-dir wheelhouse
|
||||
artifacts:
|
||||
- path: "wheelhouse\\*.whl"
|
||||
@@ -69,6 +74,31 @@ All being well, you should get wheels delivered to you in a few minutes.
|
||||
|
||||
> ⚠️ Got an error? Check the [checklist](#it-didnt-work) below.
|
||||
|
||||
### Configuration overview
|
||||
|
||||
`cibuildwheel` allows for easy customization of the various phases of the build process demonstrated above:
|
||||
|
||||
| | Option | |
|
||||
|---|---|---|
|
||||
| **Target wheels** | `CIBW_PLATFORM` | Override the auto-detected target platform |
|
||||
| | `CIBW_SKIP` | Skip certain Python versions |
|
||||
| **Build parameters** | `CIBW_BUILD_VERBOSITY` | Increase or decrease the output of `pip wheel` |
|
||||
| **Build environment** | `CIBW_ENVIRONMENT` | Set environment variables needed during the build |
|
||||
| | `CIBW_BEFORE_BUILD` | Execute a shell command preparing each wheel's build |
|
||||
| | `CIBW_MANYLINUX1_X86_64_IMAGE` | Specify an alternative manylinx1 x86_64 docker image |
|
||||
| | `CIBW_MANYLINUX1_I686_IMAGE` | Specify an alternative manylinux1 i686 docker image |
|
||||
| **Tests** | `CIBW_TEST_COMMAND` | Execute a shell command to test all built wheels |
|
||||
| | `CIBW_TEST_REQUIRES` | Install Python dependencies before running the tests |
|
||||
|
||||
A more detailed description of the options, the allowed values, and some examples can be found in the [Options](#options) section.
|
||||
|
||||
### Linux builds on Docker
|
||||
|
||||
Linux wheels are built in the [`manylinux1` docker images](https://github.com/pypa/manylinux) to provide binary compatible wheels on Linux, according to [PEP 513](https://www.python.org/dev/peps/pep-0513/). Because of this, when building with `cibuildwheel` on Linux, a few things should be taken into account:
|
||||
- Progams and libraries cannot be installed on the Travis CI Ubuntu host with `apt-get`, but can be installed inside of the Docker image using `yum` or manually. The same goes for environment variables that are potentially needed to customize the wheel building. `cibuildwheel` supports this by providing the `CIBW_ENVIRONMENT` and `CIBW_BEFORE_BUILD` options to setup the build environment inside the running Docker image. See [below](#options) for details on these options.
|
||||
- The project directory is mounted in the running Docker instance as `/project`, the output directory for the wheels as `/output`. In general, this is handled transparently by `cibuildwheel`. For a more finegrained level of control however, the root of the host file system is mounted as `/host`, allowing for example to access shared files, caches, etc. on the host file system.
|
||||
- Alternative dockers images can be specified with the `CIBW_MANYLINUX1_X86_64_IMAGE` and `CIBW_MANYLINUX1_I686_IMAGE` options to allow for a custom, preconfigured build environment for the Linux builds. See [below](#options) for more details.
|
||||
|
||||
|
||||
Options
|
||||
-------
|
||||
@@ -124,13 +154,28 @@ The format is `python_tag-platform_tag`. The tags are as defined in [PEP 0425](h
|
||||
|
||||
Python tags look like `cp27` `cp34` `cp35` `cp36`
|
||||
|
||||
Platform tags look like `macosx_10_6_intel` `manylinux1_x86_64` `manylinux1_i386` `win32` `win_amd64`
|
||||
Platform tags look like `macosx_10_6_intel` `manylinux1_x86_64` `manylinux1_i686` `win32` `win_amd64`
|
||||
|
||||
You can also use shell-style globbing syntax (as per `fnmatch`)
|
||||
|
||||
Example: `cp27-macosx_10_6_intel` (don't build on Python 2 on Mac)
|
||||
Example: `cp27-win*` (don't build on Python 2.7 on Windows)
|
||||
Example: `cp34-* cp35-*` (don't build on Python 3.4 or Python 3.5)
|
||||
Examples:
|
||||
- Skip building on Python 2.7 on the Mac: `cp27-macosx_10_6_intel`
|
||||
- Skip building on Python 2.7 on all platforms: `cp27-*`
|
||||
- Skip Python 2.7 on Windows: `cp27-win*`
|
||||
- Skip Python 2.7 on 32bit Windows: `cp27-win32`
|
||||
- Skip Python 3.4 and Python 3.5: `cp34-* cp35-*`
|
||||
- Skip Python 3.6 on Linux: `cp36-manylinux*`
|
||||
- Only build on Python 3.6: `cp27-* cp34-* cp35-*`
|
||||
|
||||
| Environment variable: `CIBW_BUILD_VERBOSITY`
|
||||
| ---
|
||||
|
||||
Optional.
|
||||
|
||||
An number from 1 to 3 to increase the level of verbosity (corresponding to invoking pip with `-v`, `-vv`, and `-vvv`), between -1 and -3 (`-q`, `-qq`, and `-qqq`), or just 0 (default verbosity). These flags are useful while debugging a build when the output of the actual build invoked by `pip wheel` is required.
|
||||
|
||||
Platform-specific variants also available:
|
||||
`CIBW_BUILD_VERBOSITY_MACOS` | `CIBW_BUILD_VERBOSITY_WINDOWS` | `CIBW_BUILD_VERBOSITY_LINUX`
|
||||
|
||||
| Environment variable: `CIBW_ENVIRONMENT`
|
||||
| ---
|
||||
@@ -162,7 +207,7 @@ A shell command to run before building the wheel. This option allows you to run
|
||||
|
||||
If dependencies are required to build your wheel (for example if you include a header from a Python module), set this to `{pip} install .`, and the dependencies will be installed automatically by pip. However, this means your package will be built twice - if your package takes a long time to build, you might wish to manually list the dependencies here instead.
|
||||
|
||||
The active Python binary can be accessed using `{python}`, and pip with `{pip}`. These are useful when you need to write `python3` or `pip3` on a Python 3.x build.
|
||||
The active Python binary can be accessed using `{python}`, and pip with `{pip}`. These are useful when you need to write `python3` or `pip3` on a Python 3.x build. `{project}` can be used as a placeholder for the absolute path to the project's root.
|
||||
|
||||
Example: `{pip} install .`
|
||||
Example: `{pip} install pybind11`
|
||||
@@ -171,12 +216,24 @@ Example: `yum install -y libffi-dev && {pip} install .`
|
||||
Platform-specific variants also available:
|
||||
`CIBW_BEFORE_BUILD_MACOS` | `CIBW_BEFORE_BUILD_WINDOWS` | `CIBW_BEFORE_BUILD_LINUX`
|
||||
|
||||
| Environment variables: `CIBW_MANYLINUX1_X86_64_IMAGE` and `CIBW_MANYLINUX1_I686_IMAGE`
|
||||
| ---
|
||||
|
||||
Optional.
|
||||
|
||||
An alternative docker image to be used for building [`manylinux1`](https://github.com/pypa/manylinux) wheels. `cibuildwheel` will then pull these instead of the official images, [`quay.io/pypa/manylinux1_x86_64`](https://quay.io/pypa/manylinux1_i686) and [`quay.io/pypa/manylinux1_i686`](https://quay.io/pypa/manylinux1_i686).
|
||||
|
||||
Beware to specify a valid docker image that can be used the same as the official, default docker images: all necessary Python and pip versions need to be present in `/opt/python/`, and the `auditwheel` tool needs to be present for `cibuildwheel` to work. Apart from that, the architecture and relevant shared system libraries need to be manylinux1-compatible in order to produce valid `manylinux1` wheels (see https://github.com/pypa/manylinux and [PEP 513](https://www.python.org/dev/peps/pep-0513/) for more details).
|
||||
|
||||
Example: `dockcross/manylinux-x64`
|
||||
Example: `dockcross/manylinux-x86`
|
||||
|
||||
| Environment variable: `CIBW_TEST_COMMAND`
|
||||
| ---
|
||||
|
||||
Optional.
|
||||
|
||||
Shell command to run tests after the build. The wheel will be installed automatically and available for import from the tests. The project root should be included in the command as "{project}".
|
||||
Shell command to run tests after the build. The wheel will be installed automatically and available for import from the tests. Just like in the `CIBW_BEFORE_BUILD` option, `{python}`, `{pip}`, and `{project}` will respectively be replaced by the Python executable, the pip executable, and the absolute project directory.
|
||||
|
||||
Example: `nosetests {project}/tests`
|
||||
|
||||
@@ -258,6 +315,8 @@ Here are some repos that use cibuildwheel.
|
||||
|
||||
- [pyinstrument_cext](https://github.com/joerick/pyinstrument_cext)
|
||||
- [websockets](https://github.com/aaugustin/websockets)
|
||||
- [Parselmouth](https://github.com/YannickJadoul/Parselmouth)
|
||||
- [python-admesh](https://github.com/admesh/python-admesh)
|
||||
|
||||
> Add repo here! Send a PR.
|
||||
|
||||
@@ -269,6 +328,31 @@ Since `cibuildwheel` runs the wheel through delocate or auditwheel, it will auto
|
||||
Changelog
|
||||
=========
|
||||
|
||||
### 0.7.1
|
||||
|
||||
- macOS: Fix Pip bugs resulting from PyPI TLS 1.2 enforcement
|
||||
- macOS: Fix brew Python3 version problems in the CI
|
||||
|
||||
### 0.7.0
|
||||
|
||||
- You can now specify a custom docker image using the `CIBW_MANYLINUX1_X86_64_IMAGE` and `CIBW_MANYLINUX1_I686_IMAGE` options. (#46)
|
||||
- Fixed a bug where cibuildwheel would download and build a package from PyPI(!) instead of building the package on the local machine. (#51)
|
||||
|
||||
### 0.6.0
|
||||
|
||||
- On the Linux build, the host filesystem is now accessible via `/host` (#36)
|
||||
- Fixed a bug where setup.py scripts would run the wrong version of Python when running subprocesses on Linux (#35)
|
||||
|
||||
### 0.5.1
|
||||
|
||||
- Fixed a couple of bugs on Python 3.
|
||||
- Added experimental support for Mac builds on [Bitrise.io](https://www.bitrise.io)
|
||||
|
||||
### 0.5.0
|
||||
|
||||
- `CIBW_ENVIRONMENT` added. You can now set environment variables for each build, even within the Docker container on Linux. This is a big one! (#21)
|
||||
- `CIBW_BEFORE_BUILD` now runs in a system shell on all platforms. You can now do things like `CIBW_BEFORE_BUILD="cmd1 && cmd2"`. (#32)
|
||||
|
||||
### 0.4.1
|
||||
|
||||
- Fixed a bug on Windows where subprocess' output was hidden (#23)
|
||||
|
||||
+7
-2
@@ -1,5 +1,10 @@
|
||||
environment:
|
||||
matrix:
|
||||
- PYTHON: "C:\\Python27\\python.exe"
|
||||
- PYTHON: "C:\\Python35\\python.exe"
|
||||
|
||||
build_script:
|
||||
- pip install -r requirements-dev.txt
|
||||
- "%PYTHON% -m pip install -r requirements-dev.txt"
|
||||
# the '-u' flag is required so the output is in the correct order.
|
||||
# See https://github.com/joerick/cibuildwheel/pull/24 for more info.
|
||||
- python -u ./bin/run_tests.py
|
||||
- "%PYTHON% -u ./bin/run_tests.py"
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ def single_run(test_project):
|
||||
project_env = {str(k): str(v) for k, v in project_env.items()} # unicode not allowed in env
|
||||
env.update(project_env)
|
||||
print('Building %s with environment %s' % (test_project, project_env))
|
||||
subprocess.check_call(['cibuildwheel', test_project], env=env)
|
||||
subprocess.check_call([sys.executable, '-m', 'cibuildwheel', test_project], env=env)
|
||||
wheels = glob('wheelhouse/*.whl')
|
||||
print('%s built successfully. %i wheels built.' % (test_project, len(wheels)))
|
||||
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ if __name__ == '__main__':
|
||||
|
||||
### run the unit tests
|
||||
|
||||
subprocess.check_call(['python', '-m', 'pytest', 'unit_test'])
|
||||
subprocess.check_call([sys.executable, '-m', 'pytest', 'unit_test'])
|
||||
|
||||
### run the integration tests
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
__version__ = '0.5.0'
|
||||
__version__ = '0.8.0'
|
||||
|
||||
@@ -59,6 +59,8 @@ def main():
|
||||
platform = 'macos'
|
||||
elif 'APPVEYOR' in os.environ:
|
||||
platform = 'windows'
|
||||
elif 'BITRISE_BUILD_NUMBER' in os.environ:
|
||||
platform = 'macos'
|
||||
else:
|
||||
print('cibuildwheel: Unable to detect platform. cibuildwheel should run on your CI server, '
|
||||
'Travis CI and Appveyor are supported. You can run on your development '
|
||||
@@ -72,9 +74,15 @@ def main():
|
||||
test_requires = os.environ.get('CIBW_TEST_REQUIRES', '').split()
|
||||
project_dir = args.project_dir
|
||||
before_build = get_option_from_environment('CIBW_BEFORE_BUILD', platform=platform)
|
||||
build_verbosity = get_option_from_environment('CIBW_BUILD_VERBOSITY', platform=platform) or ''
|
||||
skip_config = os.environ.get('CIBW_SKIP', '')
|
||||
environment_config = get_option_from_environment('CIBW_ENVIRONMENT', platform=platform) or ''
|
||||
|
||||
try:
|
||||
build_verbosity = min(3, max(-3, int(build_verbosity)))
|
||||
except ValueError:
|
||||
build_verbosity = 0
|
||||
|
||||
try:
|
||||
environment = parse_environment(environment_config)
|
||||
except (EnvironmentParseError, ValueError) as e:
|
||||
@@ -116,10 +124,23 @@ def main():
|
||||
test_command=test_command,
|
||||
test_requires=test_requires,
|
||||
before_build=before_build,
|
||||
build_verbosity=build_verbosity,
|
||||
skip=skip,
|
||||
environment=environment,
|
||||
)
|
||||
|
||||
if platform == 'linux':
|
||||
manylinux1_x86_64_image = os.environ.get('CIBW_MANYLINUX1_X86_64_IMAGE', None)
|
||||
manylinux1_i686_image = os.environ.get('CIBW_MANYLINUX1_I686_IMAGE', None)
|
||||
|
||||
build_options.update(
|
||||
manylinux1_images={'x86_64': manylinux1_x86_64_image, 'i686': manylinux1_i686_image},
|
||||
)
|
||||
elif platform == 'macos':
|
||||
pass
|
||||
elif platform == 'windows':
|
||||
pass
|
||||
|
||||
print_preamble(platform, build_options)
|
||||
|
||||
if not os.path.exists(output_dir):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import subprocess, shlex
|
||||
import subprocess, shlex, sys
|
||||
from collections import namedtuple
|
||||
import bashlex
|
||||
|
||||
@@ -60,8 +60,12 @@ def evaluate_word_node(node, context):
|
||||
def evaluate_command_node(node, context):
|
||||
words = [evaluate_node(part, context=context) for part in node.parts]
|
||||
command = ' '.join(words)
|
||||
return subprocess.check_output(shlex.split(command), env=context.environment)
|
||||
output = subprocess.check_output(shlex.split(command), env=context.environment)
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
return output.decode('utf8', 'replace')
|
||||
else:
|
||||
return output
|
||||
|
||||
def evaluate_parameter_node(node, context):
|
||||
return context.environment.get(node.value, '')
|
||||
|
||||
+11
-11
@@ -1,7 +1,7 @@
|
||||
from __future__ import print_function
|
||||
import os, subprocess, sys
|
||||
from collections import namedtuple
|
||||
from .util import prepare_command
|
||||
from .util import prepare_command, get_build_verbosity_extra_flags
|
||||
|
||||
try:
|
||||
from shlex import quote as shlex_quote
|
||||
@@ -9,7 +9,7 @@ except ImportError:
|
||||
from pipes import quote as shlex_quote
|
||||
|
||||
|
||||
def build(project_dir, package_name, output_dir, test_command, test_requires, before_build, skip, environment):
|
||||
def build(project_dir, package_name, output_dir, test_command, test_requires, before_build, build_verbosity, skip, environment, manylinux1_images):
|
||||
try:
|
||||
subprocess.check_call(['docker', '--version'])
|
||||
except:
|
||||
@@ -22,13 +22,11 @@ def build(project_dir, package_name, output_dir, test_command, test_requires, be
|
||||
python_configurations = [
|
||||
PythonConfiguration(identifier='cp27-manylinux1_x86_64', path='/opt/python/cp27-cp27m'),
|
||||
PythonConfiguration(identifier='cp27-manylinux1_x86_64', path='/opt/python/cp27-cp27mu'),
|
||||
PythonConfiguration(identifier='cp33-manylinux1_x86_64', path='/opt/python/cp33-cp33m'),
|
||||
PythonConfiguration(identifier='cp34-manylinux1_x86_64', path='/opt/python/cp34-cp34m'),
|
||||
PythonConfiguration(identifier='cp35-manylinux1_x86_64', path='/opt/python/cp35-cp35m'),
|
||||
PythonConfiguration(identifier='cp36-manylinux1_x86_64', path='/opt/python/cp36-cp36m'),
|
||||
PythonConfiguration(identifier='cp27-manylinux1_i686', path='/opt/python/cp27-cp27m'),
|
||||
PythonConfiguration(identifier='cp27-manylinux1_i686', path='/opt/python/cp27-cp27mu'),
|
||||
PythonConfiguration(identifier='cp33-manylinux1_i686', path='/opt/python/cp33-cp33m'),
|
||||
PythonConfiguration(identifier='cp34-manylinux1_i686', path='/opt/python/cp34-cp34m'),
|
||||
PythonConfiguration(identifier='cp35-manylinux1_i686', path='/opt/python/cp35-cp35m'),
|
||||
PythonConfiguration(identifier='cp36-manylinux1_i686', path='/opt/python/cp36-cp36m'),
|
||||
@@ -38,8 +36,8 @@ def build(project_dir, package_name, output_dir, test_command, test_requires, be
|
||||
python_configurations = [c for c in python_configurations if not skip(c.identifier)]
|
||||
|
||||
platforms = [
|
||||
('manylinux1_x86_64', 'quay.io/pypa/manylinux1_x86_64'),
|
||||
('manylinux1_i686', 'quay.io/pypa/manylinux1_i686'),
|
||||
('manylinux1_x86_64', manylinux1_images.get('x86_64') or 'quay.io/pypa/manylinux1_x86_64'),
|
||||
('manylinux1_i686', manylinux1_images.get('i686') or 'quay.io/pypa/manylinux1_i686'),
|
||||
]
|
||||
|
||||
for platform_tag, docker_image in platforms:
|
||||
@@ -62,11 +60,11 @@ def build(project_dir, package_name, output_dir, test_command, test_requires, be
|
||||
mkdir /tmp/delocated_wheel
|
||||
|
||||
if [ ! -z {before_build} ]; then
|
||||
PATH=$PYBIN:$PATH sh -c {before_build}
|
||||
PATH="$PYBIN:$PATH" sh -c {before_build}
|
||||
fi
|
||||
|
||||
# Build that wheel
|
||||
"$PYBIN/pip" wheel . -w /tmp/built_wheel --no-deps
|
||||
PATH="$PYBIN:$PATH" "$PYBIN/pip" wheel . -w /tmp/built_wheel --no-deps {build_verbosity_flag}
|
||||
built_wheel=(/tmp/built_wheel/*.whl)
|
||||
|
||||
# Delocate the wheel
|
||||
@@ -91,7 +89,7 @@ def build(project_dir, package_name, output_dir, test_command, test_requires, be
|
||||
# Run the tests from a different directory
|
||||
if [ ! -z {test_command} ]; then
|
||||
pushd $HOME
|
||||
PATH=$PYBIN:$PATH sh -c {test_command}
|
||||
PATH="$PYBIN:$PATH" sh -c {test_command}
|
||||
popd
|
||||
fi
|
||||
|
||||
@@ -103,11 +101,12 @@ def build(project_dir, package_name, output_dir, test_command, test_requires, be
|
||||
pybin_paths=' '.join(c.path+'/bin' for c in platform_configs),
|
||||
test_requires=' '.join(test_requires),
|
||||
test_command=shlex_quote(
|
||||
test_command.format(project='/project') if test_command else ''
|
||||
prepare_command(test_command, python='python', pip='pip', project='/project') if test_command else ''
|
||||
),
|
||||
before_build=shlex_quote(
|
||||
prepare_command(before_build, python='python', pip='pip') if before_build else ''
|
||||
prepare_command(before_build, python='python', pip='pip', project='/project') if before_build else ''
|
||||
),
|
||||
build_verbosity_flag=' '.join(get_build_verbosity_extra_flags(build_verbosity)),
|
||||
environment_exports='\n'.join(environment.as_shell_commands()),
|
||||
)
|
||||
|
||||
@@ -120,6 +119,7 @@ def build(project_dir, package_name, output_dir, test_command, test_requires, be
|
||||
'-i',
|
||||
'-v', '%s:/project' % os.path.abspath(project_dir),
|
||||
'-v', '%s:/output' % os.path.abspath(output_dir),
|
||||
'-v', '/:/host',
|
||||
docker_image,
|
||||
'/bin/bash'],
|
||||
stdin=subprocess.PIPE, universal_newlines=True)
|
||||
|
||||
+30
-15
@@ -7,17 +7,24 @@ try:
|
||||
except ImportError:
|
||||
from pipes import quote as shlex_quote
|
||||
|
||||
from .util import prepare_command
|
||||
from .util import prepare_command, get_build_verbosity_extra_flags
|
||||
|
||||
|
||||
def build(project_dir, package_name, output_dir, test_command, test_requires, before_build, skip, environment):
|
||||
def build(project_dir, package_name, output_dir, test_command, test_requires, before_build, build_verbosity, skip, environment):
|
||||
PythonConfiguration = namedtuple('PythonConfiguration', ['version', 'identifier', 'url'])
|
||||
python_configurations = [
|
||||
PythonConfiguration(version='2.7', identifier='cp27-macosx_10_6_intel', url='https://www.python.org/ftp/python/2.7.13/python-2.7.13-macosx10.6.pkg'),
|
||||
PythonConfiguration(version='2.7', identifier='cp27-macosx_10_6_intel', url='https://www.python.org/ftp/python/2.7.15/python-2.7.15-macosx10.6.pkg'),
|
||||
PythonConfiguration(version='3.4', identifier='cp34-macosx_10_6_intel', url='https://www.python.org/ftp/python/3.4.4/python-3.4.4-macosx10.6.pkg'),
|
||||
PythonConfiguration(version='3.5', identifier='cp35-macosx_10_6_intel', url='https://www.python.org/ftp/python/3.5.3/python-3.5.3-macosx10.6.pkg'),
|
||||
PythonConfiguration(version='3.6', identifier='cp36-macosx_10_6_intel', url='https://www.python.org/ftp/python/3.6.0/python-3.6.0-macosx10.6.pkg'),
|
||||
PythonConfiguration(version='3.5', identifier='cp35-macosx_10_6_intel', url='https://www.python.org/ftp/python/3.5.4/python-3.5.4-macosx10.6.pkg'),
|
||||
PythonConfiguration(version='3.6', identifier='cp36-macosx_10_6_intel', url='https://www.python.org/ftp/python/3.6.5/python-3.6.5-macosx10.6.pkg'),
|
||||
]
|
||||
get_pip_url = 'https://bootstrap.pypa.io/get-pip.py'
|
||||
get_pip_script = '/tmp/get-pip.py'
|
||||
|
||||
pkgs_output = subprocess.check_output(['pkgutil', '--pkgs'])
|
||||
if sys.version_info[0] >= 3:
|
||||
pkgs_output = pkgs_output.decode('utf8')
|
||||
installed_system_packages = pkgs_output.splitlines()
|
||||
|
||||
def call(args, env=None, cwd=None, shell=False):
|
||||
# print the command executing for the logs
|
||||
@@ -28,15 +35,23 @@ def build(project_dir, package_name, output_dir, test_command, test_requires, be
|
||||
|
||||
return subprocess.check_call(args, env=env, cwd=cwd, shell=shell)
|
||||
|
||||
abs_project_dir = os.path.abspath(project_dir)
|
||||
|
||||
# get latest pip once and for all
|
||||
call(['curl', '-L', '-o', get_pip_script, get_pip_url])
|
||||
|
||||
for config in python_configurations:
|
||||
if skip(config.identifier):
|
||||
print('cibuildwheel: Skipping build %s' % config.identifier, file=sys.stderr)
|
||||
continue
|
||||
|
||||
# download the pkg
|
||||
call(['curl', '-L', '-o', '/tmp/Python.pkg', config.url])
|
||||
# install
|
||||
call(['sudo', 'installer', '-pkg', '/tmp/Python.pkg', '-target', '/'])
|
||||
# if this version of python isn't installed, get it from python.org and install
|
||||
python_package_identifier = 'org.python.Python.PythonFramework-%s' % config.version
|
||||
if python_package_identifier not in installed_system_packages:
|
||||
# download the pkg
|
||||
call(['curl', '-L', '-o', '/tmp/Python.pkg', config.url])
|
||||
# install
|
||||
call(['sudo', 'installer', '-pkg', '/tmp/Python.pkg', '-target', '/'])
|
||||
|
||||
env = os.environ.copy()
|
||||
env['PATH'] = os.pathsep.join([
|
||||
@@ -53,8 +68,9 @@ def build(project_dir, package_name, output_dir, test_command, test_requires, be
|
||||
call([python, '--version'], env=env)
|
||||
|
||||
# install pip & wheel
|
||||
call([python, '-m', 'ensurepip', '--upgrade'], env=env)
|
||||
call([python, get_pip_script, '--no-setuptools', '--no-wheel'], env=env)
|
||||
call([pip, '--version'], env=env)
|
||||
call([pip, 'install', '--upgrade', 'setuptools'], env=env)
|
||||
call([pip, 'install', 'wheel'], env=env)
|
||||
call([pip, 'install', 'delocate'], env=env)
|
||||
|
||||
@@ -68,11 +84,11 @@ def build(project_dir, package_name, output_dir, test_command, test_requires, be
|
||||
|
||||
# run the before_build command
|
||||
if before_build:
|
||||
before_build_prepared = prepare_command(before_build, python=python, pip=pip)
|
||||
before_build_prepared = prepare_command(before_build, python=python, pip=pip, project=abs_project_dir)
|
||||
call(before_build_prepared, env=env, shell=True)
|
||||
|
||||
# build the wheel
|
||||
call([pip, 'wheel', project_dir, '-w', '/tmp/built_wheel', '--no-deps'], env=env)
|
||||
call([pip, 'wheel', abs_project_dir, '-w', '/tmp/built_wheel', '--no-deps'] + get_build_verbosity_extra_flags(build_verbosity), env=env)
|
||||
built_wheel = glob('/tmp/built_wheel/*.whl')[0]
|
||||
|
||||
if built_wheel.endswith('none-any.whl'):
|
||||
@@ -95,9 +111,8 @@ def build(project_dir, package_name, output_dir, test_command, test_requires, be
|
||||
# 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)
|
||||
abs_project_dir = os.path.abspath(project_dir)
|
||||
test_command_absolute = test_command.format(project=abs_project_dir)
|
||||
call(shlex.split(test_command_absolute), cwd=os.environ['HOME'], env=env)
|
||||
test_command_prepared = prepare_command(test_command, python=python, pip=pip, project=abs_project_dir)
|
||||
call(shlex.split(test_command_prepared), cwd=os.environ['HOME'], env=env)
|
||||
|
||||
# we're all done here; move it to output
|
||||
shutil.move(delocated_wheel, output_dir)
|
||||
|
||||
+28
-2
@@ -1,7 +1,7 @@
|
||||
from fnmatch import fnmatch
|
||||
|
||||
|
||||
def prepare_command(command, python, pip):
|
||||
def prepare_command(command, python, pip, project):
|
||||
'''
|
||||
Preprocesses a command by expanding variables like {python} or {pip}.
|
||||
|
||||
@@ -10,7 +10,16 @@ def prepare_command(command, python, pip):
|
||||
Python 3, the user could write `{python} setup.py test`. This command would expand
|
||||
it out to python2 or python3 as appropriate.
|
||||
'''
|
||||
return command.format(python=python, pip=pip)
|
||||
return command.format(python=python, pip=pip, project=project)
|
||||
|
||||
|
||||
def get_build_verbosity_extra_flags(level):
|
||||
if level > 0:
|
||||
return ['-' + level * 'v']
|
||||
elif level < 0:
|
||||
return ['-' + -level * 'q']
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
class BuildSkipper(object):
|
||||
@@ -22,3 +31,20 @@ class BuildSkipper(object):
|
||||
|
||||
def __repr__(self):
|
||||
return 'BuildSkipper(%r)' % ' '.join(self.patterns)
|
||||
|
||||
|
||||
# Taken from https://stackoverflow.com/a/107717
|
||||
class Unbuffered(object):
|
||||
def __init__(self, stream):
|
||||
self.stream = stream
|
||||
|
||||
def write(self, data):
|
||||
self.stream.write(data)
|
||||
self.stream.flush()
|
||||
|
||||
def writelines(self, datas):
|
||||
self.stream.writelines(datas)
|
||||
self.stream.flush()
|
||||
|
||||
def __getattr__(self, attr):
|
||||
return getattr(self.stream, attr)
|
||||
|
||||
+10
-9
@@ -7,13 +7,13 @@ except ImportError:
|
||||
from collections import namedtuple
|
||||
from glob import glob
|
||||
|
||||
from .util import prepare_command
|
||||
from .util import prepare_command, get_build_verbosity_extra_flags, Unbuffered
|
||||
|
||||
|
||||
def build(project_dir, package_name, output_dir, test_command, test_requires, before_build, skip, environment):
|
||||
def build(project_dir, package_name, output_dir, test_command, test_requires, before_build, build_verbosity, skip, environment):
|
||||
# Python under AppVeyor/Windows seems to be buffering by default, giving problems interleaving subprocess call output with unflushed calls to 'print'
|
||||
sys.stdout.flush()
|
||||
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
|
||||
sys.stdout = Unbuffered(sys.stdout)
|
||||
|
||||
# run_with_env is a cmd file that sets the right environment variables to
|
||||
run_with_env = os.path.join(tempfile.gettempdir(), 'appveyor_run_with_env.cmd')
|
||||
@@ -42,6 +42,7 @@ def build(project_dir, package_name, output_dir, test_command, test_requires, be
|
||||
PythonConfiguration(version='3.6.x', arch="64", identifier='cp36-win_amd64', path='C:\Python36-x64'),
|
||||
]
|
||||
|
||||
abs_project_dir = os.path.abspath(project_dir)
|
||||
temp_dir = tempfile.mkdtemp(prefix='cibuildwheel')
|
||||
built_wheel_dir = os.path.join(temp_dir, 'built_wheel')
|
||||
|
||||
@@ -71,17 +72,18 @@ def build(project_dir, package_name, output_dir, test_command, test_requires, be
|
||||
shell(['python', '-c', '"import struct; print(struct.calcsize(\'P\') * 8)\"'], env=env)
|
||||
|
||||
# prepare the Python environment
|
||||
shell(['pip', 'install', '--disable-pip-version-check', '--user', '--upgrade', 'pip'],
|
||||
shell(['python', '-m', 'pip', 'install', '--upgrade', 'pip'],
|
||||
env=env)
|
||||
shell(['pip', 'install', '--upgrade', 'setuptools'], env=env)
|
||||
shell(['pip', 'install', 'wheel'], env=env)
|
||||
|
||||
# run the before_build command
|
||||
if before_build:
|
||||
before_build_prepared = prepare_command(before_build, python='python', pip='pip')
|
||||
before_build_prepared = prepare_command(before_build, python='python', pip='pip', project=abs_project_dir)
|
||||
shell([before_build_prepared], env=env)
|
||||
|
||||
# build the wheel
|
||||
shell(['pip', 'wheel', project_dir, '-w', built_wheel_dir, '--no-deps'], env=env)
|
||||
shell(['pip', 'wheel', abs_project_dir, '-w', built_wheel_dir, '--no-deps'] + get_build_verbosity_extra_flags(build_verbosity), env=env)
|
||||
built_wheel = glob(built_wheel_dir+'/*.whl')[0]
|
||||
|
||||
# install the wheel
|
||||
@@ -94,9 +96,8 @@ def build(project_dir, package_name, output_dir, test_command, test_requires, be
|
||||
# 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)
|
||||
abs_project_dir = os.path.abspath(project_dir)
|
||||
test_command_absolute = test_command.format(project=abs_project_dir)
|
||||
shell([test_command_absolute], cwd='c:\\', env=env)
|
||||
test_command_prepared = prepare_command(test_command, python='python', pip='pip', project=abs_project_dir)
|
||||
shell([test_command_prepared], cwd='c:\\', env=env)
|
||||
|
||||
# we're all done here; move it to output
|
||||
shutil.move(built_wheel, output_dir)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[bumpversion]
|
||||
current_version = 0.5.0
|
||||
current_version = 0.8.0
|
||||
commit = True
|
||||
tag = True
|
||||
message = Bump version
|
||||
|
||||
@@ -8,7 +8,7 @@ except ImportError:
|
||||
|
||||
setup(
|
||||
name='cibuildwheel',
|
||||
version='0.5.0',
|
||||
version='0.8.0',
|
||||
install_requires=['bashlex'],
|
||||
description="Build Python wheels on CI with minimal configuration.",
|
||||
long_description='For readme please see http://github.com/joerick/cibuildwheel',
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"CIBW_MANYLINUX1_X86_64_IMAGE": "dockcross/manylinux-x64",
|
||||
"CIBW_MANYLINUX1_I686_IMAGE": "dockcross/manylinux-x86"
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import os, sys
|
||||
|
||||
from setuptools import setup, Extension
|
||||
|
||||
if sys.argv[-1] != '--name':
|
||||
# check that we're running in the correct docker image as specified in the
|
||||
# environment options CIBW_MANYLINUX1_*_IMAGE
|
||||
if 'linux' in sys.platform and not os.path.exists('/dockcross'):
|
||||
raise Exception('/dockcross directory not found. Is this test running in the correct docker image?')
|
||||
|
||||
setup(
|
||||
name="spam",
|
||||
ext_modules=[Extension('spam', sources=['spam.c'])],
|
||||
version="0.1.0",
|
||||
)
|
||||
@@ -0,0 +1,48 @@
|
||||
#include <Python.h>
|
||||
|
||||
static PyObject *
|
||||
spam_system(PyObject *self, PyObject *args)
|
||||
{
|
||||
const char *command;
|
||||
int sts;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s", &command))
|
||||
return NULL;
|
||||
sts = system(command);
|
||||
return PyLong_FromLong(sts);
|
||||
}
|
||||
|
||||
/* Module initialization */
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
#define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void)
|
||||
#define MOD_DEF(m, name, doc, methods, module_state_size) \
|
||||
static struct PyModuleDef moduledef = { \
|
||||
PyModuleDef_HEAD_INIT, name, doc, module_state_size, methods, }; \
|
||||
m = PyModule_Create(&moduledef);
|
||||
#define MOD_RETURN(m) return m;
|
||||
#else
|
||||
#define MOD_INIT(name) PyMODINIT_FUNC init##name(void)
|
||||
#define MOD_DEF(m, name, doc, methods, module_state_size) \
|
||||
m = Py_InitModule3(name, methods, doc);
|
||||
#define MOD_RETURN(m) return;
|
||||
#endif
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
{"system", (PyCFunction)spam_system, METH_VARARGS,
|
||||
"Execute a shell command."},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
MOD_INIT(spam)
|
||||
{
|
||||
PyObject* m;
|
||||
|
||||
MOD_DEF(m,
|
||||
"spam",
|
||||
"Example module",
|
||||
module_methods,
|
||||
-1)
|
||||
|
||||
MOD_RETURN(m)
|
||||
}
|
||||
Reference in New Issue
Block a user