Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(262)

Side by Side Diff: win_toolchain/get_toolchain_if_necessary.py

Issue 135933002: Automatic Windows toolchain (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
Patch Set: fixes 4 Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « win_toolchain/7z/LICENSE ('k') | win_toolchain/toolchain2013.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/env python
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
4 # found in the LICENSE file.
5
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.
8
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
11 you're trying to build an historical version of Chromium from before the
12 toolchain upgrade, this will cause you to build with a newer toolchain than
13 was available when that code was committed. This is done for a two main
14 reasons: 1) it would likely be annoying to have the up-to-date toolchain
15 removed and replaced by one without a service pack applied); 2) it would
16 require maintaining scripts that can build older not-up-to-date revisions of
17 the toolchain. This is likely to be a poorly tested code path that probably
18 won't be properly maintained. See http://crbug.com/323300.
19
20 This does not extend to major versions of the toolchain however, on the
21 assumption that there are more likely to be source incompatibilities between
22 major revisions. This script calls a subscript (currently, toolchain2013.py)
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
25 future when a hypothetical VS2015 is released, the 2013 script will be
26 maintained, and a new 2015 script would be added.
27 """
28
29 import ctypes.wintypes
30 import hashlib
31 import json
32 import os
33 import subprocess
34 import sys
35
36
37 BASEDIR = os.path.dirname(os.path.abspath(__file__))
38
39
40 GetFileAttributes = ctypes.windll.kernel32.GetFileAttributesW
41 GetFileAttributes.argtypes = (ctypes.wintypes.LPWSTR,)
42 GetFileAttributes.restype = ctypes.wintypes.DWORD
43 FILE_ATTRIBUTE_HIDDEN = 0x2
44 FILE_ATTRIBUTE_SYSTEM = 0x4
45
46
47 def IsHidden(file_path):
48 """Returns whether the given |file_path| has the 'system' or 'hidden'
49 attribute set."""
50 p = GetFileAttributes(file_path)
51 assert p != 0xffffffff
52 return bool(p & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM))
53
54
55 def GetFileList(root):
56 """Gets a normalized list of files under |root|."""
57 assert not os.path.isabs(root)
58 assert os.path.normpath(root) == root
59 file_list = []
60 for base, _, files in os.walk(root):
61 paths = [os.path.join(base, f) for f in files]
62 file_list.extend(x.lower() for x in paths if not IsHidden(x))
63 return sorted(file_list)
64
65
66 def MakeTimestampsFileName(root):
67 return os.path.join(root, '..', '.timestamps')
68
69
70 def CalculateHash(root):
71 """Calculates the sha1 of the paths to all files in the given |root| and the
72 contents of those files, and returns as a hex string."""
73 file_list = GetFileList(root)
74
75 # Check whether we previously saved timestamps in $root/../.timestamps. If
76 # we didn't, or they don't match, then do the full calculation, otherwise
77 # return the saved value.
78 timestamps_file = MakeTimestampsFileName(root)
79 timestamps_data = {'files': [], 'sha1': ''}
80 if os.path.exists(timestamps_file):
81 with open(timestamps_file, 'rb') as f:
82 try:
83 timestamps_data = json.load(f)
84 except ValueError:
85 # json couldn't be loaded, empty data will force a re-hash.
86 pass
87
88 matches = len(file_list) == len(timestamps_data['files'])
89 if matches:
90 for disk, cached in zip(file_list, timestamps_data['files']):
91 if disk != cached[0] or os.stat(disk).st_mtime != cached[1]:
92 matches = False
93 break
94 if matches:
95 return timestamps_data['sha1']
96
97 digest = hashlib.sha1()
98 for path in file_list:
99 digest.update(path)
100 with open(path, 'rb') as f:
101 digest.update(f.read())
102 return digest.hexdigest()
103
104
105 def SaveTimestampsAndHash(root, sha1):
106 """Save timestamps and the final hash to be able to early-out more quickly
107 next time."""
108 file_list = GetFileList(root)
109 timestamps_data = {
110 'files': [[f, os.stat(f).st_mtime] for f in file_list],
111 'sha1': sha1,
112 }
113 with open(MakeTimestampsFileName(root), 'wb') as f:
114 json.dump(timestamps_data, f)
115
116
117 def main():
118 if not sys.platform.startswith(('cygwin', 'win32')):
119 return 0
120
121 if len(sys.argv) != 1:
122 print >> sys.stderr, 'Unexpected arguments.'
123 return 1
124
125 # Move to depot_tools\win_toolchain where we'll store our files, and where
126 # the downloader script is.
127 os.chdir(os.path.normpath(os.path.join(BASEDIR)))
128 toolchain_dir = '.'
129 target_dir = os.path.normpath(os.path.join(toolchain_dir, 'vs2013_files'))
130
131 sha1path = os.path.join(toolchain_dir, 'toolchain_vs2013.hash')
132 desired_hash = ''
133 if os.path.isfile(sha1path):
134 with open(sha1path, 'rb') as f:
135 desired_hash = f.read().strip()
136
137 # If the current hash doesn't match what we want in the file, nuke and pave.
138 # Typically this script is only run when the .sha1 one file is updated, but
139 # directly calling "gclient runhooks" will also run it, so we cache
140 # based on timestamps to make that case fast.
141 current_hash = CalculateHash(target_dir)
142 if current_hash != desired_hash:
143 print 'Windows toolchain out of date or doesn\'t exist, updating...'
144 if os.path.isdir(target_dir):
145 subprocess.check_call('rmdir /s/q "%s"' % target_dir, shell=True)
146 subprocess.check_call([
147 sys.executable,
148 'toolchain2013.py',
149 '--targetdir', target_dir])
150 current_hash = CalculateHash(target_dir)
151 if current_hash != desired_hash:
152 print >> sys.stderr, (
153 'Got wrong hash after pulling a new toolchain. '
154 'Wanted \'%s\', got \'%s\'.' % (
155 desired_hash, current_hash))
156 return 1
157 SaveTimestampsAndHash(target_dir, current_hash)
158
159 return 0
160
161
162 if __name__ == '__main__':
163 sys.exit(main())
OLDNEW
« no previous file with comments | « win_toolchain/7z/LICENSE ('k') | win_toolchain/toolchain2013.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698