diff options
author | jbates@chromium.org <jbates@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-20 21:34:47 +0000 |
---|---|---|
committer | jbates@chromium.org <jbates@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-20 21:34:47 +0000 |
commit | 3ff00b717fdd13ab662adc8236e53763ab07520b (patch) | |
tree | 0a9b15a467491b0e63541afa18717bd454528474 | |
parent | 6825560e7645b6ae46da50a8a9f7f4a05c26f17f (diff) | |
download | chromium_src-3ff00b717fdd13ab662adc8236e53763ab07520b.zip chromium_src-3ff00b717fdd13ab662adc8236e53763ab07520b.tar.gz chromium_src-3ff00b717fdd13ab662adc8236e53763ab07520b.tar.bz2 |
This change adds a --recent option to bisect-builds that tells it to use the build.chromium.org/f/chromium build listings which have much better granularity, but only 2-3 months of history.
One minor bug was also fixed that caused bisect-builds to report a bigger revision range than necessary.
BUG=82421
Review URL: http://codereview.chromium.org/7461012
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@93257 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | tools/bisect-builds.py | 64 |
1 files changed, 44 insertions, 20 deletions
diff --git a/tools/bisect-builds.py b/tools/bisect-builds.py index 7016820..11711cd 100644 --- a/tools/bisect-builds.py +++ b/tools/bisect-builds.py @@ -14,6 +14,7 @@ it will ask you whether it is good or bad before continuing the search. # The root URL for storage. BASE_URL = 'http://commondatastorage.googleapis.com/chromium-browser-snapshots' +BASE_URL_RECENT = 'http://build.chromium.org/f/chromium/snapshots' # URL to the ViewVC commit page. BUILD_VIEWVC_URL = 'http://src.chromium.org/viewvc/chrome?view=rev&revision=%d' @@ -39,12 +40,13 @@ import zipfile class PathContext(object): """A PathContext is used to carry the information used to construct URLs and paths when dealing with the storage server and archives.""" - def __init__(self, platform, good_revision, bad_revision): + def __init__(self, platform, good_revision, bad_revision, use_recent): super(PathContext, self).__init__() # Store off the input parameters. self.platform = platform # What's passed in to the '-a/--archive' option. self.good_revision = good_revision self.bad_revision = bad_revision + self.use_recent = use_recent # The name of the ZIP file in a revision directory on the server. self.archive_name = None @@ -82,10 +84,19 @@ class PathContext(object): return BASE_URL + '/?delimiter=/&prefix=' + self._listing_platform_dir + \ marker_param + def GetListingURLRecent(self): + """Returns the URL for a directory listing of recent builds.""" + return BASE_URL_RECENT + '/' + self._listing_platform_dir + def GetDownloadURL(self, revision): """Gets the download URL for a build archive of a specific revision.""" - return "%s/%s%d/%s" % ( - BASE_URL, self._listing_platform_dir, revision, self.archive_name) + if self.use_recent: + return "%s/%s%d/%s" % ( + BASE_URL_RECENT, self._listing_platform_dir, revision, + self.archive_name) + else: + return "%s/%s%d/%s" % ( + BASE_URL, self._listing_platform_dir, revision, self.archive_name) def GetLastChangeURL(self): """Returns a URL to the LAST_CHANGE file.""" @@ -183,12 +194,27 @@ def ParseDirectoryIndex(context): return revisions +def ParseDirectoryIndexRecent(context): + """Parses the recent builds directory listing into a list of revision + numbers.""" + handle = urllib.urlopen(context.GetListingURLRecent()) + document = handle.read() + + # Looking for: <a href="92976/">92976/</a> + return re.findall(r"<a href=\"(\d+)/\">\1/</a>", document) + + def GetRevList(context): """Gets the list of revision numbers between |good_revision| and |bad_revision| of the |context|.""" # Download the revlist and filter for just the range between good and bad. rev_range = range(context.good_revision, context.bad_revision) - revlist = map(int, ParseDirectoryIndex(context)) + revisions = [] + if context.use_recent: + revisions = ParseDirectoryIndexRecent(context) + else: + revisions = ParseDirectoryIndex(context) + revlist = map(int, revisions) revlist = filter(lambda r: r in rev_range, revlist) revlist.sort() return revlist @@ -219,6 +245,8 @@ def TryRevision(context, rev, profile, args): print 'Fetching ' + download_url urllib.urlretrieve(download_url, context.archive_name, _ReportHook) print + # Throw an exception if the download was less than 1000 bytes. + if os.path.getsize(context.archive_name) < 1000: raise Exception() except Exception, e: print('Could not retrieve the download. Sorry.') sys.exit(-1) @@ -251,9 +279,7 @@ def AskIsGoodBuild(rev): return response == 'g' -def Bisect(good, - bad, - revlist, +def Bisect(revlist, context, try_args=(), profile='profile', @@ -261,8 +287,6 @@ def Bisect(good, """Tries to find the exact commit where a regression was introduced by running a binary search on all archived builds in a given revision range. - @param good The index in revlist of the last known good revision. - @param bad The index in revlist of the first known bad revision. @param revlist A list of chromium revision numbers to check. @param context A PathContext object. @param try_args A tuple of arguments to pass to the predicate function. @@ -271,6 +295,8 @@ def Bisect(good, chromium revision is good. """ + good = 0 + bad = len(revlist) - 1 last_known_good_rev = revlist[good] first_known_bad_rev = revlist[bad] @@ -291,7 +317,7 @@ def Bisect(good, # Let the user give this rev a spin (in her own profile, if she wants). TryRevision(context, test_rev, profile, try_args) if predicate(test_rev): - last_known_good_rev = revlist[good] + last_known_good_rev = test_rev good = test + 1 else: bad = test @@ -319,6 +345,12 @@ def main(): parser.add_option('-p', '--profile', '--user-data-dir', type = 'str', help = 'Profile to use; this will not reset every run. ' + 'Defaults to a clean profile.', default = 'profile') + parser.add_option('-r', '--recent', + dest = "recent", + default = False, + action = "store_true", + help = 'Use recent builds from about the last 2 months ' + + 'for higher granularity bisecting.') (opts, args) = parser.parse_args() if opts.archive is None: @@ -334,7 +366,7 @@ def main(): return 1 # Create the context. Initialize 0 for the revisions as they are set below. - context = PathContext(opts.archive, 0, 0) + context = PathContext(opts.archive, 0, 0, opts.recent) # Pick a starting point, try to get HEAD for this. if opts.bad: @@ -374,16 +406,8 @@ def main(): print 'We don\'t have enough builds to bisect. revlist: %s' % revlist sys.exit(1) - # If we don't have a |good_rev|, set it to be the first revision possible. - if good_rev == 0: - good_rev = revlist[0] - - # These are indexes of |revlist|. - good = 0 - bad = len(revlist) - 1 - (last_known_good_rev, first_known_bad_rev) = Bisect( - good, bad, revlist, context, args, opts.profile) + revlist, context, args, opts.profile) # We're done. Let the user know the results in an official manner. print('You are probably looking for build %d.' % first_known_bad_rev) |