comparison contrib/automation/hgautomation/windows.py @ 44772: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 d1ce0ffdd3ce
comparison
equal deleted inserted replaced
44771:802ee93c205d 44772:5e788dc7fb5d
93 if ($LASTEXITCODE -ne 0) {{ 93 if ($LASTEXITCODE -ne 0) {{
94 throw "process exited non-0: $LASTEXITCODE" 94 throw "process exited non-0: $LASTEXITCODE"
95 }} 95 }}
96 ''' 96 '''
97 97
98 BUILD_WIX = r''' 98 BUILD_WIX_PYTHON3 = r'''
99 $Env:RUSTUP_HOME = "C:\hgdev\rustup"
100 $Env:CARGO_HOME = "C:\hgdev\cargo"
101 Set-Location C:\hgdev\src
102 C:\hgdev\python37-x64\python.exe contrib\packaging\packaging.py wix --pyoxidizer-target {pyoxidizer_target} --version {version}
103 if ($LASTEXITCODE -ne 0) {{
104 throw "process exited non-0: $LASTEXITCODE"
105 }}
106 '''
107
108 BUILD_WIX_PYTHON2 = r'''
99 Set-Location C:\hgdev\src 109 Set-Location C:\hgdev\src
100 $python = "C:\hgdev\python27-{arch}\python.exe" 110 $python = "C:\hgdev\python27-{arch}\python.exe"
101 C:\hgdev\python37-x64\python.exe contrib\packaging\packaging.py wix --python $python {extra_args} 111 C:\hgdev\python37-x64\python.exe contrib\packaging\packaging.py wix --python $python {extra_args}
102 if ($LASTEXITCODE -ne 0) {{ 112 if ($LASTEXITCODE -ne 0) {{
103 throw "process exited non-0: $LASTEXITCODE" 113 throw "process exited non-0: $LASTEXITCODE"
120 130
121 EXE_FILENAME_PYTHON2_X86 = 'Mercurial-{version}-x86-python2.exe' 131 EXE_FILENAME_PYTHON2_X86 = 'Mercurial-{version}-x86-python2.exe'
122 EXE_FILENAME_PYTHON2_X64 = 'Mercurial-{version}-x64-python2.exe' 132 EXE_FILENAME_PYTHON2_X64 = 'Mercurial-{version}-x64-python2.exe'
123 EXE_FILENAME_PYTHON3_X86 = 'Mercurial-{version}-x86.exe' 133 EXE_FILENAME_PYTHON3_X86 = 'Mercurial-{version}-x86.exe'
124 EXE_FILENAME_PYTHON3_X64 = 'Mercurial-{version}-x64.exe' 134 EXE_FILENAME_PYTHON3_X64 = 'Mercurial-{version}-x64.exe'
125 X86_MSI_FILENAME = 'mercurial-{version}-x86-python2.msi' 135
126 X64_MSI_FILENAME = 'mercurial-{version}-x64-python2.msi' 136 MSI_FILENAME_PYTHON2_X86 = 'mercurial-{version}-x86-python2.msi'
137 MSI_FILENAME_PYTHON2_X64 = 'mercurial-{version}-x64-python2.msi'
138 MSI_FILENAME_PYTHON3_X86 = 'mercurial-{version}-x86.msi'
139 MSI_FILENAME_PYTHON3_X64 = 'mercurial-{version}-x64.msi'
127 140
128 MERCURIAL_SCM_BASE_URL = 'https://mercurial-scm.org/release/windows' 141 MERCURIAL_SCM_BASE_URL = 'https://mercurial-scm.org/release/windows'
129 142
130 X86_USER_AGENT_PATTERN = '.*Windows.*' 143 X86_USER_AGENT_PATTERN = '.*Windows.*'
131 X64_USER_AGENT_PATTERN = '.*Windows.*(WOW|x)64.*' 144 X64_USER_AGENT_PATTERN = '.*Windows.*(WOW|x)64.*'
145 ) 158 )
146 EXE_PYTHON3_X64_DESCRIPTION = ( 159 EXE_PYTHON3_X64_DESCRIPTION = (
147 'Mercurial {version} Inno Setup installer - x64 Windows (Python 3) ' 160 'Mercurial {version} Inno Setup installer - x64 Windows (Python 3) '
148 '- does not require admin rights' 161 '- does not require admin rights'
149 ) 162 )
150 X86_MSI_DESCRIPTION = ( 163 MSI_PYTHON2_X86_DESCRIPTION = (
151 'Mercurial {version} MSI installer - x86 Windows ' '- requires admin rights' 164 'Mercurial {version} MSI installer - x86 Windows (Python 2) '
152 ) 165 '- requires admin rights'
153 X64_MSI_DESCRIPTION = ( 166 )
154 'Mercurial {version} MSI installer - x64 Windows ' '- requires admin rights' 167 MSI_PYTHON2_X64_DESCRIPTION = (
168 'Mercurial {version} MSI installer - x64 Windows (Python 2) '
169 '- requires admin rights'
170 )
171 MSI_PYTHON3_X86_DESCRIPTION = (
172 'Mercurial {version} MSI installer - x86 Windows (Python 3) '
173 '- requires admin rights'
174 )
175 MSI_PYTHON3_X64_DESCRIPTION = (
176 'Mercurial {version} MSI installer - x64 Windows (Python 3) '
177 '- requires admin rights'
155 ) 178 )
156 179
157 180
158 def get_vc_prefix(arch): 181 def get_vc_prefix(arch):
159 if arch == 'x86': 182 if arch == 'x86':
373 run_powershell(winrm_client, ps) 396 run_powershell(winrm_client, ps)
374 copy_latest_dist(winrm_client, '*.whl', dest_path) 397 copy_latest_dist(winrm_client, '*.whl', dest_path)
375 398
376 399
377 def build_wix_installer( 400 def build_wix_installer(
378 winrm_client, arch: str, dest_path: pathlib.Path, version=None 401 winrm_client,
402 python_version: int,
403 arch: str,
404 dest_path: pathlib.Path,
405 version=None,
379 ): 406 ):
380 """Build the WiX installer on a remote machine. 407 """Build the WiX installer on a remote machine.
381 408
382 Using a WinRM client, remote commands are executed to build a WiX installer. 409 Using a WinRM client, remote commands are executed to build a WiX installer.
383 """ 410 """
384 print('Building WiX installer for %s' % arch) 411 print('Building WiX installer for Python %d %s' % (python_version, arch))
385 extra_args = [] 412
386 if version: 413 if python_version == 3:
387 extra_args.extend(['--version', version]) 414 # TODO fix this limitation in packaging code
388 415 if not version:
389 ps = get_vc_prefix(arch) + BUILD_WIX.format( 416 raise Exception(
390 arch=arch, extra_args=' '.join(extra_args) 417 "version string is required when building for Python 3"
391 ) 418 )
419
420 if arch == "x86":
421 target_triple = "i686-pc-windows-msvc"
422 elif arch == "x64":
423 target_triple = "x86_64-pc-windows-msvc"
424 else:
425 raise Exception("unhandled arch: %s" % arch)
426
427 ps = BUILD_WIX_PYTHON3.format(
428 pyoxidizer_target=target_triple, version=version,
429 )
430 else:
431 extra_args = []
432 if version:
433 extra_args.extend(['--version', version])
434
435 ps = get_vc_prefix(arch) + BUILD_WIX_PYTHON2.format(
436 arch=arch, extra_args=' '.join(extra_args)
437 )
438
392 run_powershell(winrm_client, ps) 439 run_powershell(winrm_client, ps)
393 copy_latest_dist(winrm_client, '*.msi', dest_path) 440 copy_latest_dist(winrm_client, '*.msi', dest_path)
394 441
395 442
396 def run_tests(winrm_client, python_version, arch, test_flags=''): 443 def run_tests(winrm_client, python_version, arch, test_flags=''):
437 dist_path / WHEEL_FILENAME_PYTHON38_X64.format(version=version), 484 dist_path / WHEEL_FILENAME_PYTHON38_X64.format(version=version),
438 dist_path / EXE_FILENAME_PYTHON2_X86.format(version=version), 485 dist_path / EXE_FILENAME_PYTHON2_X86.format(version=version),
439 dist_path / EXE_FILENAME_PYTHON2_X64.format(version=version), 486 dist_path / EXE_FILENAME_PYTHON2_X64.format(version=version),
440 dist_path / EXE_FILENAME_PYTHON3_X86.format(version=version), 487 dist_path / EXE_FILENAME_PYTHON3_X86.format(version=version),
441 dist_path / EXE_FILENAME_PYTHON3_X64.format(version=version), 488 dist_path / EXE_FILENAME_PYTHON3_X64.format(version=version),
442 dist_path / X86_MSI_FILENAME.format(version=version), 489 dist_path / MSI_FILENAME_PYTHON2_X86.format(version=version),
443 dist_path / X64_MSI_FILENAME.format(version=version), 490 dist_path / MSI_FILENAME_PYTHON2_X64.format(version=version),
491 dist_path / MSI_FILENAME_PYTHON3_X86.format(version=version),
492 dist_path / MSI_FILENAME_PYTHON3_X64.format(version=version),
444 ) 493 )
445 494
446 495
447 def generate_latest_dat(version: str): 496 def generate_latest_dat(version: str):
448 python2_x86_exe_filename = EXE_FILENAME_PYTHON2_X86.format(version=version) 497 python2_x86_exe_filename = EXE_FILENAME_PYTHON2_X86.format(version=version)
449 python2_x64_exe_filename = EXE_FILENAME_PYTHON2_X64.format(version=version) 498 python2_x64_exe_filename = EXE_FILENAME_PYTHON2_X64.format(version=version)
450 python3_x86_exe_filename = EXE_FILENAME_PYTHON3_X86.format(version=version) 499 python3_x86_exe_filename = EXE_FILENAME_PYTHON3_X86.format(version=version)
451 python3_x64_exe_filename = EXE_FILENAME_PYTHON3_X64.format(version=version) 500 python3_x64_exe_filename = EXE_FILENAME_PYTHON3_X64.format(version=version)
452 x86_msi_filename = X86_MSI_FILENAME.format(version=version) 501 python2_x86_msi_filename = MSI_FILENAME_PYTHON2_X86.format(version=version)
453 x64_msi_filename = X64_MSI_FILENAME.format(version=version) 502 python2_x64_msi_filename = MSI_FILENAME_PYTHON2_X64.format(version=version)
503 python3_x86_msi_filename = MSI_FILENAME_PYTHON3_X86.format(version=version)
504 python3_x64_msi_filename = MSI_FILENAME_PYTHON3_X64.format(version=version)
454 505
455 entries = ( 506 entries = (
456 ( 507 (
457 '10', 508 '10',
458 version, 509 version,
483 ), 534 ),
484 ( 535 (
485 '10', 536 '10',
486 version, 537 version,
487 X86_USER_AGENT_PATTERN, 538 X86_USER_AGENT_PATTERN,
488 '%s/%s' % (MERCURIAL_SCM_BASE_URL, x86_msi_filename), 539 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python3_x86_msi_filename),
489 X86_MSI_DESCRIPTION.format(version=version), 540 MSI_PYTHON3_X86_DESCRIPTION.format(version=version),
490 ), 541 ),
491 ( 542 (
492 '10', 543 '10',
493 version, 544 version,
494 X64_USER_AGENT_PATTERN, 545 X64_USER_AGENT_PATTERN,
495 '%s/%s' % (MERCURIAL_SCM_BASE_URL, x64_msi_filename), 546 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python3_x64_msi_filename),
496 X64_MSI_DESCRIPTION.format(version=version), 547 MSI_PYTHON3_X64_DESCRIPTION.format(version=version),
548 ),
549 (
550 '9',
551 version,
552 X86_USER_AGENT_PATTERN,
553 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python2_x86_msi_filename),
554 MSI_PYTHON2_X86_DESCRIPTION.format(version=version),
555 ),
556 (
557 '9',
558 version,
559 X64_USER_AGENT_PATTERN,
560 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python2_x64_msi_filename),
561 MSI_PYTHON2_X64_DESCRIPTION.format(version=version),
497 ), 562 ),
498 ) 563 )
499 564
500 lines = ['\t'.join(e) for e in entries] 565 lines = ['\t'.join(e) for e in entries]
501 566