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: