##// END OF EJS Templates
packaging: don't crash building wix with python3.6 and earlier...
Matt Harbison -
r42259:9c07d345 default
parent child Browse files
Show More
@@ -1,157 +1,155 b''
1 1 # util.py - Common packaging utility code.
2 2 #
3 3 # Copyright 2019 Gregory Szorc <gregory.szorc@gmail.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 # no-check-code because Python 3 native.
9 9
10 10 import distutils.version
11 11 import getpass
12 12 import os
13 13 import pathlib
14 14 import subprocess
15 15 import tarfile
16 16 import zipfile
17 17
18 18
19 19 def extract_tar_to_directory(source: pathlib.Path, dest: pathlib.Path):
20 20 with tarfile.open(source, 'r') as tf:
21 21 tf.extractall(dest)
22 22
23 23
24 24 def extract_zip_to_directory(source: pathlib.Path, dest: pathlib.Path):
25 25 with zipfile.ZipFile(source, 'r') as zf:
26 26 zf.extractall(dest)
27 27
28 28
29 29 def find_vc_runtime_files(x64=False):
30 30 """Finds Visual C++ Runtime DLLs to include in distribution."""
31 31 winsxs = pathlib.Path(os.environ['SYSTEMROOT']) / 'WinSxS'
32 32
33 33 prefix = 'amd64' if x64 else 'x86'
34 34
35 35 candidates = sorted(p for p in os.listdir(winsxs)
36 36 if p.lower().startswith('%s_microsoft.vc90.crt_' % prefix))
37 37
38 38 for p in candidates:
39 39 print('found candidate VC runtime: %s' % p)
40 40
41 41 # Take the newest version.
42 42 version = candidates[-1]
43 43
44 44 d = winsxs / version
45 45
46 46 return [
47 47 d / 'msvcm90.dll',
48 48 d / 'msvcp90.dll',
49 49 d / 'msvcr90.dll',
50 50 winsxs / 'Manifests' / ('%s.manifest' % version),
51 51 ]
52 52
53 53
54 54 def windows_10_sdk_info():
55 55 """Resolves information about the Windows 10 SDK."""
56 56
57 57 base = pathlib.Path(os.environ['ProgramFiles(x86)']) / 'Windows Kits' / '10'
58 58
59 59 if not base.is_dir():
60 60 raise Exception('unable to find Windows 10 SDK at %s' % base)
61 61
62 62 # Find the latest version.
63 63 bin_base = base / 'bin'
64 64
65 65 versions = [v for v in os.listdir(bin_base) if v.startswith('10.')]
66 66 version = sorted(versions, reverse=True)[0]
67 67
68 68 bin_version = bin_base / version
69 69
70 70 return {
71 71 'root': base,
72 72 'version': version,
73 73 'bin_root': bin_version,
74 74 'bin_x86': bin_version / 'x86',
75 75 'bin_x64': bin_version / 'x64'
76 76 }
77 77
78 78
79 79 def find_signtool():
80 80 """Find signtool.exe from the Windows SDK."""
81 81 sdk = windows_10_sdk_info()
82 82
83 83 for key in ('bin_x64', 'bin_x86'):
84 84 p = sdk[key] / 'signtool.exe'
85 85
86 86 if p.exists():
87 87 return p
88 88
89 89 raise Exception('could not find signtool.exe in Windows 10 SDK')
90 90
91 91
92 92 def sign_with_signtool(file_path, description, subject_name=None,
93 93 cert_path=None, cert_password=None,
94 94 timestamp_url=None):
95 95 """Digitally sign a file with signtool.exe.
96 96
97 97 ``file_path`` is file to sign.
98 98 ``description`` is text that goes in the signature.
99 99
100 100 The signing certificate can be specified by ``cert_path`` or
101 101 ``subject_name``. These correspond to the ``/f`` and ``/n`` arguments
102 102 to signtool.exe, respectively.
103 103
104 104 The certificate password can be specified via ``cert_password``. If
105 105 not provided, you will be prompted for the password.
106 106
107 107 ``timestamp_url`` is the URL of a RFC 3161 timestamp server (``/tr``
108 108 argument to signtool.exe).
109 109 """
110 110 if cert_path and subject_name:
111 111 raise ValueError('cannot specify both cert_path and subject_name')
112 112
113 113 while cert_path and not cert_password:
114 114 cert_password = getpass.getpass('password for %s: ' % cert_path)
115 115
116 116 args = [
117 117 str(find_signtool()), 'sign',
118 118 '/v',
119 119 '/fd', 'sha256',
120 120 '/d', description,
121 121 ]
122 122
123 123 if cert_path:
124 124 args.extend(['/f', str(cert_path), '/p', cert_password])
125 125 elif subject_name:
126 126 args.extend(['/n', subject_name])
127 127
128 128 if timestamp_url:
129 129 args.extend(['/tr', timestamp_url, '/td', 'sha256'])
130 130
131 131 args.append(str(file_path))
132 132
133 133 print('signing %s' % file_path)
134 134 subprocess.run(args, check=True)
135 135
136 136
137 137 PRINT_PYTHON_INFO = '''
138 138 import platform; print("%s:%s" % (platform.architecture()[0], platform.python_version()))
139 139 '''.strip()
140 140
141 141
142 142 def python_exe_info(python_exe: pathlib.Path):
143 143 """Obtain information about a Python executable."""
144 144
145 res = subprocess.run(
146 [str(python_exe), '-c', PRINT_PYTHON_INFO],
147 capture_output=True, check=True)
145 res = subprocess.check_output([str(python_exe), '-c', PRINT_PYTHON_INFO])
148 146
149 arch, version = res.stdout.decode('utf-8').split(':')
147 arch, version = res.decode('utf-8').split(':')
150 148
151 149 version = distutils.version.LooseVersion(version)
152 150
153 151 return {
154 152 'arch': arch,
155 153 'version': version,
156 154 'py3': version >= distutils.version.LooseVersion('3'),
157 155 }
General Comments 0
You need to be logged in to leave comments. Login now