17 |
17 |
18 from .pypi import upload as pypi_upload |
18 from .pypi import upload as pypi_upload |
19 from .winrm import run_powershell |
19 from .winrm import run_powershell |
20 |
20 |
21 |
21 |
22 # PowerShell commands to activate a Visual Studio 2008 environment. |
|
23 # This is essentially a port of vcvarsall.bat to PowerShell. |
|
24 ACTIVATE_VC9_AMD64 = r''' |
|
25 Write-Output "activating Visual Studio 2008 environment for AMD64" |
|
26 $root = "$env:LOCALAPPDATA\Programs\Common\Microsoft\Visual C++ for Python\9.0" |
|
27 $Env:VCINSTALLDIR = "${root}\VC\" |
|
28 $Env:WindowsSdkDir = "${root}\WinSDK\" |
|
29 $Env:PATH = "${root}\VC\Bin\amd64;${root}\WinSDK\Bin\x64;${root}\WinSDK\Bin;$Env:PATH" |
|
30 $Env:INCLUDE = "${root}\VC\Include;${root}\WinSDK\Include;$Env:PATH" |
|
31 $Env:LIB = "${root}\VC\Lib\amd64;${root}\WinSDK\Lib\x64;$Env:LIB" |
|
32 $Env:LIBPATH = "${root}\VC\Lib\amd64;${root}\WinSDK\Lib\x64;$Env:LIBPATH" |
|
33 '''.lstrip() |
|
34 |
|
35 ACTIVATE_VC9_X86 = r''' |
|
36 Write-Output "activating Visual Studio 2008 environment for x86" |
|
37 $root = "$env:LOCALAPPDATA\Programs\Common\Microsoft\Visual C++ for Python\9.0" |
|
38 $Env:VCINSTALLDIR = "${root}\VC\" |
|
39 $Env:WindowsSdkDir = "${root}\WinSDK\" |
|
40 $Env:PATH = "${root}\VC\Bin;${root}\WinSDK\Bin;$Env:PATH" |
|
41 $Env:INCLUDE = "${root}\VC\Include;${root}\WinSDK\Include;$Env:INCLUDE" |
|
42 $Env:LIB = "${root}\VC\Lib;${root}\WinSDK\Lib;$Env:LIB" |
|
43 $Env:LIBPATH = "${root}\VC\lib;${root}\WinSDK\Lib;$Env:LIBPATH" |
|
44 '''.lstrip() |
|
45 |
|
46 HG_PURGE = r''' |
22 HG_PURGE = r''' |
47 $Env:PATH = "C:\hgdev\venv-bootstrap\Scripts;$Env:PATH" |
23 $Env:PATH = "C:\hgdev\venv-bootstrap\Scripts;$Env:PATH" |
48 Set-Location C:\hgdev\src |
24 Set-Location C:\hgdev\src |
49 hg.exe --config extensions.purge= purge --all |
25 hg.exe --config extensions.purge= purge --all |
50 if ($LASTEXITCODE -ne 0) { |
26 if ($LASTEXITCODE -ne 0) { |
103 if ($LASTEXITCODE -ne 0) {{ |
71 if ($LASTEXITCODE -ne 0) {{ |
104 throw "process exited non-0: $LASTEXITCODE" |
72 throw "process exited non-0: $LASTEXITCODE" |
105 }} |
73 }} |
106 ''' |
74 ''' |
107 |
75 |
108 BUILD_WIX_PYTHON2 = r''' |
|
109 Set-Location C:\hgdev\src |
|
110 $python = "C:\hgdev\python27-{arch}\python.exe" |
|
111 C:\hgdev\python37-x64\python.exe contrib\packaging\packaging.py wix --python $python {extra_args} |
|
112 if ($LASTEXITCODE -ne 0) {{ |
|
113 throw "process exited non-0: $LASTEXITCODE" |
|
114 }} |
|
115 ''' |
|
116 |
76 |
117 RUN_TESTS = r''' |
77 RUN_TESTS = r''' |
118 C:\hgdev\MinGW\msys\1.0\bin\sh.exe --login -c "cd /c/hgdev/src/tests && /c/hgdev/{python_path}/python.exe run-tests.py {test_flags}" |
78 C:\hgdev\MinGW\msys\1.0\bin\sh.exe --login -c "cd /c/hgdev/src/tests && /c/hgdev/{python_path}/python.exe run-tests.py {test_flags}" |
119 if ($LASTEXITCODE -ne 0) {{ |
79 if ($LASTEXITCODE -ne 0) {{ |
120 throw "process exited non-0: $LASTEXITCODE" |
80 throw "process exited non-0: $LASTEXITCODE" |
121 }} |
81 }} |
122 ''' |
82 ''' |
123 |
83 |
124 WHEEL_FILENAME_PYTHON27_X86 = 'mercurial-{version}-cp27-cp27m-win32.whl' |
84 |
125 WHEEL_FILENAME_PYTHON27_X64 = 'mercurial-{version}-cp27-cp27m-win_amd64.whl' |
|
126 WHEEL_FILENAME_PYTHON37_X86 = 'mercurial-{version}-cp37-cp37m-win32.whl' |
85 WHEEL_FILENAME_PYTHON37_X86 = 'mercurial-{version}-cp37-cp37m-win32.whl' |
127 WHEEL_FILENAME_PYTHON37_X64 = 'mercurial-{version}-cp37-cp37m-win_amd64.whl' |
86 WHEEL_FILENAME_PYTHON37_X64 = 'mercurial-{version}-cp37-cp37m-win_amd64.whl' |
128 WHEEL_FILENAME_PYTHON38_X86 = 'mercurial-{version}-cp38-cp38-win32.whl' |
87 WHEEL_FILENAME_PYTHON38_X86 = 'mercurial-{version}-cp38-cp38-win32.whl' |
129 WHEEL_FILENAME_PYTHON38_X64 = 'mercurial-{version}-cp38-cp38-win_amd64.whl' |
88 WHEEL_FILENAME_PYTHON38_X64 = 'mercurial-{version}-cp38-cp38-win_amd64.whl' |
130 WHEEL_FILENAME_PYTHON39_X86 = 'mercurial-{version}-cp39-cp39-win32.whl' |
89 WHEEL_FILENAME_PYTHON39_X86 = 'mercurial-{version}-cp39-cp39-win32.whl' |
131 WHEEL_FILENAME_PYTHON39_X64 = 'mercurial-{version}-cp39-cp39-win_amd64.whl' |
90 WHEEL_FILENAME_PYTHON39_X64 = 'mercurial-{version}-cp39-cp39-win_amd64.whl' |
132 WHEEL_FILENAME_PYTHON310_X86 = 'mercurial-{version}-cp310-cp310-win32.whl' |
91 WHEEL_FILENAME_PYTHON310_X86 = 'mercurial-{version}-cp310-cp310-win32.whl' |
133 WHEEL_FILENAME_PYTHON310_X64 = 'mercurial-{version}-cp310-cp310-win_amd64.whl' |
92 WHEEL_FILENAME_PYTHON310_X64 = 'mercurial-{version}-cp310-cp310-win_amd64.whl' |
134 |
93 |
135 EXE_FILENAME_PYTHON2_X86 = 'Mercurial-{version}-x86-python2.exe' |
|
136 EXE_FILENAME_PYTHON2_X64 = 'Mercurial-{version}-x64-python2.exe' |
|
137 EXE_FILENAME_PYTHON3_X86 = 'Mercurial-{version}-x86.exe' |
94 EXE_FILENAME_PYTHON3_X86 = 'Mercurial-{version}-x86.exe' |
138 EXE_FILENAME_PYTHON3_X64 = 'Mercurial-{version}-x64.exe' |
95 EXE_FILENAME_PYTHON3_X64 = 'Mercurial-{version}-x64.exe' |
139 |
96 |
140 MSI_FILENAME_PYTHON2_X86 = 'mercurial-{version}-x86-python2.msi' |
|
141 MSI_FILENAME_PYTHON2_X64 = 'mercurial-{version}-x64-python2.msi' |
|
142 MSI_FILENAME_PYTHON3_X86 = 'mercurial-{version}-x86.msi' |
97 MSI_FILENAME_PYTHON3_X86 = 'mercurial-{version}-x86.msi' |
143 MSI_FILENAME_PYTHON3_X64 = 'mercurial-{version}-x64.msi' |
98 MSI_FILENAME_PYTHON3_X64 = 'mercurial-{version}-x64.msi' |
144 |
99 |
145 MERCURIAL_SCM_BASE_URL = 'https://mercurial-scm.org/release/windows' |
100 MERCURIAL_SCM_BASE_URL = 'https://mercurial-scm.org/release/windows' |
146 |
101 |
147 X86_USER_AGENT_PATTERN = '.*Windows.*' |
102 X86_USER_AGENT_PATTERN = '.*Windows.*' |
148 X64_USER_AGENT_PATTERN = '.*Windows.*(WOW|x)64.*' |
103 X64_USER_AGENT_PATTERN = '.*Windows.*(WOW|x)64.*' |
149 |
104 |
150 EXE_PYTHON2_X86_DESCRIPTION = ( |
|
151 'Mercurial {version} Inno Setup installer - x86 Windows (Python 2) ' |
|
152 '- does not require admin rights' |
|
153 ) |
|
154 EXE_PYTHON2_X64_DESCRIPTION = ( |
|
155 'Mercurial {version} Inno Setup installer - x64 Windows (Python 2) ' |
|
156 '- does not require admin rights' |
|
157 ) |
|
158 # TODO remove Python version once Python 2 is dropped. |
105 # TODO remove Python version once Python 2 is dropped. |
159 EXE_PYTHON3_X86_DESCRIPTION = ( |
106 EXE_PYTHON3_X86_DESCRIPTION = ( |
160 'Mercurial {version} Inno Setup installer - x86 Windows (Python 3) ' |
107 'Mercurial {version} Inno Setup installer - x86 Windows (Python 3) ' |
161 '- does not require admin rights' |
108 '- does not require admin rights' |
162 ) |
109 ) |
163 EXE_PYTHON3_X64_DESCRIPTION = ( |
110 EXE_PYTHON3_X64_DESCRIPTION = ( |
164 'Mercurial {version} Inno Setup installer - x64 Windows (Python 3) ' |
111 'Mercurial {version} Inno Setup installer - x64 Windows (Python 3) ' |
165 '- does not require admin rights' |
112 '- does not require admin rights' |
166 ) |
113 ) |
167 MSI_PYTHON2_X86_DESCRIPTION = ( |
|
168 'Mercurial {version} MSI installer - x86 Windows (Python 2) ' |
|
169 '- requires admin rights' |
|
170 ) |
|
171 MSI_PYTHON2_X64_DESCRIPTION = ( |
|
172 'Mercurial {version} MSI installer - x64 Windows (Python 2) ' |
|
173 '- requires admin rights' |
|
174 ) |
|
175 MSI_PYTHON3_X86_DESCRIPTION = ( |
114 MSI_PYTHON3_X86_DESCRIPTION = ( |
176 'Mercurial {version} MSI installer - x86 Windows (Python 3) ' |
115 'Mercurial {version} MSI installer - x86 Windows (Python 3) ' |
177 '- requires admin rights' |
116 '- requires admin rights' |
178 ) |
117 ) |
179 MSI_PYTHON3_X64_DESCRIPTION = ( |
118 MSI_PYTHON3_X64_DESCRIPTION = ( |
180 'Mercurial {version} MSI installer - x64 Windows (Python 3) ' |
119 'Mercurial {version} MSI installer - x64 Windows (Python 3) ' |
181 '- requires admin rights' |
120 '- requires admin rights' |
182 ) |
121 ) |
183 |
|
184 |
|
185 def get_vc_prefix(arch): |
|
186 if arch == 'x86': |
|
187 return ACTIVATE_VC9_X86 |
|
188 elif arch == 'x64': |
|
189 return ACTIVATE_VC9_AMD64 |
|
190 else: |
|
191 raise ValueError('illegal arch: %s; must be x86 or x64' % arch) |
|
192 |
122 |
193 |
123 |
194 def fix_authorized_keys_permissions(winrm_client, path): |
124 def fix_authorized_keys_permissions(winrm_client, path): |
195 commands = [ |
125 commands = [ |
196 '$ErrorActionPreference = "Stop"', |
126 '$ErrorActionPreference = "Stop"', |
347 print( |
277 print( |
348 'building Inno Setup installer for Python %d %s' |
278 'building Inno Setup installer for Python %d %s' |
349 % (python_version, arch) |
279 % (python_version, arch) |
350 ) |
280 ) |
351 |
281 |
352 if python_version == 3: |
282 # TODO fix this limitation in packaging code |
353 # TODO fix this limitation in packaging code |
283 if not version: |
354 if not version: |
284 raise Exception("version string is required when building for Python 3") |
355 raise Exception( |
285 |
356 "version string is required when building for Python 3" |
286 if arch == "x86": |
357 ) |
287 target_triple = "i686-pc-windows-msvc" |
358 |
288 elif arch == "x64": |
359 if arch == "x86": |
289 target_triple = "x86_64-pc-windows-msvc" |
360 target_triple = "i686-pc-windows-msvc" |
|
361 elif arch == "x64": |
|
362 target_triple = "x86_64-pc-windows-msvc" |
|
363 else: |
|
364 raise Exception("unhandled arch: %s" % arch) |
|
365 |
|
366 ps = BUILD_INNO_PYTHON3.format( |
|
367 pyoxidizer_target=target_triple, |
|
368 version=version, |
|
369 ) |
|
370 else: |
290 else: |
371 extra_args = [] |
291 raise Exception("unhandled arch: %s" % arch) |
372 if version: |
292 |
373 extra_args.extend(['--version', version]) |
293 ps = BUILD_INNO_PYTHON3.format( |
374 |
294 pyoxidizer_target=target_triple, |
375 ps = get_vc_prefix(arch) + BUILD_INNO_PYTHON2.format( |
295 version=version, |
376 arch=arch, extra_args=' '.join(extra_args) |
296 ) |
377 ) |
|
378 |
297 |
379 run_powershell(winrm_client, ps) |
298 run_powershell(winrm_client, ps) |
380 copy_latest_dist(winrm_client, '*.exe', dest_path) |
299 copy_latest_dist(winrm_client, '*.exe', dest_path) |
381 |
300 |
382 |
301 |
413 |
328 |
414 Using a WinRM client, remote commands are executed to build a WiX installer. |
329 Using a WinRM client, remote commands are executed to build a WiX installer. |
415 """ |
330 """ |
416 print('Building WiX installer for Python %d %s' % (python_version, arch)) |
331 print('Building WiX installer for Python %d %s' % (python_version, arch)) |
417 |
332 |
418 if python_version == 3: |
333 # TODO fix this limitation in packaging code |
419 # TODO fix this limitation in packaging code |
334 if not version: |
420 if not version: |
335 raise Exception("version string is required when building for Python 3") |
421 raise Exception( |
336 |
422 "version string is required when building for Python 3" |
337 if arch == "x86": |
423 ) |
338 target_triple = "i686-pc-windows-msvc" |
424 |
339 elif arch == "x64": |
425 if arch == "x86": |
340 target_triple = "x86_64-pc-windows-msvc" |
426 target_triple = "i686-pc-windows-msvc" |
|
427 elif arch == "x64": |
|
428 target_triple = "x86_64-pc-windows-msvc" |
|
429 else: |
|
430 raise Exception("unhandled arch: %s" % arch) |
|
431 |
|
432 ps = BUILD_WIX_PYTHON3.format( |
|
433 pyoxidizer_target=target_triple, |
|
434 version=version, |
|
435 ) |
|
436 else: |
341 else: |
437 extra_args = [] |
342 raise Exception("unhandled arch: %s" % arch) |
438 if version: |
343 |
439 extra_args.extend(['--version', version]) |
344 ps = BUILD_WIX_PYTHON3.format( |
440 |
345 pyoxidizer_target=target_triple, |
441 ps = get_vc_prefix(arch) + BUILD_WIX_PYTHON2.format( |
346 version=version, |
442 arch=arch, extra_args=' '.join(extra_args) |
347 ) |
443 ) |
|
444 |
348 |
445 run_powershell(winrm_client, ps) |
349 run_powershell(winrm_client, ps) |
446 copy_latest_dist(winrm_client, '*.msi', dest_path) |
350 copy_latest_dist(winrm_client, '*.msi', dest_path) |
447 |
351 |
448 |
352 |
472 run_powershell(winrm_client, ps) |
376 run_powershell(winrm_client, ps) |
473 |
377 |
474 |
378 |
475 def resolve_wheel_artifacts(dist_path: pathlib.Path, version: str): |
379 def resolve_wheel_artifacts(dist_path: pathlib.Path, version: str): |
476 return ( |
380 return ( |
477 dist_path / WHEEL_FILENAME_PYTHON27_X86.format(version=version), |
|
478 dist_path / WHEEL_FILENAME_PYTHON27_X64.format(version=version), |
|
479 dist_path / WHEEL_FILENAME_PYTHON37_X86.format(version=version), |
381 dist_path / WHEEL_FILENAME_PYTHON37_X86.format(version=version), |
480 dist_path / WHEEL_FILENAME_PYTHON37_X64.format(version=version), |
382 dist_path / WHEEL_FILENAME_PYTHON37_X64.format(version=version), |
481 dist_path / WHEEL_FILENAME_PYTHON38_X86.format(version=version), |
383 dist_path / WHEEL_FILENAME_PYTHON38_X86.format(version=version), |
482 dist_path / WHEEL_FILENAME_PYTHON38_X64.format(version=version), |
384 dist_path / WHEEL_FILENAME_PYTHON38_X64.format(version=version), |
483 dist_path / WHEEL_FILENAME_PYTHON39_X86.format(version=version), |
385 dist_path / WHEEL_FILENAME_PYTHON39_X86.format(version=version), |
487 ) |
389 ) |
488 |
390 |
489 |
391 |
490 def resolve_all_artifacts(dist_path: pathlib.Path, version: str): |
392 def resolve_all_artifacts(dist_path: pathlib.Path, version: str): |
491 return ( |
393 return ( |
492 dist_path / WHEEL_FILENAME_PYTHON27_X86.format(version=version), |
|
493 dist_path / WHEEL_FILENAME_PYTHON27_X64.format(version=version), |
|
494 dist_path / WHEEL_FILENAME_PYTHON37_X86.format(version=version), |
394 dist_path / WHEEL_FILENAME_PYTHON37_X86.format(version=version), |
495 dist_path / WHEEL_FILENAME_PYTHON37_X64.format(version=version), |
395 dist_path / WHEEL_FILENAME_PYTHON37_X64.format(version=version), |
496 dist_path / WHEEL_FILENAME_PYTHON38_X86.format(version=version), |
396 dist_path / WHEEL_FILENAME_PYTHON38_X86.format(version=version), |
497 dist_path / WHEEL_FILENAME_PYTHON38_X64.format(version=version), |
397 dist_path / WHEEL_FILENAME_PYTHON38_X64.format(version=version), |
498 dist_path / WHEEL_FILENAME_PYTHON39_X86.format(version=version), |
398 dist_path / WHEEL_FILENAME_PYTHON39_X86.format(version=version), |
499 dist_path / WHEEL_FILENAME_PYTHON39_X64.format(version=version), |
399 dist_path / WHEEL_FILENAME_PYTHON39_X64.format(version=version), |
500 dist_path / WHEEL_FILENAME_PYTHON310_X86.format(version=version), |
400 dist_path / WHEEL_FILENAME_PYTHON310_X86.format(version=version), |
501 dist_path / WHEEL_FILENAME_PYTHON310_X64.format(version=version), |
401 dist_path / WHEEL_FILENAME_PYTHON310_X64.format(version=version), |
502 dist_path / EXE_FILENAME_PYTHON2_X86.format(version=version), |
|
503 dist_path / EXE_FILENAME_PYTHON2_X64.format(version=version), |
|
504 dist_path / EXE_FILENAME_PYTHON3_X86.format(version=version), |
402 dist_path / EXE_FILENAME_PYTHON3_X86.format(version=version), |
505 dist_path / EXE_FILENAME_PYTHON3_X64.format(version=version), |
403 dist_path / EXE_FILENAME_PYTHON3_X64.format(version=version), |
506 dist_path / MSI_FILENAME_PYTHON2_X86.format(version=version), |
|
507 dist_path / MSI_FILENAME_PYTHON2_X64.format(version=version), |
|
508 dist_path / MSI_FILENAME_PYTHON3_X86.format(version=version), |
404 dist_path / MSI_FILENAME_PYTHON3_X86.format(version=version), |
509 dist_path / MSI_FILENAME_PYTHON3_X64.format(version=version), |
405 dist_path / MSI_FILENAME_PYTHON3_X64.format(version=version), |
510 ) |
406 ) |
511 |
407 |
512 |
408 |
513 def generate_latest_dat(version: str): |
409 def generate_latest_dat(version: str): |
514 python2_x86_exe_filename = EXE_FILENAME_PYTHON2_X86.format(version=version) |
|
515 python2_x64_exe_filename = EXE_FILENAME_PYTHON2_X64.format(version=version) |
|
516 python3_x86_exe_filename = EXE_FILENAME_PYTHON3_X86.format(version=version) |
410 python3_x86_exe_filename = EXE_FILENAME_PYTHON3_X86.format(version=version) |
517 python3_x64_exe_filename = EXE_FILENAME_PYTHON3_X64.format(version=version) |
411 python3_x64_exe_filename = EXE_FILENAME_PYTHON3_X64.format(version=version) |
518 python2_x86_msi_filename = MSI_FILENAME_PYTHON2_X86.format(version=version) |
|
519 python2_x64_msi_filename = MSI_FILENAME_PYTHON2_X64.format(version=version) |
|
520 python3_x86_msi_filename = MSI_FILENAME_PYTHON3_X86.format(version=version) |
412 python3_x86_msi_filename = MSI_FILENAME_PYTHON3_X86.format(version=version) |
521 python3_x64_msi_filename = MSI_FILENAME_PYTHON3_X64.format(version=version) |
413 python3_x64_msi_filename = MSI_FILENAME_PYTHON3_X64.format(version=version) |
522 |
414 |
523 entries = ( |
415 entries = ( |
524 ( |
416 ( |
534 X64_USER_AGENT_PATTERN, |
426 X64_USER_AGENT_PATTERN, |
535 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python3_x64_exe_filename), |
427 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python3_x64_exe_filename), |
536 EXE_PYTHON3_X64_DESCRIPTION.format(version=version), |
428 EXE_PYTHON3_X64_DESCRIPTION.format(version=version), |
537 ), |
429 ), |
538 ( |
430 ( |
539 '9', |
|
540 version, |
|
541 X86_USER_AGENT_PATTERN, |
|
542 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python2_x86_exe_filename), |
|
543 EXE_PYTHON2_X86_DESCRIPTION.format(version=version), |
|
544 ), |
|
545 ( |
|
546 '9', |
|
547 version, |
|
548 X64_USER_AGENT_PATTERN, |
|
549 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python2_x64_exe_filename), |
|
550 EXE_PYTHON2_X64_DESCRIPTION.format(version=version), |
|
551 ), |
|
552 ( |
|
553 '10', |
431 '10', |
554 version, |
432 version, |
555 X86_USER_AGENT_PATTERN, |
433 X86_USER_AGENT_PATTERN, |
556 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python3_x86_msi_filename), |
434 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python3_x86_msi_filename), |
557 MSI_PYTHON3_X86_DESCRIPTION.format(version=version), |
435 MSI_PYTHON3_X86_DESCRIPTION.format(version=version), |
561 version, |
439 version, |
562 X64_USER_AGENT_PATTERN, |
440 X64_USER_AGENT_PATTERN, |
563 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python3_x64_msi_filename), |
441 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python3_x64_msi_filename), |
564 MSI_PYTHON3_X64_DESCRIPTION.format(version=version), |
442 MSI_PYTHON3_X64_DESCRIPTION.format(version=version), |
565 ), |
443 ), |
566 ( |
|
567 '9', |
|
568 version, |
|
569 X86_USER_AGENT_PATTERN, |
|
570 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python2_x86_msi_filename), |
|
571 MSI_PYTHON2_X86_DESCRIPTION.format(version=version), |
|
572 ), |
|
573 ( |
|
574 '9', |
|
575 version, |
|
576 X64_USER_AGENT_PATTERN, |
|
577 '%s/%s' % (MERCURIAL_SCM_BASE_URL, python2_x64_msi_filename), |
|
578 MSI_PYTHON2_X64_DESCRIPTION.format(version=version), |
|
579 ), |
|
580 ) |
444 ) |
581 |
445 |
582 lines = ['\t'.join(e) for e in entries] |
446 lines = ['\t'.join(e) for e in entries] |
583 |
447 |
584 return '\n'.join(lines) + '\n' |
448 return '\n'.join(lines) + '\n' |