Mercurial > hg
comparison contrib/packaging/hgpackaging/util.py @ 48848:17d5e25b8e78
packaging: remove py2exe / Python 2.7 support
This commit started by deleting references to py2exe (which is only used
on Python 2). After pulling the thread, quite a lot of code was orphaned
and was deleted.
Differential Revision: https://phab.mercurial-scm.org/D12265
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Sat, 19 Feb 2022 22:13:11 -0700 |
parents | e3f23814bac7 |
children |
comparison
equal
deleted
inserted
replaced
48847:4561ec90d3c1 | 48848:17d5e25b8e78 |
---|---|
5 # This software may be used and distributed according to the terms of the | 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. | 6 # GNU General Public License version 2 or any later version. |
7 | 7 |
8 # no-check-code because Python 3 native. | 8 # no-check-code because Python 3 native. |
9 | 9 |
10 import distutils.version | |
11 import getpass | |
12 import glob | 10 import glob |
13 import os | 11 import os |
14 import pathlib | 12 import pathlib |
15 import re | 13 import re |
16 import shutil | 14 import shutil |
17 import subprocess | 15 import subprocess |
18 import tarfile | |
19 import zipfile | 16 import zipfile |
20 | |
21 | |
22 def extract_tar_to_directory(source: pathlib.Path, dest: pathlib.Path): | |
23 with tarfile.open(source, 'r') as tf: | |
24 tf.extractall(dest) | |
25 | 17 |
26 | 18 |
27 def extract_zip_to_directory(source: pathlib.Path, dest: pathlib.Path): | 19 def extract_zip_to_directory(source: pathlib.Path, dest: pathlib.Path): |
28 with zipfile.ZipFile(source, 'r') as zf: | 20 with zipfile.ZipFile(source, 'r') as zf: |
29 zf.extractall(dest) | 21 zf.extractall(dest) |
77 | 69 |
78 for candidate in reversed(candidates): | 70 for candidate in reversed(candidates): |
79 return pathlib.Path(candidate) | 71 return pathlib.Path(candidate) |
80 | 72 |
81 raise Exception("could not find vcruntime140.dll") | 73 raise Exception("could not find vcruntime140.dll") |
82 | |
83 | |
84 def find_legacy_vc_runtime_files(x64=False): | |
85 """Finds Visual C++ Runtime DLLs to include in distribution.""" | |
86 winsxs = pathlib.Path(os.environ['SYSTEMROOT']) / 'WinSxS' | |
87 | |
88 prefix = 'amd64' if x64 else 'x86' | |
89 | |
90 candidates = sorted( | |
91 p | |
92 for p in os.listdir(winsxs) | |
93 if p.lower().startswith('%s_microsoft.vc90.crt_' % prefix) | |
94 ) | |
95 | |
96 for p in candidates: | |
97 print('found candidate VC runtime: %s' % p) | |
98 | |
99 # Take the newest version. | |
100 version = candidates[-1] | |
101 | |
102 d = winsxs / version | |
103 | |
104 return [ | |
105 d / 'msvcm90.dll', | |
106 d / 'msvcp90.dll', | |
107 d / 'msvcr90.dll', | |
108 winsxs / 'Manifests' / ('%s.manifest' % version), | |
109 ] | |
110 | |
111 | |
112 def windows_10_sdk_info(): | |
113 """Resolves information about the Windows 10 SDK.""" | |
114 | |
115 base = pathlib.Path(os.environ['ProgramFiles(x86)']) / 'Windows Kits' / '10' | |
116 | |
117 if not base.is_dir(): | |
118 raise Exception('unable to find Windows 10 SDK at %s' % base) | |
119 | |
120 # Find the latest version. | |
121 bin_base = base / 'bin' | |
122 | |
123 versions = [v for v in os.listdir(bin_base) if v.startswith('10.')] | |
124 version = sorted(versions, reverse=True)[0] | |
125 | |
126 bin_version = bin_base / version | |
127 | |
128 return { | |
129 'root': base, | |
130 'version': version, | |
131 'bin_root': bin_version, | |
132 'bin_x86': bin_version / 'x86', | |
133 'bin_x64': bin_version / 'x64', | |
134 } | |
135 | 74 |
136 | 75 |
137 def normalize_windows_version(version): | 76 def normalize_windows_version(version): |
138 """Normalize Mercurial version string so WiX/Inno accepts it. | 77 """Normalize Mercurial version string so WiX/Inno accepts it. |
139 | 78 |
192 versions.append(int(extra.split('.')[0][2:])) | 131 versions.append(int(extra.split('.')[0][2:])) |
193 | 132 |
194 return '.'.join('%d' % x for x in versions[0:4]) | 133 return '.'.join('%d' % x for x in versions[0:4]) |
195 | 134 |
196 | 135 |
197 def find_signtool(): | |
198 """Find signtool.exe from the Windows SDK.""" | |
199 sdk = windows_10_sdk_info() | |
200 | |
201 for key in ('bin_x64', 'bin_x86'): | |
202 p = sdk[key] / 'signtool.exe' | |
203 | |
204 if p.exists(): | |
205 return p | |
206 | |
207 raise Exception('could not find signtool.exe in Windows 10 SDK') | |
208 | |
209 | |
210 def sign_with_signtool( | |
211 file_path, | |
212 description, | |
213 subject_name=None, | |
214 cert_path=None, | |
215 cert_password=None, | |
216 timestamp_url=None, | |
217 ): | |
218 """Digitally sign a file with signtool.exe. | |
219 | |
220 ``file_path`` is file to sign. | |
221 ``description`` is text that goes in the signature. | |
222 | |
223 The signing certificate can be specified by ``cert_path`` or | |
224 ``subject_name``. These correspond to the ``/f`` and ``/n`` arguments | |
225 to signtool.exe, respectively. | |
226 | |
227 The certificate password can be specified via ``cert_password``. If | |
228 not provided, you will be prompted for the password. | |
229 | |
230 ``timestamp_url`` is the URL of a RFC 3161 timestamp server (``/tr`` | |
231 argument to signtool.exe). | |
232 """ | |
233 if cert_path and subject_name: | |
234 raise ValueError('cannot specify both cert_path and subject_name') | |
235 | |
236 while cert_path and not cert_password: | |
237 cert_password = getpass.getpass('password for %s: ' % cert_path) | |
238 | |
239 args = [ | |
240 str(find_signtool()), | |
241 'sign', | |
242 '/v', | |
243 '/fd', | |
244 'sha256', | |
245 '/d', | |
246 description, | |
247 ] | |
248 | |
249 if cert_path: | |
250 args.extend(['/f', str(cert_path), '/p', cert_password]) | |
251 elif subject_name: | |
252 args.extend(['/n', subject_name]) | |
253 | |
254 if timestamp_url: | |
255 args.extend(['/tr', timestamp_url, '/td', 'sha256']) | |
256 | |
257 args.append(str(file_path)) | |
258 | |
259 print('signing %s' % file_path) | |
260 subprocess.run(args, check=True) | |
261 | |
262 | |
263 PRINT_PYTHON_INFO = ''' | |
264 import platform; print("%s:%s" % (platform.architecture()[0], platform.python_version())) | |
265 '''.strip() | |
266 | |
267 | |
268 def python_exe_info(python_exe: pathlib.Path): | |
269 """Obtain information about a Python executable.""" | |
270 | |
271 res = subprocess.check_output([str(python_exe), '-c', PRINT_PYTHON_INFO]) | |
272 | |
273 arch, version = res.decode('utf-8').split(':') | |
274 | |
275 version = distutils.version.LooseVersion(version) | |
276 | |
277 return { | |
278 'arch': arch, | |
279 'version': version, | |
280 'py3': version >= distutils.version.LooseVersion('3'), | |
281 } | |
282 | |
283 | |
284 def process_install_rules( | 136 def process_install_rules( |
285 rules: list, source_dir: pathlib.Path, dest_dir: pathlib.Path | 137 rules: list, source_dir: pathlib.Path, dest_dir: pathlib.Path |
286 ): | 138 ): |
287 for source, dest in rules: | 139 for source, dest in rules: |
288 if '*' in source: | 140 if '*' in source: |