OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 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 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
293 | 293 |
294 download_url = context.GetDownloadURL(rev) | 294 download_url = context.GetDownloadURL(rev) |
295 try: | 295 try: |
296 urllib.urlretrieve(download_url, filename, ReportHook) | 296 urllib.urlretrieve(download_url, filename, ReportHook) |
297 if progress_event and progress_event.isSet(): | 297 if progress_event and progress_event.isSet(): |
298 print | 298 print |
299 except RuntimeError, e: | 299 except RuntimeError, e: |
300 pass | 300 pass |
301 | 301 |
302 | 302 |
303 def RunRevision(context, revision, zipfile, profile, num_runs, args): | 303 def RunRevision(context, revision, zipfile, num_runs, testargs, tempdir, |
304 outdir=None): | |
Ian Vollick
2012/09/18 17:46:32
Why is tempdir a parameter? It doesn't look like g
hartmanng
2012/09/19 02:17:55
Done.
| |
304 """Given a zipped revision, unzip it and run the test.""" | 305 """Given a zipped revision, unzip it and run the test.""" |
305 print "Trying revision %s..." % str(revision) | 306 print "Trying revision %s..." % str(revision) |
306 | 307 |
307 # Create a temp directory and unzip the revision into it. | |
308 cwd = os.getcwd() | |
309 tempdir = tempfile.mkdtemp(prefix='bisect_tmp') | |
310 UnzipFilenameToDir(zipfile, tempdir) | 308 UnzipFilenameToDir(zipfile, tempdir) |
311 os.chdir(tempdir) | |
312 | 309 |
313 # Run the build as many times as specified. | |
314 testargs = [context.GetLaunchPath(), '--user-data-dir=%s' % profile] + args | |
315 # The sandbox must be run as root on Official Chrome, so bypass it. | 310 # The sandbox must be run as root on Official Chrome, so bypass it. |
316 if context.is_official and (context.platform == 'linux' or | 311 if context.is_official and (context.platform == 'linux' or |
317 context.platform == 'linux64'): | 312 context.platform == 'linux64'): |
318 testargs.append('--no-sandbox') | 313 testargs.append('--no-sandbox') |
319 | 314 |
315 # Run the build as many times as specified. | |
320 for i in range(0, num_runs): | 316 for i in range(0, num_runs): |
321 subproc = subprocess.Popen(testargs, | 317 subproc = subprocess.Popen(testargs, |
322 bufsize=-1, | 318 bufsize=-1, |
323 stdout=subprocess.PIPE, | 319 stdout=subprocess.PIPE, |
324 stderr=subprocess.PIPE) | 320 stderr=subprocess.PIPE) |
325 (stdout, stderr) = subproc.communicate() | 321 (stdout, stderr) = subproc.communicate() |
326 | 322 |
327 os.chdir(cwd) | 323 if outdir is not None: |
328 try: | 324 if not os.path.isdir(outdir): |
329 shutil.rmtree(tempdir, True) | 325 os.mkdir(outdir) |
330 except Exception, e: | 326 |
331 pass | 327 fout = open(os.path.join(outdir, '%s_%s.out' % (str(revision), str(i))), |
328 'w') | |
329 fout.write(stdout) | |
330 fout.close() | |
331 ferr = open(os.path.join(outdir, '%s_%s.err' % (str(revision), str(i))), | |
332 'w') | |
333 ferr.write(stderr) | |
334 ferr.close() | |
Ian Vollick
2012/09/18 17:46:32
It looks like we shutil.rmtree after every call to
hartmanng
2012/09/19 02:17:55
Done.
| |
332 | 335 |
333 return (subproc.returncode, stdout, stderr) | 336 return (subproc.returncode, stdout, stderr) |
334 | 337 |
335 | 338 |
336 def AskIsGoodBuild(rev, official_builds, status, stdout, stderr): | 339 def AskIsGoodBuild(rev, official_builds, status, stdout, stderr): |
337 """Ask the user whether build |rev| is good or bad.""" | 340 """Ask the user whether build |rev| is good or bad.""" |
338 # Loop until we get a response that we can parse. | 341 # Loop until we get a response that we can parse. |
339 while True: | 342 while True: |
340 response = raw_input('Revision %s is [(g)ood/(b)ad/(u)nknown/(q)uit]: ' % | 343 response = raw_input('Revision %s is [(g)ood/(b)ad/(u)nknown/(q)uit]: ' % |
341 str(rev)) | 344 str(rev)) |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
469 | 472 |
470 up_pivot = int((bad - pivot) / 2) + pivot | 473 up_pivot = int((bad - pivot) / 2) + pivot |
471 up_fetch = None | 474 up_fetch = None |
472 if up_pivot != pivot and up_pivot != bad: | 475 if up_pivot != pivot and up_pivot != bad: |
473 up_rev = revlist[up_pivot] | 476 up_rev = revlist[up_pivot] |
474 up_fetch = DownloadJob(context, 'up_fetch', up_rev, | 477 up_fetch = DownloadJob(context, 'up_fetch', up_rev, |
475 _GetDownloadPath(up_rev)) | 478 _GetDownloadPath(up_rev)) |
476 up_fetch.Start() | 479 up_fetch.Start() |
477 | 480 |
478 # Run test on the pivot revision. | 481 # Run test on the pivot revision. |
482 tempdir = tempfile.mkdtemp(prefix='bisect_tmp') | |
483 testargs = [os.path.join(tempdir, context.GetLaunchPath()), | |
484 '--user-data-dir=%s' % profile] + try_args | |
479 (status, stdout, stderr) = RunRevision(context, | 485 (status, stdout, stderr) = RunRevision(context, |
480 rev, | 486 rev, |
481 zipfile, | 487 zipfile, |
482 profile, | |
483 num_runs, | 488 num_runs, |
484 try_args) | 489 testargs, |
490 tempdir) | |
491 try: | |
492 shutil.rmtree(tempdir, True) | |
493 except Exception, e: | |
494 pass | |
495 | |
485 os.unlink(zipfile) | 496 os.unlink(zipfile) |
486 zipfile = None | 497 zipfile = None |
487 | 498 |
488 # Call the evaluate function to see if the current revision is good or bad. | 499 # Call the evaluate function to see if the current revision is good or bad. |
489 # On that basis, kill one of the background downloads and complete the | 500 # On that basis, kill one of the background downloads and complete the |
490 # other, as described in the comments above. | 501 # other, as described in the comments above. |
491 try: | 502 try: |
492 answer = evaluate(rev, official_builds, status, stdout, stderr) | 503 answer = evaluate(rev, official_builds, status, stdout, stderr) |
493 if answer == 'g': | 504 if answer == 'g': |
494 good = pivot | 505 good = pivot |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
669 print ' ' + WEBKIT_CHANGELOG_URL % (first_known_bad_webkit_rev, | 680 print ' ' + WEBKIT_CHANGELOG_URL % (first_known_bad_webkit_rev, |
670 last_known_good_webkit_rev) | 681 last_known_good_webkit_rev) |
671 print 'CHANGELOG URL:' | 682 print 'CHANGELOG URL:' |
672 if opts.official_builds: | 683 if opts.official_builds: |
673 print OFFICIAL_CHANGELOG_URL % (last_known_good_rev, first_known_bad_rev) | 684 print OFFICIAL_CHANGELOG_URL % (last_known_good_rev, first_known_bad_rev) |
674 else: | 685 else: |
675 print ' ' + CHANGELOG_URL % (last_known_good_rev, first_known_bad_rev) | 686 print ' ' + CHANGELOG_URL % (last_known_good_rev, first_known_bad_rev) |
676 | 687 |
677 if __name__ == '__main__': | 688 if __name__ == '__main__': |
678 sys.exit(main()) | 689 sys.exit(main()) |
OLD | NEW |