Mercurial > public > mercurial-scm > hg
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, |