OLD | NEW |
1 # Copyright 2014 The Chromium Authors. All rights reserved. | 1 # Copyright 2014 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 # Monkeypatch IMapIterator so that Ctrl-C can kill everything properly. | 5 # Monkeypatch IMapIterator so that Ctrl-C can kill everything properly. |
6 # Derived from https://gist.github.com/aljungberg/626518 | 6 # Derived from https://gist.github.com/aljungberg/626518 |
7 import multiprocessing.pool | 7 import multiprocessing.pool |
8 from multiprocessing.pool import IMapIterator | 8 from multiprocessing.pool import IMapIterator |
9 def wrapper(func): | 9 def wrapper(func): |
10 def wrap(self, timeout=None): | 10 def wrap(self, timeout=None): |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
84 # crbug.com/315421 | 84 # crbug.com/315421 |
85 r'The requested URL returned error: 500 while accessing', | 85 r'The requested URL returned error: 500 while accessing', |
86 | 86 |
87 # crbug.com/388876 | 87 # crbug.com/388876 |
88 r'Connection timed out', | 88 r'Connection timed out', |
89 ) | 89 ) |
90 | 90 |
91 GIT_TRANSIENT_ERRORS_RE = re.compile('|'.join(GIT_TRANSIENT_ERRORS), | 91 GIT_TRANSIENT_ERRORS_RE = re.compile('|'.join(GIT_TRANSIENT_ERRORS), |
92 re.IGNORECASE) | 92 re.IGNORECASE) |
93 | 93 |
| 94 # First version where the for-each-ref command's format string supported the |
| 95 # upstream:track token. |
| 96 MIN_UPSTREAM_TRACK_GIT_VERSION = (1, 9) |
94 | 97 |
95 class BadCommitRefException(Exception): | 98 class BadCommitRefException(Exception): |
96 def __init__(self, refs): | 99 def __init__(self, refs): |
97 msg = ('one of %s does not seem to be a valid commitref.' % | 100 msg = ('one of %s does not seem to be a valid commitref.' % |
98 str(refs)) | 101 str(refs)) |
99 super(BadCommitRefException, self).__init__(msg) | 102 super(BadCommitRefException, self).__init__(msg) |
100 | 103 |
101 | 104 |
102 def memoize_one(**kwargs): | 105 def memoize_one(**kwargs): |
103 """Memoizes a single-argument pure function. | 106 """Memoizes a single-argument pure function. |
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
429 base = actual_merge_base | 432 base = actual_merge_base |
430 manual_merge_base(branch, base, parent) | 433 manual_merge_base(branch, base, parent) |
431 | 434 |
432 return base | 435 return base |
433 | 436 |
434 | 437 |
435 def hash_multi(*reflike): | 438 def hash_multi(*reflike): |
436 return run('rev-parse', *reflike).splitlines() | 439 return run('rev-parse', *reflike).splitlines() |
437 | 440 |
438 | 441 |
439 def hash_one(reflike): | 442 def hash_one(reflike, short=False): |
440 return run('rev-parse', reflike) | 443 args = ['rev-parse', reflike] |
| 444 if short: |
| 445 args.insert(1, '--short') |
| 446 return run(*args) |
441 | 447 |
442 | 448 |
443 def in_rebase(): | 449 def in_rebase(): |
444 git_dir = run('rev-parse', '--git-dir') | 450 git_dir = run('rev-parse', '--git-dir') |
445 return ( | 451 return ( |
446 os.path.exists(os.path.join(git_dir, 'rebase-merge')) or | 452 os.path.exists(os.path.join(git_dir, 'rebase-merge')) or |
447 os.path.exists(os.path.join(git_dir, 'rebase-apply'))) | 453 os.path.exists(os.path.join(git_dir, 'rebase-apply'))) |
448 | 454 |
449 | 455 |
450 def intern_f(f, kind='blob'): | 456 def intern_f(f, kind='blob'): |
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
709 return None | 715 return None |
710 return ret | 716 return ret |
711 | 717 |
712 | 718 |
713 def upstream(branch): | 719 def upstream(branch): |
714 try: | 720 try: |
715 return run('rev-parse', '--abbrev-ref', '--symbolic-full-name', | 721 return run('rev-parse', '--abbrev-ref', '--symbolic-full-name', |
716 branch+'@{upstream}') | 722 branch+'@{upstream}') |
717 except subprocess2.CalledProcessError: | 723 except subprocess2.CalledProcessError: |
718 return None | 724 return None |
| 725 |
| 726 def get_git_version(): |
| 727 """Returns a tuple that contains the numeric components of the current git |
| 728 version.""" |
| 729 version_string = run('--version') |
| 730 version_match = re.search(r'(\d+.)+(\d+)', version_string) |
| 731 version = version_match.group() if version_match else '' |
| 732 |
| 733 return tuple(int(x) for x in version.split('.')) |
| 734 |
| 735 |
| 736 def get_all_tracking_info(): |
| 737 format_string = ( |
| 738 '--format=%(refname:short):%(objectname:short):%(upstream:short):') |
| 739 |
| 740 # This is not covered by the depot_tools CQ which only has git version 1.8. |
| 741 if get_git_version() >= MIN_UPSTREAM_TRACK_GIT_VERSION: # pragma: no cover |
| 742 format_string += '%(upstream:track)' |
| 743 |
| 744 info_map = {} |
| 745 data = run('for-each-ref', format_string, 'refs/heads') |
| 746 TrackingInfo = collections.namedtuple( |
| 747 'TrackingInfo', 'hash upstream ahead behind') |
| 748 for line in data.splitlines(): |
| 749 (branch, branch_hash, upstream_branch, tracking_status) = line.split(':') |
| 750 |
| 751 ahead_match = re.search(r'ahead (\d+)', tracking_status) |
| 752 ahead = int(ahead_match.group(1)) if ahead_match else None |
| 753 |
| 754 behind_match = re.search(r'behind (\d+)', tracking_status) |
| 755 behind = int(behind_match.group(1)) if behind_match else None |
| 756 |
| 757 info_map[branch] = TrackingInfo( |
| 758 hash=branch_hash, upstream=upstream_branch, ahead=ahead, behind=behind) |
| 759 |
| 760 # Set None for upstreams which are not branches (e.g empty upstream, remotes |
| 761 # and deleted upstream branches). |
| 762 missing_upstreams = {} |
| 763 for info in info_map.values(): |
| 764 if info.upstream not in info_map and info.upstream not in missing_upstreams: |
| 765 missing_upstreams[info.upstream] = None |
| 766 |
| 767 return dict(info_map.items() + missing_upstreams.items()) |
OLD | NEW |