OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/env 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, |
11 unzipping, and opening Chromium for you. After testing the specific revision, | 11 unzipping, and opening Chromium for you. After testing the specific revision, |
(...skipping 26 matching lines...) Expand all Loading... |
38 import re | 38 import re |
39 import shutil | 39 import shutil |
40 import subprocess | 40 import subprocess |
41 import sys | 41 import sys |
42 import tempfile | 42 import tempfile |
43 import threading | 43 import threading |
44 import urllib | 44 import urllib |
45 from xml.etree import ElementTree | 45 from xml.etree import ElementTree |
46 import zipfile | 46 import zipfile |
47 | 47 |
| 48 |
48 class PathContext(object): | 49 class PathContext(object): |
49 """A PathContext is used to carry the information used to construct URLs and | 50 """A PathContext is used to carry the information used to construct URLs and |
50 paths when dealing with the storage server and archives.""" | 51 paths when dealing with the storage server and archives.""" |
51 def __init__(self, platform, good_revision, bad_revision): | 52 def __init__(self, platform, good_revision, bad_revision): |
52 super(PathContext, self).__init__() | 53 super(PathContext, self).__init__() |
53 # Store off the input parameters. | 54 # Store off the input parameters. |
54 self.platform = platform # What's passed in to the '-a/--archive' option. | 55 self.platform = platform # What's passed in to the '-a/--archive' option. |
55 self.good_revision = good_revision | 56 self.good_revision = good_revision |
56 self.bad_revision = bad_revision | 57 self.bad_revision = bad_revision |
57 | 58 |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
260 (stdout, stderr) = subproc.communicate() | 261 (stdout, stderr) = subproc.communicate() |
261 | 262 |
262 os.chdir(cwd) | 263 os.chdir(cwd) |
263 try: | 264 try: |
264 shutil.rmtree(tempdir, True) | 265 shutil.rmtree(tempdir, True) |
265 except Exception, e: | 266 except Exception, e: |
266 pass | 267 pass |
267 | 268 |
268 return (subproc.returncode, stdout, stderr) | 269 return (subproc.returncode, stdout, stderr) |
269 | 270 |
| 271 |
270 def AskIsGoodBuild(rev, status, stdout, stderr): | 272 def AskIsGoodBuild(rev, status, stdout, stderr): |
271 """Ask the user whether build |rev| is good or bad.""" | 273 """Ask the user whether build |rev| is good or bad.""" |
272 # Loop until we get a response that we can parse. | 274 # Loop until we get a response that we can parse. |
273 while True: | 275 while True: |
274 response = raw_input('Revision %d is [(g)ood/(b)ad/(q)uit]: ' % int(rev)) | 276 response = raw_input('Revision %d is [(g)ood/(b)ad/(q)uit]: ' % int(rev)) |
275 if response and response in ('g', 'b'): | 277 if response and response in ('g', 'b'): |
276 return response == 'g' | 278 return response == 'g' |
277 if response and response == 'q': | 279 if response and response == 'q': |
278 raise SystemExit() | 280 raise SystemExit() |
279 | 281 |
| 282 |
280 def Bisect(platform, | 283 def Bisect(platform, |
281 good_rev=0, | 284 good_rev=0, |
282 bad_rev=0, | 285 bad_rev=0, |
283 try_args=(), | 286 try_args=(), |
284 profile=None, | 287 profile=None, |
285 predicate=AskIsGoodBuild): | 288 predicate=AskIsGoodBuild): |
286 """Given known good and known bad revisions, run a binary search on all | 289 """Given known good and known bad revisions, run a binary search on all |
287 archived revisions to determine the last known good revision. | 290 archived revisions to determine the last known good revision. |
288 | 291 |
289 @param platform Which build to download/run ('mac', 'win', 'linux64', etc.). | 292 @param platform Which build to download/run ('mac', 'win', 'linux64', etc.). |
(...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
527 print('You are probably looking for build %d.' % first_known_bad_rev) | 530 print('You are probably looking for build %d.' % first_known_bad_rev) |
528 if last_known_good_webkit_rev != first_known_bad_webkit_rev: | 531 if last_known_good_webkit_rev != first_known_bad_webkit_rev: |
529 print 'WEBKIT CHANGELOG URL:' | 532 print 'WEBKIT CHANGELOG URL:' |
530 print WEBKIT_CHANGELOG_URL % (first_known_bad_webkit_rev, | 533 print WEBKIT_CHANGELOG_URL % (first_known_bad_webkit_rev, |
531 last_known_good_webkit_rev) | 534 last_known_good_webkit_rev) |
532 print 'CHANGELOG URL:' | 535 print 'CHANGELOG URL:' |
533 print CHANGELOG_URL % (last_known_good_rev, first_known_bad_rev) | 536 print CHANGELOG_URL % (last_known_good_rev, first_known_bad_rev) |
534 print 'Built at revision:' | 537 print 'Built at revision:' |
535 print BUILD_VIEWVC_URL % first_known_bad_rev | 538 print BUILD_VIEWVC_URL % first_known_bad_rev |
536 | 539 |
| 540 |
537 if __name__ == '__main__': | 541 if __name__ == '__main__': |
538 sys.exit(main()) | 542 sys.exit(main()) |
OLD | NEW |