diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5a9e501c..6d67dfbb 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,7 +1,7 @@ jobs: - job: linux - pool: {vmImage: 'Ubuntu-16.04'} - steps: + pool: {vmImage: 'Ubuntu-18.04'} + steps: - task: UsePythonVersion@0 - bash: | python -m pip install -r requirements-dev.txt @@ -9,7 +9,7 @@ jobs: - job: macos pool: {vmImage: 'macOS-10.13'} - steps: + steps: - task: UsePythonVersion@0 - bash: | python -m pip install -r requirements-dev.txt @@ -17,15 +17,8 @@ jobs: - job: windows pool: {vmImage: 'vs2017-win2016'} - steps: - - {task: UsePythonVersion@0, inputs: {versionSpec: '2.7', architecture: x86}} - - {task: UsePythonVersion@0, inputs: {versionSpec: '2.7', architecture: x64}} - - {task: UsePythonVersion@0, inputs: {versionSpec: '3.5', architecture: x86}} - - {task: UsePythonVersion@0, inputs: {versionSpec: '3.5', architecture: x64}} - - {task: UsePythonVersion@0, inputs: {versionSpec: '3.6', architecture: x86}} - - {task: UsePythonVersion@0, inputs: {versionSpec: '3.6', architecture: x64}} - - {task: UsePythonVersion@0, inputs: {versionSpec: '3.7', architecture: x86}} - - {task: UsePythonVersion@0, inputs: {versionSpec: '3.7', architecture: x64}} + steps: + - task: UsePythonVersion@0 - script: choco install vcpython27 -f -y displayName: Install Visual C++ for Python 2.7 - bash: | diff --git a/cibuildwheel/windows.py b/cibuildwheel/windows.py index 7f7eaae2..d37d7509 100644 --- a/cibuildwheel/windows.py +++ b/cibuildwheel/windows.py @@ -8,67 +8,48 @@ try: except ImportError: from pipes import quote as shlex_quote +try: + from urllib.request import urlopen +except ImportError: + from urllib2 import urlopen + from .util import prepare_command, get_build_verbosity_extra_flags IS_RUNNING_ON_AZURE = os.path.exists('C:\\hostedtoolcache') IS_RUNNING_ON_TRAVIS = os.environ.get('TRAVIS_OS_NAME') == 'windows' + def get_python_path(config): - if IS_RUNNING_ON_AZURE: - # We can't hard-code the paths because on Azure, we don't know which - # bugfix release of Python we are getting so we need to check which - # ones exist. We just use the first one that is found since there should - # only be one. - path_pattern = 'C:\\hostedtoolcache\\windows\\Python\\{version}\\{arch}'.format( - version=config.version.replace('x', '*'), - arch='x86' if config.arch == '32' else 'x64' - ) - try: - return glob(path_pattern)[0] - except IndexError: - raise Exception('Could not find a Python install at ' + path_pattern) - elif IS_RUNNING_ON_TRAVIS: - if config.version == "3.4.x": - return config.path - else: - nuget_args = get_nuget_args(config) - return os.path.join(nuget_args[-1], nuget_args[0] + "." + config.nuget_version, "tools") - else: - # Assume we're running on AppVeyor - major, minor = config.version.split('.')[:2] - return 'C:\\Python{major}{minor}{arch}'.format( - major=major, - minor=minor, - arch = '-x64' if config.arch == '64' else '' - ) + nuget_args = get_nuget_args(config) + return os.path.join(nuget_args[-1], nuget_args[0] + "." + config.version, "tools") def get_nuget_args(configuration): - if configuration.nuget_version is None: - return None python_name = "python" if configuration.version[0] == '3' else "python2" if configuration.arch == "32": python_name = python_name + "x86" - return [python_name, "-Version", configuration.nuget_version, "-OutputDirectory", "C:/python"] + return [python_name, "-Version", configuration.version, "-OutputDirectory", "C:/python"] def get_python_configurations(build_selector): - PythonConfiguration = namedtuple('PythonConfiguration', ['version', 'arch', 'identifier', 'path', "nuget_version"]) + PythonConfiguration = namedtuple('PythonConfiguration', ['version', 'arch', 'identifier']) python_configurations = [ - PythonConfiguration(version='2.7.x', arch="32", identifier='cp27-win32', path='C:\\Python27', nuget_version="2.7.16"), - PythonConfiguration(version='2.7.x', arch="64", identifier='cp27-win_amd64', path='C:\\Python27-x64', nuget_version="2.7.16"), - PythonConfiguration(version='3.5.x', arch="32", identifier='cp35-win32', path='C:\\Python35', nuget_version="3.5.4"), - PythonConfiguration(version='3.5.x', arch="64", identifier='cp35-win_amd64', path='C:\\Python35-x64', nuget_version="3.5.4"), - PythonConfiguration(version='3.6.x', arch="32", identifier='cp36-win32', path='C:\\Python36', nuget_version="3.6.8"), - PythonConfiguration(version='3.6.x', arch="64", identifier='cp36-win_amd64', path='C:\\Python36-x64', nuget_version="3.6.8"), - PythonConfiguration(version='3.7.x', arch="32", identifier='cp37-win32', path='C:\\Python37', nuget_version="3.7.4"), - PythonConfiguration(version='3.7.x', arch="64", identifier='cp37-win_amd64', path='C:\\Python37-x64', nuget_version="3.7.4") + PythonConfiguration(version='2.7.17', arch="32", identifier='cp27-win32'), + PythonConfiguration(version='2.7.17', arch="64", identifier='cp27-win_amd64'), + PythonConfiguration(version='3.5.4', arch="32", identifier='cp35-win32'), + PythonConfiguration(version='3.5.4', arch="64", identifier='cp35-win_amd64'), + PythonConfiguration(version='3.6.8', arch="32", identifier='cp36-win32'), + PythonConfiguration(version='3.6.8', arch="64", identifier='cp36-win_amd64'), + PythonConfiguration(version='3.7.5', arch="32", identifier='cp37-win32'), + PythonConfiguration(version='3.7.5', arch="64", identifier='cp37-win_amd64'), + PythonConfiguration(version='3.8.0', arch="32", identifier='cp38-win32'), + PythonConfiguration(version='3.8.0', arch="64", identifier='cp38-win_amd64'), ] if IS_RUNNING_ON_TRAVIS: # cannot install VCForPython27.msi which is needed for compiling C software # try with (and similar): msiexec /i VCForPython27.msi ALLUSERS=1 ACCEPT=YES /passive - python_configurations = [c for c in python_configurations if c.version != '2.7.x'] + python_configurations = [c for c in python_configurations if not c.version.startswith('2.7.')] # skip builds as required python_configurations = [c for c in python_configurations if build_selector(c.identifier)] @@ -78,11 +59,20 @@ def get_python_configurations(build_selector): def build(project_dir, output_dir, test_command, test_requires, test_extras, before_build, build_verbosity, build_selector, environment): + def simple_shell(args, env=None, cwd=None): + print('+ ' + ' '.join(args)) + args = ['cmd', '/E:ON', '/V:ON', '/C'] + args + return subprocess.check_call(' '.join(args), env=env, cwd=cwd) + def download(url, dest): + print('+ Download ' + url + ' to ' + dest) + response = urlopen(url) + try: + with open(dest, 'wb') as file: + file.write(response.read()) + finally: + response.close() if IS_RUNNING_ON_AZURE or IS_RUNNING_ON_TRAVIS: - def shell(args, env=None, cwd=None): - print('+ ' + ' '.join(args)) - args = ['cmd', '/E:ON', '/V:ON', '/C'] + args - return subprocess.check_call(' '.join(args), env=env, cwd=cwd) + shell = simple_shell else: run_with_env = os.path.abspath(os.path.join(os.path.dirname(__file__), 'resources', 'appveyor_run_with_env.cmd')) @@ -98,21 +88,19 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef temp_dir = tempfile.mkdtemp(prefix='cibuildwheel') built_wheel_dir = os.path.join(temp_dir, 'built_wheel') - if IS_RUNNING_ON_TRAVIS: - # instal nuget as best way for provide python - shell(["choco", "install", "nuget.commandline"]) - # get pip fo this installation which not have. - get_pip_url = 'https://bootstrap.pypa.io/get-pip.py' - get_pip_script = 'C:\\get-pip.py' - shell(['curl', '-L', '-o', get_pip_script, get_pip_url]) + # install nuget as best way to provide python + nuget = 'C:\\nuget.exe' + download('https://dist.nuget.org/win-x86-commandline/latest/nuget.exe', nuget) + # get pip fo this installation which not have. + get_pip_script = 'C:\\get-pip.py' + download('https://bootstrap.pypa.io/get-pip.py', get_pip_script) python_configurations = get_python_configurations(build_selector) for config in python_configurations: config_python_path = get_python_path(config) - if IS_RUNNING_ON_TRAVIS and config.nuget_version is not None and not os.path.exists(config_python_path): - shell(["nuget", "install"] + get_nuget_args(config)) - if not os.path.exists(os.path.join(config_python_path, 'Scripts', 'pip.exe')): - shell([os.path.join(config_python_path, 'python.exe'), get_pip_script ]) + simple_shell([nuget, "install"] + get_nuget_args(config)) + if not os.path.exists(os.path.join(config_python_path, 'Scripts', 'pip.exe')): + simple_shell([os.path.join(config_python_path, 'python.exe'), get_pip_script ]) # check python & pip exist for this configuration assert os.path.exists(os.path.join(config_python_path, 'python.exe')) @@ -139,12 +127,7 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef shell(['python', '-c', '"import struct; print(struct.calcsize(\'P\') * 8)\"'], env=env) # prepare the Python environment - if config.version == "3.4.x": - shell(['python', '-m', 'pip', 'install', 'pip==19.1.1'], - env=env) - else: - shell(['python', '-m', 'pip', 'install', '--upgrade', 'pip'], - env=env) + shell(['python', '-m', 'pip', 'install', '--upgrade', 'pip'], env=env) shell(['pip', 'install', '--upgrade', 'setuptools'], env=env) shell(['pip', 'install', 'wheel'], env=env) diff --git a/test/shared/utils.py b/test/shared/utils.py index 2a96df61..94aa96d3 100644 --- a/test/shared/utils.py +++ b/test/shared/utils.py @@ -76,10 +76,12 @@ def expected_wheels(package_name, package_version): '{package_name}-{package_version}-cp35-cp35m-win32.whl', '{package_name}-{package_version}-cp36-cp36m-win32.whl', '{package_name}-{package_version}-cp37-cp37m-win32.whl', + '{package_name}-{package_version}-cp38-cp38-win32.whl', '{package_name}-{package_version}-cp27-cp27m-win_amd64.whl', '{package_name}-{package_version}-cp35-cp35m-win_amd64.whl', '{package_name}-{package_version}-cp36-cp36m-win_amd64.whl', '{package_name}-{package_version}-cp37-cp37m-win_amd64.whl', + '{package_name}-{package_version}-cp38-cp38-win_amd64.whl', ] elif platform == 'macos': templates = [ @@ -92,7 +94,7 @@ def expected_wheels(package_name, package_version): raise Exception('unsupported platform') if IS_WINDOWS_RUNNING_ON_TRAVIS: - # Python 2.7 and 3.4 isn't supported on Travis. + # Python 2.7 isn't supported on Travis. templates = [t for t in templates if '-cp27-' not in t] return [filename.format(package_name=package_name, package_version=package_version)