diff --git a/cibuildwheel/linux.py b/cibuildwheel/linux.py index 80306634..ee420262 100644 --- a/cibuildwheel/linux.py +++ b/cibuildwheel/linux.py @@ -69,110 +69,114 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef constraints_file = dependency_constraints.get_for_python_version(config.version) subprocess.run(['docker', 'cp', os.path.abspath(constraints_file), container_name + ':/constraints.txt']) - subprocess.run(['docker', 'start', '-i', '-a', container_name], stdin_str=''' - set -o errexit - set -o xtrace - mkdir -p /output - cd /project + subprocess.run( + ['docker', 'start', '-i', '-a', container_name], + universal_newlines=True, + input=''' + set -o errexit + set -o xtrace + mkdir -p /output + cd /project - PYBIN="{config_python_bin}" - export PATH="$PYBIN:$PATH" + PYBIN="{config_python_bin}" + export PATH="$PYBIN:$PATH" - {environment_exports} + {environment_exports} - # check the active python and pip are in PYBIN - # if `test` returns false, the script will exit due to errexit - test "$(which pip)" = "$PYBIN/pip" - test "$(which python)" = "$PYBIN/python" + # check the active python and pip are in PYBIN + # if `test` returns false, the script will exit due to errexit + test "$(which pip)" = "$PYBIN/pip" + test "$(which python)" = "$PYBIN/python" - if [ ! -z {before_build} ]; then - sh -c {before_build} - fi - - # Build the wheel - rm -rf /tmp/built_wheel - mkdir /tmp/built_wheel - pip wheel . -w /tmp/built_wheel --no-deps {build_verbosity_flag} - built_wheel=(/tmp/built_wheel/*.whl) - - # repair the wheel - rm -rf /tmp/repaired_wheels - mkdir /tmp/repaired_wheels - # NOTE: 'built_wheel' here is a bash array of glob matches; "$built_wheel" returns - # the first element - if [[ "$built_wheel" == *none-any.whl ]] || [ -z {repair_command} ]; then - # pure Python wheel or empty repair command - mv "$built_wheel" /tmp/repaired_wheels - else - sh -c {repair_command} repair_command "$built_wheel" - fi - repaired_wheels=(/tmp/repaired_wheels/*.whl) - - if [ ! -z {test_command} ]; then - # Set up a virtual environment to install and test from, to make sure - # there are no dependencies that were pulled in at build time. - pip install {dependency_install_flags} virtualenv - venv_dir=`mktemp -d`/venv - python -m virtualenv "$venv_dir" - - # run the tests in a subshell to keep that `activate` - # script from polluting the env - ( - source "$venv_dir/bin/activate" - - echo "Running tests using `which python`" - - # Install the wheel we just built - # Note: If auditwheel produced two wheels, it's because the earlier produced wheel - # conforms to multiple manylinux standards. These multiple versions of the wheel are - # functionally the same, differing only in name, wheel metadata, and possibly include - # different external shared libraries. so it doesn't matter which one we run the tests on. - # Let's just pick the first one. - pip install "${{repaired_wheels[0]}}"{test_extras} - - # Install any requirements to run the tests - if [ ! -z "{test_requires}" ]; then - pip install {test_requires} - fi - - # Run the tests from a different directory - pushd $HOME - sh -c {test_command} - popd - ) - # exit if tests failed (needed for older bash versions) - if [ $? -ne 0 ]; then - exit 1; + if [ ! -z {before_build} ]; then + sh -c {before_build} fi - # clean up - rm -rf "$venv_dir" - fi + # Build the wheel + rm -rf /tmp/built_wheel + mkdir /tmp/built_wheel + pip wheel . -w /tmp/built_wheel --no-deps {build_verbosity_flag} + built_wheel=(/tmp/built_wheel/*.whl) - # we're all done here; move it to output - mv "${{repaired_wheels[@]}}" /output - for repaired_wheel in "${{repaired_wheels[@]}}"; do - chown {uid}:{gid} "/output/$(basename "$repaired_wheel")" - done - '''.format( - config_python_bin=config.path + '/bin', - test_requires=' '.join(test_requires), - test_extras=test_extras, - test_command=shlex.quote( - prepare_command(test_command, project='/project') if test_command else '' - ), - before_build=shlex.quote( - prepare_command(before_build, project='/project') if before_build else '' - ), - build_verbosity_flag=' '.join(get_build_verbosity_extra_flags(build_verbosity)), - repair_command=shlex.quote( - prepare_command(repair_command, wheel='"$1"', dest_dir='/tmp/repaired_wheels') if repair_command else '' - ), - environment_exports='\n'.join(environment.as_shell_commands()), - uid=os.getuid(), - gid=os.getgid(), - dependency_install_flags='-c /constraints.txt' if dependency_constraints else '', - )) + # repair the wheel + rm -rf /tmp/repaired_wheels + mkdir /tmp/repaired_wheels + # NOTE: 'built_wheel' here is a bash array of glob matches; "$built_wheel" returns + # the first element + if [[ "$built_wheel" == *none-any.whl ]] || [ -z {repair_command} ]; then + # pure Python wheel or empty repair command + mv "$built_wheel" /tmp/repaired_wheels + else + sh -c {repair_command} repair_command "$built_wheel" + fi + repaired_wheels=(/tmp/repaired_wheels/*.whl) + + if [ ! -z {test_command} ]; then + # Set up a virtual environment to install and test from, to make sure + # there are no dependencies that were pulled in at build time. + pip install {dependency_install_flags} virtualenv + venv_dir=`mktemp -d`/venv + python -m virtualenv "$venv_dir" + + # run the tests in a subshell to keep that `activate` + # script from polluting the env + ( + source "$venv_dir/bin/activate" + + echo "Running tests using `which python`" + + # Install the wheel we just built + # Note: If auditwheel produced two wheels, it's because the earlier produced wheel + # conforms to multiple manylinux standards. These multiple versions of the wheel are + # functionally the same, differing only in name, wheel metadata, and possibly include + # different external shared libraries. so it doesn't matter which one we run the tests on. + # Let's just pick the first one. + pip install "${{repaired_wheels[0]}}"{test_extras} + + # Install any requirements to run the tests + if [ ! -z "{test_requires}" ]; then + pip install {test_requires} + fi + + # Run the tests from a different directory + pushd $HOME + sh -c {test_command} + popd + ) + # exit if tests failed (needed for older bash versions) + if [ $? -ne 0 ]; then + exit 1; + fi + + # clean up + rm -rf "$venv_dir" + fi + + # we're all done here; move it to output + mv "${{repaired_wheels[@]}}" /output + for repaired_wheel in "${{repaired_wheels[@]}}"; do + chown {uid}:{gid} "/output/$(basename "$repaired_wheel")" + done + '''.format( + config_python_bin=config.path + '/bin', + test_requires=' '.join(test_requires), + test_extras=test_extras, + test_command=shlex.quote( + prepare_command(test_command, project='/project') if test_command else '' + ), + before_build=shlex.quote( + prepare_command(before_build, project='/project') if before_build else '' + ), + build_verbosity_flag=' '.join(get_build_verbosity_extra_flags(build_verbosity)), + repair_command=shlex.quote( + prepare_command(repair_command, wheel='"$1"', dest_dir='/tmp/repaired_wheels') if repair_command else '' + ), + environment_exports='\n'.join(environment.as_shell_commands()), + uid=os.getuid(), + gid=os.getgid(), + dependency_install_flags='-c /constraints.txt' if dependency_constraints else '', + ) + ) # copy the output back into the host subprocess.run(['docker', 'cp', container_name + ':/output/.', os.path.abspath(output_dir)])