Chromium Code Reviews| 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 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 175 # trailing slash to just have a number. | 175 # trailing slash to just have a number. |
| 176 revisions = [] | 176 revisions = [] |
| 177 for prefix in all_prefixes: | 177 for prefix in all_prefixes: |
| 178 revnum = prefix.text[prefix_len:-1] | 178 revnum = prefix.text[prefix_len:-1] |
| 179 try: | 179 try: |
| 180 revnum = int(revnum) | 180 revnum = int(revnum) |
| 181 revisions.append(revnum) | 181 revisions.append(revnum) |
| 182 except ValueError: | 182 except ValueError: |
| 183 pass | 183 pass |
| 184 return (revisions, next_marker) | 184 return (revisions, next_marker) |
| 185 | 185 |
| 186 # Fetch the first list of revisions. | 186 # Fetch the first list of revisions. |
| 187 (revisions, next_marker) = _FetchAndParse(self.GetListingURL()) | 187 (revisions, next_marker) = _FetchAndParse(self.GetListingURL()) |
| 188 | 188 |
| 189 # If the result list was truncated, refetch with the next marker. Do this | 189 # If the result list was truncated, refetch with the next marker. Do this |
| 190 # until an entire directory listing is done. | 190 # until an entire directory listing is done. |
| 191 while next_marker: | 191 while next_marker: |
| 192 next_url = self.GetListingURL(next_marker) | 192 next_url = self.GetListingURL(next_marker) |
| 193 (new_revisions, next_marker) = _FetchAndParse(next_url) | 193 (new_revisions, next_marker) = _FetchAndParse(next_url) |
| 194 revisions.extend(new_revisions) | 194 revisions.extend(new_revisions) |
| 195 return revisions | 195 return revisions |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 289 | 289 |
| 290 download_url = context.GetDownloadURL(rev) | 290 download_url = context.GetDownloadURL(rev) |
| 291 try: | 291 try: |
| 292 urllib.urlretrieve(download_url, filename, ReportHook) | 292 urllib.urlretrieve(download_url, filename, ReportHook) |
| 293 if progress_event and progress_event.isSet(): | 293 if progress_event and progress_event.isSet(): |
| 294 print | 294 print |
| 295 except RuntimeError, e: | 295 except RuntimeError, e: |
| 296 pass | 296 pass |
| 297 | 297 |
| 298 | 298 |
| 299 def RunRevision(context, revision, zipfile, profile, num_runs, args): | 299 def RunRevision(context, revision, zipfile, num_runs, exec_args, outdir=None): |
| 300 """Given a zipped revision, unzip it and run the test.""" | 300 """Given a zipped revision, unzip it and run the test.""" |
|
Robert Sesek
2012/09/24 17:52:30
Can you properly document this function's params?
hartmanng
2012/09/24 20:13:20
Done.
| |
| 301 print "Trying revision %s..." % str(revision) | 301 print "Trying revision %s..." % str(revision) |
| 302 | 302 |
| 303 # Create a temp directory and unzip the revision into it. | |
| 304 cwd = os.getcwd() | |
| 305 tempdir = tempfile.mkdtemp(prefix='bisect_tmp') | 303 tempdir = tempfile.mkdtemp(prefix='bisect_tmp') |
| 306 UnzipFilenameToDir(zipfile, tempdir) | 304 UnzipFilenameToDir(zipfile, tempdir) |
| 307 os.chdir(tempdir) | 305 testargs = exec_args(os.path.join(tempdir, context.GetLaunchPath())) |
| 308 | 306 |
| 309 # Run the build as many times as specified. | |
| 310 testargs = [context.GetLaunchPath(), '--user-data-dir=%s' % profile] + args | |
| 311 # The sandbox must be run as root on Official Chrome, so bypass it. | 307 # The sandbox must be run as root on Official Chrome, so bypass it. |
| 312 if context.is_official and (context.platform == 'linux' or | 308 if context.is_official and (context.platform == 'linux' or |
| 313 context.platform == 'linux64'): | 309 context.platform == 'linux64'): |
| 314 testargs.append('--no-sandbox') | 310 testargs.append('--no-sandbox') |
| 315 | 311 |
| 312 # Run the build as many times as specified. | |
| 316 for i in range(0, num_runs): | 313 for i in range(0, num_runs): |
| 317 subproc = subprocess.Popen(testargs, | 314 subproc = subprocess.Popen(testargs, |
| 318 bufsize=-1, | 315 bufsize=-1, |
| 319 stdout=subprocess.PIPE, | 316 stdout=subprocess.PIPE, |
| 320 stderr=subprocess.PIPE) | 317 stderr=subprocess.PIPE) |
| 321 (stdout, stderr) = subproc.communicate() | 318 (stdout, stderr) = subproc.communicate() |
| 322 | 319 |
| 323 os.chdir(cwd) | 320 if outdir is not None: |
| 321 if not os.path.isdir(outdir): | |
| 322 os.mkdir(outdir) | |
| 323 | |
| 324 fout = open(os.path.join(outdir, '%s_%s.out' % (str(revision), str(i))), | |
| 325 'w') | |
|
Robert Sesek
2012/09/24 17:52:30
This should probably align with the 'o' in |os| si
hartmanng
2012/09/24 20:13:20
Done.
| |
| 326 fout.write(stdout) | |
| 327 fout.close() | |
| 328 ferr = open(os.path.join(outdir, '%s_%s.err' % (str(revision), str(i))), | |
| 329 'w') | |
| 330 ferr.write(stderr) | |
| 331 ferr.close() | |
| 332 | |
| 324 try: | 333 try: |
| 325 shutil.rmtree(tempdir, True) | 334 shutil.rmtree(tempdir, True) |
| 326 except Exception, e: | 335 except Exception, e: |
| 327 pass | 336 pass |
| 328 | 337 |
| 329 return (subproc.returncode, stdout, stderr) | 338 return (subproc.returncode, stdout, stderr) |
| 330 | 339 |
| 331 | 340 |
| 332 def AskIsGoodBuild(rev, official_builds, status, stdout, stderr): | 341 def AskIsGoodBuild(rev, official_builds, status, stdout, stderr): |
| 333 """Ask the user whether build |rev| is good or bad.""" | 342 """Ask the user whether build |rev| is good or bad.""" |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 464 down_fetch.Start() | 473 down_fetch.Start() |
| 465 | 474 |
| 466 up_pivot = int((bad - pivot) / 2) + pivot | 475 up_pivot = int((bad - pivot) / 2) + pivot |
| 467 up_fetch = None | 476 up_fetch = None |
| 468 if up_pivot != pivot and up_pivot != bad: | 477 if up_pivot != pivot and up_pivot != bad: |
| 469 up_rev = revlist[up_pivot] | 478 up_rev = revlist[up_pivot] |
| 470 up_fetch = DownloadJob(context, 'up_fetch', up_rev, | 479 up_fetch = DownloadJob(context, 'up_fetch', up_rev, |
| 471 _GetDownloadPath(up_rev)) | 480 _GetDownloadPath(up_rev)) |
| 472 up_fetch.Start() | 481 up_fetch.Start() |
| 473 | 482 |
| 483 def execute_args(chrome_path): | |
| 484 return [chrome_path, '--user-data-dir=%s' % profile] + try_args | |
| 485 | |
| 474 # Run test on the pivot revision. | 486 # Run test on the pivot revision. |
| 475 status = None | 487 status = None |
| 476 stdout = None | 488 stdout = None |
| 477 stderr = None | 489 stderr = None |
| 478 try: | 490 try: |
| 479 (status, stdout, stderr) = RunRevision(context, | 491 (status, stdout, stderr) = RunRevision(context, |
| 480 rev, | 492 rev, |
| 481 zipfile, | 493 zipfile, |
| 482 profile, | |
| 483 num_runs, | 494 num_runs, |
| 484 try_args) | 495 execute_args) |
| 485 except Exception, e: | 496 except Exception, e: |
| 486 print >>sys.stderr, e | 497 print >>sys.stderr, e |
| 498 | |
| 487 os.unlink(zipfile) | 499 os.unlink(zipfile) |
| 488 zipfile = None | 500 zipfile = None |
| 489 | 501 |
| 490 # Call the evaluate function to see if the current revision is good or bad. | 502 # Call the evaluate function to see if the current revision is good or bad. |
| 491 # On that basis, kill one of the background downloads and complete the | 503 # On that basis, kill one of the background downloads and complete the |
| 492 # other, as described in the comments above. | 504 # other, as described in the comments above. |
| 493 try: | 505 try: |
| 494 answer = evaluate(rev, official_builds, status, stdout, stderr) | 506 answer = evaluate(rev, official_builds, status, stdout, stderr) |
| 495 if answer == 'g': | 507 if answer == 'g': |
| 496 good = pivot | 508 good = pivot |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 671 print ' ' + WEBKIT_CHANGELOG_URL % (first_known_bad_webkit_rev, | 683 print ' ' + WEBKIT_CHANGELOG_URL % (first_known_bad_webkit_rev, |
| 672 last_known_good_webkit_rev) | 684 last_known_good_webkit_rev) |
| 673 print 'CHANGELOG URL:' | 685 print 'CHANGELOG URL:' |
| 674 if opts.official_builds: | 686 if opts.official_builds: |
| 675 print OFFICIAL_CHANGELOG_URL % (last_known_good_rev, first_known_bad_rev) | 687 print OFFICIAL_CHANGELOG_URL % (last_known_good_rev, first_known_bad_rev) |
| 676 else: | 688 else: |
| 677 print ' ' + CHANGELOG_URL % (last_known_good_rev, first_known_bad_rev) | 689 print ' ' + CHANGELOG_URL % (last_known_good_rev, first_known_bad_rev) |
| 678 | 690 |
| 679 if __name__ == '__main__': | 691 if __name__ == '__main__': |
| 680 sys.exit(main()) | 692 sys.exit(main()) |
| OLD | NEW |