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 |