OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/python |
| 2 # |
| 3 # Copyright 2015 The Chromium Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. |
| 6 |
| 7 """Gets list of revisions between two commits and their commit positions. |
| 8 |
| 9 Example usage: |
| 10 ./fetchInterveningRevisions.py 343b531d31 7b43807df3 chromium |
| 11 ./fetchInterveningRevisions.py 235eff9574 1e4681c33f v8 |
| 12 |
| 13 Note: Another implementation of this functionality can be found in |
| 14 findit/common/gitRepository.py (https://goo.gl/Rr8j9O). |
| 15 """ |
| 16 |
| 17 import argparse |
| 18 import json |
| 19 import os |
| 20 import re |
| 21 import sys |
| 22 import urllib2 |
| 23 |
| 24 import depot_map # pylint: disable=relative-import |
| 25 |
| 26 _GITILES_PADDING = ')]}\'\n' |
| 27 _URL_TEMPLATE = ('https://chromium.googlesource.com/%s/+log/%s..%s' |
| 28 '?format=json&n=%d') |
| 29 |
| 30 # Gitiles paginates the list of commits; since we want to get all of the |
| 31 # commits at once, the page size should be larger than the largest revision |
| 32 # range that we expect to get. |
| 33 _PAGE_SIZE = 512 |
| 34 |
| 35 def FetchInterveningRevisions(start, end, depot_name): |
| 36 """Fetches a list of revision in between two commits. |
| 37 |
| 38 Args: |
| 39 start (str): A git commit hash in the Chromium src repository. |
| 40 end (str): Another git commit hash, after start. |
| 41 depot_name (str): A respository name. |
| 42 |
| 43 Returns: |
| 44 A list of pairs (commit hash, commit position), from earliest to latest, |
| 45 for all commits in between the two given commits, not including either |
| 46 of the given commits. |
| 47 |
| 48 Raises: |
| 49 urllib2.URLError: The request to gitiles failed. |
| 50 ValueError: The response wasn't valid JSON. |
| 51 KeyError: The JSON didn't contain the expected data. |
| 52 """ |
| 53 revisions = _FetchRangeFromGitiles(start, end, depot_name) |
| 54 # The response from gitiles includes the end revision and is ordered |
| 55 # from latest to earliest. |
| 56 return [_CommitPair(r) for r in reversed(revisions[1:])] |
| 57 |
| 58 |
| 59 def _FetchRangeFromGitiles(start, end, depot_name): |
| 60 """Fetches a list of revision dicts from gitiles. |
| 61 |
| 62 Make multiple requests to get multiple pages, if necessary. |
| 63 """ |
| 64 revisions = [] |
| 65 url = _URL_TEMPLATE % ( |
| 66 depot_map.DEPOT_PATH_MAP[depot_name], start, end, _PAGE_SIZE) |
| 67 current_page_url = url |
| 68 while True: |
| 69 response = urllib2.urlopen(current_page_url).read() |
| 70 response_json = response[len(_GITILES_PADDING):] # Remove padding. |
| 71 response_dict = json.loads(response_json) |
| 72 revisions.extend(response_dict['log']) |
| 73 if 'next' not in response_dict: |
| 74 break |
| 75 current_page_url = url + '&s=' + response_dict['next'] |
| 76 return revisions |
| 77 |
| 78 |
| 79 def _CommitPair(commit_dict): |
| 80 return (commit_dict['commit'], |
| 81 _CommitPositionFromMessage(commit_dict['message'])) |
| 82 |
| 83 |
| 84 def _CommitPositionFromMessage(message): |
| 85 for line in reversed(message.splitlines()): |
| 86 if line.startswith('Cr-Commit-Position:'): |
| 87 return line.split('#')[1].split('}')[0] |
| 88 return None |
| 89 |
| 90 |
| 91 def Main(): |
| 92 parser = argparse.ArgumentParser() |
| 93 parser.addArgument('start') |
| 94 parser.addArgument('end') |
| 95 parser.addArgument('depot', choices=list(depot_map.DEPOT_PATH_MAP)) |
| 96 args = parser.parseArgs() |
| 97 revision_pairs = FetchInterveningRevisions(args.start, args.end, args.depot) |
| 98 print json.dumps(revision_pairs) |
| 99 |
| 100 |
| 101 if __name__ == '__main__': |
| 102 Main() |
OLD | NEW |