Patchwork D8478: automation: support building Windows wheels for Python 3.7 and 3.8

login
register
mail settings
Submitter phabricator
Date April 24, 2020, 3:28 a.m.
Message ID <differential-rev-PHID-DREV-f6iya2wk5pjpuup5vuul-req@mercurial-scm.org>
Download mbox | patch
Permalink /patch/46229/
State Superseded
Headers show

Comments

phabricator - April 24, 2020, 3:28 a.m.
indygreg created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REVISION SUMMARY
  The time has come to support Python 3 on Windows.
  
  Let's teach our automation code to produce Windows wheels for
  Python 3.7 and 3.8.
  
  We could theoretically support 3.5 and 3.6. But I don't think
  it is worth it. People on Windows generally use the Mercurial
  installers, not wheels. And I'd prefer we limit variability
  and not have to worry about supporting earlier Python versions
  if it can be helped.
  
  As part of this, we change the invocation of pip to `python.exe -m pip`,
  as this is what is being recommended in Python docs these days. And
  it seemed to be required to avoid a weird build error. Why, I'm not
  sure. But it looks like pip was having trouble finding a Visual Studio
  files when invoked as `pip.exe` but not when using `python.exe -m pip`.
  Who knows.

REPOSITORY
  rHG Mercurial

BRANCH
  stable

REVISION DETAIL
  https://phab.mercurial-scm.org/D8478

AFFECTED FILES
  contrib/automation/hgautomation/cli.py
  contrib/automation/hgautomation/windows.py

CHANGE DETAILS




To: indygreg, #hg-reviewers
Cc: mercurial-patches, mercurial-devel

Patch

diff --git a/contrib/automation/hgautomation/windows.py b/contrib/automation/hgautomation/windows.py
--- a/contrib/automation/hgautomation/windows.py
+++ b/contrib/automation/hgautomation/windows.py
@@ -79,7 +79,7 @@ 
 
 BUILD_WHEEL = r'''
 Set-Location C:\hgdev\src
-C:\hgdev\python27-{arch}\Scripts\pip.exe wheel --wheel-dir dist .
+C:\hgdev\python{python_version}-{arch}\python.exe -m pip wheel --wheel-dir dist .
 if ($LASTEXITCODE -ne 0) {{
     throw "process exited non-0: $LASTEXITCODE"
 }}
@@ -101,8 +101,13 @@ 
 }}
 '''
 
-X86_WHEEL_FILENAME = 'mercurial-{version}-cp27-cp27m-win32.whl'
-X64_WHEEL_FILENAME = 'mercurial-{version}-cp27-cp27m-win_amd64.whl'
+WHEEL_FILENAME_PYTHON27_X86 = 'mercurial-{version}-cp27-cp27m-win32.whl'
+WHEEL_FILENAME_PYTHON27_X64 = 'mercurial-{version}-cp27-cp27m-win_amd64.whl'
+WHEEL_FILENAME_PYTHON37_X86 = 'mercurial-{version}-cp37-cp37m-win32.whl'
+WHEEL_FILENAME_PYTHON37_X64 = 'mercurial-{version}-cp37-cp37m-win_amd64.whl'
+WHEEL_FILENAME_PYTHON38_X86 = 'mercurial-{version}-cp38-cp38-win32.whl'
+WHEEL_FILENAME_PYTHON38_X64 = 'mercurial-{version}-cp38-cp38-win_amd64.whl'
+
 X86_EXE_FILENAME = 'Mercurial-{version}.exe'
 X64_EXE_FILENAME = 'Mercurial-{version}-x64.exe'
 X86_MSI_FILENAME = 'mercurial-{version}-x86.msi'
@@ -300,14 +305,24 @@ 
     copy_latest_dist(winrm_client, '*.exe', dest_path)
 
 
-def build_wheel(winrm_client, arch: str, dest_path: pathlib.Path):
+def build_wheel(
+    winrm_client, python_version: str, arch: str, dest_path: pathlib.Path
+):
     """Build Python wheels on a remote machine.
 
     Using a WinRM client, remote commands are executed to build a Python wheel
     for Mercurial.
     """
-    print('Building Windows wheel for %s' % arch)
-    ps = get_vc_prefix(arch) + BUILD_WHEEL.format(arch=arch)
+    print('Building Windows wheel for Python %s %s' % (python_version, arch))
+
+    ps = BUILD_WHEEL.format(
+        python_version=python_version.replace(".", ""), arch=arch
+    )
+
+    # Python 2.7 requires an activated environment.
+    if python_version == "2.7":
+        ps = get_vc_prefix(arch) + ps
+
     run_powershell(winrm_client, ps)
     copy_latest_dist(winrm_client, '*.whl', dest_path)
 
@@ -356,15 +371,23 @@ 
 
 def resolve_wheel_artifacts(dist_path: pathlib.Path, version: str):
     return (
-        dist_path / X86_WHEEL_FILENAME.format(version=version),
-        dist_path / X64_WHEEL_FILENAME.format(version=version),
+        dist_path / WHEEL_FILENAME_PYTHON27_X86.format(version=version),
+        dist_path / WHEEL_FILENAME_PYTHON27_X64.format(version=version),
+        dist_path / WHEEL_FILENAME_PYTHON37_X86.format(version=version),
+        dist_path / WHEEL_FILENAME_PYTHON37_X64.format(version=version),
+        dist_path / WHEEL_FILENAME_PYTHON38_X86.format(version=version),
+        dist_path / WHEEL_FILENAME_PYTHON38_X64.format(version=version),
     )
 
 
 def resolve_all_artifacts(dist_path: pathlib.Path, version: str):
     return (
-        dist_path / X86_WHEEL_FILENAME.format(version=version),
-        dist_path / X64_WHEEL_FILENAME.format(version=version),
+        dist_path / WHEEL_FILENAME_PYTHON27_X86.format(version=version),
+        dist_path / WHEEL_FILENAME_PYTHON27_X64.format(version=version),
+        dist_path / WHEEL_FILENAME_PYTHON37_X86.format(version=version),
+        dist_path / WHEEL_FILENAME_PYTHON37_X64.format(version=version),
+        dist_path / WHEEL_FILENAME_PYTHON38_X86.format(version=version),
+        dist_path / WHEEL_FILENAME_PYTHON38_X64.format(version=version),
         dist_path / X86_EXE_FILENAME.format(version=version),
         dist_path / X64_EXE_FILENAME.format(version=version),
         dist_path / X86_MSI_FILENAME.format(version=version),
diff --git a/contrib/automation/hgautomation/cli.py b/contrib/automation/hgautomation/cli.py
--- a/contrib/automation/hgautomation/cli.py
+++ b/contrib/automation/hgautomation/cli.py
@@ -99,7 +99,12 @@ 
 
 
 def build_windows_wheel(
-    hga: HGAutomation, aws_region, arch, revision, base_image_name
+    hga: HGAutomation,
+    aws_region,
+    python_version,
+    arch,
+    revision,
+    base_image_name,
 ):
     c = hga.aws_connection(aws_region)
     image = aws.ensure_windows_dev_ami(c, base_image_name=base_image_name)
@@ -110,8 +115,11 @@ 
 
         windows.synchronize_hg(SOURCE_ROOT, revision, instance)
 
-        for a in arch:
-            windows.build_wheel(instance.winrm_client, a, DIST_PATH)
+        for py_version in python_version:
+            for a in arch:
+                windows.build_wheel(
+                    instance.winrm_client, py_version, a, DIST_PATH
+                )
 
 
 def build_all_windows_packages(
@@ -128,10 +136,18 @@ 
 
         windows.synchronize_hg(SOURCE_ROOT, revision, instance)
 
+        for py_version in ("2.7", "3.7", "3.8"):
+            for arch in ("x86", "x64"):
+                windows.purge_hg(winrm_client)
+                windows.build_wheel(
+                    winrm_client,
+                    python_version=py_version,
+                    arch=arch,
+                    dest_path=DIST_PATH,
+                )
+
         for arch in ('x86', 'x64'):
             windows.purge_hg(winrm_client)
-            windows.build_wheel(winrm_client, arch, DIST_PATH)
-            windows.purge_hg(winrm_client)
             windows.build_inno_installer(
                 winrm_client, arch, DIST_PATH, version=version
             )
@@ -316,6 +332,13 @@ 
         'build-windows-wheel', help='Build Windows wheel(s)',
     )
     sp.add_argument(
+        '--python-version',
+        help='Python version to build for',
+        choices={'2.7', '3.7', '3.8'},
+        nargs='*',
+        default=['3.8'],
+    )
+    sp.add_argument(
         '--arch',
         help='Architecture to build for',
         choices={'x86', 'x64'},