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 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
140 | 140 |
141 | 141 |
142 def CanAccessToolchainBucket(): | 142 def CanAccessToolchainBucket(): |
143 """Checks whether the user has access to gs://chrome-wintoolchain/.""" | 143 """Checks whether the user has access to gs://chrome-wintoolchain/.""" |
144 gsutil = download_from_google_storage.Gsutil( | 144 gsutil = download_from_google_storage.Gsutil( |
145 download_from_google_storage.GSUTIL_DEFAULT_PATH, boto_path=None) | 145 download_from_google_storage.GSUTIL_DEFAULT_PATH, boto_path=None) |
146 code, _, _ = gsutil.check_call('ls', 'gs://chrome-wintoolchain/') | 146 code, _, _ = gsutil.check_call('ls', 'gs://chrome-wintoolchain/') |
147 return code == 0 | 147 return code == 0 |
148 | 148 |
149 | 149 |
150 def ConfigureGsAccess(): | 150 def RequestGsAuthentication(): |
151 """Starts the authentication flow for gs://, and confirms that it's | 151 """Requests that the user authenticate to be able to access gs:// as a |
152 accessible after completion, or retries indefinitely. | 152 Googler. This allows much faster downloads, and pulling (old) toolchains |
| 153 that match src/ revisions. |
153 """ | 154 """ |
154 while not CanAccessToolchainBucket(): | 155 print 'Access to gs://chrome-wintoolchain/ not configured.' |
155 print 'Access to gs://chrome-wintoolchain/ not configured.' | 156 print '-----------------------------------------------------------------' |
156 print '-----------------------------------------------------------------' | 157 print |
157 print | 158 print 'You appear to be a Googler.' |
158 print 'You appear to be a Googler.' | 159 print |
159 print | 160 print 'I\'m sorry for the hassle, but you need to do a one-time manual' |
160 print 'I\'m sorry for the hassle, but you need to do a one-time manual' | 161 print 'authentication. Please run:' |
161 print 'authentication. Instructions will open in a new window. This is' | 162 print |
162 print 'a run of "gsutil config".' | 163 print ' download_from_google_storage --config' |
163 print | 164 print |
164 print 'NOTE: Just press Enter when asked for a "project-id".' | 165 print 'and follow the instructions. NOTE: Just press Enter when asked for' |
165 print | 166 print 'a "project-id".' |
166 print '-----------------------------------------------------------------' | 167 print |
167 print | 168 print '-----------------------------------------------------------------' |
168 sys.stdout.flush() | 169 print |
169 # gclient's buffering makes this hang if we're run from inside gclient | 170 sys.stdout.flush() |
170 # as is typical. So, spawn a new window for the config prompt. :( | 171 sys.exit(1) |
171 subprocess.check_call( | |
172 ['start', '/wait', 'cmd', '/c', | |
173 'download_from_google_storage', '--config'], | |
174 shell=True) | |
175 | 172 |
176 | 173 |
177 def DelayBeforeRemoving(target_dir): | 174 def DelayBeforeRemoving(target_dir): |
178 """A grace period before deleting the out of date toolchain directory.""" | 175 """A grace period before deleting the out of date toolchain directory.""" |
179 if (os.path.isdir(target_dir) and | 176 if (os.path.isdir(target_dir) and |
180 not bool(int(os.environ.get('CHROME_HEADLESS', '0')))): | 177 not bool(int(os.environ.get('CHROME_HEADLESS', '0')))): |
181 for i in range(9, 0, -1): | 178 for i in range(9, 0, -1): |
182 sys.stdout.write( | 179 sys.stdout.write( |
183 '\rRemoving old toolchain in %ds... (Ctrl-C to cancel)' % i) | 180 '\rRemoving old toolchain in %ds... (Ctrl-C to cancel)' % i) |
184 sys.stdout.flush() | 181 sys.stdout.flush() |
185 time.sleep(1) | 182 time.sleep(1) |
186 print | 183 print |
187 | 184 |
188 | 185 |
189 def main(): | 186 def main(): |
190 if not sys.platform.startswith(('cygwin', 'win32')): | 187 if not sys.platform.startswith(('cygwin', 'win32')): |
191 return 0 | 188 return 0 |
192 | 189 |
193 parser = optparse.OptionParser(description=sys.modules[__name__].__doc__) | 190 parser = optparse.OptionParser(description=sys.modules[__name__].__doc__) |
194 parser.add_option('--output-json', metavar='FILE', | 191 parser.add_option('--output-json', metavar='FILE', |
195 help='write information about toolchain to FILE') | 192 help='write information about toolchain to FILE') |
196 options, args = parser.parse_args() | 193 options, args = parser.parse_args() |
197 | 194 |
198 # We assume that the Pro hash is the first one. | 195 # We assume that the Pro hash is the first one. |
199 desired_hashes = args | 196 desired_hashes = args |
| 197 if len(desired_hashes) == 0: |
| 198 sys.exit('Desired hashes are required.') |
200 | 199 |
201 # Move to depot_tools\win_toolchain where we'll store our files, and where | 200 # Move to depot_tools\win_toolchain where we'll store our files, and where |
202 # the downloader script is. | 201 # the downloader script is. |
203 os.chdir(os.path.normpath(os.path.join(BASEDIR))) | 202 os.chdir(os.path.normpath(os.path.join(BASEDIR))) |
204 toolchain_dir = '.' | 203 toolchain_dir = '.' |
205 target_dir = os.path.normpath(os.path.join(toolchain_dir, 'vs2013_files')) | 204 target_dir = os.path.normpath(os.path.join(toolchain_dir, 'vs2013_files')) |
206 | 205 |
207 # If the current hash doesn't match what we want in the file, nuke and pave. | 206 # If the current hash doesn't match what we want in the file, nuke and pave. |
208 # Typically this script is only run when the .sha1 one file is updated, but | 207 # Typically this script is only run when the .sha1 one file is updated, but |
209 # directly calling "gclient runhooks" will also run it, so we cache | 208 # directly calling "gclient runhooks" will also run it, so we cache |
210 # based on timestamps to make that case fast. | 209 # based on timestamps to make that case fast. |
211 current_hash = CalculateHash(target_dir) | 210 current_hash = CalculateHash(target_dir) |
212 if current_hash not in desired_hashes: | 211 if current_hash not in desired_hashes: |
213 should_use_gs = False | 212 should_use_gs = False |
214 if (CanAccessToolchainBucket() or | 213 if HaveSrcInternalAccess() or LooksLikeGoogler(): |
215 HaveSrcInternalAccess() or | |
216 LooksLikeGoogler()): | |
217 should_use_gs = True | 214 should_use_gs = True |
218 ConfigureGsAccess() | 215 if not CanAccessToolchainBucket(): |
| 216 RequestGsAuthentication() |
219 print('Windows toolchain out of date or doesn\'t exist, updating (%s)...' % | 217 print('Windows toolchain out of date or doesn\'t exist, updating (%s)...' % |
220 ('Pro' if should_use_gs else 'Express')) | 218 ('Pro' if should_use_gs else 'Express')) |
221 print(' current_hash: %s' % current_hash) | 219 print(' current_hash: %s' % current_hash) |
222 print(' desired_hashes: %s' % ', '.join(desired_hashes)) | 220 print(' desired_hashes: %s' % ', '.join(desired_hashes)) |
223 sys.stdout.flush() | 221 sys.stdout.flush() |
224 DelayBeforeRemoving(target_dir) | 222 DelayBeforeRemoving(target_dir) |
225 # This stays resident and will make the rmdir below fail. | 223 # This stays resident and will make the rmdir below fail. |
226 with open(os.devnull, 'wb') as nul: | 224 with open(os.devnull, 'wb') as nul: |
227 subprocess.call(['taskkill', '/f', '/im', 'mspdbsrv.exe'], | 225 subprocess.call(['taskkill', '/f', '/im', 'mspdbsrv.exe'], |
228 stdin=nul, stdout=nul, stderr=nul) | 226 stdin=nul, stdout=nul, stderr=nul) |
(...skipping 19 matching lines...) Expand all Loading... |
248 | 246 |
249 if options.output_json: | 247 if options.output_json: |
250 shutil.copyfile(os.path.join(target_dir, '..', 'data.json'), | 248 shutil.copyfile(os.path.join(target_dir, '..', 'data.json'), |
251 options.output_json) | 249 options.output_json) |
252 | 250 |
253 return 0 | 251 return 0 |
254 | 252 |
255 | 253 |
256 if __name__ == '__main__': | 254 if __name__ == '__main__': |
257 sys.exit(main()) | 255 sys.exit(main()) |
OLD | NEW |