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

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.
DaleCurtis 2014/08/20 22:56:19 Remove?
pshenoy 2014/08/20 23:21:55 Done.
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 CheckDeoptToolsInPath():
DaleCurtis 2014/08/20 22:56:18 Name is wrong.
pshenoy 2014/08/20 23:21:55 Done.
405 if os.environ['PATH'].find('depot_tools') != -1:
DaleCurtis 2014/08/20 22:56:19 Might as well just split and look for it instead o
pshenoy 2014/08/20 23:21:55 Done.
406 delimiter = ';' if sys.platform.startswith('win') else ':'
DaleCurtis 2014/08/20 22:56:18 Hmm, does this syntax actually work?
pshenoy 2014/08/20 23:21:55 Yes. It does :-)
407 path_list = os.environ['PATH'].split(delimiter)
408 for path in path_list:
409 if path.find('depot_tools') != -1:
410 return path
411 return None
412
413 def RunGsutilCommand(args):
414 gsutil_path = CheckDeoptToolsInPath()
415 if gsutil_path is None:
416 print ('Follow the instructions in this document '
417 'http://dev.chromium.org/developers/how-tos/install-depot-tools'
418 ' to install depot_tools and then try again.'
419 sys.exit(1)
420 gsutil_path = os.path.join(gsutil_path, 'third_party', 'gsutil', 'gsutil')
421 gsutil = subprocess.Popen([sys.executable, gsutil_path] + args,
422 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
423 env=None)
424 stdout, stderr = gsutil.communicate()
425 if gsutil.returncode:
426 if ('status=403' in stderr or 'status 403' in stderr or
DaleCurtis 2014/08/20 22:56:18 just re.findall(r'status[ |=]40[1|3]', stderr) ?
pshenoy 2014/08/20 23:21:55 Done.
427 'status=401' in stderr or 'status 401' in stderr):
428 print ('Follow these steps to configure your credentials and try'
429 ' running the bisect-builds.py again.:\n'
430 ' 1. Run "python %s config" and follow its instructions.\n'
431 ' 2. If you have a @google.com account, use that account.\n'
432 ' 3. For the project-id, just enter 0.' % gsutil_path)
433 sys.exit(1)
434 else:
435 raise Exception('Error running the gsutil command')
436 return stdout
437
438 def GsutilList(bucket):
439 query = 'gs://%s/' % bucket
440 stdout = RunGsutilCommand(['ls', query])
441 return [url[len(query):].strip('/') for url in stdout.splitlines()]
442
396 # Download the revlist and filter for just the range between good and bad. 443 # Download the revlist and filter for just the range between good and bad.
397 minrev = min(self.good_revision, self.bad_revision) 444 minrev = min(self.good_revision, self.bad_revision)
398 maxrev = max(self.good_revision, self.bad_revision) 445 maxrev = max(self.good_revision, self.bad_revision)
399 handle = urllib.urlopen(OFFICIAL_BASE_URL) 446 build_numbers = GsutilList('chrome-unsigned/desktop-W15K3Y')
DaleCurtis 2014/08/20 22:56:19 Constant.
pshenoy 2014/08/20 23:21:55 Done.
400 dirindex = handle.read() 447 revision_re = re.compile(r'(\d\d\.\d\.\d{4}\.\d+)')
401 handle.close() 448 build_numbers = filter(lambda b: revision_re.search(b), build_numbers)
402 build_numbers = re.findall(r'<a href="([0-9][0-9].*)/">', dirindex)
403 final_list = [] 449 final_list = []
404 i = 0 450 i = 0
405 parsed_build_numbers = [LooseVersion(x) for x in build_numbers] 451 parsed_build_numbers = [LooseVersion(x) for x in build_numbers]
452 connection = httplib.HTTPConnection('commondatastorage.googleapis.com')
DaleCurtis 2014/08/20 22:56:19 Put this as a constant with the official_url ?
pshenoy 2014/08/20 23:21:55 Done.
406 for build_number in sorted(parsed_build_numbers): 453 for build_number in sorted(parsed_build_numbers):
407 path = (OFFICIAL_BASE_URL + '/' + str(build_number) + '/' + 454 if build_number > maxrev:
455 break
456 if build_number < minrev:
457 continue
458 path = ('/chrome-unsigned/desktop-W15K3Y/' + str(build_number) + '/' +
DaleCurtis 2014/08/20 22:56:19 Ditto.
pshenoy 2014/08/20 23:21:55 Done.
408 self._listing_platform_dir + self.archive_name) 459 self._listing_platform_dir + self.archive_name)
409 i = i + 1 460 i = i + 1
410 try: 461 connection.request('HEAD', path)
411 connection = urllib.urlopen(path) 462 response = connection.getresponse()
412 connection.close() 463 if response.status == 200:
413 if build_number > maxrev: 464 final_list.append(str(build_number))
414 break 465 response.read()
415 if build_number >= minrev: 466 connection.close()
416 final_list.append(str(build_number)) 467 return sorted(list(set(final_list)))
DaleCurtis 2014/08/20 22:56:19 I think I had a bug in my patch previously, this s
pshenoy 2014/08/20 23:21:55 Done.
417 except urllib.HTTPError:
418 pass
419 return final_list
420 468
421 def UnzipFilenameToDir(filename, directory): 469 def UnzipFilenameToDir(filename, directory):
422 """Unzip |filename| to |directory|.""" 470 """Unzip |filename| to |directory|."""
423 cwd = os.getcwd() 471 cwd = os.getcwd()
424 if not os.path.isabs(filename): 472 if not os.path.isabs(filename):
425 filename = os.path.join(cwd, filename) 473 filename = os.path.join(cwd, filename)
426 zf = zipfile.ZipFile(filename) 474 zf = zipfile.ZipFile(filename)
427 # Make base. 475 # Make base.
428 if not os.path.isdir(directory): 476 if not os.path.isdir(directory):
429 os.mkdir(directory) 477 os.mkdir(directory)
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after
650 """ 698 """
651 699
652 if not profile: 700 if not profile:
653 profile = 'profile' 701 profile = 'profile'
654 702
655 good_rev = context.good_revision 703 good_rev = context.good_revision
656 bad_rev = context.bad_revision 704 bad_rev = context.bad_revision
657 cwd = os.getcwd() 705 cwd = os.getcwd()
658 706
659 print 'Downloading list of known revisions...', 707 print 'Downloading list of known revisions...',
660 if not context.use_local_repo: 708 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)' 709 print '(use --use-local-repo for speed if you have a local checkout)'
662 else: 710 else:
663 print 711 print
664 _GetDownloadPath = lambda rev: os.path.join(cwd, 712 _GetDownloadPath = lambda rev: os.path.join(cwd,
665 '%s-%s' % (str(rev), context.archive_name)) 713 '%s-%s' % (str(rev), context.archive_name))
666 if context.is_official: 714 if context.is_official:
667 revlist = context.GetOfficialBuildsList() 715 revlist = context.GetOfficialBuildsList()
668 else: 716 else:
669 revlist = context.GetRevList() 717 revlist = context.GetRevList()
670 718
(...skipping 417 matching lines...) Expand 10 before | Expand all | Expand 10 after
1088 1136
1089 print 'CHANGELOG URL:' 1137 print 'CHANGELOG URL:'
1090 if opts.official_builds: 1138 if opts.official_builds:
1091 print OFFICIAL_CHANGELOG_URL % (min_chromium_rev, max_chromium_rev) 1139 print OFFICIAL_CHANGELOG_URL % (min_chromium_rev, max_chromium_rev)
1092 else: 1140 else:
1093 print ' ' + CHANGELOG_URL % (min_chromium_rev, max_chromium_rev) 1141 print ' ' + CHANGELOG_URL % (min_chromium_rev, max_chromium_rev)
1094 1142
1095 1143
1096 if __name__ == '__main__': 1144 if __name__ == '__main__':
1097 sys.exit(main()) 1145 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