Index: experimental/bisect_lib/fetch_intervening_revisions.py |
diff --git a/experimental/bisect_lib/fetch_intervening_revisions.py b/experimental/bisect_lib/fetch_intervening_revisions.py |
new file mode 100755 |
index 0000000000000000000000000000000000000000..6b86ca243ea369296e6ca72b2ea7da84bb16b12c |
--- /dev/null |
+++ b/experimental/bisect_lib/fetch_intervening_revisions.py |
@@ -0,0 +1,102 @@ |
+#!/usr/bin/python |
+# |
+# Copyright 2015 The Chromium Authors. All rights reserved. |
+# Use of this source code is governed by a BSD-style license that can be |
+# found in the LICENSE file. |
+ |
+"""Gets list of revisions between two commits and their commit positions. |
+ |
+Example usage: |
+ ./fetchInterveningRevisions.py 343b531d31 7b43807df3 chromium |
+ ./fetchInterveningRevisions.py 235eff9574 1e4681c33f v8 |
+ |
+Note: Another implementation of this functionality can be found in |
+findit/common/gitRepository.py (https://goo.gl/Rr8j9O). |
+""" |
+ |
+import argparse |
+import json |
+import os |
+import re |
+import sys |
+import urllib2 |
+ |
+import depot_map # pylint: disable=relative-import |
+ |
+_GITILES_PADDING = ')]}\'\n' |
+_URL_TEMPLATE = ('https://chromium.googlesource.com/%s/+log/%s..%s' |
+ '?format=json&n=%d') |
+ |
+# Gitiles paginates the list of commits; since we want to get all of the |
+# commits at once, the page size should be larger than the largest revision |
+# range that we expect to get. |
+_PAGE_SIZE = 512 |
+ |
+def FetchInterveningRevisions(start, end, depot_name): |
+ """Fetches a list of revision in between two commits. |
+ |
+ Args: |
+ start (str): A git commit hash in the Chromium src repository. |
+ end (str): Another git commit hash, after start. |
+ depot_name (str): A respository name. |
+ |
+ Returns: |
+ A list of pairs (commit hash, commit position), from earliest to latest, |
+ for all commits in between the two given commits, not including either |
+ of the given commits. |
+ |
+ Raises: |
+ urllib2.URLError: The request to gitiles failed. |
+ ValueError: The response wasn't valid JSON. |
+ KeyError: The JSON didn't contain the expected data. |
+ """ |
+ revisions = _FetchRangeFromGitiles(start, end, depot_name) |
+ # The response from gitiles includes the end revision and is ordered |
+ # from latest to earliest. |
+ return [_CommitPair(r) for r in reversed(revisions[1:])] |
+ |
+ |
+def _FetchRangeFromGitiles(start, end, depot_name): |
+ """Fetches a list of revision dicts from gitiles. |
+ |
+ Make multiple requests to get multiple pages, if necessary. |
+ """ |
+ revisions = [] |
+ url = _URL_TEMPLATE % ( |
+ depot_map.DEPOT_PATH_MAP[depot_name], start, end, _PAGE_SIZE) |
+ current_page_url = url |
+ while True: |
+ response = urllib2.urlopen(current_page_url).read() |
+ response_json = response[len(_GITILES_PADDING):] # Remove padding. |
+ response_dict = json.loads(response_json) |
+ revisions.extend(response_dict['log']) |
+ if 'next' not in response_dict: |
+ break |
+ current_page_url = url + '&s=' + response_dict['next'] |
+ return revisions |
+ |
+ |
+def _CommitPair(commit_dict): |
+ return (commit_dict['commit'], |
+ _CommitPositionFromMessage(commit_dict['message'])) |
+ |
+ |
+def _CommitPositionFromMessage(message): |
+ for line in reversed(message.splitlines()): |
+ if line.startswith('Cr-Commit-Position:'): |
+ return line.split('#')[1].split('}')[0] |
+ return None |
+ |
+ |
+def Main(): |
+ parser = argparse.ArgumentParser() |
+ parser.addArgument('start') |
+ parser.addArgument('end') |
+ parser.addArgument('depot', choices=list(depot_map.DEPOT_PATH_MAP)) |
+ args = parser.parseArgs() |
+ revision_pairs = FetchInterveningRevisions(args.start, args.end, args.depot) |
+ print json.dumps(revision_pairs) |
+ |
+ |
+if __name__ == '__main__': |
+ Main() |