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

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

Issue 7606001: Restored download progress, and cleaned up terminal messages. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: nit Created 9 years, 4 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 181 matching lines...) Expand 10 before | Expand all | Expand 10 after
192 out.write(zf.read(name)) 192 out.write(zf.read(name))
193 out.close() 193 out.close()
194 # Set permissions. Permission info in external_attr is shifted 16 bits. 194 # Set permissions. Permission info in external_attr is shifted 16 bits.
195 os.chmod(name, info.external_attr >> 16L) 195 os.chmod(name, info.external_attr >> 16L)
196 os.chdir(cwd) 196 os.chdir(cwd)
197 except Exception, e: 197 except Exception, e:
198 print >>sys.stderr, e 198 print >>sys.stderr, e
199 sys.exit(1) 199 sys.exit(1)
200 200
201 201
202 def FetchRevision(context, rev, filename, quit_event=None): 202 def FetchRevision(context, rev, filename, quit_event=None, progress_event=None):
203 """Downloads and unzips revision |rev|. 203 """Downloads and unzips revision |rev|.
204 @param context A PathContext instance. 204 @param context A PathContext instance.
205 @param rev The Chromium revision number/tag to download. 205 @param rev The Chromium revision number/tag to download.
206 @param filename The destination for the downloaded file. 206 @param filename The destination for the downloaded file.
207 @param quit_event A threading.Event which will be set by the master thread to 207 @param quit_event A threading.Event which will be set by the master thread to
208 indicate that the download should be aborted. 208 indicate that the download should be aborted.
209 @param progress_event A threading.Event which will be set by the master thread
210 to indicate that the progress of the download should be
211 displayed.
209 """ 212 """
210 def ReportHook(blocknum, blocksize, totalsize): 213 def ReportHook(blocknum, blocksize, totalsize):
211 if quit_event and quit_event.is_set(): 214 if quit_event and quit_event.is_set():
212 raise RuntimeError("Aborting download of revision %d" % rev) 215 raise RuntimeError("Aborting download of revision %d" % rev)
216 if progress_event and progress_event.is_set():
217 size = blocknum * blocksize
218 if totalsize == -1: # Total size not known.
219 progress = "Received %d bytes" % size
220 else:
221 size = min(totalsize, size)
222 progress = "Received %d of %d bytes, %.2f%%" % (
223 size, totalsize, 100.0 * size / totalsize)
224 # Send a \r to let all progress messages use just one line of output.
225 sys.stdout.write("\r" + progress)
226 sys.stdout.flush()
213 227
214 download_url = context.GetDownloadURL(rev) 228 download_url = context.GetDownloadURL(rev)
215 try: 229 try:
216 urllib.urlretrieve(download_url, filename, ReportHook) 230 urllib.urlretrieve(download_url, filename, ReportHook)
231 if progress_event and progress_event.is_set():
232 print()
217 except RuntimeError, e: 233 except RuntimeError, e:
218 pass 234 pass
219 235
220 236
221 def RunRevision(context, revision, zipfile, profile, args): 237 def RunRevision(context, revision, zipfile, profile, args):
222 """Given a zipped revision, unzip it and run the test.""" 238 """Given a zipped revision, unzip it and run the test."""
223 print "Trying revision %d..." % revision 239 print "Trying revision %d..." % revision
224 240
225 # Create a temp directory and unzip the revision into it. 241 # Create a temp directory and unzip the revision into it.
226 cwd = os.getcwd() 242 cwd = os.getcwd()
(...skipping 14 matching lines...) Expand all
241 shutil.rmtree(tempdir, True) 257 shutil.rmtree(tempdir, True)
242 except Exception, e: 258 except Exception, e:
243 pass 259 pass
244 260
245 return (subproc.returncode, stdout, stderr) 261 return (subproc.returncode, stdout, stderr)
246 262
247 def AskIsGoodBuild(rev, status, stdout, stderr): 263 def AskIsGoodBuild(rev, status, stdout, stderr):
248 """Ask the user whether build |rev| is good or bad.""" 264 """Ask the user whether build |rev| is good or bad."""
249 # Loop until we get a response that we can parse. 265 # Loop until we get a response that we can parse.
250 while True: 266 while True:
251 response = raw_input('\nRevision %d is [(g)ood/(b)ad/(q)uit]: ' % int(rev)) 267 response = raw_input('Revision %d is [(g)ood/(b)ad/(q)uit]: ' % int(rev))
252 if response and response in ('g', 'b'): 268 if response and response in ('g', 'b'):
253 return response == 'g' 269 return response == 'g'
254 if response and response == 'q': 270 if response and response == 'q':
255 raise SystemExit() 271 raise SystemExit()
256 272
257 def Bisect(platform, 273 def Bisect(platform,
258 good_rev=0, 274 good_rev=0,
259 bad_rev=0, 275 bad_rev=0,
260 try_args=(), 276 try_args=(),
261 profile=None, 277 profile=None,
(...skipping 26 matching lines...) Expand all
288 304
289 if not profile: 305 if not profile:
290 profile = 'profile' 306 profile = 'profile'
291 307
292 context = PathContext(platform, good_rev, bad_rev) 308 context = PathContext(platform, good_rev, bad_rev)
293 cwd = os.getcwd() 309 cwd = os.getcwd()
294 310
295 _GetDownloadPath = lambda rev: os.path.join(cwd, 311 _GetDownloadPath = lambda rev: os.path.join(cwd,
296 '%d-%s' % (rev, context.archive_name)) 312 '%d-%s' % (rev, context.archive_name))
297 313
314 print "Downloading list of known revisions..."
315
298 revlist = context.GetRevList() 316 revlist = context.GetRevList()
299 317
300 # Get a list of revisions to bisect across. 318 # Get a list of revisions to bisect across.
301 if len(revlist) < 2: # Don't have enough builds to bisect. 319 if len(revlist) < 2: # Don't have enough builds to bisect.
302 msg = 'We don\'t have enough builds to bisect. revlist: %s' % revlist 320 msg = 'We don\'t have enough builds to bisect. revlist: %s' % revlist
303 raise RuntimeError(msg) 321 raise RuntimeError(msg)
304 322
305 # Figure out our bookends and first pivot point; fetch the pivot revision. 323 # Figure out our bookends and first pivot point; fetch the pivot revision.
306 good = 0 324 good = 0
307 bad = len(revlist) - 1 325 bad = len(revlist) - 1
308 pivot = bad / 2 326 pivot = bad / 2
309 rev = revlist[pivot] 327 rev = revlist[pivot]
310 zipfile = _GetDownloadPath(rev) 328 zipfile = _GetDownloadPath(rev)
329 progress_event = threading.Event()
330 progress_event.set()
311 print "Downloading revision %d..." % rev 331 print "Downloading revision %d..." % rev
312 FetchRevision(context, rev, zipfile) 332 FetchRevision(context, rev, zipfile,
333 quit_event=None, progress_event=progress_event)
313 334
314 # Binary search time! 335 # Binary search time!
315 while zipfile and bad - good > 1: 336 while zipfile and bad - good > 1:
316 # Pre-fetch next two possible pivots 337 # Pre-fetch next two possible pivots
317 # - down_pivot is the next revision to check if the current revision turns 338 # - down_pivot is the next revision to check if the current revision turns
318 # out to be bad. 339 # out to be bad.
319 # - up_pivot is the next revision to check if the current revision turns 340 # - up_pivot is the next revision to check if the current revision turns
320 # out to be good. 341 # out to be good.
321 down_pivot = int((pivot - good) / 2) + good 342 down_pivot = int((pivot - good) / 2) + good
322 down_thread = None 343 down_thread = None
323 if down_pivot != pivot and down_pivot != good: 344 if down_pivot != pivot and down_pivot != good:
324 down_rev = revlist[down_pivot] 345 down_rev = revlist[down_pivot]
325 down_zipfile = _GetDownloadPath(down_rev) 346 down_zipfile = _GetDownloadPath(down_rev)
326 down_event = threading.Event() 347 down_quit_event = threading.Event()
327 fetchargs = (context, down_rev, down_zipfile, down_event) 348 down_progress_event = threading.Event()
349 fetchargs = (context,
350 down_rev,
351 down_zipfile,
352 down_quit_event,
353 down_progress_event)
328 down_thread = threading.Thread(target=FetchRevision, 354 down_thread = threading.Thread(target=FetchRevision,
329 name='down_fetch', 355 name='down_fetch',
330 args=fetchargs) 356 args=fetchargs)
331 down_thread.start() 357 down_thread.start()
332 358
333 up_pivot = int((bad - pivot) / 2) + pivot 359 up_pivot = int((bad - pivot) / 2) + pivot
334 up_thread = None 360 up_thread = None
335 if up_pivot != pivot and up_pivot != bad: 361 if up_pivot != pivot and up_pivot != bad:
336 up_rev = revlist[up_pivot] 362 up_rev = revlist[up_pivot]
337 up_zipfile = _GetDownloadPath(up_rev) 363 up_zipfile = _GetDownloadPath(up_rev)
338 up_event = threading.Event() 364 up_quit_event = threading.Event()
339 fetchargs = (context, up_rev, up_zipfile, up_event) 365 up_progress_event = threading.Event()
366 fetchargs = (context,
367 up_rev,
368 up_zipfile,
369 up_quit_event,
370 up_progress_event)
340 up_thread = threading.Thread(target=FetchRevision, 371 up_thread = threading.Thread(target=FetchRevision,
341 name='up_fetch', 372 name='up_fetch',
342 args=fetchargs) 373 args=fetchargs)
343 up_thread.start() 374 up_thread.start()
344 375
345 # Run test on the pivot revision. 376 # Run test on the pivot revision.
346 (status, stdout, stderr) = RunRevision(context, 377 (status, stdout, stderr) = RunRevision(context,
347 rev, 378 rev,
348 zipfile, 379 zipfile,
349 profile, 380 profile,
350 try_args) 381 try_args)
351 os.unlink(zipfile) 382 os.unlink(zipfile)
352 zipfile = None 383 zipfile = None
353 384
354 # Call the predicate function to see if the current revision is good or bad. 385 # Call the predicate function to see if the current revision is good or bad.
355 # On that basis, kill one of the background downloads and complete the 386 # On that basis, kill one of the background downloads and complete the
356 # other, as described in the comments above. 387 # other, as described in the comments above.
357 try: 388 try:
358 if predicate(rev, status, stdout, stderr): 389 if predicate(rev, status, stdout, stderr):
359 good = pivot 390 good = pivot
360 if down_thread: 391 if down_thread:
361 down_event.set() # Kill the download of older revision. 392 down_quit_event.set() # Kill the download of older revision.
362 down_thread.join() 393 down_thread.join()
363 os.unlink(down_zipfile) 394 os.unlink(down_zipfile)
364 if up_thread: 395 if up_thread:
365 print "Downloading revision %d..." % up_rev 396 print "Downloading revision %d..." % up_rev
397 up_progress_event.set() # Display progress of download.
366 up_thread.join() # Wait for newer revision to finish downloading. 398 up_thread.join() # Wait for newer revision to finish downloading.
367 pivot = up_pivot 399 pivot = up_pivot
368 zipfile = up_zipfile 400 zipfile = up_zipfile
369 else: 401 else:
370 bad = pivot 402 bad = pivot
371 if up_thread: 403 if up_thread:
372 up_event.set() # Kill download of newer revision. 404 up_quit_event.set() # Kill download of newer revision.
373 up_thread.join() 405 up_thread.join()
374 os.unlink(up_zipfile) 406 os.unlink(up_zipfile)
375 if down_thread: 407 if down_thread:
376 print "Downloading revision %d..." % down_rev 408 print "Downloading revision %d..." % down_rev
409 down_progress_event.set() # Display progress of download.
377 down_thread.join() # Wait for older revision to finish downloading. 410 down_thread.join() # Wait for older revision to finish downloading.
378 pivot = down_pivot 411 pivot = down_pivot
379 zipfile = down_zipfile 412 zipfile = down_zipfile
380 except SystemExit: 413 except SystemExit:
414 print "Cleaning up..."
381 for f in [down_zipfile, up_zipfile]: 415 for f in [down_zipfile, up_zipfile]:
382 try: 416 try:
383 os.unlink(f) 417 os.unlink(f)
384 except OSError: 418 except OSError:
385 pass 419 pass
386 sys.exit(0) 420 sys.exit(0)
387 421
388 rev = revlist[pivot] 422 rev = revlist[pivot]
389 423
390 return (revlist[good], revlist[bad]) 424 return (revlist[good], revlist[bad])
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
460 494
461 # We're done. Let the user know the results in an official manner. 495 # We're done. Let the user know the results in an official manner.
462 print('You are probably looking for build %d.' % first_known_bad_rev) 496 print('You are probably looking for build %d.' % first_known_bad_rev)
463 print('CHANGELOG URL:') 497 print('CHANGELOG URL:')
464 print(CHANGELOG_URL % (last_known_good_rev, first_known_bad_rev)) 498 print(CHANGELOG_URL % (last_known_good_rev, first_known_bad_rev))
465 print('Built at revision:') 499 print('Built at revision:')
466 print(BUILD_VIEWVC_URL % first_known_bad_rev) 500 print(BUILD_VIEWVC_URL % first_known_bad_rev)
467 501
468 if __name__ == '__main__': 502 if __name__ == '__main__':
469 sys.exit(main()) 503 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