changeset 44757:5e788dc7fb5d stable

automation: support building Python 3 MSI installers This is very similar to what we just did for Inno. Differential Revision: https://phab.mercurial-scm.org/D8484
author Gregory Szorc <gregory.szorc@gmail.com>
date Fri, 24 Apr 2020 12:37:43 -0700
parents 802ee93c205d
children c1c922391314 16cba0ad8ac2
files contrib/automation/hgautomation/cli.py contrib/automation/hgautomation/windows.py
diffstat 2 files changed, 115 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/contrib/automation/hgautomation/cli.py	Fri Apr 24 12:11:08 2020 -0700
+++ b/contrib/automation/hgautomation/cli.py	Fri Apr 24 12:37:43 2020 -0700
@@ -92,7 +92,13 @@
 
 
 def build_wix(
-    hga: HGAutomation, aws_region, arch, revision, version, base_image_name
+    hga: HGAutomation,
+    aws_region,
+    python_version,
+    arch,
+    revision,
+    version,
+    base_image_name,
 ):
     c = hga.aws_connection(aws_region)
     image = aws.ensure_windows_dev_ami(c, base_image_name=base_image_name)
@@ -103,10 +109,15 @@
 
         windows.synchronize_hg(SOURCE_ROOT, revision, instance)
 
-        for a in arch:
-            windows.build_wix_installer(
-                instance.winrm_client, a, DIST_PATH, version=version
-            )
+        for py_version in python_version:
+            for a in arch:
+                windows.build_wix_installer(
+                    instance.winrm_client,
+                    py_version,
+                    a,
+                    DIST_PATH,
+                    version=version,
+                )
 
 
 def build_windows_wheel(
@@ -163,12 +174,9 @@
                 windows.build_inno_installer(
                     winrm_client, py_version, arch, DIST_PATH, version=version
                 )
-
-        for arch in ('x86', 'x64'):
-            windows.purge_hg(winrm_client)
-            windows.build_wix_installer(
-                winrm_client, arch, DIST_PATH, version=version
-            )
+                windows.build_wix_installer(
+                    winrm_client, py_version, arch, DIST_PATH, version=version
+                )
 
 
 def terminate_ec2_instances(hga: HGAutomation, aws_region):
@@ -379,6 +387,14 @@
 
     sp = subparsers.add_parser('build-wix', help='Build WiX installer(s)')
     sp.add_argument(
+        '--python-version',
+        help='Which version of Python to target',
+        choices={2, 3},
+        type=int,
+        nargs='*',
+        default=[3],
+    )
+    sp.add_argument(
         '--arch',
         help='Architecture to build for',
         choices={'x86', 'x64'},
--- a/contrib/automation/hgautomation/windows.py	Fri Apr 24 12:11:08 2020 -0700
+++ b/contrib/automation/hgautomation/windows.py	Fri Apr 24 12:37:43 2020 -0700
@@ -95,7 +95,17 @@
 }}
 '''
 
-BUILD_WIX = r'''
+BUILD_WIX_PYTHON3 = r'''
+$Env:RUSTUP_HOME = "C:\hgdev\rustup"
+$Env:CARGO_HOME = "C:\hgdev\cargo"
+Set-Location C:\hgdev\src
+C:\hgdev\python37-x64\python.exe contrib\packaging\packaging.py wix --pyoxidizer-target {pyoxidizer_target} --version {version}
+if ($LASTEXITCODE -ne 0) {{
+    throw "process exited non-0: $LASTEXITCODE"
+}}
+'''
+
+BUILD_WIX_PYTHON2 = r'''
 Set-Location C:\hgdev\src
 $python = "C:\hgdev\python27-{arch}\python.exe"
 C:\hgdev\python37-x64\python.exe contrib\packaging\packaging.py wix --python $python {extra_args}
@@ -122,8 +132,11 @@
 EXE_FILENAME_PYTHON2_X64 = 'Mercurial-{version}-x64-python2.exe'
 EXE_FILENAME_PYTHON3_X86 = 'Mercurial-{version}-x86.exe'
 EXE_FILENAME_PYTHON3_X64 = 'Mercurial-{version}-x64.exe'
-X86_MSI_FILENAME = 'mercurial-{version}-x86-python2.msi'
-X64_MSI_FILENAME = 'mercurial-{version}-x64-python2.msi'
+
+MSI_FILENAME_PYTHON2_X86 = 'mercurial-{version}-x86-python2.msi'
+MSI_FILENAME_PYTHON2_X64 = 'mercurial-{version}-x64-python2.msi'
+MSI_FILENAME_PYTHON3_X86 = 'mercurial-{version}-x86.msi'
+MSI_FILENAME_PYTHON3_X64 = 'mercurial-{version}-x64.msi'
 
 MERCURIAL_SCM_BASE_URL = 'https://mercurial-scm.org/release/windows'
 
@@ -147,11 +160,21 @@
     'Mercurial {version} Inno Setup installer - x64 Windows (Python 3) '
     '- does not require admin rights'
 )
-X86_MSI_DESCRIPTION = (
-    'Mercurial {version} MSI installer - x86 Windows ' '- requires admin rights'
+MSI_PYTHON2_X86_DESCRIPTION = (
+    'Mercurial {version} MSI installer - x86 Windows (Python 2) '
+    '- requires admin rights'
+)
+MSI_PYTHON2_X64_DESCRIPTION = (
+    'Mercurial {version} MSI installer - x64 Windows (Python 2) '
+    '- requires admin rights'
 )
-X64_MSI_DESCRIPTION = (
-    'Mercurial {version} MSI installer - x64 Windows ' '- requires admin rights'
+MSI_PYTHON3_X86_DESCRIPTION = (
+    'Mercurial {version} MSI installer - x86 Windows (Python 3) '
+    '- requires admin rights'
+)
+MSI_PYTHON3_X64_DESCRIPTION = (
+    'Mercurial {version} MSI installer - x64 Windows (Python 3) '
+    '- requires admin rights'
 )
 
 
@@ -375,20 +398,44 @@
 
 
 def build_wix_installer(
-    winrm_client, arch: str, dest_path: pathlib.Path, version=None
+    winrm_client,
+    python_version: int,
+    arch: str,
+    dest_path: pathlib.Path,
+    version=None,
 ):
     """Build the WiX installer on a remote machine.
 
     Using a WinRM client, remote commands are executed to build a WiX installer.
     """
-    print('Building WiX installer for %s' % arch)
-    extra_args = []
-    if version:
-        extra_args.extend(['--version', version])
+    print('Building WiX installer for Python %d %s' % (python_version, arch))
+
+    if python_version == 3:
+        # TODO fix this limitation in packaging code
+        if not version:
+            raise Exception(
+                "version string is required when building for Python 3"
+            )
 
-    ps = get_vc_prefix(arch) + BUILD_WIX.format(
-        arch=arch, extra_args=' '.join(extra_args)
-    )
+        if arch == "x86":
+            target_triple = "i686-pc-windows-msvc"
+        elif arch == "x64":
+            target_triple = "x86_64-pc-windows-msvc"
+        else:
+            raise Exception("unhandled arch: %s" % arch)
+
+        ps = BUILD_WIX_PYTHON3.format(
+            pyoxidizer_target=target_triple, version=version,
+        )
+    else:
+        extra_args = []
+        if version:
+            extra_args.extend(['--version', version])
+
+        ps = get_vc_prefix(arch) + BUILD_WIX_PYTHON2.format(
+            arch=arch, extra_args=' '.join(extra_args)
+        )
+
     run_powershell(winrm_client, ps)
     copy_latest_dist(winrm_client, '*.msi', dest_path)
 
@@ -439,8 +486,10 @@
         dist_path / EXE_FILENAME_PYTHON2_X64.format(version=version),
         dist_path / EXE_FILENAME_PYTHON3_X86.format(version=version),
         dist_path / EXE_FILENAME_PYTHON3_X64.format(version=version),
-        dist_path / X86_MSI_FILENAME.format(version=version),
-        dist_path / X64_MSI_FILENAME.format(version=version),
+        dist_path / MSI_FILENAME_PYTHON2_X86.format(version=version),
+        dist_path / MSI_FILENAME_PYTHON2_X64.format(version=version),
+        dist_path / MSI_FILENAME_PYTHON3_X86.format(version=version),
+        dist_path / MSI_FILENAME_PYTHON3_X64.format(version=version),
     )
 
 
@@ -449,8 +498,10 @@
     python2_x64_exe_filename = EXE_FILENAME_PYTHON2_X64.format(version=version)
     python3_x86_exe_filename = EXE_FILENAME_PYTHON3_X86.format(version=version)
     python3_x64_exe_filename = EXE_FILENAME_PYTHON3_X64.format(version=version)
-    x86_msi_filename = X86_MSI_FILENAME.format(version=version)
-    x64_msi_filename = X64_MSI_FILENAME.format(version=version)
+    python2_x86_msi_filename = MSI_FILENAME_PYTHON2_X86.format(version=version)
+    python2_x64_msi_filename = MSI_FILENAME_PYTHON2_X64.format(version=version)
+    python3_x86_msi_filename = MSI_FILENAME_PYTHON3_X86.format(version=version)
+    python3_x64_msi_filename = MSI_FILENAME_PYTHON3_X64.format(version=version)
 
     entries = (
         (
@@ -485,15 +536,29 @@
             '10',
             version,
             X86_USER_AGENT_PATTERN,
-            '%s/%s' % (MERCURIAL_SCM_BASE_URL, x86_msi_filename),
-            X86_MSI_DESCRIPTION.format(version=version),
+            '%s/%s' % (MERCURIAL_SCM_BASE_URL, python3_x86_msi_filename),
+            MSI_PYTHON3_X86_DESCRIPTION.format(version=version),
         ),
         (
             '10',
             version,
             X64_USER_AGENT_PATTERN,
-            '%s/%s' % (MERCURIAL_SCM_BASE_URL, x64_msi_filename),
-            X64_MSI_DESCRIPTION.format(version=version),
+            '%s/%s' % (MERCURIAL_SCM_BASE_URL, python3_x64_msi_filename),
+            MSI_PYTHON3_X64_DESCRIPTION.format(version=version),
+        ),
+        (
+            '9',
+            version,
+            X86_USER_AGENT_PATTERN,
+            '%s/%s' % (MERCURIAL_SCM_BASE_URL, python2_x86_msi_filename),
+            MSI_PYTHON2_X86_DESCRIPTION.format(version=version),
+        ),
+        (
+            '9',
+            version,
+            X64_USER_AGENT_PATTERN,
+            '%s/%s' % (MERCURIAL_SCM_BASE_URL, python2_x64_msi_filename),
+            MSI_PYTHON2_X64_DESCRIPTION.format(version=version),
         ),
     )