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

Side by Side Diff: tools/bisect-builds.py

Issue 7468020: Update bisect-builds.py to automatically determine download server. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 9 years, 5 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | 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/python 1 #!/usr/bin/python
2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2011 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 """Snapshot Build Bisect Tool 6 """Snapshot Build Bisect Tool
7 7
8 This script bisects a snapshot archive using binary search. It starts at 8 This script bisects a snapshot archive using binary search. It starts at
9 a bad revision (it will try to guess HEAD) and asks for a last known-good 9 a bad revision (it will try to guess HEAD) and asks for a last known-good
10 revision. It will then binary search across this revision range by downloading, 10 revision. It will then binary search across this revision range by downloading,
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
197 def ParseDirectoryIndexRecent(context): 197 def ParseDirectoryIndexRecent(context):
198 """Parses the recent builds directory listing into a list of revision 198 """Parses the recent builds directory listing into a list of revision
199 numbers.""" 199 numbers."""
200 handle = urllib.urlopen(context.GetListingURLRecent()) 200 handle = urllib.urlopen(context.GetListingURLRecent())
201 document = handle.read() 201 document = handle.read()
202 202
203 # Looking for: <a href="92976/">92976/</a> 203 # Looking for: <a href="92976/">92976/</a>
204 return re.findall(r"<a href=\"(\d+)/\">\1/</a>", document) 204 return re.findall(r"<a href=\"(\d+)/\">\1/</a>", document)
205 205
206 206
207 def GetRevList(context): 207 def FilterRevList(context, revlist):
208 """Gets the list of revision numbers between |good_revision| and 208 """Filter revlist to the revisions between |good_revision| and
209 |bad_revision| of the |context|.""" 209 |bad_revision| of the |context|."""
210 # Download the revlist and filter for just the range between good and bad. 210 # Download the revlist and filter for just the range between good and bad.
211 rev_range = range(context.good_revision, context.bad_revision) 211 rev_range = range(context.good_revision, context.bad_revision)
212 revisions = []
213 if context.use_recent:
214 revisions = ParseDirectoryIndexRecent(context)
215 else:
216 revisions = ParseDirectoryIndex(context)
217 revlist = map(int, revisions)
218 revlist = filter(lambda r: r in rev_range, revlist) 212 revlist = filter(lambda r: r in rev_range, revlist)
219 revlist.sort() 213 revlist.sort()
220 return revlist 214 return revlist
221 215
222 216
223 def TryRevision(context, rev, profile, args): 217 def TryRevision(context, rev, profile, args):
224 """Downloads revision |rev|, unzips it, and opens it for the user to test. 218 """Downloads revision |rev|, unzips it, and opens it for the user to test.
225 |profile| is the profile to use.""" 219 |profile| is the profile to use."""
226 # Do this in a temp dir so we don't collide with user files. 220 # Do this in a temp dir so we don't collide with user files.
227 cwd = os.getcwd() 221 cwd = os.getcwd()
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
338 choices = choices, 332 choices = choices,
339 help = 'The buildbot archive to bisect [%s].' % 333 help = 'The buildbot archive to bisect [%s].' %
340 '|'.join(choices)) 334 '|'.join(choices))
341 parser.add_option('-b', '--bad', type = 'int', 335 parser.add_option('-b', '--bad', type = 'int',
342 help = 'The bad revision to bisect to.') 336 help = 'The bad revision to bisect to.')
343 parser.add_option('-g', '--good', type = 'int', 337 parser.add_option('-g', '--good', type = 'int',
344 help = 'The last known good revision to bisect from.') 338 help = 'The last known good revision to bisect from.')
345 parser.add_option('-p', '--profile', '--user-data-dir', type = 'str', 339 parser.add_option('-p', '--profile', '--user-data-dir', type = 'str',
346 help = 'Profile to use; this will not reset every run. ' + 340 help = 'Profile to use; this will not reset every run. ' +
347 'Defaults to a clean profile.', default = 'profile') 341 'Defaults to a clean profile.', default = 'profile')
348 parser.add_option('-r', '--recent',
349 dest = "recent",
350 default = False,
351 action = "store_true",
352 help = 'Use recent builds from about the last 2 months ' +
353 'for higher granularity bisecting.')
354 (opts, args) = parser.parse_args() 342 (opts, args) = parser.parse_args()
355 343
356 if opts.archive is None: 344 if opts.archive is None:
357 print 'Error: missing required parameter: --archive' 345 print 'Error: missing required parameter: --archive'
358 print 346 print
359 parser.print_help() 347 parser.print_help()
360 return 1 348 return 1
361 349
362 if opts.bad and opts.good and (opts.good > opts.bad): 350 if opts.bad and opts.good and (opts.good > opts.bad):
363 print ('The good revision (%d) must precede the bad revision (%d).\n' % 351 print ('The good revision (%d) must precede the bad revision (%d).\n' %
364 (opts.good, opts.bad)) 352 (opts.good, opts.bad))
365 parser.print_help() 353 parser.print_help()
366 return 1 354 return 1
367 355
368 # Create the context. Initialize 0 for the revisions as they are set below. 356 # Create the context. Initialize 0 for the revisions as they are set below.
369 context = PathContext(opts.archive, 0, 0, opts.recent) 357 context = PathContext(opts.archive, 0, 0, use_recent=False)
370 358
371 # Pick a starting point, try to get HEAD for this. 359 # Pick a starting point, try to get HEAD for this.
372 if opts.bad: 360 if opts.bad:
373 bad_rev = opts.bad 361 bad_rev = opts.bad
374 else: 362 else:
375 bad_rev = 0 363 bad_rev = 0
376 try: 364 try:
377 # Location of the latest build revision number 365 # Location of the latest build revision number
378 nh = urllib.urlopen(context.GetLastChangeURL()) 366 nh = urllib.urlopen(context.GetLastChangeURL())
379 latest = int(nh.read()) 367 latest = int(nh.read())
(...skipping 13 matching lines...) Expand all
393 good_rev = 0 381 good_rev = 0
394 try: 382 try:
395 good_rev = int(raw_input('Last known good [0]: ')) 383 good_rev = int(raw_input('Last known good [0]: '))
396 except Exception, e: 384 except Exception, e:
397 pass 385 pass
398 386
399 # Set the input parameters now that they've been validated. 387 # Set the input parameters now that they've been validated.
400 context.good_revision = good_rev 388 context.good_revision = good_rev
401 context.bad_revision = bad_rev 389 context.bad_revision = bad_rev
402 390
403 # Get a list of revisions to bisect across. 391 # Get recent revision list and check whether it's sufficient.
404 revlist = GetRevList(context) 392 all_revs_recent = map(int, ParseDirectoryIndexRecent(context))
393 all_revs_recent.sort()
394 # Skipping 0 since it might be deleted off the server soon:
395 all_revs_recent = all_revs_recent[1:]
396 oldest_recent_rev = all_revs_recent[0]
397 if good_rev >= oldest_recent_rev:
398 # The range is within recent builds, so switch on use_recent.
399 context.use_recent = True
400 elif bad_rev >= oldest_recent_rev:
401 # The range spans both old and recent builds.
402 # If oldest_recent_rev is good, we bisect the recent builds.
403 context.use_recent = True
404 TryRevision(context, oldest_recent_rev, opts.profile, args)
405 if AskIsGoodBuild(oldest_recent_rev):
406 # context.use_recent is True
407 context.good_revision = oldest_recent_rev
408 else:
409 context.use_recent = False
410 context.bad_revision = oldest_recent_rev
411
412 all_revs = []
413 if context.use_recent:
414 all_revs = all_revs_recent
415 else:
416 all_revs = map(int, ParseDirectoryIndex(context))
417
418 # Filter list of revisions to bisect across.
419 revlist = FilterRevList(context, all_revs)
405 if len(revlist) < 2: # Don't have enough builds to bisect 420 if len(revlist) < 2: # Don't have enough builds to bisect
406 print 'We don\'t have enough builds to bisect. revlist: %s' % revlist 421 print 'We don\'t have enough builds to bisect. revlist: %s' % revlist
407 sys.exit(1) 422 sys.exit(1)
408 423
409 (last_known_good_rev, first_known_bad_rev) = Bisect( 424 (last_known_good_rev, first_known_bad_rev) = Bisect(
410 revlist, context, args, opts.profile) 425 revlist, context, args, opts.profile)
411 426
412 # We're done. Let the user know the results in an official manner. 427 # We're done. Let the user know the results in an official manner.
413 print('You are probably looking for build %d.' % first_known_bad_rev) 428 print('You are probably looking for build %d.' % first_known_bad_rev)
414 print('CHANGELOG URL:') 429 print('CHANGELOG URL:')
415 print(CHANGELOG_URL % (last_known_good_rev, first_known_bad_rev)) 430 print(CHANGELOG_URL % (last_known_good_rev, first_known_bad_rev))
416 print('Built at revision:') 431 print('Built at revision:')
417 print(BUILD_VIEWVC_URL % first_known_bad_rev) 432 print(BUILD_VIEWVC_URL % first_known_bad_rev)
418 433
419 if __name__ == '__main__': 434 if __name__ == '__main__':
420 sys.exit(main()) 435 sys.exit(main())
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698