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

Side by Side Diff: build/build-bisect.py

Issue 1549006: Make build-bisect script work on win.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 8 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/python2.5 1 #!/usr/bin/python2.5
2 # Copyright (c) 2009 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2009 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 # Base URL to download snapshots from. 15 # Base URL to download snapshots from.
16 BUILD_BASE_URL = "http://build.chromium.org/buildbot/snapshots/" 16 BUILD_BASE_URL = 'http://build.chromium.org/buildbot/snapshots/'
17 17
18 # The type (platform) of the build archive. This is what's passed in to the 18 # The type (platform) of the build archive. This is what's passed in to the
19 # '-a/--archive' option. 19 # '-a/--archive' option.
20 BUILD_ARCHIVE_TYPE = '' 20 BUILD_ARCHIVE_TYPE = ''
21 21
22 # The selected archive to bisect. 22 # The selected archive to bisect.
23 BUILD_ARCHIVE_DIR = '' 23 BUILD_ARCHIVE_DIR = ''
24 24
25 # The location of the builds. 25 # The location of the builds.
26 BUILD_ARCHIVE_URL = "/%d/" 26 BUILD_ARCHIVE_URL = '/%d/'
27 27
28 # Name of the build archive. 28 # Name of the build archive.
29 BUILD_ZIP_NAME = '' 29 BUILD_ZIP_NAME = ''
30 30
31 # Directory name inside the archive. 31 # Directory name inside the archive.
32 BUILD_DIR_NAME = '' 32 BUILD_DIR_NAME = ''
33 33
34 # Name of the executable. 34 # Name of the executable.
35 BUILD_EXE_NAME = '' 35 BUILD_EXE_NAME = ''
36 36
37 # URL to the ViewVC commit page. 37 # URL to the ViewVC commit page.
38 BUILD_VIEWVC_URL = "http://src.chromium.org/viewvc/chrome?view=rev&revision=%d" 38 BUILD_VIEWVC_URL = 'http://src.chromium.org/viewvc/chrome?view=rev&revision=%d'
39 39
40 # Changelogs URL 40 # Changelogs URL
41 CHANGELOG_URL = "http://build.chromium.org/buildbot/" \ 41 CHANGELOG_URL = 'http://build.chromium.org/buildbot/' \
42 "perf/dashboard/ui/changelog.html?url=/trunk/src&range=%d:%d" 42 'perf/dashboard/ui/changelog.html?url=/trunk/src&range=%d:%d'
43 43
44 ############################################################################### 44 ###############################################################################
45 45
46 import math 46 import math
47 import optparse 47 import optparse
48 import os 48 import os
49 import pipes 49 import pipes
50 import re 50 import re
51 import shutil 51 import shutil
52 import sys 52 import sys
53 import tempfile 53 import tempfile
54 import urllib 54 import urllib
55 import zipfile
56
57
58 def UnzipFilenameToDir(filename, dir):
59 """Unzip |filename| to directory |dir|."""
60 zf = zipfile.ZipFile(filename)
61 # Make base.
62 pushd = os.getcwd()
63 try:
64 if not os.path.isdir(dir):
65 os.mkdir(dir)
66 os.chdir(dir)
67 # Extract files.
68 for info in zf.infolist():
69 name = info.filename
70 if name.endswith('/'): # dir
71 if not os.path.isdir(name):
72 os.makedirs(name)
73 else: # file
74 dir = os.path.dirname(name)
75 if not os.path.isdir(dir):
76 os.makedirs(dir)
77 out = open(name, 'wb')
78 out.write(zf.read(name))
79 out.close()
80 # Set permissions. Permission info in external_attr is shifted 16 bits.
81 os.chmod(name, info.external_attr >> 16L)
82 os.chdir(pushd)
83 except Exception, e:
84 print >>sys.stderr, e
85 sys.exit(1)
86
55 87
56 def SetArchiveVars(archive): 88 def SetArchiveVars(archive):
57 """Set a bunch of global variables appropriate for the specified archive.""" 89 """Set a bunch of global variables appropriate for the specified archive."""
58 global BUILD_ARCHIVE_TYPE 90 global BUILD_ARCHIVE_TYPE
59 global BUILD_ARCHIVE_DIR 91 global BUILD_ARCHIVE_DIR
60 global BUILD_ZIP_NAME 92 global BUILD_ZIP_NAME
61 global BUILD_DIR_NAME 93 global BUILD_DIR_NAME
62 global BUILD_EXE_NAME 94 global BUILD_EXE_NAME
63 global BUILD_BASE_URL 95 global BUILD_BASE_URL
64 96
65 BUILD_ARCHIVE_TYPE = archive 97 BUILD_ARCHIVE_TYPE = archive
66 BUILD_ARCHIVE_DIR = 'chromium-rel-' + BUILD_ARCHIVE_TYPE 98 BUILD_ARCHIVE_DIR = 'chromium-rel-' + BUILD_ARCHIVE_TYPE
67 99
68 if BUILD_ARCHIVE_TYPE in ('linux', 'linux-64'): 100 if BUILD_ARCHIVE_TYPE in ('linux', 'linux-64'):
69 BUILD_ZIP_NAME = 'chrome-linux.zip' 101 BUILD_ZIP_NAME = 'chrome-linux.zip'
70 BUILD_DIR_NAME = 'chrome-linux' 102 BUILD_DIR_NAME = 'chrome-linux'
71 BUILD_EXE_NAME = "chrome" 103 BUILD_EXE_NAME = 'chrome'
72 elif BUILD_ARCHIVE_TYPE in ('mac'): 104 elif BUILD_ARCHIVE_TYPE in ('mac'):
73 BUILD_ZIP_NAME = 'chrome-mac.zip' 105 BUILD_ZIP_NAME = 'chrome-mac.zip'
74 BUILD_DIR_NAME = 'chrome-mac' 106 BUILD_DIR_NAME = 'chrome-mac'
75 BUILD_EXE_NAME = "Chromium.app/Contents/MacOS/Chromium" 107 BUILD_EXE_NAME = 'Chromium.app/Contents/MacOS/Chromium'
76 elif BUILD_ARCHIVE_TYPE in ('xp'): 108 elif BUILD_ARCHIVE_TYPE in ('xp'):
77 BUILD_ZIP_NAME = 'chrome-win32.zip' 109 BUILD_ZIP_NAME = 'chrome-win32.zip'
78 BUILD_DIR_NAME = 'chrome-win32' 110 BUILD_DIR_NAME = 'chrome-win32'
79 BUILD_EXE_NAME = "chrome.exe" 111 BUILD_EXE_NAME = 'chrome.exe'
80 112
81 BUILD_BASE_URL += BUILD_ARCHIVE_DIR 113 BUILD_BASE_URL += BUILD_ARCHIVE_DIR
82 114
83 def ParseDirectoryIndex(url): 115 def ParseDirectoryIndex(url):
84 """Parses the HTML directory listing into a list of revision numbers.""" 116 """Parses the HTML directory listing into a list of revision numbers."""
85 handle = urllib.urlopen(url) 117 handle = urllib.urlopen(url)
86 dirindex = handle.read() 118 dirindex = handle.read()
87 handle.close() 119 handle.close()
88 return re.findall(r'<a href="([0-9]*)/">\1/</a>', dirindex) 120 return re.findall(r'<a href="([0-9]*)/">\1/</a>', dirindex)
89 121
(...skipping 13 matching lines...) Expand all
103 cwd = os.getcwd() 135 cwd = os.getcwd()
104 tempdir = tempfile.mkdtemp(prefix='bisect_tmp') 136 tempdir = tempfile.mkdtemp(prefix='bisect_tmp')
105 os.chdir(tempdir) 137 os.chdir(tempdir)
106 138
107 # Download the file. 139 # Download the file.
108 download_url = BUILD_BASE_URL + (BUILD_ARCHIVE_URL % rev) + BUILD_ZIP_NAME 140 download_url = BUILD_BASE_URL + (BUILD_ARCHIVE_URL % rev) + BUILD_ZIP_NAME
109 try: 141 try:
110 print 'Fetching ' + download_url 142 print 'Fetching ' + download_url
111 urllib.urlretrieve(download_url, BUILD_ZIP_NAME) 143 urllib.urlretrieve(download_url, BUILD_ZIP_NAME)
112 except Exception, e: 144 except Exception, e:
113 print("Could not retrieve the download. Sorry.") 145 print('Could not retrieve the download. Sorry.')
114 sys.exit(-1) 146 sys.exit(-1)
115 147
116 # Unzip the file. 148 # Unzip the file.
117 print 'Unzipping ...' 149 print 'Unziping ...'
118 os.system("unzip -q %s" % BUILD_ZIP_NAME) 150 UnzipFilenameToDir(BUILD_ZIP_NAME, os.curdir)
119 151
120 # Tell the system to open the app. 152 # Tell the system to open the app.
121 args = ['--user-data-dir=%s' % profile] + args 153 args = ['--user-data-dir=%s' % profile] + args
122 flags = ' '.join(map(pipes.quote, args)) 154 flags = ' '.join(map(pipes.quote, args))
123 print 'Running %s/%s/%s %s' % (os.getcwd(), BUILD_DIR_NAME, BUILD_EXE_NAME, 155 exe = os.path.join(os.getcwd(), BUILD_DIR_NAME, BUILD_EXE_NAME)
124 flags) 156 cmd = '%s %s' % (exe, flags)
125 if BUILD_ARCHIVE_TYPE in ('linux', 'linux-64', 'mac'): 157 print 'Running %s' % cmd
126 os.system("%s/%s %s" % (BUILD_DIR_NAME, BUILD_EXE_NAME, flags)) 158 os.system(cmd)
127 elif BUILD_ARCHIVE_TYPE in ('xp'):
128 # TODO(mmoss) Does Windows need 'start' or something?
129 os.system("%s/%s %s" % (BUILD_DIR_NAME, BUILD_EXE_NAME, flags))
130 159
131 os.chdir(cwd) 160 os.chdir(cwd)
132 print 'Cleaning temp dir ...' 161 print 'Cleaning temp dir ...'
133 try: 162 try:
134 shutil.rmtree(tempdir, True) 163 shutil.rmtree(tempdir, True)
135 except Exception, e: 164 except Exception, e:
136 pass 165 pass
137 166
138 167
139 def AskIsGoodBuild(rev): 168 def AskIsGoodBuild(rev):
140 """Ask the user whether build |rev| is good or bad.""" 169 """Ask the user whether build |rev| is good or bad."""
141 # Loop until we get a response that we can parse. 170 # Loop until we get a response that we can parse.
142 while True: 171 while True:
143 response = raw_input("\nBuild %d is [(g)ood/(b)ad]: " % int(rev)) 172 response = raw_input('\nBuild %d is [(g)ood/(b)ad]: ' % int(rev))
144 if response and response in ("g", "b"): 173 if response and response in ('g', 'b'):
145 return response == "g" 174 return response == 'g'
146 175
147 def main(): 176 def main():
148 usage = ('%prog [options] [-- chromium-options]\n' 177 usage = ('%prog [options] [-- chromium-options]\n'
149 'Perform binary search on the snapshot builds.') 178 'Perform binary search on the snapshot builds.')
150 parser = optparse.OptionParser(usage=usage) 179 parser = optparse.OptionParser(usage=usage)
151 # Strangely, the default help output doesn't include the choice list. 180 # Strangely, the default help output doesn't include the choice list.
152 choices = ['mac', 'xp', 'linux', 'linux-64'] 181 choices = ['mac', 'xp', 'linux', 'linux-64']
153 parser.add_option('-a', '--archive', 182 parser.add_option('-a', '--archive',
154 choices = choices, 183 choices = choices,
155 help = 'The buildbot archive to bisect [%s].' % 184 help = 'The buildbot archive to bisect [%s].' %
(...skipping 19 matching lines...) Expand all
175 204
176 SetArchiveVars(opts.archive) 205 SetArchiveVars(opts.archive)
177 206
178 # Pick a starting point, try to get HEAD for this. 207 # Pick a starting point, try to get HEAD for this.
179 if opts.bad: 208 if opts.bad:
180 bad_rev = opts.bad 209 bad_rev = opts.bad
181 else: 210 else:
182 bad_rev = 0 211 bad_rev = 0
183 try: 212 try:
184 # Location of the latest build revision number 213 # Location of the latest build revision number
185 BUILD_LATEST_URL = "%s/LATEST" % (BUILD_BASE_URL) 214 BUILD_LATEST_URL = '%s/LATEST' % (BUILD_BASE_URL)
186 nh = urllib.urlopen(BUILD_LATEST_URL) 215 nh = urllib.urlopen(BUILD_LATEST_URL)
187 latest = int(nh.read()) 216 latest = int(nh.read())
188 nh.close() 217 nh.close()
189 bad_rev = raw_input("Bad revision [HEAD:%d]: " % latest) 218 bad_rev = raw_input('Bad revision [HEAD:%d]: ' % latest)
190 if (bad_rev == ""): 219 if (bad_rev == ''):
191 bad_rev = latest 220 bad_rev = latest
192 bad_rev = int(bad_rev) 221 bad_rev = int(bad_rev)
193 except Exception, e: 222 except Exception, e:
194 print("Could not determine latest revision. This could be bad...") 223 print('Could not determine latest revision. This could be bad...')
195 bad_rev = int(raw_input("Bad revision: ")) 224 bad_rev = int(raw_input('Bad revision: '))
196 225
197 # Find out when we were good. 226 # Find out when we were good.
198 if opts.good: 227 if opts.good:
199 good_rev = opts.good 228 good_rev = opts.good
200 else: 229 else:
201 good_rev = 0 230 good_rev = 0
202 try: 231 try:
203 good_rev = int(raw_input("Last known good [0]: ")) 232 good_rev = int(raw_input('Last known good [0]: '))
204 except Exception, e: 233 except Exception, e:
205 pass 234 pass
206 235
207 # Get a list of revisions to bisect across. 236 # Get a list of revisions to bisect across.
208 revlist = GetRevList(good_rev, bad_rev) 237 revlist = GetRevList(good_rev, bad_rev)
209 if len(revlist) < 2: # Don't have enough builds to bisect 238 if len(revlist) < 2: # Don't have enough builds to bisect
210 print "We don't have enough builds to bisect. revlist: %s" % revlist 239 print 'We don\'t have enough builds to bisect. revlist: %s' % revlist
211 sys.exit(1) 240 sys.exit(1)
212 241
213 # If we don't have a |good_rev|, set it to be the first revision possible. 242 # If we don't have a |good_rev|, set it to be the first revision possible.
214 if good_rev == 0: 243 if good_rev == 0:
215 good_rev = revlist[0] 244 good_rev = revlist[0]
216 245
217 # These are indexes of |revlist|. 246 # These are indexes of |revlist|.
218 good = 0 247 good = 0
219 bad = len(revlist) - 1 248 bad = len(revlist) - 1
220 last_known_good_rev = revlist[good] 249 last_known_good_rev = revlist[good]
221 250
222 # Binary search time! 251 # Binary search time!
223 while good < bad: 252 while good < bad:
224 candidates = revlist[good:bad] 253 candidates = revlist[good:bad]
225 num_poss = len(candidates) 254 num_poss = len(candidates)
226 if num_poss > 10: 255 if num_poss > 10:
227 print("%d candidates. %d tries left." % 256 print('%d candidates. %d tries left.' %
228 (num_poss, round(math.log(num_poss, 2)))) 257 (num_poss, round(math.log(num_poss, 2))))
229 else: 258 else:
230 print("Candidates: %s" % revlist[good:bad]) 259 print('Candidates: %s' % revlist[good:bad])
231 260
232 # Cut the problem in half... 261 # Cut the problem in half...
233 test = int((bad - good) / 2) + good 262 test = int((bad - good) / 2) + good
234 test_rev = revlist[test] 263 test_rev = revlist[test]
235 264
236 # Let the user give this rev a spin (in her own profile, if she wants). 265 # Let the user give this rev a spin (in her own profile, if she wants).
237 profile = opts.profile 266 profile = opts.profile
238 if not profile: 267 if not profile:
239 profile = 'profile' # In a temp dir. 268 profile = 'profile' # In a temp dir.
240 TryRevision(test_rev, profile, args) 269 TryRevision(test_rev, profile, args)
241 if AskIsGoodBuild(test_rev): 270 if AskIsGoodBuild(test_rev):
242 last_known_good_rev = revlist[good] 271 last_known_good_rev = revlist[good]
243 good = test + 1 272 good = test + 1
244 else: 273 else:
245 bad = test 274 bad = test
246 275
247 # We're done. Let the user know the results in an official manner. 276 # We're done. Let the user know the results in an official manner.
248 print("You are probably looking for build %d." % revlist[bad]) 277 print('You are probably looking for build %d.' % revlist[bad])
249 print("CHANGELOG URL:") 278 print('CHANGELOG URL:')
250 print(CHANGELOG_URL % (last_known_good_rev, revlist[bad])) 279 print(CHANGELOG_URL % (last_known_good_rev, revlist[bad]))
251 print("Built at revision:") 280 print('Built at revision:')
252 print(BUILD_VIEWVC_URL % revlist[bad]) 281 print(BUILD_VIEWVC_URL % revlist[bad])
253 282
254 if __name__ == '__main__': 283 if __name__ == '__main__':
255 sys.exit(main()) 284 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