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 20 matching lines...) Expand all Loading... |
31 import json | 31 import json |
32 import optparse | 32 import optparse |
33 import os | 33 import os |
34 import shutil | 34 import shutil |
35 import subprocess | 35 import subprocess |
36 import sys | 36 import sys |
37 import time | 37 import time |
38 | 38 |
39 | 39 |
40 BASEDIR = os.path.dirname(os.path.abspath(__file__)) | 40 BASEDIR = os.path.dirname(os.path.abspath(__file__)) |
| 41 sys.path.append(os.path.join(BASEDIR, '..')) |
| 42 import download_from_google_storage |
41 | 43 |
42 | 44 |
43 GetFileAttributes = ctypes.windll.kernel32.GetFileAttributesW | 45 GetFileAttributes = ctypes.windll.kernel32.GetFileAttributesW |
44 GetFileAttributes.argtypes = (ctypes.wintypes.LPWSTR,) | 46 GetFileAttributes.argtypes = (ctypes.wintypes.LPWSTR,) |
45 GetFileAttributes.restype = ctypes.wintypes.DWORD | 47 GetFileAttributes.restype = ctypes.wintypes.DWORD |
46 FILE_ATTRIBUTE_HIDDEN = 0x2 | 48 FILE_ATTRIBUTE_HIDDEN = 0x2 |
47 FILE_ATTRIBUTE_SYSTEM = 0x4 | 49 FILE_ATTRIBUTE_SYSTEM = 0x4 |
48 | 50 |
49 | 51 |
50 def IsHidden(file_path): | 52 def IsHidden(file_path): |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
124 ['svn', 'ls', '--non-interactive', | 126 ['svn', 'ls', '--non-interactive', |
125 'svn://svn.chromium.org/chrome-internal/trunk/src-internal/'], | 127 'svn://svn.chromium.org/chrome-internal/trunk/src-internal/'], |
126 shell=True, stdin=nul, stdout=nul, stderr=nul) == 0: | 128 shell=True, stdin=nul, stdout=nul, stderr=nul) == 0: |
127 return True | 129 return True |
128 return subprocess.call( | 130 return subprocess.call( |
129 ['git', '-c', 'core.askpass=true', 'remote', 'show', | 131 ['git', '-c', 'core.askpass=true', 'remote', 'show', |
130 'https://chrome-internal.googlesource.com/chrome/src-internal/'], | 132 'https://chrome-internal.googlesource.com/chrome/src-internal/'], |
131 shell=True, stdin=nul, stdout=nul, stderr=nul) == 0 | 133 shell=True, stdin=nul, stdout=nul, stderr=nul) == 0 |
132 | 134 |
133 | 135 |
| 136 def LooksLikeGoogler(): |
| 137 """Checks for a USERDOMAIN environment variable of 'GOOGLE', which |
| 138 probably implies the current user is a Googler.""" |
| 139 return os.environ.get('USERDOMAIN').upper() == 'GOOGLE' |
| 140 |
| 141 |
| 142 def CanAccessToolchainBucket(): |
| 143 """Checks whether the user has access to gs://chrome-wintoolchain/.""" |
| 144 gsutil = download_from_google_storage.Gsutil( |
| 145 download_from_google_storage.GSUTIL_DEFAULT_PATH, boto_path=None) |
| 146 code, _, _ = gsutil.check_call('ls', 'gs://chrome-wintoolchain/') |
| 147 return code == 0 |
| 148 |
| 149 |
| 150 def ConfigureGsAccess(): |
| 151 """Starts the authentication flow for gs://, and confirms that it's |
| 152 accessible after completion, or retries indefinitely. |
| 153 """ |
| 154 while not CanAccessToolchainBucket(): |
| 155 print 'Access to gs://chrome-wintoolchain/ not configured.' |
| 156 print '-----------------------------------------------------------------' |
| 157 print |
| 158 print 'You appear to be a Googler.' |
| 159 print |
| 160 print 'I\'m sorry for the hassle, but you need to do a one-time manual' |
| 161 print 'authentication. Instructions will open in a new window. This is' |
| 162 print 'a run of "gsutil config".' |
| 163 print |
| 164 print 'NOTE: Just press Enter when asked for a "project-id".' |
| 165 print |
| 166 print '-----------------------------------------------------------------' |
| 167 print |
| 168 sys.stdout.flush() |
| 169 # gclient's buffering makes this hang if we're run from inside gclient |
| 170 # as is typical. So, spawn a new window for the config prompt. :( |
| 171 subprocess.check_call( |
| 172 ['start', '/wait', 'cmd', '/c', |
| 173 'download_from_google_storage', '--config'], |
| 174 shell=True) |
| 175 |
| 176 |
134 def DelayBeforeRemoving(target_dir): | 177 def DelayBeforeRemoving(target_dir): |
135 """A grace period before deleting the out of date toolchain directory.""" | 178 """A grace period before deleting the out of date toolchain directory.""" |
136 if (os.path.isdir(target_dir) and | 179 if (os.path.isdir(target_dir) and |
137 not bool(int(os.environ.get('CHROME_HEADLESS', '0')))): | 180 not bool(int(os.environ.get('CHROME_HEADLESS', '0')))): |
138 for i in range(9, 0, -1): | 181 for i in range(9, 0, -1): |
139 sys.stdout.write( | 182 sys.stdout.write( |
140 '\rRemoving old toolchain in %ds... (Ctrl-C to cancel)' % i) | 183 '\rRemoving old toolchain in %ds... (Ctrl-C to cancel)' % i) |
141 sys.stdout.flush() | 184 sys.stdout.flush() |
142 time.sleep(1) | 185 time.sleep(1) |
143 print | 186 print |
(...skipping 16 matching lines...) Expand all Loading... |
160 os.chdir(os.path.normpath(os.path.join(BASEDIR))) | 203 os.chdir(os.path.normpath(os.path.join(BASEDIR))) |
161 toolchain_dir = '.' | 204 toolchain_dir = '.' |
162 target_dir = os.path.normpath(os.path.join(toolchain_dir, 'vs2013_files')) | 205 target_dir = os.path.normpath(os.path.join(toolchain_dir, 'vs2013_files')) |
163 | 206 |
164 # If the current hash doesn't match what we want in the file, nuke and pave. | 207 # If the current hash doesn't match what we want in the file, nuke and pave. |
165 # Typically this script is only run when the .sha1 one file is updated, but | 208 # Typically this script is only run when the .sha1 one file is updated, but |
166 # directly calling "gclient runhooks" will also run it, so we cache | 209 # directly calling "gclient runhooks" will also run it, so we cache |
167 # based on timestamps to make that case fast. | 210 # based on timestamps to make that case fast. |
168 current_hash = CalculateHash(target_dir) | 211 current_hash = CalculateHash(target_dir) |
169 if current_hash not in desired_hashes: | 212 if current_hash not in desired_hashes: |
170 should_get_pro = (os.path.isfile(os.path.join(BASEDIR, '.vspro')) or | 213 should_use_gs = False |
171 HaveSrcInternalAccess()) | 214 if (CanAccessToolchainBucket() or |
| 215 HaveSrcInternalAccess() or |
| 216 LooksLikeGoogler()): |
| 217 should_use_gs = True |
| 218 ConfigureGsAccess() |
172 print('Windows toolchain out of date or doesn\'t exist, updating (%s)...' % | 219 print('Windows toolchain out of date or doesn\'t exist, updating (%s)...' % |
173 ('Pro' if should_get_pro else 'Express')) | 220 ('Pro' if should_use_gs else 'Express')) |
174 print(' current_hash: %s' % current_hash) | 221 print(' current_hash: %s' % current_hash) |
175 print(' desired_hashes: %s' % ', '.join(desired_hashes)) | 222 print(' desired_hashes: %s' % ', '.join(desired_hashes)) |
| 223 sys.stdout.flush() |
176 DelayBeforeRemoving(target_dir) | 224 DelayBeforeRemoving(target_dir) |
177 # This stays resident and will make the rmdir below fail. | 225 # This stays resident and will make the rmdir below fail. |
178 with open(os.devnull, 'wb') as nul: | 226 with open(os.devnull, 'wb') as nul: |
179 subprocess.call(['taskkill', '/f', '/im', 'mspdbsrv.exe'], | 227 subprocess.call(['taskkill', '/f', '/im', 'mspdbsrv.exe'], |
180 stdin=nul, stdout=nul, stderr=nul) | 228 stdin=nul, stdout=nul, stderr=nul) |
181 if os.path.isdir(target_dir): | 229 if os.path.isdir(target_dir): |
182 subprocess.check_call('rmdir /s/q "%s"' % target_dir, shell=True) | 230 subprocess.check_call('rmdir /s/q "%s"' % target_dir, shell=True) |
183 args = [sys.executable, | 231 args = [sys.executable, |
184 'toolchain2013.py', | 232 'toolchain2013.py', |
185 '--targetdir', target_dir, | 233 '--targetdir', target_dir, |
186 '--sha1', desired_hashes[0]] | 234 '--sha1', desired_hashes[0]] |
187 if not should_get_pro: | 235 if should_use_gs: |
| 236 args.append('--use-gs') |
| 237 else: |
188 args.append('--express') | 238 args.append('--express') |
189 subprocess.check_call(args) | 239 subprocess.check_call(args) |
190 current_hash = CalculateHash(target_dir) | 240 current_hash = CalculateHash(target_dir) |
191 if current_hash not in desired_hashes: | 241 if current_hash not in desired_hashes: |
192 print >> sys.stderr, ( | 242 print >> sys.stderr, ( |
193 'Got wrong hash after pulling a new toolchain. ' | 243 'Got wrong hash after pulling a new toolchain. ' |
194 'Wanted one of \'%s\', got \'%s\'.' % ( | 244 'Wanted one of \'%s\', got \'%s\'.' % ( |
195 ', '.join(desired_hashes), current_hash)) | 245 ', '.join(desired_hashes), current_hash)) |
196 return 1 | 246 return 1 |
197 SaveTimestampsAndHash(target_dir, current_hash) | 247 SaveTimestampsAndHash(target_dir, current_hash) |
198 | 248 |
199 if options.output_json: | 249 if options.output_json: |
200 shutil.copyfile(os.path.join(target_dir, '..', 'data.json'), | 250 shutil.copyfile(os.path.join(target_dir, '..', 'data.json'), |
201 options.output_json) | 251 options.output_json) |
202 | 252 |
203 return 0 | 253 return 0 |
204 | 254 |
205 | 255 |
206 if __name__ == '__main__': | 256 if __name__ == '__main__': |
207 sys.exit(main()) | 257 sys.exit(main()) |
OLD | NEW |