OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2013 The Chromium Authors. All rights reserved. | 2 # Copyright 2013 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Downloads and unpacks a toolchain for building on Windows. The contents are | 6 """Downloads and unpacks a toolchain for building on Windows. The contents are |
7 matched by sha1 which will be updated when the toolchain is updated. | 7 matched by sha1 which will be updated when the toolchain is updated. |
8 | 8 |
9 Having a toolchain script in depot_tools means that it's not versioned | 9 Having a toolchain script in depot_tools means that it's not versioned |
10 directly with the source code. That is, if the toolchain is upgraded, but | 10 directly with the source code. That is, if the toolchain is upgraded, but |
(...skipping 12 matching lines...) Expand all Loading... | |
23 to do the main work. It is expected that toolchain2013.py will always be able | 23 to do the main work. It is expected that toolchain2013.py will always be able |
24 to acquire/build the most current revision of a VS2013-based toolchain. In the | 24 to acquire/build the most current revision of a VS2013-based toolchain. In the |
25 future when a hypothetical VS2015 is released, the 2013 script will be | 25 future when a hypothetical VS2015 is released, the 2013 script will be |
26 maintained, and a new 2015 script would be added. | 26 maintained, and a new 2015 script would be added. |
27 """ | 27 """ |
28 | 28 |
29 import hashlib | 29 import hashlib |
30 import json | 30 import json |
31 import optparse | 31 import optparse |
32 import os | 32 import os |
33 import platform | |
34 import re | |
33 import shutil | 35 import shutil |
34 import subprocess | 36 import subprocess |
35 import sys | 37 import sys |
36 import tempfile | 38 import tempfile |
37 import time | 39 import time |
38 import zipfile | 40 import zipfile |
39 | 41 |
40 | 42 |
41 BASEDIR = os.path.dirname(os.path.abspath(__file__)) | 43 BASEDIR = os.path.dirname(os.path.abspath(__file__)) |
42 DEPOT_TOOLS_PATH = os.path.join(BASEDIR, '..') | 44 DEPOT_TOOLS_PATH = os.path.join(BASEDIR, '..') |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
210 else: | 212 else: |
211 temp_dir, local_zip = DownloadUsingGsutil(tree_sha1 + '.zip') | 213 temp_dir, local_zip = DownloadUsingGsutil(tree_sha1 + '.zip') |
212 sys.stdout.write('Extracting %s...\n' % local_zip) | 214 sys.stdout.write('Extracting %s...\n' % local_zip) |
213 sys.stdout.flush() | 215 sys.stdout.flush() |
214 with zipfile.ZipFile(local_zip, 'r', zipfile.ZIP_DEFLATED, True) as zf: | 216 with zipfile.ZipFile(local_zip, 'r', zipfile.ZIP_DEFLATED, True) as zf: |
215 zf.extractall(target_dir) | 217 zf.extractall(target_dir) |
216 if temp_dir: | 218 if temp_dir: |
217 RmDir(temp_dir) | 219 RmDir(temp_dir) |
218 | 220 |
219 | 221 |
222 def GetInstallerName(): | |
223 """Return the name of the Windows 10 Universal C Runtime installer for the | |
224 current platform, or None if installer is not needed or not applicable. | |
225 The registry has to be used instead of sys.getwindowsversion() because | |
226 Python 2.7 is only manifested as being compatible up to Windows 8, so the | |
227 version APIs helpfully return a maximum of 6.2 (Windows 8). | |
228 """ | |
229 ver_re = re.compile('.*REG_SZ * (\d+)\.(\d+)') | |
230 key_name = '"HKLM\Software\Microsoft\Windows NT\CurrentVersion"' | |
231 output = subprocess.check_output('reg query %s /v CurrentVersion' % key_name) | |
scottmg
2016/01/14 21:49:59
Can you do this with https://docs.python.org/2/lib
brucedawson
2016/01/14 22:22:02
Done.
| |
232 match = ver_re.match(output.replace('\n', ' ')) | |
233 if match.groups() == ('6', '1'): | |
234 # Windows 7 and Windows Server 2008 R2 | |
235 return 'Windows6.1-KB2999226-x64.msu' | |
236 elif match.groups() == ('6', '2'): | |
237 # Windows 8 and Windows Server 2012 | |
238 return 'Windows8-RT-KB2999226-x64.msu' | |
239 elif match.groups() == ('6', '3'): | |
240 # Windows 8.1 and Windows Server 2012 R2 | |
241 return 'Windows8.1-KB2999226-x64.msu' | |
242 else: | |
243 # Windows 10 or higher assumed | |
244 return None | |
245 | |
246 | |
247 def InstallUniversalCRTIfNeeded(abs_target_dir): | |
248 installer_name = GetInstallerName() | |
249 if not installer_name: | |
250 # Assumed to be Windows 10+ so nothing to do | |
251 return | |
252 | |
253 bitness = platform.architecture()[0] | |
254 # When running 64-bit python the x64 DLLs will be in System32 | |
255 x64_path = 'System32' if bitness == '64bit' else 'Sysnative' | |
256 x64_path = os.path.join(r'C:\Windows', x64_path) | |
257 sample_crt_file = os.path.join(x64_path, 'api-ms-win-crt-math-l1-1-0.dll') | |
258 | |
259 if os.path.exists(sample_crt_file): | |
260 # Nothing to do. | |
261 return | |
262 | |
263 print ('%s does not exist - installing Windows 10 Universal C Runtime' % | |
264 sample_crt_file) | |
265 | |
266 installer = os.path.join(abs_target_dir, "installers", installer_name) | |
267 command = r'wusa.exe /quiet "%s"' % installer | |
268 print 'Running %s' % command | |
269 | |
270 try: | |
271 subprocess.check_call(command) | |
272 except WindowsError as e: | |
273 if e.winerror == 740: # The requested operation requires elevation | |
274 print | |
275 print '-'*80 | |
276 print | |
277 print 'Elevation required. You must manually install this update:' | |
278 print ' %s' % installer | |
279 print | |
280 print '-'*80 | |
281 print | |
282 raise Exception('Elevation required. You must manually install %s' % | |
283 installer) | |
284 raise e | |
285 | |
286 | |
220 def main(): | 287 def main(): |
221 parser = optparse.OptionParser(description=sys.modules[__name__].__doc__) | 288 parser = optparse.OptionParser(description=sys.modules[__name__].__doc__) |
222 parser.add_option('--output-json', metavar='FILE', | 289 parser.add_option('--output-json', metavar='FILE', |
223 help='write information about toolchain to FILE') | 290 help='write information about toolchain to FILE') |
224 parser.add_option('--force', action='store_true', | 291 parser.add_option('--force', action='store_true', |
225 help='force script to run on non-Windows hosts') | 292 help='force script to run on non-Windows hosts') |
226 options, args = parser.parse_args() | 293 options, args = parser.parse_args() |
227 | 294 |
228 if not (sys.platform.startswith(('cygwin', 'win32')) or options.force): | 295 if not (sys.platform.startswith(('cygwin', 'win32')) or options.force): |
229 return 0 | 296 return 0 |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
324 'Got wrong hash after pulling a new toolchain. ' | 391 'Got wrong hash after pulling a new toolchain. ' |
325 'Wanted one of \'%s\', got \'%s\'.' % ( | 392 'Wanted one of \'%s\', got \'%s\'.' % ( |
326 ', '.join(desired_hashes), current_hash)) | 393 ', '.join(desired_hashes), current_hash)) |
327 return 1 | 394 return 1 |
328 SaveTimestampsAndHash(target_dir, current_hash) | 395 SaveTimestampsAndHash(target_dir, current_hash) |
329 | 396 |
330 if options.output_json: | 397 if options.output_json: |
331 shutil.copyfile(os.path.join(target_dir, '..', 'data.json'), | 398 shutil.copyfile(os.path.join(target_dir, '..', 'data.json'), |
332 options.output_json) | 399 options.output_json) |
333 | 400 |
401 InstallUniversalCRTIfNeeded(abs_target_dir) | |
402 | |
334 return 0 | 403 return 0 |
335 | 404 |
336 | 405 |
337 if __name__ == '__main__': | 406 if __name__ == '__main__': |
338 sys.exit(main()) | 407 sys.exit(main()) |
OLD | NEW |