Show More
@@ -0,0 +1,145 b'' | |||
|
1 | # pyoxidizer.py - Packaging support for PyOxidizer | |
|
2 | # | |
|
3 | # Copyright 2020 Gregory Szorc <gregory.szorc@gmail.com> | |
|
4 | # | |
|
5 | # This software may be used and distributed according to the terms of the | |
|
6 | # GNU General Public License version 2 or any later version. | |
|
7 | ||
|
8 | # no-check-code because Python 3 native. | |
|
9 | ||
|
10 | import os | |
|
11 | import pathlib | |
|
12 | import shutil | |
|
13 | import subprocess | |
|
14 | import sys | |
|
15 | ||
|
16 | from .downloads import download_entry | |
|
17 | from .util import ( | |
|
18 | extract_zip_to_directory, | |
|
19 | process_install_rules, | |
|
20 | find_vc_runtime_dll, | |
|
21 | ) | |
|
22 | ||
|
23 | ||
|
24 | STAGING_RULES_WINDOWS = [ | |
|
25 | ('contrib/bash_completion', 'contrib/'), | |
|
26 | ('contrib/hgk', 'contrib/hgk.tcl'), | |
|
27 | ('contrib/hgweb.fcgi', 'contrib/'), | |
|
28 | ('contrib/hgweb.wsgi', 'contrib/'), | |
|
29 | ('contrib/logo-droplets.svg', 'contrib/'), | |
|
30 | ('contrib/mercurial.el', 'contrib/'), | |
|
31 | ('contrib/mq.el', 'contrib/'), | |
|
32 | ('contrib/tcsh_completion', 'contrib/'), | |
|
33 | ('contrib/tcsh_completion_build.sh', 'contrib/'), | |
|
34 | ('contrib/vim/*', 'contrib/vim/'), | |
|
35 | ('contrib/win32/postinstall.txt', 'ReleaseNotes.txt'), | |
|
36 | ('contrib/win32/ReadMe.html', 'ReadMe.html'), | |
|
37 | ('contrib/xml.rnc', 'contrib/'), | |
|
38 | ('contrib/zsh_completion', 'contrib/'), | |
|
39 | ('doc/*.html', 'doc/'), | |
|
40 | ('doc/style.css', 'doc/'), | |
|
41 | ('COPYING', 'Copying.txt'), | |
|
42 | ] | |
|
43 | ||
|
44 | STAGING_RULES_APP = [ | |
|
45 | ('mercurial/helptext/**/*.txt', 'helptext/'), | |
|
46 | ('mercurial/defaultrc/*.rc', 'defaultrc/'), | |
|
47 | ('mercurial/locale/**/*', 'locale/'), | |
|
48 | ('mercurial/templates/**/*', 'templates/'), | |
|
49 | ] | |
|
50 | ||
|
51 | STAGING_EXCLUDES_WINDOWS = [ | |
|
52 | "doc/hg-ssh.8.html", | |
|
53 | ] | |
|
54 | ||
|
55 | ||
|
56 | def run_pyoxidizer( | |
|
57 | source_dir: pathlib.Path, | |
|
58 | build_dir: pathlib.Path, | |
|
59 | out_dir: pathlib.Path, | |
|
60 | target_triple: str, | |
|
61 | ): | |
|
62 | """Build Mercurial with PyOxidizer and copy additional files into place. | |
|
63 | ||
|
64 | After successful completion, ``out_dir`` contains files constituting a | |
|
65 | Mercurial install. | |
|
66 | """ | |
|
67 | # We need to make gettext binaries available for compiling i18n files. | |
|
68 | gettext_pkg, gettext_entry = download_entry('gettext', build_dir) | |
|
69 | gettext_dep_pkg = download_entry('gettext-dep', build_dir)[0] | |
|
70 | ||
|
71 | gettext_root = build_dir / ('gettext-win-%s' % gettext_entry['version']) | |
|
72 | ||
|
73 | if not gettext_root.exists(): | |
|
74 | extract_zip_to_directory(gettext_pkg, gettext_root) | |
|
75 | extract_zip_to_directory(gettext_dep_pkg, gettext_root) | |
|
76 | ||
|
77 | env = dict(os.environ) | |
|
78 | env["PATH"] = "%s%s%s" % ( | |
|
79 | env["PATH"], | |
|
80 | os.pathsep, | |
|
81 | str(gettext_root / "bin"), | |
|
82 | ) | |
|
83 | ||
|
84 | args = [ | |
|
85 | "pyoxidizer", | |
|
86 | "build", | |
|
87 | "--path", | |
|
88 | str(source_dir / "rust" / "hgcli"), | |
|
89 | "--release", | |
|
90 | "--target-triple", | |
|
91 | target_triple, | |
|
92 | ] | |
|
93 | ||
|
94 | subprocess.run(args, env=env, check=True) | |
|
95 | ||
|
96 | if "windows" in target_triple: | |
|
97 | target = "app_windows" | |
|
98 | else: | |
|
99 | target = "app_posix" | |
|
100 | ||
|
101 | build_dir = ( | |
|
102 | source_dir / "build" / "pyoxidizer" / target_triple / "release" / target | |
|
103 | ) | |
|
104 | ||
|
105 | if out_dir.exists(): | |
|
106 | print("purging %s" % out_dir) | |
|
107 | shutil.rmtree(out_dir) | |
|
108 | ||
|
109 | # Now assemble all the files from PyOxidizer into the staging directory. | |
|
110 | shutil.copytree(build_dir, out_dir) | |
|
111 | ||
|
112 | # Move some of those files around. | |
|
113 | process_install_rules(STAGING_RULES_APP, build_dir, out_dir) | |
|
114 | # Nuke the mercurial/* directory, as we copied resources | |
|
115 | # to an appropriate location just above. | |
|
116 | shutil.rmtree(out_dir / "mercurial") | |
|
117 | ||
|
118 | # We also need to run setup.py build_doc to produce html files, | |
|
119 | # as they aren't built as part of ``pip install``. | |
|
120 | # This will fail if docutils isn't installed. | |
|
121 | subprocess.run( | |
|
122 | [sys.executable, str(source_dir / "setup.py"), "build_doc", "--html"], | |
|
123 | cwd=str(source_dir), | |
|
124 | check=True, | |
|
125 | ) | |
|
126 | ||
|
127 | if "windows" in target_triple: | |
|
128 | process_install_rules(STAGING_RULES_WINDOWS, source_dir, out_dir) | |
|
129 | ||
|
130 | # Write out a default editor.rc file to configure notepad as the | |
|
131 | # default editor. | |
|
132 | with (out_dir / "defaultrc" / "editor.rc").open( | |
|
133 | "w", encoding="utf-8" | |
|
134 | ) as fh: | |
|
135 | fh.write("[ui]\neditor = notepad\n") | |
|
136 | ||
|
137 | for f in STAGING_EXCLUDES_WINDOWS: | |
|
138 | p = out_dir / f | |
|
139 | if p.exists(): | |
|
140 | print("removing %s" % p) | |
|
141 | p.unlink() | |
|
142 | ||
|
143 | # Add vcruntimeXXX.dll next to executable. | |
|
144 | vc_runtime_dll = find_vc_runtime_dll(x64="x86_64" in target_triple) | |
|
145 | shutil.copy(vc_runtime_dll, out_dir / vc_runtime_dll.name) |
@@ -63,7 +63,13 b' def bootstrap_windows_dev(hga: HGAutomat' | |||
|
63 | 63 | |
|
64 | 64 | |
|
65 | 65 | def build_inno( |
|
66 | hga: HGAutomation, aws_region, arch, revision, version, base_image_name | |
|
66 | hga: HGAutomation, | |
|
67 | aws_region, | |
|
68 | python_version, | |
|
69 | arch, | |
|
70 | revision, | |
|
71 | version, | |
|
72 | base_image_name, | |
|
67 | 73 | ): |
|
68 | 74 | c = hga.aws_connection(aws_region) |
|
69 | 75 | image = aws.ensure_windows_dev_ami(c, base_image_name=base_image_name) |
@@ -74,14 +80,25 b' def build_inno(' | |||
|
74 | 80 | |
|
75 | 81 | windows.synchronize_hg(SOURCE_ROOT, revision, instance) |
|
76 | 82 | |
|
77 | for a in arch: | |
|
78 | windows.build_inno_installer( | |
|
79 | instance.winrm_client, a, DIST_PATH, version=version | |
|
80 | ) | |
|
83 | for py_version in python_version: | |
|
84 | for a in arch: | |
|
85 | windows.build_inno_installer( | |
|
86 | instance.winrm_client, | |
|
87 | py_version, | |
|
88 | a, | |
|
89 | DIST_PATH, | |
|
90 | version=version, | |
|
91 | ) | |
|
81 | 92 | |
|
82 | 93 | |
|
83 | 94 | def build_wix( |
|
84 | hga: HGAutomation, aws_region, arch, revision, version, base_image_name | |
|
95 | hga: HGAutomation, | |
|
96 | aws_region, | |
|
97 | python_version, | |
|
98 | arch, | |
|
99 | revision, | |
|
100 | version, | |
|
101 | base_image_name, | |
|
85 | 102 | ): |
|
86 | 103 | c = hga.aws_connection(aws_region) |
|
87 | 104 | image = aws.ensure_windows_dev_ami(c, base_image_name=base_image_name) |
@@ -92,14 +109,24 b' def build_wix(' | |||
|
92 | 109 | |
|
93 | 110 | windows.synchronize_hg(SOURCE_ROOT, revision, instance) |
|
94 | 111 | |
|
95 | for a in arch: | |
|
96 | windows.build_wix_installer( | |
|
97 | instance.winrm_client, a, DIST_PATH, version=version | |
|
98 | ) | |
|
112 | for py_version in python_version: | |
|
113 | for a in arch: | |
|
114 | windows.build_wix_installer( | |
|
115 | instance.winrm_client, | |
|
116 | py_version, | |
|
117 | a, | |
|
118 | DIST_PATH, | |
|
119 | version=version, | |
|
120 | ) | |
|
99 | 121 | |
|
100 | 122 | |
|
101 | 123 | def build_windows_wheel( |
|
102 | hga: HGAutomation, aws_region, arch, revision, base_image_name | |
|
124 | hga: HGAutomation, | |
|
125 | aws_region, | |
|
126 | python_version, | |
|
127 | arch, | |
|
128 | revision, | |
|
129 | base_image_name, | |
|
103 | 130 | ): |
|
104 | 131 | c = hga.aws_connection(aws_region) |
|
105 | 132 | image = aws.ensure_windows_dev_ami(c, base_image_name=base_image_name) |
@@ -110,8 +137,11 b' def build_windows_wheel(' | |||
|
110 | 137 | |
|
111 | 138 | windows.synchronize_hg(SOURCE_ROOT, revision, instance) |
|
112 | 139 | |
|
113 | for a in arch: | |
|
114 | windows.build_wheel(instance.winrm_client, a, DIST_PATH) | |
|
140 | for py_version in python_version: | |
|
141 | for a in arch: | |
|
142 | windows.build_wheel( | |
|
143 | instance.winrm_client, py_version, a, DIST_PATH | |
|
144 | ) | |
|
115 | 145 | |
|
116 | 146 | |
|
117 | 147 | def build_all_windows_packages( |
@@ -128,17 +158,25 b' def build_all_windows_packages(' | |||
|
128 | 158 | |
|
129 | 159 | windows.synchronize_hg(SOURCE_ROOT, revision, instance) |
|
130 | 160 | |
|
131 | for arch in ('x86', 'x64'): | |
|
132 | windows.purge_hg(winrm_client) | |
|
133 |
windows. |
|
|
134 | windows.purge_hg(winrm_client) | |
|
135 | windows.build_inno_installer( | |
|
136 |
|
|
|
137 | ) | |
|
138 | windows.purge_hg(winrm_client) | |
|
139 | windows.build_wix_installer( | |
|
140 | winrm_client, arch, DIST_PATH, version=version | |
|
141 | ) | |
|
161 | for py_version in ("2.7", "3.7", "3.8"): | |
|
162 | for arch in ("x86", "x64"): | |
|
163 | windows.purge_hg(winrm_client) | |
|
164 | windows.build_wheel( | |
|
165 | winrm_client, | |
|
166 | python_version=py_version, | |
|
167 | arch=arch, | |
|
168 | dest_path=DIST_PATH, | |
|
169 | ) | |
|
170 | ||
|
171 | for py_version in (2, 3): | |
|
172 | for arch in ('x86', 'x64'): | |
|
173 | windows.purge_hg(winrm_client) | |
|
174 | windows.build_inno_installer( | |
|
175 | winrm_client, py_version, arch, DIST_PATH, version=version | |
|
176 | ) | |
|
177 | windows.build_wix_installer( | |
|
178 | winrm_client, py_version, arch, DIST_PATH, version=version | |
|
179 | ) | |
|
142 | 180 | |
|
143 | 181 | |
|
144 | 182 | def terminate_ec2_instances(hga: HGAutomation, aws_region): |
@@ -293,6 +331,14 b' def get_parser():' | |||
|
293 | 331 | 'build-inno', help='Build Inno Setup installer(s)', |
|
294 | 332 | ) |
|
295 | 333 | sp.add_argument( |
|
334 | '--python-version', | |
|
335 | help='Which version of Python to target', | |
|
336 | choices={2, 3}, | |
|
337 | type=int, | |
|
338 | nargs='*', | |
|
339 | default=[3], | |
|
340 | ) | |
|
341 | sp.add_argument( | |
|
296 | 342 | '--arch', |
|
297 | 343 | help='Architecture to build for', |
|
298 | 344 | choices={'x86', 'x64'}, |
@@ -316,6 +362,13 b' def get_parser():' | |||
|
316 | 362 | 'build-windows-wheel', help='Build Windows wheel(s)', |
|
317 | 363 | ) |
|
318 | 364 | sp.add_argument( |
|
365 | '--python-version', | |
|
366 | help='Python version to build for', | |
|
367 | choices={'2.7', '3.7', '3.8'}, | |
|
368 | nargs='*', | |
|
369 | default=['3.8'], | |
|
370 | ) | |
|
371 | sp.add_argument( | |
|
319 | 372 | '--arch', |
|
320 | 373 | help='Architecture to build for', |
|
321 | 374 | choices={'x86', 'x64'}, |
@@ -334,6 +387,14 b' def get_parser():' | |||
|
334 | 387 | |
|
335 | 388 | sp = subparsers.add_parser('build-wix', help='Build WiX installer(s)') |
|
336 | 389 | sp.add_argument( |
|
390 | '--python-version', | |
|
391 | help='Which version of Python to target', | |
|
392 | choices={2, 3}, | |
|
393 | type=int, | |
|
394 | nargs='*', | |
|
395 | default=[3], | |
|
396 | ) | |
|
397 | sp.add_argument( | |
|
337 | 398 | '--arch', |
|
338 | 399 | help='Architecture to build for', |
|
339 | 400 | choices={'x86', 'x64'}, |
@@ -72,8 +72,10 b' echo "${RUSTUP_INIT_SHA256} rustup-init"' | |||
|
72 | 72 | |
|
73 | 73 | chmod +x rustup-init |
|
74 | 74 | sudo -H -u hg -g hg ./rustup-init -y |
|
75 |
sudo -H -u hg -g hg /home/hg/.cargo/bin/rustup install 1.31.1 1. |
|
|
75 | sudo -H -u hg -g hg /home/hg/.cargo/bin/rustup install 1.31.1 1.42.0 | |
|
76 | 76 | sudo -H -u hg -g hg /home/hg/.cargo/bin/rustup component add clippy |
|
77 | ||
|
78 | sudo -H -u hg -g hg /home/hg/.cargo/bin/cargo install --version 0.7.0 pyoxidizer | |
|
77 | 79 | ''' |
|
78 | 80 | |
|
79 | 81 |
@@ -68,10 +68,20 b' hg.exe log -r .' | |||
|
68 | 68 | Write-Output "updated Mercurial working directory to {revision}" |
|
69 | 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 | 82 | Set-Location C:\hgdev\src |
|
73 | 83 | $python = "C:\hgdev\python27-{arch}\python.exe" |
|
74 | C:\hgdev\python37-x64\python.exe contrib\packaging\packaging.py inno --python $python | |
|
84 | C:\hgdev\python37-x64\python.exe contrib\packaging\packaging.py inno --python $python {extra_args} | |
|
75 | 85 | if ($LASTEXITCODE -ne 0) {{ |
|
76 | 86 | throw "process exited non-0: $LASTEXITCODE" |
|
77 | 87 | }} |
@@ -79,13 +89,23 b' if ($LASTEXITCODE -ne 0) {{' | |||
|
79 | 89 | |
|
80 | 90 | BUILD_WHEEL = r''' |
|
81 | 91 | Set-Location C:\hgdev\src |
|
82 |
C:\hgdev\python |
|
|
92 | C:\hgdev\python{python_version}-{arch}\python.exe -m pip wheel --wheel-dir dist . | |
|
83 | 93 | if ($LASTEXITCODE -ne 0) {{ |
|
84 | 94 | throw "process exited non-0: $LASTEXITCODE" |
|
85 | 95 | }} |
|
86 | 96 | ''' |
|
87 | 97 | |
|
88 | 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''' | |
|
89 | 109 | Set-Location C:\hgdev\src |
|
90 | 110 | $python = "C:\hgdev\python27-{arch}\python.exe" |
|
91 | 111 | C:\hgdev\python37-x64\python.exe contrib\packaging\packaging.py wix --python $python {extra_args} |
@@ -101,31 +121,60 b' if ($LASTEXITCODE -ne 0) {{' | |||
|
101 | 121 | }} |
|
102 | 122 | ''' |
|
103 | 123 | |
|
104 |
|
|
|
105 |
|
|
|
106 |
|
|
|
107 |
|
|
|
108 |
|
|
|
109 |
|
|
|
124 | WHEEL_FILENAME_PYTHON27_X86 = 'mercurial-{version}-cp27-cp27m-win32.whl' | |
|
125 | WHEEL_FILENAME_PYTHON27_X64 = 'mercurial-{version}-cp27-cp27m-win_amd64.whl' | |
|
126 | WHEEL_FILENAME_PYTHON37_X86 = 'mercurial-{version}-cp37-cp37m-win32.whl' | |
|
127 | WHEEL_FILENAME_PYTHON37_X64 = 'mercurial-{version}-cp37-cp37m-win_amd64.whl' | |
|
128 | WHEEL_FILENAME_PYTHON38_X86 = 'mercurial-{version}-cp38-cp38-win32.whl' | |
|
129 | WHEEL_FILENAME_PYTHON38_X64 = 'mercurial-{version}-cp38-cp38-win_amd64.whl' | |
|
130 | ||
|
131 | EXE_FILENAME_PYTHON2_X86 = 'Mercurial-{version}-x86-python2.exe' | |
|
132 | EXE_FILENAME_PYTHON2_X64 = 'Mercurial-{version}-x64-python2.exe' | |
|
133 | EXE_FILENAME_PYTHON3_X86 = 'Mercurial-{version}-x86.exe' | |
|
134 | EXE_FILENAME_PYTHON3_X64 = 'Mercurial-{version}-x64.exe' | |
|
135 | ||
|
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' | |
|
110 | 140 | |
|
111 | 141 | MERCURIAL_SCM_BASE_URL = 'https://mercurial-scm.org/release/windows' |
|
112 | 142 | |
|
113 | 143 | X86_USER_AGENT_PATTERN = '.*Windows.*' |
|
114 | 144 | X64_USER_AGENT_PATTERN = '.*Windows.*(WOW|x)64.*' |
|
115 | 145 | |
|
116 |
|
|
|
117 | 'Mercurial {version} Inno Setup installer - x86 Windows ' | |
|
146 | EXE_PYTHON2_X86_DESCRIPTION = ( | |
|
147 | 'Mercurial {version} Inno Setup installer - x86 Windows (Python 2) ' | |
|
148 | '- does not require admin rights' | |
|
149 | ) | |
|
150 | EXE_PYTHON2_X64_DESCRIPTION = ( | |
|
151 | 'Mercurial {version} Inno Setup installer - x64 Windows (Python 2) ' | |
|
152 | '- does not require admin rights' | |
|
153 | ) | |
|
154 | # TODO remove Python version once Python 2 is dropped. | |
|
155 | EXE_PYTHON3_X86_DESCRIPTION = ( | |
|
156 | 'Mercurial {version} Inno Setup installer - x86 Windows (Python 3) ' | |
|
118 | 157 | '- does not require admin rights' |
|
119 | 158 | ) |
|
120 |
|
|
|
121 | 'Mercurial {version} Inno Setup installer - x64 Windows ' | |
|
159 | EXE_PYTHON3_X64_DESCRIPTION = ( | |
|
160 | 'Mercurial {version} Inno Setup installer - x64 Windows (Python 3) ' | |
|
122 | 161 | '- does not require admin rights' |
|
123 | 162 | ) |
|
124 |
|
|
|
125 |
'Mercurial {version} MSI installer - x86 Windows |
|
|
163 | MSI_PYTHON2_X86_DESCRIPTION = ( | |
|
164 | 'Mercurial {version} MSI installer - x86 Windows (Python 2) ' | |
|
165 | '- requires admin rights' | |
|
166 | ) | |
|
167 | MSI_PYTHON2_X64_DESCRIPTION = ( | |
|
168 | 'Mercurial {version} MSI installer - x64 Windows (Python 2) ' | |
|
169 | '- requires admin rights' | |
|
126 | 170 | ) |
|
127 |
|
|
|
128 |
'Mercurial {version} MSI installer - x6 |
|
|
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' | |
|
129 | 178 | ) |
|
130 | 179 | |
|
131 | 180 | |
@@ -280,53 +329,113 b' def copy_latest_dist(winrm_client, patte' | |||
|
280 | 329 | |
|
281 | 330 | |
|
282 | 331 | def build_inno_installer( |
|
283 | winrm_client, arch: str, dest_path: pathlib.Path, version=None | |
|
332 | winrm_client, | |
|
333 | python_version: int, | |
|
334 | arch: str, | |
|
335 | dest_path: pathlib.Path, | |
|
336 | version=None, | |
|
284 | 337 | ): |
|
285 | 338 | """Build the Inno Setup installer on a remote machine. |
|
286 | 339 | |
|
287 | 340 | Using a WinRM client, remote commands are executed to build |
|
288 | 341 | a Mercurial Inno Setup installer. |
|
289 | 342 | """ |
|
290 | print('building Inno Setup installer for %s' % arch) | |
|
343 | print( | |
|
344 | 'building Inno Setup installer for Python %d %s' | |
|
345 | % (python_version, arch) | |
|
346 | ) | |
|
347 | ||
|
348 | if python_version == 3: | |
|
349 | # TODO fix this limitation in packaging code | |
|
350 | if not version: | |
|
351 | raise Exception( | |
|
352 | "version string is required when building for Python 3" | |
|
353 | ) | |
|
291 | 354 | |
|
292 | extra_args = [] | |
|
293 | if version: | |
|
294 | extra_args.extend(['--version', version]) | |
|
355 | if arch == "x86": | |
|
356 | target_triple = "i686-pc-windows-msvc" | |
|
357 | elif arch == "x64": | |
|
358 | target_triple = "x86_64-pc-windows-msvc" | |
|
359 | else: | |
|
360 | raise Exception("unhandled arch: %s" % arch) | |
|
295 | 361 | |
|
296 |
ps = |
|
|
297 | arch=arch, extra_args=' '.join(extra_args) | |
|
298 | ) | |
|
362 | ps = BUILD_INNO_PYTHON3.format( | |
|
363 | pyoxidizer_target=target_triple, version=version, | |
|
364 | ) | |
|
365 | else: | |
|
366 | extra_args = [] | |
|
367 | if version: | |
|
368 | extra_args.extend(['--version', version]) | |
|
369 | ||
|
370 | ps = get_vc_prefix(arch) + BUILD_INNO_PYTHON2.format( | |
|
371 | arch=arch, extra_args=' '.join(extra_args) | |
|
372 | ) | |
|
373 | ||
|
299 | 374 | run_powershell(winrm_client, ps) |
|
300 | 375 | copy_latest_dist(winrm_client, '*.exe', dest_path) |
|
301 | 376 | |
|
302 | 377 | |
|
303 | def build_wheel(winrm_client, arch: str, dest_path: pathlib.Path): | |
|
378 | def build_wheel( | |
|
379 | winrm_client, python_version: str, arch: str, dest_path: pathlib.Path | |
|
380 | ): | |
|
304 | 381 | """Build Python wheels on a remote machine. |
|
305 | 382 | |
|
306 | 383 | Using a WinRM client, remote commands are executed to build a Python wheel |
|
307 | 384 | for Mercurial. |
|
308 | 385 | """ |
|
309 | print('Building Windows wheel for %s' % arch) | |
|
310 | ps = get_vc_prefix(arch) + BUILD_WHEEL.format(arch=arch) | |
|
386 | print('Building Windows wheel for Python %s %s' % (python_version, arch)) | |
|
387 | ||
|
388 | ps = BUILD_WHEEL.format( | |
|
389 | python_version=python_version.replace(".", ""), arch=arch | |
|
390 | ) | |
|
391 | ||
|
392 | # Python 2.7 requires an activated environment. | |
|
393 | if python_version == "2.7": | |
|
394 | ps = get_vc_prefix(arch) + ps | |
|
395 | ||
|
311 | 396 | run_powershell(winrm_client, ps) |
|
312 | 397 | copy_latest_dist(winrm_client, '*.whl', dest_path) |
|
313 | 398 | |
|
314 | 399 | |
|
315 | 400 | def build_wix_installer( |
|
316 | 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, | |
|
317 | 406 | ): |
|
318 | 407 | """Build the WiX installer on a remote machine. |
|
319 | 408 | |
|
320 | 409 | Using a WinRM client, remote commands are executed to build a WiX installer. |
|
321 | 410 | """ |
|
322 | print('Building WiX installer for %s' % arch) | |
|
323 | extra_args = [] | |
|
324 | if version: | |
|
325 | extra_args.extend(['--version', version]) | |
|
411 | print('Building WiX installer for Python %d %s' % (python_version, arch)) | |
|
412 | ||
|
413 | if python_version == 3: | |
|
414 | # TODO fix this limitation in packaging code | |
|
415 | if not version: | |
|
416 | raise Exception( | |
|
417 | "version string is required when building for Python 3" | |
|
418 | ) | |
|
326 | 419 | |
|
327 | ps = get_vc_prefix(arch) + BUILD_WIX.format( | |
|
328 | arch=arch, extra_args=' '.join(extra_args) | |
|
329 | ) | |
|
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 | ||
|
330 | 439 | run_powershell(winrm_client, ps) |
|
331 | 440 | copy_latest_dist(winrm_client, '*.msi', dest_path) |
|
332 | 441 | |
@@ -356,56 +465,100 b' def run_tests(winrm_client, python_versi' | |||
|
356 | 465 | |
|
357 | 466 | def resolve_wheel_artifacts(dist_path: pathlib.Path, version: str): |
|
358 | 467 | return ( |
|
359 |
dist_path / |
|
|
360 |
dist_path / |
|
|
468 | dist_path / WHEEL_FILENAME_PYTHON27_X86.format(version=version), | |
|
469 | dist_path / WHEEL_FILENAME_PYTHON27_X64.format(version=version), | |
|
470 | dist_path / WHEEL_FILENAME_PYTHON37_X86.format(version=version), | |
|
471 | dist_path / WHEEL_FILENAME_PYTHON37_X64.format(version=version), | |
|
472 | dist_path / WHEEL_FILENAME_PYTHON38_X86.format(version=version), | |
|
473 | dist_path / WHEEL_FILENAME_PYTHON38_X64.format(version=version), | |
|
361 | 474 | ) |
|
362 | 475 | |
|
363 | 476 | |
|
364 | 477 | def resolve_all_artifacts(dist_path: pathlib.Path, version: str): |
|
365 | 478 | return ( |
|
366 |
dist_path / |
|
|
367 |
dist_path / |
|
|
368 |
dist_path / |
|
|
369 |
dist_path / |
|
|
370 |
dist_path / |
|
|
371 |
dist_path / |
|
|
479 | dist_path / WHEEL_FILENAME_PYTHON27_X86.format(version=version), | |
|
480 | dist_path / WHEEL_FILENAME_PYTHON27_X64.format(version=version), | |
|
481 | dist_path / WHEEL_FILENAME_PYTHON37_X86.format(version=version), | |
|
482 | dist_path / WHEEL_FILENAME_PYTHON37_X64.format(version=version), | |
|
483 | dist_path / WHEEL_FILENAME_PYTHON38_X86.format(version=version), | |
|
484 | dist_path / WHEEL_FILENAME_PYTHON38_X64.format(version=version), | |
|
485 | dist_path / EXE_FILENAME_PYTHON2_X86.format(version=version), | |
|
486 | dist_path / EXE_FILENAME_PYTHON2_X64.format(version=version), | |
|
487 | dist_path / EXE_FILENAME_PYTHON3_X86.format(version=version), | |
|
488 | dist_path / EXE_FILENAME_PYTHON3_X64.format(version=version), | |
|
489 | dist_path / MSI_FILENAME_PYTHON2_X86.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), | |
|
372 | 493 | ) |
|
373 | 494 | |
|
374 | 495 | |
|
375 | 496 | def generate_latest_dat(version: str): |
|
376 |
x86_exe_filename = |
|
|
377 |
x64_exe_filename = |
|
|
378 |
|
|
|
379 |
|
|
|
497 | python2_x86_exe_filename = EXE_FILENAME_PYTHON2_X86.format(version=version) | |
|
498 | python2_x64_exe_filename = EXE_FILENAME_PYTHON2_X64.format(version=version) | |
|
499 | python3_x86_exe_filename = EXE_FILENAME_PYTHON3_X86.format(version=version) | |
|
500 | python3_x64_exe_filename = EXE_FILENAME_PYTHON3_X64.format(version=version) | |
|
501 | python2_x86_msi_filename = MSI_FILENAME_PYTHON2_X86.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) | |
|
380 | 505 | |
|
381 | 506 | entries = ( |
|
382 | 507 | ( |
|
383 | 508 | '10', |
|
384 | 509 | version, |
|
385 | 510 | X86_USER_AGENT_PATTERN, |
|
386 | '%s/%s' % (MERCURIAL_SCM_BASE_URL, x86_exe_filename), | |
|
387 |
|
|
|
511 | '%s/%s' % (MERCURIAL_SCM_BASE_URL, python3_x86_exe_filename), | |
|
512 | EXE_PYTHON3_X86_DESCRIPTION.format(version=version), | |
|
388 | 513 | ), |
|
389 | 514 | ( |
|
390 | 515 | '10', |
|
391 | 516 | version, |
|
392 | 517 | X64_USER_AGENT_PATTERN, |
|
393 | '%s/%s' % (MERCURIAL_SCM_BASE_URL, x64_exe_filename), | |
|
394 |
|
|
|
518 | '%s/%s' % (MERCURIAL_SCM_BASE_URL, python3_x64_exe_filename), | |
|
519 | EXE_PYTHON3_X64_DESCRIPTION.format(version=version), | |
|
520 | ), | |
|
521 | ( | |
|
522 | '9', | |
|
523 | version, | |
|
524 | X86_USER_AGENT_PATTERN, | |
|
525 | '%s/%s' % (MERCURIAL_SCM_BASE_URL, python2_x86_exe_filename), | |
|
526 | EXE_PYTHON2_X86_DESCRIPTION.format(version=version), | |
|
527 | ), | |
|
528 | ( | |
|
529 | '9', | |
|
530 | version, | |
|
531 | X64_USER_AGENT_PATTERN, | |
|
532 | '%s/%s' % (MERCURIAL_SCM_BASE_URL, python2_x64_exe_filename), | |
|
533 | EXE_PYTHON2_X64_DESCRIPTION.format(version=version), | |
|
395 | 534 | ), |
|
396 | 535 | ( |
|
397 | 536 | '10', |
|
398 | 537 | version, |
|
399 | 538 | X86_USER_AGENT_PATTERN, |
|
400 | '%s/%s' % (MERCURIAL_SCM_BASE_URL, x86_msi_filename), | |
|
401 |
|
|
|
539 | '%s/%s' % (MERCURIAL_SCM_BASE_URL, python3_x86_msi_filename), | |
|
540 | MSI_PYTHON3_X86_DESCRIPTION.format(version=version), | |
|
402 | 541 | ), |
|
403 | 542 | ( |
|
404 | 543 | '10', |
|
405 | 544 | version, |
|
406 | 545 | X64_USER_AGENT_PATTERN, |
|
407 | '%s/%s' % (MERCURIAL_SCM_BASE_URL, x64_msi_filename), | |
|
408 |
|
|
|
546 | '%s/%s' % (MERCURIAL_SCM_BASE_URL, python3_x64_msi_filename), | |
|
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), | |
|
409 | 562 | ), |
|
410 | 563 | ) |
|
411 | 564 |
@@ -64,6 +64,9 b'' | |||
|
64 | 64 | $MERCURIAL_WHEEL_URL = "https://files.pythonhosted.org/packages/6d/47/e031e47f7fe9b16e4e3383da47e2b0a7eae6e603996bc67a03ec4fa1b3f4/$MERCURIAL_WHEEL_FILENAME" |
|
65 | 65 | $MERCURIAL_WHEEL_SHA256 = "1d18c7f6ca1456f0f62ee65c9a50c14cbba48ce6e924930cdb10537f5c9eaf5f" |
|
66 | 66 | |
|
67 | $RUSTUP_INIT_URL = "https://static.rust-lang.org/rustup/archive/1.21.1/x86_64-pc-windows-gnu/rustup-init.exe" | |
|
68 | $RUSTUP_INIT_SHA256 = "d17df34ba974b9b19cf5c75883a95475aa22ddc364591d75d174090d55711c72" | |
|
69 | ||
|
67 | 70 | # Writing progress slows down downloads substantially. So disable it. |
|
68 | 71 | $progressPreference = 'silentlyContinue' |
|
69 | 72 | |
@@ -116,6 +119,20 b' function Install-Python3($name, $install' | |||
|
116 | 119 | Invoke-Process ${dest}\python.exe $pip |
|
117 | 120 | } |
|
118 | 121 | |
|
122 | function Install-Rust($prefix) { | |
|
123 | Write-Output "installing Rust" | |
|
124 | $Env:RUSTUP_HOME = "${prefix}\rustup" | |
|
125 | $Env:CARGO_HOME = "${prefix}\cargo" | |
|
126 | ||
|
127 | Invoke-Process "${prefix}\assets\rustup-init.exe" "-y --default-host x86_64-pc-windows-msvc" | |
|
128 | Invoke-Process "${prefix}\cargo\bin\rustup.exe" "target add i686-pc-windows-msvc" | |
|
129 | Invoke-Process "${prefix}\cargo\bin\rustup.exe" "install 1.42.0" | |
|
130 | Invoke-Process "${prefix}\cargo\bin\rustup.exe" "component add clippy" | |
|
131 | ||
|
132 | # Install PyOxidizer for packaging. | |
|
133 | Invoke-Process "${prefix}\cargo\bin\cargo.exe" "install --version 0.7.0 pyoxidizer" | |
|
134 | } | |
|
135 | ||
|
119 | 136 | function Install-Dependencies($prefix) { |
|
120 | 137 | if (!(Test-Path -Path $prefix\assets)) { |
|
121 | 138 | New-Item -Path $prefix\assets -ItemType Directory |
@@ -140,6 +157,7 b' function Install-Dependencies($prefix) {' | |||
|
140 | 157 | Secure-Download $INNO_SETUP_URL ${prefix}\assets\InnoSetup.exe $INNO_SETUP_SHA256 |
|
141 | 158 | Secure-Download $MINGW_BIN_URL ${prefix}\assets\mingw-get-bin.zip $MINGW_BIN_SHA256 |
|
142 | 159 | Secure-Download $MERCURIAL_WHEEL_URL ${prefix}\assets\${MERCURIAL_WHEEL_FILENAME} $MERCURIAL_WHEEL_SHA256 |
|
160 | Secure-Download $RUSTUP_INIT_URL ${prefix}\assets\rustup-init.exe $RUSTUP_INIT_SHA256 | |
|
143 | 161 | |
|
144 | 162 | Write-Output "installing Python 2.7 32-bit" |
|
145 | 163 | Invoke-Process msiexec.exe "/i ${prefix}\assets\python27-x86.msi /l* ${prefix}\assets\python27-x86.log /q TARGETDIR=${prefix}\python27-x86 ALLUSERS=" |
@@ -163,6 +181,8 b' function Install-Dependencies($prefix) {' | |||
|
163 | 181 | Write-Output "installing Visual Studio 2017 Build Tools and SDKs" |
|
164 | 182 | Invoke-Process ${prefix}\assets\vs_buildtools.exe "--quiet --wait --norestart --nocache --channelUri https://aka.ms/vs/15/release/channel --add Microsoft.VisualStudio.Workload.MSBuildTools --add Microsoft.VisualStudio.Component.Windows10SDK.17763 --add Microsoft.VisualStudio.Workload.VCTools --add Microsoft.VisualStudio.Component.Windows10SDK --add Microsoft.VisualStudio.Component.VC.140" |
|
165 | 183 | |
|
184 | Install-Rust ${prefix} | |
|
185 | ||
|
166 | 186 | Write-Output "installing Visual C++ 9.0 for Python 2.7" |
|
167 | 187 | Invoke-Process msiexec.exe "/i ${prefix}\assets\VCForPython27.msi /l* ${prefix}\assets\VCForPython27.log /q" |
|
168 | 188 |
@@ -20,8 +20,11 b' HERE = pathlib.Path(os.path.abspath(os.p' | |||
|
20 | 20 | SOURCE_DIR = HERE.parent.parent.parent |
|
21 | 21 | |
|
22 | 22 | |
|
23 | def build_inno(python=None, iscc=None, version=None): | |
|
24 | if not os.path.isabs(python): | |
|
23 | def build_inno(pyoxidizer_target=None, python=None, iscc=None, version=None): | |
|
24 | if not pyoxidizer_target and not python: | |
|
25 | raise Exception("--python required unless building with PyOxidizer") | |
|
26 | ||
|
27 | if python and not os.path.isabs(python): | |
|
25 | 28 | raise Exception("--python arg must be an absolute path") |
|
26 | 29 | |
|
27 | 30 | if iscc: |
@@ -35,13 +38,19 b' def build_inno(python=None, iscc=None, v' | |||
|
35 | 38 | |
|
36 | 39 | build_dir = SOURCE_DIR / "build" |
|
37 | 40 | |
|
38 | inno.build( | |
|
39 | SOURCE_DIR, build_dir, pathlib.Path(python), iscc, version=version, | |
|
40 | ) | |
|
41 | if pyoxidizer_target: | |
|
42 | inno.build_with_pyoxidizer( | |
|
43 | SOURCE_DIR, build_dir, pyoxidizer_target, iscc, version=version | |
|
44 | ) | |
|
45 | else: | |
|
46 | inno.build_with_py2exe( | |
|
47 | SOURCE_DIR, build_dir, pathlib.Path(python), iscc, version=version, | |
|
48 | ) | |
|
41 | 49 | |
|
42 | 50 | |
|
43 | 51 | def build_wix( |
|
44 | 52 | name=None, |
|
53 | pyoxidizer_target=None, | |
|
45 | 54 | python=None, |
|
46 | 55 | version=None, |
|
47 | 56 | sign_sn=None, |
@@ -52,17 +61,29 b' def build_wix(' | |||
|
52 | 61 | extra_wxs=None, |
|
53 | 62 | extra_features=None, |
|
54 | 63 | ): |
|
55 | fn = wix.build_installer | |
|
64 | if not pyoxidizer_target and not python: | |
|
65 | raise Exception("--python required unless building with PyOxidizer") | |
|
66 | ||
|
67 | if python and not os.path.isabs(python): | |
|
68 | raise Exception("--python arg must be an absolute path") | |
|
69 | ||
|
56 | 70 | kwargs = { |
|
57 | 71 | "source_dir": SOURCE_DIR, |
|
58 | "python_exe": pathlib.Path(python), | |
|
59 | 72 | "version": version, |
|
60 | 73 | } |
|
61 | 74 | |
|
62 | if not os.path.isabs(python): | |
|
63 | raise Exception("--python arg must be an absolute path") | |
|
75 | if pyoxidizer_target: | |
|
76 | fn = wix.build_installer_pyoxidizer | |
|
77 | kwargs["target_triple"] = pyoxidizer_target | |
|
78 | else: | |
|
79 | fn = wix.build_installer_py2exe | |
|
80 | kwargs["python_exe"] = pathlib.Path(python) | |
|
64 | 81 | |
|
65 | 82 | if extra_packages_script: |
|
83 | if pyoxidizer_target: | |
|
84 | raise Exception( | |
|
85 | "pyoxidizer does not support --extra-packages-script" | |
|
86 | ) | |
|
66 | 87 | kwargs["extra_packages_script"] = extra_packages_script |
|
67 | 88 | if extra_wxs: |
|
68 | 89 | kwargs["extra_wxs"] = dict( |
@@ -72,12 +93,13 b' def build_wix(' | |||
|
72 | 93 | kwargs["extra_features"] = extra_features.split(",") |
|
73 | 94 | |
|
74 | 95 | if sign_sn or sign_cert: |
|
75 | fn = wix.build_signed_installer | |
|
76 |
|
|
|
77 |
|
|
|
78 |
|
|
|
79 |
|
|
|
80 |
|
|
|
96 | kwargs["signing_info"] = { | |
|
97 | "name": name, | |
|
98 | "subject_name": sign_sn, | |
|
99 | "cert_path": sign_cert, | |
|
100 | "cert_password": sign_password, | |
|
101 | "timestamp_url": sign_timestamp_url, | |
|
102 | } | |
|
81 | 103 | |
|
82 | 104 | fn(**kwargs) |
|
83 | 105 | |
@@ -88,7 +110,12 b' def get_parser():' | |||
|
88 | 110 | subparsers = parser.add_subparsers() |
|
89 | 111 | |
|
90 | 112 | sp = subparsers.add_parser("inno", help="Build Inno Setup installer") |
|
91 | sp.add_argument("--python", required=True, help="path to python.exe to use") | |
|
113 | sp.add_argument( | |
|
114 | "--pyoxidizer-target", | |
|
115 | choices={"i686-pc-windows-msvc", "x86_64-pc-windows-msvc"}, | |
|
116 | help="Build with PyOxidizer targeting this host triple", | |
|
117 | ) | |
|
118 | sp.add_argument("--python", help="path to python.exe to use") | |
|
92 | 119 | sp.add_argument("--iscc", help="path to iscc.exe to use") |
|
93 | 120 | sp.add_argument( |
|
94 | 121 | "--version", |
@@ -102,8 +129,11 b' def get_parser():' | |||
|
102 | 129 | ) |
|
103 | 130 | sp.add_argument("--name", help="Application name", default="Mercurial") |
|
104 | 131 | sp.add_argument( |
|
105 | "--python", help="Path to Python executable to use", required=True | |
|
132 | "--pyoxidizer-target", | |
|
133 | choices={"i686-pc-windows-msvc", "x86_64-pc-windows-msvc"}, | |
|
134 | help="Build with PyOxidizer targeting this host triple", | |
|
106 | 135 | ) |
|
136 | sp.add_argument("--python", help="Path to Python executable to use") | |
|
107 | 137 | sp.add_argument( |
|
108 | 138 | "--sign-sn", |
|
109 | 139 | help="Subject name (or fragment thereof) of certificate " |
@@ -18,8 +18,9 b' from .py2exe import (' | |||
|
18 | 18 | build_py2exe, |
|
19 | 19 | stage_install, |
|
20 | 20 | ) |
|
21 | from .pyoxidizer import run_pyoxidizer | |
|
21 | 22 | from .util import ( |
|
22 | find_vc_runtime_files, | |
|
23 | find_legacy_vc_runtime_files, | |
|
23 | 24 | normalize_windows_version, |
|
24 | 25 | process_install_rules, |
|
25 | 26 | read_version_py, |
@@ -41,14 +42,14 b' PACKAGE_FILES_METADATA = {' | |||
|
41 | 42 | } |
|
42 | 43 | |
|
43 | 44 | |
|
44 | def build( | |
|
45 | def build_with_py2exe( | |
|
45 | 46 | source_dir: pathlib.Path, |
|
46 | 47 | build_dir: pathlib.Path, |
|
47 | 48 | python_exe: pathlib.Path, |
|
48 | 49 | iscc_exe: pathlib.Path, |
|
49 | 50 | version=None, |
|
50 | 51 | ): |
|
51 | """Build the Inno installer. | |
|
52 | """Build the Inno installer using py2exe. | |
|
52 | 53 | |
|
53 | 54 | Build files will be placed in ``build_dir``. |
|
54 | 55 | |
@@ -61,8 +62,7 b' def build(' | |||
|
61 | 62 | |
|
62 | 63 | vc_x64 = r'\x64' in os.environ.get('LIB', '') |
|
63 | 64 | arch = 'x64' if vc_x64 else 'x86' |
|
64 | inno_source_dir = source_dir / 'contrib' / 'packaging' / 'inno' | |
|
65 | inno_build_dir = build_dir / ('inno-%s' % arch) | |
|
65 | inno_build_dir = build_dir / ('inno-py2exe-%s' % arch) | |
|
66 | 66 | staging_dir = inno_build_dir / 'stage' |
|
67 | 67 | |
|
68 | 68 | requirements_txt = ( |
@@ -93,7 +93,7 b' def build(' | |||
|
93 | 93 | process_install_rules(EXTRA_INSTALL_RULES, source_dir, staging_dir) |
|
94 | 94 | |
|
95 | 95 | # hg.exe depends on VC9 runtime DLLs. Copy those into place. |
|
96 | for f in find_vc_runtime_files(vc_x64): | |
|
96 | for f in find_legacy_vc_runtime_files(vc_x64): | |
|
97 | 97 | if f.name.endswith('.manifest'): |
|
98 | 98 | basename = 'Microsoft.VC90.CRT.manifest' |
|
99 | 99 | else: |
@@ -104,6 +104,62 b' def build(' | |||
|
104 | 104 | print('copying %s to %s' % (f, dest_path)) |
|
105 | 105 | shutil.copyfile(f, dest_path) |
|
106 | 106 | |
|
107 | build_installer( | |
|
108 | source_dir, | |
|
109 | inno_build_dir, | |
|
110 | staging_dir, | |
|
111 | iscc_exe, | |
|
112 | version, | |
|
113 | arch="x64" if vc_x64 else None, | |
|
114 | suffix="-python2", | |
|
115 | ) | |
|
116 | ||
|
117 | ||
|
118 | def build_with_pyoxidizer( | |
|
119 | source_dir: pathlib.Path, | |
|
120 | build_dir: pathlib.Path, | |
|
121 | target_triple: str, | |
|
122 | iscc_exe: pathlib.Path, | |
|
123 | version=None, | |
|
124 | ): | |
|
125 | """Build the Inno installer using PyOxidizer.""" | |
|
126 | if not iscc_exe.exists(): | |
|
127 | raise Exception("%s does not exist" % iscc_exe) | |
|
128 | ||
|
129 | inno_build_dir = build_dir / ("inno-pyoxidizer-%s" % target_triple) | |
|
130 | staging_dir = inno_build_dir / "stage" | |
|
131 | ||
|
132 | inno_build_dir.mkdir(parents=True, exist_ok=True) | |
|
133 | run_pyoxidizer(source_dir, inno_build_dir, staging_dir, target_triple) | |
|
134 | ||
|
135 | process_install_rules(EXTRA_INSTALL_RULES, source_dir, staging_dir) | |
|
136 | ||
|
137 | build_installer( | |
|
138 | source_dir, | |
|
139 | inno_build_dir, | |
|
140 | staging_dir, | |
|
141 | iscc_exe, | |
|
142 | version, | |
|
143 | arch="x64" if "x86_64" in target_triple else None, | |
|
144 | ) | |
|
145 | ||
|
146 | ||
|
147 | def build_installer( | |
|
148 | source_dir: pathlib.Path, | |
|
149 | inno_build_dir: pathlib.Path, | |
|
150 | staging_dir: pathlib.Path, | |
|
151 | iscc_exe: pathlib.Path, | |
|
152 | version, | |
|
153 | arch=None, | |
|
154 | suffix="", | |
|
155 | ): | |
|
156 | """Build an Inno installer from staged Mercurial files. | |
|
157 | ||
|
158 | This function is agnostic about how to build Mercurial. It just | |
|
159 | cares that Mercurial files are in ``staging_dir``. | |
|
160 | """ | |
|
161 | inno_source_dir = source_dir / "contrib" / "packaging" / "inno" | |
|
162 | ||
|
107 | 163 | # The final package layout is simply a mirror of the staging directory. |
|
108 | 164 | package_files = [] |
|
109 | 165 | for root, dirs, files in os.walk(staging_dir): |
@@ -158,8 +214,11 b' def build(' | |||
|
158 | 214 | |
|
159 | 215 | args = [str(iscc_exe)] |
|
160 | 216 | |
|
161 |
if |
|
|
162 |
args.append('/dARCH= |
|
|
217 | if arch: | |
|
218 | args.append('/dARCH=%s' % arch) | |
|
219 | args.append('/dSUFFIX=-%s%s' % (arch, suffix)) | |
|
220 | else: | |
|
221 | args.append('/dSUFFIX=-x86%s' % suffix) | |
|
163 | 222 | |
|
164 | 223 | if not version: |
|
165 | 224 | version = read_version_py(source_dir) |
@@ -29,7 +29,59 b' def extract_zip_to_directory(source: pat' | |||
|
29 | 29 | zf.extractall(dest) |
|
30 | 30 | |
|
31 | 31 | |
|
32 |
def find_vc_runtime_ |
|
|
32 | def find_vc_runtime_dll(x64=False): | |
|
33 | """Finds Visual C++ Runtime DLL to include in distribution.""" | |
|
34 | # We invoke vswhere to find the latest Visual Studio install. | |
|
35 | vswhere = ( | |
|
36 | pathlib.Path(os.environ["ProgramFiles(x86)"]) | |
|
37 | / "Microsoft Visual Studio" | |
|
38 | / "Installer" | |
|
39 | / "vswhere.exe" | |
|
40 | ) | |
|
41 | ||
|
42 | if not vswhere.exists(): | |
|
43 | raise Exception( | |
|
44 | "could not find vswhere.exe: %s does not exist" % vswhere | |
|
45 | ) | |
|
46 | ||
|
47 | args = [ | |
|
48 | str(vswhere), | |
|
49 | # -products * is necessary to return results from Build Tools | |
|
50 | # (as opposed to full IDE installs). | |
|
51 | "-products", | |
|
52 | "*", | |
|
53 | "-requires", | |
|
54 | "Microsoft.VisualCpp.Redist.14.Latest", | |
|
55 | "-latest", | |
|
56 | "-property", | |
|
57 | "installationPath", | |
|
58 | ] | |
|
59 | ||
|
60 | vs_install_path = pathlib.Path( | |
|
61 | os.fsdecode(subprocess.check_output(args).strip()) | |
|
62 | ) | |
|
63 | ||
|
64 | # This just gets us a path like | |
|
65 | # C:\Program Files (x86)\Microsoft Visual Studio\2019\Community | |
|
66 | # Actually vcruntime140.dll is under a path like: | |
|
67 | # VC\Redist\MSVC\<version>\<arch>\Microsoft.VC14<X>.CRT\vcruntime140.dll. | |
|
68 | ||
|
69 | arch = "x64" if x64 else "x86" | |
|
70 | ||
|
71 | search_glob = ( | |
|
72 | r"%s\VC\Redist\MSVC\*\%s\Microsoft.VC14*.CRT\vcruntime140.dll" | |
|
73 | % (vs_install_path, arch) | |
|
74 | ) | |
|
75 | ||
|
76 | candidates = glob.glob(search_glob, recursive=True) | |
|
77 | ||
|
78 | for candidate in reversed(candidates): | |
|
79 | return pathlib.Path(candidate) | |
|
80 | ||
|
81 | raise Exception("could not find vcruntime140.dll") | |
|
82 | ||
|
83 | ||
|
84 | def find_legacy_vc_runtime_files(x64=False): | |
|
33 | 85 | """Finds Visual C++ Runtime DLLs to include in distribution.""" |
|
34 | 86 | winsxs = pathlib.Path(os.environ['SYSTEMROOT']) / 'WinSxS' |
|
35 | 87 |
@@ -22,6 +22,7 b' from .py2exe import (' | |||
|
22 | 22 | build_py2exe, |
|
23 | 23 | stage_install, |
|
24 | 24 | ) |
|
25 | from .pyoxidizer import run_pyoxidizer | |
|
25 | 26 | from .util import ( |
|
26 | 27 | extract_zip_to_directory, |
|
27 | 28 | normalize_windows_version, |
@@ -121,30 +122,6 b' def run_candle(wix, cwd, wxs, source_dir' | |||
|
121 | 122 | subprocess.run(args, cwd=str(cwd), check=True) |
|
122 | 123 | |
|
123 | 124 | |
|
124 | def make_post_build_signing_fn( | |
|
125 | name, | |
|
126 | subject_name=None, | |
|
127 | cert_path=None, | |
|
128 | cert_password=None, | |
|
129 | timestamp_url=None, | |
|
130 | ): | |
|
131 | """Create a callable that will use signtool to sign hg.exe.""" | |
|
132 | ||
|
133 | def post_build_sign(source_dir, build_dir, dist_dir, version): | |
|
134 | description = '%s %s' % (name, version) | |
|
135 | ||
|
136 | sign_with_signtool( | |
|
137 | dist_dir / 'hg.exe', | |
|
138 | description, | |
|
139 | subject_name=subject_name, | |
|
140 | cert_path=cert_path, | |
|
141 | cert_password=cert_password, | |
|
142 | timestamp_url=timestamp_url, | |
|
143 | ) | |
|
144 | ||
|
145 | return post_build_sign | |
|
146 | ||
|
147 | ||
|
148 | 125 | def make_files_xml(staging_dir: pathlib.Path, is_x64) -> str: |
|
149 | 126 | """Create XML string listing every file to be installed.""" |
|
150 | 127 | |
@@ -308,27 +285,23 b' def make_files_xml(staging_dir: pathlib.' | |||
|
308 | 285 | return doc.toprettyxml() |
|
309 | 286 | |
|
310 | 287 | |
|
311 | def build_installer( | |
|
288 | def build_installer_py2exe( | |
|
312 | 289 | source_dir: pathlib.Path, |
|
313 | 290 | python_exe: pathlib.Path, |
|
314 | 291 | msi_name='mercurial', |
|
315 | 292 | version=None, |
|
316 | post_build_fn=None, | |
|
317 | 293 | extra_packages_script=None, |
|
318 | 294 | extra_wxs: typing.Optional[typing.Dict[str, str]] = None, |
|
319 | 295 | extra_features: typing.Optional[typing.List[str]] = None, |
|
296 | signing_info: typing.Optional[typing.Dict[str, str]] = None, | |
|
320 | 297 | ): |
|
321 | """Build a WiX MSI installer. | |
|
298 | """Build a WiX MSI installer using py2exe. | |
|
322 | 299 | |
|
323 | 300 | ``source_dir`` is the path to the Mercurial source tree to use. |
|
324 | 301 | ``arch`` is the target architecture. either ``x86`` or ``x64``. |
|
325 | 302 | ``python_exe`` is the path to the Python executable to use/bundle. |
|
326 | 303 | ``version`` is the Mercurial version string. If not defined, |
|
327 | 304 | ``mercurial/__version__.py`` will be consulted. |
|
328 | ``post_build_fn`` is a callable that will be called after building | |
|
329 | Mercurial but before invoking WiX. It can be used to e.g. facilitate | |
|
330 | signing. It is passed the paths to the Mercurial source, build, and | |
|
331 | dist directories and the resolved Mercurial version. | |
|
332 | 305 | ``extra_packages_script`` is a command to be run to inject extra packages |
|
333 | 306 | into the py2exe binary. It should stage packages into the virtualenv and |
|
334 | 307 | print a null byte followed by a newline-separated list of packages that |
@@ -340,8 +313,6 b' def build_installer(' | |||
|
340 | 313 | arch = 'x64' if r'\x64' in os.environ.get('LIB', '') else 'x86' |
|
341 | 314 | |
|
342 | 315 | hg_build_dir = source_dir / 'build' |
|
343 | dist_dir = source_dir / 'dist' | |
|
344 | wix_dir = source_dir / 'contrib' / 'packaging' / 'wix' | |
|
345 | 316 | |
|
346 | 317 | requirements_txt = ( |
|
347 | 318 | source_dir / 'contrib' / 'packaging' / 'requirements_win32.txt' |
@@ -357,15 +328,6 b' def build_installer(' | |||
|
357 | 328 | extra_packages_script=extra_packages_script, |
|
358 | 329 | ) |
|
359 | 330 | |
|
360 | orig_version = version or find_version(source_dir) | |
|
361 | version = normalize_windows_version(orig_version) | |
|
362 | print('using version string: %s' % version) | |
|
363 | if version != orig_version: | |
|
364 | print('(normalized from: %s)' % orig_version) | |
|
365 | ||
|
366 | if post_build_fn: | |
|
367 | post_build_fn(source_dir, hg_build_dir, dist_dir, version) | |
|
368 | ||
|
369 | 331 | build_dir = hg_build_dir / ('wix-%s' % arch) |
|
370 | 332 | staging_dir = build_dir / 'stage' |
|
371 | 333 | |
@@ -388,13 +350,112 b' def build_installer(' | |||
|
388 | 350 | print('removing %s' % p) |
|
389 | 351 | p.unlink() |
|
390 | 352 | |
|
391 | wix_pkg, wix_entry = download_entry('wix', hg_build_dir) | |
|
392 | wix_path = hg_build_dir / ('wix-%s' % wix_entry['version']) | |
|
353 | return run_wix_packaging( | |
|
354 | source_dir, | |
|
355 | build_dir, | |
|
356 | staging_dir, | |
|
357 | arch, | |
|
358 | version=version, | |
|
359 | python2=True, | |
|
360 | msi_name=msi_name, | |
|
361 | suffix="-python2", | |
|
362 | extra_wxs=extra_wxs, | |
|
363 | extra_features=extra_features, | |
|
364 | signing_info=signing_info, | |
|
365 | ) | |
|
366 | ||
|
367 | ||
|
368 | def build_installer_pyoxidizer( | |
|
369 | source_dir: pathlib.Path, | |
|
370 | target_triple: str, | |
|
371 | msi_name='mercurial', | |
|
372 | version=None, | |
|
373 | extra_wxs: typing.Optional[typing.Dict[str, str]] = None, | |
|
374 | extra_features: typing.Optional[typing.List[str]] = None, | |
|
375 | signing_info: typing.Optional[typing.Dict[str, str]] = None, | |
|
376 | ): | |
|
377 | """Build a WiX MSI installer using PyOxidizer.""" | |
|
378 | hg_build_dir = source_dir / "build" | |
|
379 | build_dir = hg_build_dir / ("wix-%s" % target_triple) | |
|
380 | staging_dir = build_dir / "stage" | |
|
381 | ||
|
382 | arch = "x64" if "x86_64" in target_triple else "x86" | |
|
383 | ||
|
384 | build_dir.mkdir(parents=True, exist_ok=True) | |
|
385 | run_pyoxidizer(source_dir, build_dir, staging_dir, target_triple) | |
|
386 | ||
|
387 | # We also install some extra files. | |
|
388 | process_install_rules(EXTRA_INSTALL_RULES, source_dir, staging_dir) | |
|
389 | ||
|
390 | # And remove some files we don't want. | |
|
391 | for f in STAGING_REMOVE_FILES: | |
|
392 | p = staging_dir / f | |
|
393 | if p.exists(): | |
|
394 | print('removing %s' % p) | |
|
395 | p.unlink() | |
|
396 | ||
|
397 | return run_wix_packaging( | |
|
398 | source_dir, | |
|
399 | build_dir, | |
|
400 | staging_dir, | |
|
401 | arch, | |
|
402 | version, | |
|
403 | python2=False, | |
|
404 | msi_name=msi_name, | |
|
405 | extra_wxs=extra_wxs, | |
|
406 | extra_features=extra_features, | |
|
407 | signing_info=signing_info, | |
|
408 | ) | |
|
409 | ||
|
410 | ||
|
411 | def run_wix_packaging( | |
|
412 | source_dir: pathlib.Path, | |
|
413 | build_dir: pathlib.Path, | |
|
414 | staging_dir: pathlib.Path, | |
|
415 | arch: str, | |
|
416 | version: str, | |
|
417 | python2: bool, | |
|
418 | msi_name: typing.Optional[str] = "mercurial", | |
|
419 | suffix: str = "", | |
|
420 | extra_wxs: typing.Optional[typing.Dict[str, str]] = None, | |
|
421 | extra_features: typing.Optional[typing.List[str]] = None, | |
|
422 | signing_info: typing.Optional[typing.Dict[str, str]] = None, | |
|
423 | ): | |
|
424 | """Invokes WiX to package up a built Mercurial. | |
|
425 | ||
|
426 | ``signing_info`` is a dict defining properties to facilitate signing the | |
|
427 | installer. Recognized keys include ``name``, ``subject_name``, | |
|
428 | ``cert_path``, ``cert_password``, and ``timestamp_url``. If populated, | |
|
429 | we will sign both the hg.exe and the .msi using the signing credentials | |
|
430 | specified. | |
|
431 | """ | |
|
432 | ||
|
433 | orig_version = version or find_version(source_dir) | |
|
434 | version = normalize_windows_version(orig_version) | |
|
435 | print('using version string: %s' % version) | |
|
436 | if version != orig_version: | |
|
437 | print('(normalized from: %s)' % orig_version) | |
|
438 | ||
|
439 | if signing_info: | |
|
440 | sign_with_signtool( | |
|
441 | staging_dir / "hg.exe", | |
|
442 | "%s %s" % (signing_info["name"], version), | |
|
443 | subject_name=signing_info["subject_name"], | |
|
444 | cert_path=signing_info["cert_path"], | |
|
445 | cert_password=signing_info["cert_password"], | |
|
446 | timestamp_url=signing_info["timestamp_url"], | |
|
447 | ) | |
|
448 | ||
|
449 | wix_dir = source_dir / 'contrib' / 'packaging' / 'wix' | |
|
450 | ||
|
451 | wix_pkg, wix_entry = download_entry('wix', build_dir) | |
|
452 | wix_path = build_dir / ('wix-%s' % wix_entry['version']) | |
|
393 | 453 | |
|
394 | 454 | if not wix_path.exists(): |
|
395 | 455 | extract_zip_to_directory(wix_pkg, wix_path) |
|
396 | 456 | |
|
397 | ensure_vc90_merge_modules(hg_build_dir) | |
|
457 | if python2: | |
|
458 | ensure_vc90_merge_modules(build_dir) | |
|
398 | 459 | |
|
399 | 460 | source_build_rel = pathlib.Path(os.path.relpath(source_dir, build_dir)) |
|
400 | 461 | |
@@ -413,7 +474,16 b' def build_installer(' | |||
|
413 | 474 | source = wix_dir / 'mercurial.wxs' |
|
414 | 475 | defines['Version'] = version |
|
415 | 476 | defines['Comments'] = 'Installs Mercurial version %s' % version |
|
416 | defines['VCRedistSrcDir'] = str(hg_build_dir) | |
|
477 | ||
|
478 | if python2: | |
|
479 | defines["PythonVersion"] = "2" | |
|
480 | defines['VCRedistSrcDir'] = str(build_dir) | |
|
481 | else: | |
|
482 | defines["PythonVersion"] = "3" | |
|
483 | ||
|
484 | if (staging_dir / "lib").exists(): | |
|
485 | defines["MercurialHasLib"] = "1" | |
|
486 | ||
|
417 | 487 | if extra_features: |
|
418 | 488 | assert all(';' not in f for f in extra_features) |
|
419 | 489 | defines['MercurialExtraFeatures'] = ';'.join(extra_features) |
@@ -421,7 +491,9 b' def build_installer(' | |||
|
421 | 491 | run_candle(wix_path, build_dir, source, source_build_rel, defines=defines) |
|
422 | 492 | |
|
423 | 493 | msi_path = ( |
|
424 | source_dir / 'dist' / ('%s-%s-%s.msi' % (msi_name, orig_version, arch)) | |
|
494 | source_dir | |
|
495 | / 'dist' | |
|
496 | / ('%s-%s-%s%s.msi' % (msi_name, orig_version, arch, suffix)) | |
|
425 | 497 | ) |
|
426 | 498 | |
|
427 | 499 | args = [ |
@@ -448,52 +520,16 b' def build_installer(' | |||
|
448 | 520 | |
|
449 | 521 | print('%s created' % msi_path) |
|
450 | 522 | |
|
523 | if signing_info: | |
|
524 | sign_with_signtool( | |
|
525 | msi_path, | |
|
526 | "%s %s" % (signing_info["name"], version), | |
|
527 | subject_name=signing_info["subject_name"], | |
|
528 | cert_path=signing_info["cert_path"], | |
|
529 | cert_password=signing_info["cert_password"], | |
|
530 | timestamp_url=signing_info["timestamp_url"], | |
|
531 | ) | |
|
532 | ||
|
451 | 533 | return { |
|
452 | 534 | 'msi_path': msi_path, |
|
453 | 535 | } |
|
454 | ||
|
455 | ||
|
456 | def build_signed_installer( | |
|
457 | source_dir: pathlib.Path, | |
|
458 | python_exe: pathlib.Path, | |
|
459 | name: str, | |
|
460 | version=None, | |
|
461 | subject_name=None, | |
|
462 | cert_path=None, | |
|
463 | cert_password=None, | |
|
464 | timestamp_url=None, | |
|
465 | extra_packages_script=None, | |
|
466 | extra_wxs=None, | |
|
467 | extra_features=None, | |
|
468 | ): | |
|
469 | """Build an installer with signed executables.""" | |
|
470 | ||
|
471 | post_build_fn = make_post_build_signing_fn( | |
|
472 | name, | |
|
473 | subject_name=subject_name, | |
|
474 | cert_path=cert_path, | |
|
475 | cert_password=cert_password, | |
|
476 | timestamp_url=timestamp_url, | |
|
477 | ) | |
|
478 | ||
|
479 | info = build_installer( | |
|
480 | source_dir, | |
|
481 | python_exe=python_exe, | |
|
482 | msi_name=name.lower(), | |
|
483 | version=version, | |
|
484 | post_build_fn=post_build_fn, | |
|
485 | extra_packages_script=extra_packages_script, | |
|
486 | extra_wxs=extra_wxs, | |
|
487 | extra_features=extra_features, | |
|
488 | ) | |
|
489 | ||
|
490 | description = '%s %s' % (name, version) | |
|
491 | ||
|
492 | sign_with_signtool( | |
|
493 | info['msi_path'], | |
|
494 | description, | |
|
495 | subject_name=subject_name, | |
|
496 | cert_path=cert_path, | |
|
497 | cert_password=cert_password, | |
|
498 | timestamp_url=timestamp_url, | |
|
499 | ) |
@@ -9,14 +9,13 b'' | |||
|
9 | 9 | AppCopyright=Copyright 2005-2020 Matt Mackall and others |
|
10 | 10 | AppName=Mercurial |
|
11 | 11 | AppVersion={#VERSION} |
|
12 | OutputBaseFilename=Mercurial-{#VERSION}{#SUFFIX} | |
|
12 | 13 | #if ARCH == "x64" |
|
13 | 14 | AppVerName=Mercurial {#VERSION} (64-bit) |
|
14 | OutputBaseFilename=Mercurial-{#VERSION}-x64 | |
|
15 | 15 | ArchitecturesAllowed=x64 |
|
16 | 16 | ArchitecturesInstallIn64BitMode=x64 |
|
17 | 17 | #else |
|
18 | 18 | AppVerName=Mercurial {#VERSION} |
|
19 | OutputBaseFilename=Mercurial-{#VERSION} | |
|
20 | 19 | #endif |
|
21 | 20 | InfoAfterFile=../postinstall.txt |
|
22 | 21 | LicenseFile=Copying.txt |
@@ -79,16 +79,21 b'' | |||
|
79 | 79 | </Directory> |
|
80 | 80 | </Directory> |
|
81 | 81 | |
|
82 | <?if $(var.Platform) = "x86" ?> | |
|
83 | <Merge Id='VCRuntime' DiskId='1' Language='1033' | |
|
84 | SourceFile='$(var.VCRedistSrcDir)\microsoft.vcxx.crt.x86_msm.msm' /> | |
|
85 | <Merge Id='VCRuntimePolicy' DiskId='1' Language='1033' | |
|
86 | SourceFile='$(var.VCRedistSrcDir)\policy.x.xx.microsoft.vcxx.crt.x86_msm.msm' /> | |
|
87 | <?else?> | |
|
88 | <Merge Id='VCRuntime' DiskId='1' Language='1033' | |
|
89 | SourceFile='$(var.VCRedistSrcDir)\microsoft.vcxx.crt.x64_msm.msm' /> | |
|
90 | <Merge Id='VCRuntimePolicy' DiskId='1' Language='1033' | |
|
91 | SourceFile='$(var.VCRedistSrcDir)\policy.x.xx.microsoft.vcxx.crt.x64_msm.msm' /> | |
|
82 | <!-- Install VCRedist merge modules on Python 2. On Python 3, | |
|
83 | vcruntimeXXX.dll is part of the install layout and gets picked up | |
|
84 | as a regular file. --> | |
|
85 | <?if $(var.PythonVersion) = "2" ?> | |
|
86 | <?if $(var.Platform) = "x86" ?> | |
|
87 | <Merge Id='VCRuntime' DiskId='1' Language='1033' | |
|
88 | SourceFile='$(var.VCRedistSrcDir)\microsoft.vcxx.crt.x86_msm.msm' /> | |
|
89 | <Merge Id='VCRuntimePolicy' DiskId='1' Language='1033' | |
|
90 | SourceFile='$(var.VCRedistSrcDir)\policy.x.xx.microsoft.vcxx.crt.x86_msm.msm' /> | |
|
91 | <?else?> | |
|
92 | <Merge Id='VCRuntime' DiskId='1' Language='1033' | |
|
93 | SourceFile='$(var.VCRedistSrcDir)\microsoft.vcxx.crt.x64_msm.msm' /> | |
|
94 | <Merge Id='VCRuntimePolicy' DiskId='1' Language='1033' | |
|
95 | SourceFile='$(var.VCRedistSrcDir)\policy.x.xx.microsoft.vcxx.crt.x64_msm.msm' /> | |
|
96 | <?endif?> | |
|
92 | 97 | <?endif?> |
|
93 | 98 | </Directory> |
|
94 | 99 | |
@@ -101,10 +106,14 b'' | |||
|
101 | 106 | <ComponentGroupRef Id="hg.group.ROOT" /> |
|
102 | 107 | <ComponentGroupRef Id="hg.group.defaultrc" /> |
|
103 | 108 | <ComponentGroupRef Id="hg.group.helptext" /> |
|
104 | <ComponentGroupRef Id="hg.group.lib" /> | |
|
109 | <?ifdef MercurialHasLib?> | |
|
110 | <ComponentGroupRef Id="hg.group.lib" /> | |
|
111 | <?endif?> | |
|
105 | 112 | <ComponentGroupRef Id="hg.group.templates" /> |
|
106 | <MergeRef Id='VCRuntime' /> | |
|
107 |
<MergeRef Id='VCRuntime |
|
|
113 | <?if $(var.PythonVersion) = "2" ?> | |
|
114 | <MergeRef Id='VCRuntime' /> | |
|
115 | <MergeRef Id='VCRuntimePolicy' /> | |
|
116 | <?endif?> | |
|
108 | 117 | </Feature> |
|
109 | 118 | <?ifdef MercurialExtraFeatures?> |
|
110 | 119 | <?foreach EXTRAFEAT in $(var.MercurialExtraFeatures)?> |
@@ -2558,7 +2558,7 b' def diff(' | |||
|
2558 | 2558 | fctx2 is not None |
|
2559 | 2559 | ), b'fctx2 unexpectly None in diff hunks filtering' |
|
2560 | 2560 | hunks = hunksfilterfn(fctx2, hunks) |
|
2561 |
text = b''.join( |
|
|
2561 | text = b''.join(b''.join(hlines) for hrange, hlines in hunks) | |
|
2562 | 2562 | if hdr and (text or len(hdr) > 1): |
|
2563 | 2563 | yield b'\n'.join(hdr) + b'\n' |
|
2564 | 2564 | if text: |
@@ -1,13 +1,24 b'' | |||
|
1 | 1 | ROOT = CWD + "/../.." |
|
2 | 2 | |
|
3 | def make_exe(): | |
|
4 | dist = default_python_distribution() | |
|
3 | # Code to run in Python interpreter. | |
|
4 | RUN_CODE = "import hgdemandimport; hgdemandimport.enable(); from mercurial import dispatch; dispatch.run()" | |
|
5 | ||
|
6 | ||
|
7 | set_build_path(ROOT + "/build/pyoxidizer") | |
|
8 | ||
|
5 | 9 | |
|
6 | code = "import hgdemandimport; hgdemandimport.enable(); from mercurial import dispatch; dispatch.run()" | |
|
10 | def make_distribution(): | |
|
11 | return default_python_distribution() | |
|
12 | ||
|
7 | 13 | |
|
14 | def make_distribution_windows(): | |
|
15 | return default_python_distribution(flavor="standalone_dynamic") | |
|
16 | ||
|
17 | ||
|
18 | def make_exe(dist): | |
|
8 | 19 | config = PythonInterpreterConfig( |
|
9 | 20 | raw_allocator = "system", |
|
10 |
run_eval = |
|
|
21 | run_eval = RUN_CODE, | |
|
11 | 22 | # We want to let the user load extensions from the file system |
|
12 | 23 | filesystem_importer = True, |
|
13 | 24 | # We need this to make resourceutil happy, since it looks for sys.frozen. |
@@ -24,30 +35,65 b' def make_exe():' | |||
|
24 | 35 | extension_module_filter = "all", |
|
25 | 36 | ) |
|
26 | 37 | |
|
27 | exe.add_python_resources(dist.pip_install([ROOT])) | |
|
38 | # Add Mercurial to resources. | |
|
39 | for resource in dist.pip_install(["--verbose", ROOT]): | |
|
40 | # This is a bit wonky and worth explaining. | |
|
41 | # | |
|
42 | # Various parts of Mercurial don't yet support loading package | |
|
43 | # resources via the ResourceReader interface. Or, not having | |
|
44 | # file-based resources would be too inconvenient for users. | |
|
45 | # | |
|
46 | # So, for package resources, we package them both in the | |
|
47 | # filesystem as well as in memory. If both are defined, | |
|
48 | # PyOxidizer will prefer the in-memory location. So even | |
|
49 | # if the filesystem file isn't packaged in the location | |
|
50 | # specified here, we should never encounter an errors as the | |
|
51 | # resource will always be available in memory. | |
|
52 | if type(resource) == "PythonPackageResource": | |
|
53 | exe.add_filesystem_relative_python_resource(".", resource) | |
|
54 | exe.add_in_memory_python_resource(resource) | |
|
55 | else: | |
|
56 | exe.add_python_resource(resource) | |
|
57 | ||
|
58 | # On Windows, we install extra packages for convenience. | |
|
59 | if "windows" in BUILD_TARGET_TRIPLE: | |
|
60 | exe.add_python_resources( | |
|
61 | dist.pip_install(["-r", ROOT + "/contrib/packaging/requirements_win32.txt"]) | |
|
62 | ) | |
|
28 | 63 | |
|
29 | 64 | return exe |
|
30 | 65 | |
|
31 | def make_install(exe): | |
|
66 | ||
|
67 | def make_manifest(dist, exe): | |
|
32 | 68 | m = FileManifest() |
|
33 | ||
|
34 | # `hg` goes in root directory. | |
|
35 | 69 | m.add_python_resource(".", exe) |
|
36 | 70 | |
|
37 | templates = glob( | |
|
38 | include = [ROOT + "/mercurial/templates/**/*"], | |
|
39 | strip_prefix = ROOT + "/mercurial/", | |
|
40 | ) | |
|
41 | m.add_manifest(templates) | |
|
71 | return m | |
|
42 | 72 | |
|
43 | return m | |
|
44 | 73 | |
|
45 | 74 | def make_embedded_resources(exe): |
|
46 | 75 | return exe.to_embedded_resources() |
|
47 | 76 | |
|
48 | register_target("exe", make_exe) | |
|
49 | register_target("app", make_install, depends = ["exe"], default = True) | |
|
50 | register_target("embedded", make_embedded_resources, depends = ["exe"], default_build_script = True) | |
|
77 | ||
|
78 | register_target("distribution_posix", make_distribution) | |
|
79 | register_target("distribution_windows", make_distribution_windows) | |
|
80 | ||
|
81 | register_target("exe_posix", make_exe, depends = ["distribution_posix"]) | |
|
82 | register_target("exe_windows", make_exe, depends = ["distribution_windows"]) | |
|
83 | ||
|
84 | register_target( | |
|
85 | "app_posix", | |
|
86 | make_manifest, | |
|
87 | depends = ["distribution_posix", "exe_posix"], | |
|
88 | default = "windows" not in BUILD_TARGET_TRIPLE, | |
|
89 | ) | |
|
90 | register_target( | |
|
91 | "app_windows", | |
|
92 | make_manifest, | |
|
93 | depends = ["distribution_windows", "exe_windows"], | |
|
94 | default = "windows" in BUILD_TARGET_TRIPLE, | |
|
95 | ) | |
|
96 | ||
|
51 | 97 | resolve_targets() |
|
52 | 98 | |
|
53 | 99 | # END OF COMMON USER-ADJUSTED SETTINGS. |
@@ -55,5 +101,4 b' resolve_targets()' | |||
|
55 | 101 | # Everything below this is typically managed by PyOxidizer and doesn't need |
|
56 | 102 | # to be updated by people. |
|
57 | 103 | |
|
58 |
PYOXIDIZER_VERSION = "0.7.0 |
|
|
59 | PYOXIDIZER_COMMIT = "c772a1379c3026314eda1c8ea244b86c0658951d" | |
|
104 | PYOXIDIZER_VERSION = "0.7.0" |
@@ -27,6 +27,7 b' New errors are not allowed. Warnings are' | |||
|
27 | 27 | Skipping contrib/packaging/hgpackaging/downloads.py it has no-che?k-code (glob) |
|
28 | 28 | Skipping contrib/packaging/hgpackaging/inno.py it has no-che?k-code (glob) |
|
29 | 29 | Skipping contrib/packaging/hgpackaging/py2exe.py it has no-che?k-code (glob) |
|
30 | Skipping contrib/packaging/hgpackaging/pyoxidizer.py it has no-che?k-code (glob) | |
|
30 | 31 | Skipping contrib/packaging/hgpackaging/util.py it has no-che?k-code (glob) |
|
31 | 32 | Skipping contrib/packaging/hgpackaging/wix.py it has no-che?k-code (glob) |
|
32 | 33 | Skipping i18n/polib.py it has no-che?k-code (glob) |
|
1 | NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now