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

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

Issue 492853002: bisect-builds.py: Fix official Google Chrome build bisection. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 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/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,
11 unzipping, and opening Chromium for you. After testing the specific revision, 11 unzipping, and opening Chromium for you. After testing the specific revision,
12 it will ask you whether it is good or bad before continuing the search. 12 it will ask you whether it is good or bad before continuing the search.
13 """ 13 """
14 14
15 # The base URL for stored build archives. 15 # The base URL for stored build archives.
16 CHROMIUM_BASE_URL = ('http://commondatastorage.googleapis.com' 16 CHROMIUM_BASE_URL = ('http://commondatastorage.googleapis.com'
17 '/chromium-browser-snapshots') 17 '/chromium-browser-snapshots')
18 WEBKIT_BASE_URL = ('http://commondatastorage.googleapis.com' 18 WEBKIT_BASE_URL = ('http://commondatastorage.googleapis.com'
19 '/chromium-webkit-snapshots') 19 '/chromium-webkit-snapshots')
20 ASAN_BASE_URL = ('http://commondatastorage.googleapis.com' 20 ASAN_BASE_URL = ('http://commondatastorage.googleapis.com'
21 '/chromium-browser-asan') 21 '/chromium-browser-asan')
22 22
23 # The base URL for official builds. 23 # The base URL for official builds.
24 OFFICIAL_BASE_URL = 'http://master.chrome.corp.google.com/official_builds' 24 OFFICIAL_BASE_URL = ('http://commondatastorage.googleapis.com/'
25 'chrome-unsigned/desktop-W15K3Y')
25 26
26 # URL template for viewing changelogs between revisions. 27 # URL template for viewing changelogs between revisions.
27 CHANGELOG_URL = ('http://build.chromium.org' 28 CHANGELOG_URL = ('http://build.chromium.org'
28 '/f/chromium/perf/dashboard/ui/changelog.html' 29 '/f/chromium/perf/dashboard/ui/changelog.html'
29 '?url=/trunk/src&range=%d%%3A%d') 30 '?url=/trunk/src&range=%d%%3A%d')
30 31
31 # URL template for viewing changelogs between official versions. 32 # URL template for viewing changelogs between official versions.
32 OFFICIAL_CHANGELOG_URL = ('http://omahaproxy.appspot.com/changelog' 33 OFFICIAL_CHANGELOG_URL = ('http://omahaproxy.appspot.com/changelog'
33 '?old_version=%s&new_version=%s') 34 '?old_version=%s&new_version=%s')
34 35
35 # DEPS file URL. 36 # DEPS file URL.
36 DEPS_FILE = 'http://src.chromium.org/viewvc/chrome/trunk/src/DEPS?revision=%d' 37 DEPS_FILE = 'http://src.chromium.org/viewvc/chrome/trunk/src/DEPS?revision=%d'
37 38
39 # GSUtil download URL.
40 GSUTIL_URL = 'http://storage.googleapis.com/pub/gsutil.tar.gz'
41
38 # Blink changelogs URL. 42 # Blink changelogs URL.
39 BLINK_CHANGELOG_URL = ('http://build.chromium.org' 43 BLINK_CHANGELOG_URL = ('http://build.chromium.org'
40 '/f/chromium/perf/dashboard/ui/changelog_blink.html' 44 '/f/chromium/perf/dashboard/ui/changelog_blink.html'
41 '?url=/trunk&range=%d%%3A%d') 45 '?url=/trunk&range=%d%%3A%d')
42 46
43 DONE_MESSAGE_GOOD_MIN = ('You are probably looking for a change made after %s (' 47 DONE_MESSAGE_GOOD_MIN = ('You are probably looking for a change made after %s ('
44 'known good), but no later than %s (first known bad).') 48 'known good), but no later than %s (first known bad).')
45 DONE_MESSAGE_GOOD_MAX = ('You are probably looking for a change made after %s (' 49 DONE_MESSAGE_GOOD_MAX = ('You are probably looking for a change made after %s ('
46 'known bad), but no later than %s (first known good).') 50 'known bad), but no later than %s (first known good).')
47 51
(...skipping 18 matching lines...) Expand all
66 BLINK_SEARCH_PATTERN = ( 70 BLINK_SEARCH_PATTERN = (
67 r'.*git-svn-id: svn://svn.chromium.org/blink/trunk@(\d+) ') 71 r'.*git-svn-id: svn://svn.chromium.org/blink/trunk@(\d+) ')
68 72
69 SEARCH_PATTERN = { 73 SEARCH_PATTERN = {
70 'chromium': CHROMIUM_SEARCH_PATTERN, 74 'chromium': CHROMIUM_SEARCH_PATTERN,
71 'blink': BLINK_SEARCH_PATTERN, 75 'blink': BLINK_SEARCH_PATTERN,
72 } 76 }
73 77
74 ############################################################################### 78 ###############################################################################
75 79
80 import cStringIO
81 import httplib
76 import json 82 import json
77 import optparse 83 import optparse
78 import os 84 import os
79 import re 85 import re
80 import shlex 86 import shlex
81 import shutil 87 import shutil
82 import subprocess 88 import subprocess
83 import sys 89 import sys
90 import tarfile
84 import tempfile 91 import tempfile
85 import threading 92 import threading
86 import urllib 93 import urllib
87 from distutils.version import LooseVersion 94 from distutils.version import LooseVersion
88 from xml.etree import ElementTree 95 from xml.etree import ElementTree
89 import zipfile 96 import zipfile
90 97
91 98
92 class PathContext(object): 99 class PathContext(object):
93 """A PathContext is used to carry the information used to construct URLs and 100 """A PathContext is used to carry the information used to construct URLs and
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
132 self._archive_extract_dir = 'chrome-mac' 139 self._archive_extract_dir = 'chrome-mac'
133 elif self.platform == 'win': 140 elif self.platform == 'win':
134 self.archive_name = 'chrome-win32.zip' 141 self.archive_name = 'chrome-win32.zip'
135 self._archive_extract_dir = 'chrome-win32' 142 self._archive_extract_dir = 'chrome-win32'
136 self._binary_name = 'chrome.exe' 143 self._binary_name = 'chrome.exe'
137 else: 144 else:
138 raise Exception('Invalid platform: %s' % self.platform) 145 raise Exception('Invalid platform: %s' % self.platform)
139 146
140 if is_official: 147 if is_official:
141 if self.platform == 'linux': 148 if self.platform == 'linux':
142 self._listing_platform_dir = 'precise32bit/' 149 self._listing_platform_dir = 'precise32/'
143 self.archive_name = 'chrome-precise32bit.zip' 150 self.archive_name = 'chrome-precise32.zip'
144 self._archive_extract_dir = 'chrome-precise32bit' 151 self._archive_extract_dir = 'chrome-precise32'
145 elif self.platform == 'linux64': 152 elif self.platform == 'linux64':
146 self._listing_platform_dir = 'precise64bit/' 153 self._listing_platform_dir = 'precise64/'
147 self.archive_name = 'chrome-precise64bit.zip' 154 self.archive_name = 'chrome-precise64.zip'
148 self._archive_extract_dir = 'chrome-precise64bit' 155 self._archive_extract_dir = 'chrome-precise64'
149 elif self.platform == 'mac': 156 elif self.platform == 'mac':
150 self._listing_platform_dir = 'mac/' 157 self._listing_platform_dir = 'mac/'
151 self._binary_name = 'Google Chrome.app/Contents/MacOS/Google Chrome' 158 self._binary_name = 'Google Chrome.app/Contents/MacOS/Google Chrome'
152 elif self.platform == 'win': 159 elif self.platform == 'win':
153 self._listing_platform_dir = 'win/' 160 self._listing_platform_dir = 'win/'
154 else: 161 else:
155 if self.platform in ('linux', 'linux64', 'linux-arm'): 162 if self.platform in ('linux', 'linux64', 'linux-arm'):
156 self.archive_name = 'chrome-linux.zip' 163 self.archive_name = 'chrome-linux.zip'
157 self._archive_extract_dir = 'chrome-linux' 164 self._archive_extract_dir = 'chrome-linux'
158 if self.platform == 'linux': 165 if self.platform == 'linux':
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after
386 self.good_revision) 393 self.good_revision)
387 self.bad_revision = FixChromiumRevForBlink(revlist, 394 self.bad_revision = FixChromiumRevForBlink(revlist,
388 revlist_all, 395 revlist_all,
389 self, 396 self,
390 self.bad_revision) 397 self.bad_revision)
391 return revlist 398 return revlist
392 399
393 def GetOfficialBuildsList(self): 400 def GetOfficialBuildsList(self):
394 """Gets the list of official build numbers between self.good_revision and 401 """Gets the list of official build numbers between self.good_revision and
395 self.bad_revision.""" 402 self.bad_revision."""
403
404 def DownloadGsutil():
405 gsutil_path = os.path.join(os.getcwd(), 'gsutil')
406 if not os.path.exists(gsutil_path):
407 print 'Downloading gsutil'
408 response = urllib.urlopen(GSUTIL_URL)
409 if response.getcode() == 200:
410 tar_file = tarfile.open(fileobj=cStringIO.StringIO(response.read()))
411 tar_file.extractall(os.getcwd())
412 print 'Downloaded gsutil to %s' % gsutil_path
413 else:
414 raise Exception('HTTP Error %d' % response.getcode())
415 return os.path.join(gsutil_path, 'gsutil')
416
417 def RunGsutilCommand(args):
418 gsutil_path = DownloadGsutil()
419 gsutil = subprocess.Popen([sys.executable, gsutil_path] + args,
420 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
421 env=None)
422 stdout, stderr = gsutil.communicate()
423 if gsutil.returncode:
424 if ('status=403' in stderr or 'status 403' in stderr or
425 'status=401' in stderr or 'status 401' in stderr):
426 print ('Follow these steps to configure your credentials and try'
427 ' running the bisect-builds.py again.:\n'
428 ' 1. Run "python %s config" and follow its instructions.\n'
429 ' 2. If you have a @google.com account, use that account.\n'
430 ' 3. For the project-id, just enter 0.' % gsutil_path)
431 sys.exit(1)
432 else:
433 raise Exception('Error running the gsutil command')
434 return stdout
435
436 def GsutilList(bucket):
437 query = 'gs://%s/' % bucket
438 stdout = RunGsutilCommand(['ls', query])
439 return [url[len(query):].strip('/') for url in stdout.splitlines()]
440
441 def IsValidBuildNumber(build):
442 revision_re = re.compile(r'(\d\d\.\d\.\d{4}\.\d+)')
DaleCurtis 2014/08/20 20:46:43 No point in using re.compile inside the function.
pshenoy 2014/08/20 22:42:43 Done.
443 return revision_re.search(build)
444
396 # Download the revlist and filter for just the range between good and bad. 445 # Download the revlist and filter for just the range between good and bad.
397 minrev = min(self.good_revision, self.bad_revision) 446 minrev = min(self.good_revision, self.bad_revision)
398 maxrev = max(self.good_revision, self.bad_revision) 447 maxrev = max(self.good_revision, self.bad_revision)
399 handle = urllib.urlopen(OFFICIAL_BASE_URL) 448 build_numbers = GsutilList('chrome-unsigned/desktop-W15K3Y')
400 dirindex = handle.read() 449 build_numbers = filter(IsValidBuildNumber, build_numbers)
401 handle.close()
402 build_numbers = re.findall(r'<a href="([0-9][0-9].*)/">', dirindex)
403 final_list = [] 450 final_list = []
404 i = 0 451 i = 0
405 parsed_build_numbers = [LooseVersion(x) for x in build_numbers] 452 parsed_build_numbers = [LooseVersion(x) for x in build_numbers]
453 connection = httplib.HTTPConnection('commondatastorage.googleapis.com')
406 for build_number in sorted(parsed_build_numbers): 454 for build_number in sorted(parsed_build_numbers):
407 path = (OFFICIAL_BASE_URL + '/' + str(build_number) + '/' + 455 if build_number > maxrev:
456 break
457 if build_number < minrev:
458 continue
459 path = ('/chrome-unsigned/desktop-W15K3Y/' + str(build_number) + '/' +
408 self._listing_platform_dir + self.archive_name) 460 self._listing_platform_dir + self.archive_name)
409 i = i + 1 461 i = i + 1
410 try: 462 connection.request('HEAD', path)
411 connection = urllib.urlopen(path) 463 response = connection.getresponse()
412 connection.close() 464 if response.status == 200:
413 if build_number > maxrev: 465 final_list.append(str(build_number))
414 break 466 response.read()
415 if build_number >= minrev: 467 connection.close()
416 final_list.append(str(build_number)) 468 return sorted(list(set(final_list)))
417 except urllib.HTTPError:
418 pass
419 return final_list
420 469
421 def UnzipFilenameToDir(filename, directory): 470 def UnzipFilenameToDir(filename, directory):
422 """Unzip |filename| to |directory|.""" 471 """Unzip |filename| to |directory|."""
423 cwd = os.getcwd() 472 cwd = os.getcwd()
424 if not os.path.isabs(filename): 473 if not os.path.isabs(filename):
425 filename = os.path.join(cwd, filename) 474 filename = os.path.join(cwd, filename)
426 zf = zipfile.ZipFile(filename) 475 zf = zipfile.ZipFile(filename)
427 # Make base. 476 # Make base.
428 if not os.path.isdir(directory): 477 if not os.path.isdir(directory):
429 os.mkdir(directory) 478 os.mkdir(directory)
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after
650 """ 699 """
651 700
652 if not profile: 701 if not profile:
653 profile = 'profile' 702 profile = 'profile'
654 703
655 good_rev = context.good_revision 704 good_rev = context.good_revision
656 bad_rev = context.bad_revision 705 bad_rev = context.bad_revision
657 cwd = os.getcwd() 706 cwd = os.getcwd()
658 707
659 print 'Downloading list of known revisions...', 708 print 'Downloading list of known revisions...',
660 if not context.use_local_repo: 709 if not context.use_local_repo and not context.is_official:
661 print '(use --use-local-repo for speed if you have a local checkout)' 710 print '(use --use-local-repo for speed if you have a local checkout)'
662 else: 711 else:
663 print 712 print
664 _GetDownloadPath = lambda rev: os.path.join(cwd, 713 _GetDownloadPath = lambda rev: os.path.join(cwd,
665 '%s-%s' % (str(rev), context.archive_name)) 714 '%s-%s' % (str(rev), context.archive_name))
666 if context.is_official: 715 if context.is_official:
667 revlist = context.GetOfficialBuildsList() 716 revlist = context.GetOfficialBuildsList()
668 else: 717 else:
669 revlist = context.GetRevList() 718 revlist = context.GetRevList()
670 719
(...skipping 417 matching lines...) Expand 10 before | Expand all | Expand 10 after
1088 1137
1089 print 'CHANGELOG URL:' 1138 print 'CHANGELOG URL:'
1090 if opts.official_builds: 1139 if opts.official_builds:
1091 print OFFICIAL_CHANGELOG_URL % (min_chromium_rev, max_chromium_rev) 1140 print OFFICIAL_CHANGELOG_URL % (min_chromium_rev, max_chromium_rev)
1092 else: 1141 else:
1093 print ' ' + CHANGELOG_URL % (min_chromium_rev, max_chromium_rev) 1142 print ' ' + CHANGELOG_URL % (min_chromium_rev, max_chromium_rev)
1094 1143
1095 1144
1096 if __name__ == '__main__': 1145 if __name__ == '__main__':
1097 sys.exit(main()) 1146 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