| Index: build/build-bisect.py
|
| diff --git a/build/build-bisect.py b/build/build-bisect.py
|
| index 38fc54f85fd1182f2f2cbf2d2c9eaf38661ec8b8..6eddf6dc6f91b7295a3903d793c37b0a78b39cc2 100755
|
| --- a/build/build-bisect.py
|
| +++ b/build/build-bisect.py
|
| @@ -5,34 +5,34 @@
|
|
|
| """Snapshot Build Bisect Tool
|
|
|
| -This script bisects the Mac snapshot archive using binary search. It starts at
|
| +This script bisects a snapshot archive using binary search. It starts at
|
| a bad revision (it will try to guess HEAD) and asks for a last known-good
|
| revision. It will then binary search across this revision range by downloading,
|
| unzipping, and opening Chromium for you. After testing the specific revision,
|
| it will ask you whether it is good or bad before continuing the search.
|
| -
|
| -Currently this only works on Mac, but with some effort it could be ported to
|
| -other platforms.
|
| """
|
|
|
| # Base URL to download snapshots from.
|
| -BUILD_BASE_URL = \
|
| - "http://build.chromium.org/buildbot/snapshots/chromium-rel-mac"
|
| +BUILD_BASE_URL = "http://build.chromium.org/buildbot/snapshots/"
|
| +
|
| +# The type (platform) of the build archive. This is what's passed in to the
|
| +# '-a/--archive' option.
|
| +BUILD_ARCHIVE_TYPE = ''
|
|
|
| -# Location of the latest build revision number
|
| -BUILD_LATEST_URL = "%s/LATEST" % BUILD_BASE_URL
|
| +# The selected archive to bisect.
|
| +BUILD_ARCHIVE_DIR = ''
|
|
|
| # The location of the builds.
|
| BUILD_ARCHIVE_URL = "/%d/"
|
|
|
| # Name of the build archive.
|
| -BUILD_ZIP_NAME = "chrome-mac.zip"
|
| +BUILD_ZIP_NAME = ''
|
|
|
| # Directory name inside the archive.
|
| -BUILD_DIR_NAME = "chrome-mac"
|
| +BUILD_DIR_NAME = ''
|
|
|
| # Name of the executable.
|
| -BUILD_EXE_NAME = "Chromium.app"
|
| +BUILD_EXE_NAME = ''
|
|
|
| # URL to the ViewVC commit page.
|
| BUILD_VIEWVC_URL = "http://src.chromium.org/viewvc/chrome?view=rev&revision=%d"
|
| @@ -40,12 +40,41 @@ BUILD_VIEWVC_URL = "http://src.chromium.org/viewvc/chrome?view=rev&revision=%d"
|
| ###############################################################################
|
|
|
| import math
|
| +import optparse
|
| import os
|
| import re
|
| import shutil
|
| import sys
|
| +import tempfile
|
| import urllib
|
|
|
| +def SetArchiveVars(archive):
|
| + """Set a bunch of global variables appropriate for the specified archive."""
|
| + global BUILD_ARCHIVE_TYPE
|
| + global BUILD_ARCHIVE_DIR
|
| + global BUILD_ZIP_NAME
|
| + global BUILD_DIR_NAME
|
| + global BUILD_EXE_NAME
|
| + global BUILD_BASE_URL
|
| +
|
| + BUILD_ARCHIVE_TYPE = archive
|
| + BUILD_ARCHIVE_DIR = 'chromium-rel-' + BUILD_ARCHIVE_TYPE
|
| +
|
| + if BUILD_ARCHIVE_TYPE in ('linux', 'linux-64'):
|
| + BUILD_ZIP_NAME = 'chrome-linux.zip'
|
| + BUILD_DIR_NAME = 'chrome-linux'
|
| + BUILD_EXE_NAME = "chrome"
|
| + elif BUILD_ARCHIVE_TYPE in ('mac'):
|
| + BUILD_ZIP_NAME = 'chrome-mac.zip'
|
| + BUILD_DIR_NAME = 'chrome-mac'
|
| + BUILD_EXE_NAME = "Chromium.app"
|
| + elif BUILD_ARCHIVE_TYPE in ('xp'):
|
| + BUILD_ZIP_NAME = 'chrome-win32.zip'
|
| + BUILD_DIR_NAME = 'chrome-win32'
|
| + BUILD_EXE_NAME = "chrome.exe"
|
| +
|
| + BUILD_BASE_URL += BUILD_ARCHIVE_DIR
|
| +
|
| def ParseDirectoryIndex(url):
|
| """Parses the HTML directory listing into a list of revision numbers."""
|
| handle = urllib.urlopen(url)
|
| @@ -64,60 +93,103 @@ def GetRevList(good, bad):
|
|
|
| def TryRevision(rev):
|
| """Downloads revision |rev|, unzips it, and opens it for the user to test."""
|
| - # Clear anything that's currently there.
|
| - try:
|
| - os.remove(BUILD_ZIP_NAME)
|
| - shutil.rmtree(BUILD_DIR_NAME, True)
|
| - except Exception, e:
|
| - pass
|
| + # Do this in a temp dir so we don't collide with user files.
|
| + cwd = os.getcwd()
|
| + tempdir = tempfile.mkdtemp(prefix='bisect_tmp')
|
| + os.chdir(tempdir)
|
|
|
| # Download the file.
|
| download_url = BUILD_BASE_URL + (BUILD_ARCHIVE_URL % rev) + BUILD_ZIP_NAME
|
| try:
|
| + print 'Fetching ' + download_url
|
| urllib.urlretrieve(download_url, BUILD_ZIP_NAME)
|
| except Exception, e:
|
| print("Could not retrieve the download. Sorry.")
|
| - print("Tried to get: %s" % download_url)
|
| sys.exit(-1)
|
|
|
| # Unzip the file.
|
| + print 'Unzipping ...'
|
| os.system("unzip -q %s" % BUILD_ZIP_NAME)
|
|
|
| - # Tell Finder to open the app.
|
| - os.system("open %s/%s" % (BUILD_DIR_NAME, BUILD_EXE_NAME))
|
| + # Tell the system to open the app.
|
| + print 'Running %s/%s/%s' % (os.getcwd(), BUILD_DIR_NAME, BUILD_EXE_NAME)
|
| + if BUILD_ARCHIVE_TYPE in ('linux', 'linux-64'):
|
| + os.system("%s/%s" % (BUILD_DIR_NAME, BUILD_EXE_NAME))
|
| + elif BUILD_ARCHIVE_TYPE in ('mac'):
|
| + os.system("open %s/%s" % (BUILD_DIR_NAME, BUILD_EXE_NAME))
|
| + elif BUILD_ARCHIVE_TYPE in ('xp'):
|
| + # TODO(mmoss) Does Windows need 'start' or something?
|
| + os.system("%s/%s" % (BUILD_DIR_NAME, BUILD_EXE_NAME))
|
| +
|
| + os.chdir(cwd)
|
| + print 'Cleaning temp dir ...'
|
| + try:
|
| + shutil.rmtree(tempdir, True)
|
| + except Exception, e:
|
| + pass
|
|
|
| def AskIsGoodBuild(rev):
|
| """Annoyingly ask the user whether build |rev| is good or bad."""
|
| while True:
|
| - check = raw_input("Build %d [g/b]: " % int(rev))[0]
|
| + check = raw_input("\nBuild %d is [(g)ood/(b)ad]: " % int(rev))[0]
|
| if (check == "g" or check == "b"):
|
| return (check == "g")
|
| else:
|
| print("Just answer the question...")
|
|
|
| def main():
|
| - print("chrome-bisect: Perform binary search on the snapshot builds")
|
| + usage = ('%prog [options]\n'
|
| + 'Perform binary search on the snapshot builds.')
|
| + parser = optparse.OptionParser(usage=usage)
|
| + parser.add_option('-a', '--archive',
|
| + choices = ['mac', 'xp', 'linux', 'linux-64'],
|
| + help = 'The buildbot archive to bisect.')
|
| + parser.add_option('-b', '--bad', type = 'int',
|
| + help = 'The bad revision to bisect to.')
|
| + parser.add_option('-g', '--good', type = 'int',
|
| + help = 'The last known good revision to bisect from.')
|
| + (opts, args) = parser.parse_args()
|
| +
|
| + if opts.archive is None:
|
| + parser.print_help()
|
| + return 1
|
| +
|
| + if opts.bad and opts.good and (opts.good > opts.bad):
|
| + print ('The good revision (%d) must precede the bad revision (%d).\n' %
|
| + (opts.good, opts.bad))
|
| + parser.print_help()
|
| + return 1
|
| +
|
| + SetArchiveVars(opts.archive)
|
|
|
| # Pick a starting point, try to get HEAD for this.
|
| - bad_rev = 0
|
| - try:
|
| - nh = urllib.urlopen(BUILD_LATEST_URL)
|
| - latest = int(nh.read())
|
| - nh.close()
|
| - bad_rev = raw_input("Bad revision [HEAD:%d]: " % latest)
|
| - if (bad_rev == ""):
|
| - bad_rev = latest
|
| - bad_rev = int(bad_rev)
|
| - except Exception, e:
|
| - print("Could not determine latest revision. This could be bad...")
|
| - bad_rev = int(raw_input("Bad revision: "))
|
| + if opts.bad:
|
| + bad_rev = opts.bad
|
| + else:
|
| + bad_rev = 0
|
| + try:
|
| + # Location of the latest build revision number
|
| + BUILD_LATEST_URL = "%s/LATEST" % (BUILD_BASE_URL)
|
| + nh = urllib.urlopen(BUILD_LATEST_URL)
|
| + latest = int(nh.read())
|
| + nh.close()
|
| + bad_rev = raw_input("Bad revision [HEAD:%d]: " % latest)
|
| + if (bad_rev == ""):
|
| + bad_rev = latest
|
| + bad_rev = int(bad_rev)
|
| + except Exception, e:
|
| + print("Could not determine latest revision. This could be bad...")
|
| + bad_rev = int(raw_input("Bad revision: "))
|
|
|
| # Find out when we were good.
|
| - good_rev = 0
|
| - try:
|
| - good_rev = int(raw_input("Last known good [0]: "))
|
| - except Exception, e:
|
| - pass
|
| + if opts.good:
|
| + good_rev = opts.good
|
| + else:
|
| + good_rev = 0
|
| + try:
|
| + good_rev = int(raw_input("Last known good [0]: "))
|
| + except Exception, e:
|
| + pass
|
|
|
| # Get a list of revisions to bisect across.
|
| revlist = GetRevList(good_rev, bad_rev)
|
| @@ -157,4 +229,4 @@ def main():
|
| print(BUILD_VIEWVC_URL % revlist[bad])
|
|
|
| if __name__ == '__main__':
|
| - main()
|
| + sys.exit(main())
|
|
|