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

Side by Side Diff: build/get_syzygy_binaries.py

Issue 306543006: Bring Syzygy binaries in using a script rather than as a dependency. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Bugfix. Created 6 years, 6 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 | « DEPS ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright 2014 The Chromium Authors. All rights reserved. 2 # Copyright 2014 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 """A utility script for downloading versioned Syzygy binaries.""" 6 """A utility script for downloading versioned Syzygy binaries."""
7 7
8 import cStringIO 8 import cStringIO
9 import hashlib 9 import hashlib
10 import errno
10 import json 11 import json
11 import logging 12 import logging
12 import optparse 13 import optparse
13 import os 14 import os
14 import re 15 import re
15 import shutil 16 import shutil
17 import stat
18 import sys
16 import subprocess 19 import subprocess
17 import urllib2 20 import urllib2
18 import zipfile 21 import zipfile
19 22
20 23
21 _LOGGER = logging.getLogger(os.path.basename(__file__)) 24 _LOGGER = logging.getLogger(os.path.basename(__file__))
22 25
23 # The URL where official builds are archived. 26 # The URL where official builds are archived.
24 _SYZYGY_ARCHIVE_URL = ('http://syzygy-archive.commondatastorage.googleapis.com/' 27 _SYZYGY_ARCHIVE_URL = ('http://syzygy-archive.commondatastorage.googleapis.com/'
25 'builds/official/%(revision)s') 28 'builds/official/%(revision)s')
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
165 return (stored, False) 168 return (stored, False)
166 return (stored, True) 169 return (stored, True)
167 170
168 171
169 def _DirIsEmpty(path): 172 def _DirIsEmpty(path):
170 """Returns true if the given directory is empty, false otherwise.""" 173 """Returns true if the given directory is empty, false otherwise."""
171 for root, dirs, files in os.walk(path): 174 for root, dirs, files in os.walk(path):
172 return not dirs and not files 175 return not dirs and not files
173 176
174 177
178 def _RmTreeHandleReadOnly(func, path, exc):
179 """An error handling function for use with shutil.rmtree. This will
180 detect failures to remove read-only files, and will change their properties
181 prior to removing them. This is necessary on Windows as os.remove will return
182 an access error for read-only files, and git repos contain read-only
183 pack/index files.
184 """
185 excvalue = exc[1]
186 if func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES:
187 _LOGGER.debug('Removing read-only path: %s', path)
188 os.chmod(path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
189 func(path)
190 else:
191 raise
192
193
194 def _RmTree(path):
195 """A wrapper of shutil.rmtree that handles read-only files."""
196 shutil.rmtree(path, ignore_errors=False, onerror=_RmTreeHandleReadOnly)
197
198
175 def _CleanState(output_dir, state, dry_run=False): 199 def _CleanState(output_dir, state, dry_run=False):
176 """Cleans up files/directories in |output_dir| that are referenced by 200 """Cleans up files/directories in |output_dir| that are referenced by
177 the given |state|. Raises an error if there are local changes. Returns a 201 the given |state|. Raises an error if there are local changes. Returns a
178 dictionary of files that were deleted. 202 dictionary of files that were deleted.
179 """ 203 """
180 _LOGGER.debug('Deleting files from previous installation.') 204 _LOGGER.debug('Deleting files from previous installation.')
181 deleted = {} 205 deleted = {}
182 206
183 # Generate a list of files to delete, relative to |output_dir|. 207 # Generate a list of files to delete, relative to |output_dir|.
184 contents = state['contents'] 208 contents = state['contents']
(...skipping 24 matching lines...) Expand all
209 if not dry_run: 233 if not dry_run:
210 os.unlink(fullpath) 234 os.unlink(fullpath)
211 235
212 # Sort directories from longest name to shortest. This lets us remove empty 236 # Sort directories from longest name to shortest. This lets us remove empty
213 # directories from the most nested paths first. 237 # directories from the most nested paths first.
214 dirs = sorted(dirs.keys(), key=lambda x: len(x), reverse=True) 238 dirs = sorted(dirs.keys(), key=lambda x: len(x), reverse=True)
215 for p in dirs: 239 for p in dirs:
216 if os.path.exists(p) and _DirIsEmpty(p): 240 if os.path.exists(p) and _DirIsEmpty(p):
217 _LOGGER.debug('Deleting empty directory "%s".', p) 241 _LOGGER.debug('Deleting empty directory "%s".', p)
218 if not dry_run: 242 if not dry_run:
219 shutil.rmtree(p, False) 243 _RmTree(p)
220 244
221 return deleted 245 return deleted
222 246
223 247
224 def _Download(url): 248 def _Download(url):
225 """Downloads the given URL and returns the contents as a string.""" 249 """Downloads the given URL and returns the contents as a string."""
226 response = urllib2.urlopen(url) 250 response = urllib2.urlopen(url)
227 if response.code != 200: 251 if response.code != 200:
228 raise RuntimeError('Failed to download "%s".' % url) 252 raise RuntimeError('Failed to download "%s".' % url)
229 return response.read() 253 return response.read()
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
321 if not _REVISION_RE.match(options.revision): 345 if not _REVISION_RE.match(options.revision):
322 option_parser.error('Must specify a valid SVN or GIT revision.') 346 option_parser.error('Must specify a valid SVN or GIT revision.')
323 347
324 # This just makes output prettier to read. 348 # This just makes output prettier to read.
325 options.output_dir = os.path.normpath(options.output_dir) 349 options.output_dir = os.path.normpath(options.output_dir)
326 350
327 return options 351 return options
328 352
329 353
330 def main(): 354 def main():
355 # We only care about Windows platforms, as the Syzygy binaries aren't used
356 # elsewhere.
357 if sys.platform != 'win32':
358 return
359
331 options = _ParseCommandLine() 360 options = _ParseCommandLine()
332 361
333 if options.dry_run: 362 if options.dry_run:
334 _LOGGER.debug('Performing a dry-run.') 363 _LOGGER.debug('Performing a dry-run.')
335 364
336 # Load the current installation state, and validate it against the 365 # Load the current installation state, and validate it against the
337 # requested installation. 366 # requested installation.
338 state, is_consistent = _GetCurrentState(options.revision, options.output_dir) 367 state, is_consistent = _GetCurrentState(options.revision, options.output_dir)
339 368
340 # Decide whether or not an install is necessary. 369 # Decide whether or not an install is necessary.
341 if options.force: 370 if options.force:
342 _LOGGER.debug('Forcing reinstall of binaries.') 371 _LOGGER.debug('Forcing reinstall of binaries.')
343 elif is_consistent: 372 elif is_consistent:
344 # Avoid doing any work if the contents of the directory are consistent. 373 # Avoid doing any work if the contents of the directory are consistent.
345 _LOGGER.debug('State unchanged, no reinstall necessary.') 374 _LOGGER.debug('State unchanged, no reinstall necessary.')
346 return 375 return
347 376
348 # Under normal logging this is the only only message that will be reported. 377 # Under normal logging this is the only only message that will be reported.
349 _LOGGER.info('Installing revision %s Syzygy binaries.', 378 _LOGGER.info('Installing revision %s Syzygy binaries.',
350 options.revision[0:12]) 379 options.revision[0:12])
351 380
352 # Clean up the old state to begin with. 381 # Clean up the old state to begin with.
353 deleted = [] 382 deleted = []
354 if options.overwrite: 383 if options.overwrite:
355 if os.path.exists(options.output_dir): 384 if os.path.exists(options.output_dir):
356 # If overwrite was specified then take a heavy-handed approach. 385 # If overwrite was specified then take a heavy-handed approach.
357 _LOGGER.debug('Deleting entire installation directory.') 386 _LOGGER.debug('Deleting entire installation directory.')
358 if not options.dry_run: 387 if not options.dry_run:
359 shutil.rmtree(options.output_dir, False) 388 _RmTree(options.output_dir)
360 else: 389 else:
361 # Otherwise only delete things that the previous installation put in place, 390 # Otherwise only delete things that the previous installation put in place,
362 # and take care to preserve any local changes. 391 # and take care to preserve any local changes.
363 deleted = _CleanState(options.output_dir, state, options.dry_run) 392 deleted = _CleanState(options.output_dir, state, options.dry_run)
364 393
365 # Install the new binaries. In a dry-run this will actually download the 394 # Install the new binaries. In a dry-run this will actually download the
366 # archives, but it won't write anything to disk. 395 # archives, but it won't write anything to disk.
367 state = _InstallBinaries(options, deleted) 396 state = _InstallBinaries(options, deleted)
368 397
369 # Build and save the state for the directory. 398 # Build and save the state for the directory.
370 _SaveState(options.output_dir, state, options.dry_run) 399 _SaveState(options.output_dir, state, options.dry_run)
371 400
372 401
373 if __name__ == '__main__': 402 if __name__ == '__main__':
374 main() 403 main()
OLDNEW
« no previous file with comments | « DEPS ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698