comparison contrib/automation/hgautomation/windows.py @ 44771:802ee93c205d stable

automation: support building Python 3 Inno installers The core packaging code now supports building Python 3 installers using PyOxidizer. Let's teach the automation code to invoke it so that we produce both Python 2 and Python 3 based exe installers. When publishing the artifacts, the Python 3 versions are preferred over the Python 2 versions given their higher weight (10 versus 9). This may be a controversial change. But I think making Python 3 the default is warranted, as it is the future. The Python 2 installers are still fully supported and can be installed should issues with Python 3 arise. Differential Revision: https://phab.mercurial-scm.org/D8483
author Gregory Szorc <gregory.szorc@gmail.com>
date Fri, 24 Apr 2020 12:11:08 -0700
parents 47609da15379
children 5e788dc7fb5d
comparison
equal deleted inserted replaced
44770:47609da15379 44771:802ee93c205d
66 }} 66 }}
67 hg.exe log -r . 67 hg.exe log -r .
68 Write-Output "updated Mercurial working directory to {revision}" 68 Write-Output "updated Mercurial working directory to {revision}"
69 '''.lstrip() 69 '''.lstrip()
70 70
71 BUILD_INNO = r''' 71 BUILD_INNO_PYTHON3 = r'''
72 $Env:RUSTUP_HOME = "C:\hgdev\rustup"
73 $Env:CARGO_HOME = "C:\hgdev\cargo"
74 Set-Location C:\hgdev\src
75 C:\hgdev\python37-x64\python.exe contrib\packaging\packaging.py inno --pyoxidizer-target {pyoxidizer_target} --version {version}
76 if ($LASTEXITCODE -ne 0) {{
77 throw "process exited non-0: $LASTEXITCODE"
78 }}
79 '''
80
81 BUILD_INNO_PYTHON2 = r'''
72 Set-Location C:\hgdev\src 82 Set-Location C:\hgdev\src
73 $python = "C:\hgdev\python27-{arch}\python.exe" 83 $python = "C:\hgdev\python27-{arch}\python.exe"
74 C:\hgdev\python37-x64\python.exe contrib\packaging\packaging.py inno --python $python {extra_args} 84 C:\hgdev\python37-x64\python.exe contrib\packaging\packaging.py inno --python $python {extra_args}
75 if ($LASTEXITCODE -ne 0) {{ 85 if ($LASTEXITCODE -ne 0) {{
76 throw "process exited non-0: $LASTEXITCODE" 86 throw "process exited non-0: $LASTEXITCODE"
106 WHEEL_FILENAME_PYTHON37_X86 = 'mercurial-{version}-cp37-cp37m-win32.whl' 116 WHEEL_FILENAME_PYTHON37_X86 = 'mercurial-{version}-cp37-cp37m-win32.whl'
107 WHEEL_FILENAME_PYTHON37_X64 = 'mercurial-{version}-cp37-cp37m-win_amd64.whl' 117 WHEEL_FILENAME_PYTHON37_X64 = 'mercurial-{version}-cp37-cp37m-win_amd64.whl'
108 WHEEL_FILENAME_PYTHON38_X86 = 'mercurial-{version}-cp38-cp38-win32.whl' 118 WHEEL_FILENAME_PYTHON38_X86 = 'mercurial-{version}-cp38-cp38-win32.whl'
109 WHEEL_FILENAME_PYTHON38_X64 = 'mercurial-{version}-cp38-cp38-win_amd64.whl' 119 WHEEL_FILENAME_PYTHON38_X64 = 'mercurial-{version}-cp38-cp38-win_amd64.whl'
110 120
111 X86_EXE_FILENAME = 'Mercurial-{version}-x86-python2.exe' 121 EXE_FILENAME_PYTHON2_X86 = 'Mercurial-{version}-x86-python2.exe'
112 X64_EXE_FILENAME = 'Mercurial-{version}-x64-python2.exe' 122 EXE_FILENAME_PYTHON2_X64 = 'Mercurial-{version}-x64-python2.exe'
123 EXE_FILENAME_PYTHON3_X86 = 'Mercurial-{version}-x86.exe'
124 EXE_FILENAME_PYTHON3_X64 = 'Mercurial-{version}-x64.exe'
113 X86_MSI_FILENAME = 'mercurial-{version}-x86-python2.msi' 125 X86_MSI_FILENAME = 'mercurial-{version}-x86-python2.msi'
114 X64_MSI_FILENAME = 'mercurial-{version}-x64-python2.msi' 126 X64_MSI_FILENAME = 'mercurial-{version}-x64-python2.msi'
115 127
116 MERCURIAL_SCM_BASE_URL = 'https://mercurial-scm.org/release/windows' 128 MERCURIAL_SCM_BASE_URL = 'https://mercurial-scm.org/release/windows'
117 129
118 X86_USER_AGENT_PATTERN = '.*Windows.*' 130 X86_USER_AGENT_PATTERN = '.*Windows.*'
119 X64_USER_AGENT_PATTERN = '.*Windows.*(WOW|x)64.*' 131 X64_USER_AGENT_PATTERN = '.*Windows.*(WOW|x)64.*'
120 132
121 X86_EXE_DESCRIPTION = ( 133 EXE_PYTHON2_X86_DESCRIPTION = (
122 'Mercurial {version} Inno Setup installer - x86 Windows ' 134 'Mercurial {version} Inno Setup installer - x86 Windows (Python 2) '
123 '- does not require admin rights' 135 '- does not require admin rights'
124 ) 136 )
125 X64_EXE_DESCRIPTION = ( 137 EXE_PYTHON2_X64_DESCRIPTION = (
126 'Mercurial {version} Inno Setup installer - x64 Windows ' 138 'Mercurial {version} Inno Setup installer - x64 Windows (Python 2) '
139 '- does not require admin rights'
140 )
141 # TODO remove Python version once Python 2 is dropped.
142 EXE_PYTHON3_X86_DESCRIPTION = (
143 'Mercurial {version} Inno Setup installer - x86 Windows (Python 3) '
144 '- does not require admin rights'
145 )
146 EXE_PYTHON3_X64_DESCRIPTION = (
147 'Mercurial {version} Inno Setup installer - x64 Windows (Python 3) '
127 '- does not require admin rights' 148 '- does not require admin rights'
128 ) 149 )
129 X86_MSI_DESCRIPTION = ( 150 X86_MSI_DESCRIPTION = (
130 'Mercurial {version} MSI installer - x86 Windows ' '- requires admin rights' 151 'Mercurial {version} MSI installer - x86 Windows ' '- requires admin rights'
131 ) 152 )
283 print('copying %s to %s' % (source, dest)) 304 print('copying %s to %s' % (source, dest))
284 winrm_client.fetch(source, str(dest)) 305 winrm_client.fetch(source, str(dest))
285 306
286 307
287 def build_inno_installer( 308 def build_inno_installer(
288 winrm_client, arch: str, dest_path: pathlib.Path, version=None 309 winrm_client,
310 python_version: int,
311 arch: str,
312 dest_path: pathlib.Path,
313 version=None,
289 ): 314 ):
290 """Build the Inno Setup installer on a remote machine. 315 """Build the Inno Setup installer on a remote machine.
291 316
292 Using a WinRM client, remote commands are executed to build 317 Using a WinRM client, remote commands are executed to build
293 a Mercurial Inno Setup installer. 318 a Mercurial Inno Setup installer.
294 """ 319 """
295 print('building Inno Setup installer for %s' % arch) 320 print(
296 321 'building Inno Setup installer for Python %d %s'
297 extra_args = [] 322 % (python_version, arch)
298 if version: 323 )
299 extra_args.extend(['--version', version]) 324
300 325 if python_version == 3:
301 ps = get_vc_prefix(arch) + BUILD_INNO.format( 326 # TODO fix this limitation in packaging code
302 arch=arch, extra_args=' '.join(extra_args) 327 if not version:
303 ) 328 raise Exception(
329 "version string is required when building for Python 3"
330 )
331
332 if arch == "x86":
333 target_triple = "i686-pc-windows-msvc"
334 elif arch == "x64":
335 target_triple = "x86_64-pc-windows-msvc"
336 else:
337 raise Exception("unhandled arch: %s" % arch)
338
339 ps = BUILD_INNO_PYTHON3.format(
340 pyoxidizer_target=target_triple, version=version,
341 )
342 else:
343 extra_args = []
344 if version:
345 extra_args.extend(['--version', version])
346
347 ps = get_vc_prefix(arch) + BUILD_INNO_PYTHON2.format(
348 arch=arch, extra_args=' '.join(extra_args)
349 )
350
304 run_powershell(winrm_client, ps) 351 run_powershell(winrm_client, ps)
305 copy_latest_dist(winrm_client, '*.exe', dest_path) 352 copy_latest_dist(winrm_client, '*.exe', dest_path)
306 353
307 354
308 def build_wheel( 355 def build_wheel(
386 dist_path / WHEEL_FILENAME_PYTHON27_X64.format(version=version), 433 dist_path / WHEEL_FILENAME_PYTHON27_X64.format(version=version),
387 dist_path / WHEEL_FILENAME_PYTHON37_X86.format(version=version), 434 dist_path / WHEEL_FILENAME_PYTHON37_X86.format(version=version),
388 dist_path / WHEEL_FILENAME_PYTHON37_X64.format(version=version), 435 dist_path / WHEEL_FILENAME_PYTHON37_X64.format(version=version),
389 dist_path / WHEEL_FILENAME_PYTHON38_X86.format(version=version), 436 dist_path / WHEEL_FILENAME_PYTHON38_X86.format(version=version),
390 dist_path / WHEEL_FILENAME_PYTHON38_X64.format(version=version), 437 dist_path / WHEEL_FILENAME_PYTHON38_X64.format(version=version),
391 dist_path / X86_EXE_FILENAME.format(version=version), 438 dist_path / EXE_FILENAME_PYTHON2_X86.format(version=version),
392 dist_path / X64_EXE_FILENAME.format(version=version), 439 dist_path / EXE_FILENAME_PYTHON2_X64.format(version=version),
440 dist_path / EXE_FILENAME_PYTHON3_X86.format(version=version),
441 dist_path / EXE_FILENAME_PYTHON3_X64.format(version=version),
393 dist_path / X86_MSI_FILENAME.format(version=version), 442 dist_path / X86_MSI_FILENAME.format(version=version),
394 dist_path / X64_MSI_FILENAME.format(version=version), 443 dist_path / X64_MSI_FILENAME.format(version=version),
395 ) 444 )
396 445
397 446
398 def generate_latest_dat(version: str): 447 def generate_latest_dat(version: str):
399 x86_exe_filename = X86_EXE_FILENAME.format(version=version) 448 python2_x86_exe_filename = EXE_FILENAME_PYTHON2_X86.format(version=version)
400 x64_exe_filename = X64_EXE_FILENAME.format(version=version) 449 python2_x64_exe_filename = EXE_FILENAME_PYTHON2_X64.format(version=version)
450 python3_x86_exe_filename = EXE_FILENAME_PYTHON3_X86.format(version=version)
451 python3_x64_exe_filename = EXE_FILENAME_PYTHON3_X64.format(version=version)
401 x86_msi_filename = X86_MSI_FILENAME.format(version=version) 452 x86_msi_filename = X86_MSI_FILENAME.format(version=version)
402 x64_msi_filename = X64_MSI_FILENAME.format(version=version) 453 x64_msi_filename = X64_MSI_FILENAME.format(version=version)
403 454
404 entries = ( 455 entries = (
405 ( 456 (
406 '10', 457 '10',
407 version, 458 version,
408 X86_USER_AGENT_PATTERN, 459 X86_USER_AGENT_PATTERN,
409 '%s/%s' % (MERCURIAL_SCM_BASE_URL, x86_exe_filename), 460 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python3_x86_exe_filename),
410 X86_EXE_DESCRIPTION.format(version=version), 461 EXE_PYTHON3_X86_DESCRIPTION.format(version=version),
411 ), 462 ),
412 ( 463 (
413 '10', 464 '10',
414 version, 465 version,
415 X64_USER_AGENT_PATTERN, 466 X64_USER_AGENT_PATTERN,
416 '%s/%s' % (MERCURIAL_SCM_BASE_URL, x64_exe_filename), 467 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python3_x64_exe_filename),
417 X64_EXE_DESCRIPTION.format(version=version), 468 EXE_PYTHON3_X64_DESCRIPTION.format(version=version),
469 ),
470 (
471 '9',
472 version,
473 X86_USER_AGENT_PATTERN,
474 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python2_x86_exe_filename),
475 EXE_PYTHON2_X86_DESCRIPTION.format(version=version),
476 ),
477 (
478 '9',
479 version,
480 X64_USER_AGENT_PATTERN,
481 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python2_x64_exe_filename),
482 EXE_PYTHON2_X64_DESCRIPTION.format(version=version),
418 ), 483 ),
419 ( 484 (
420 '10', 485 '10',
421 version, 486 version,
422 X86_USER_AGENT_PATTERN, 487 X86_USER_AGENT_PATTERN,