| Björn Pedersen | c357ceb | 2015-05-27 10:17:36 +0200 | [diff] [blame] | 1 | #!/usr/bin/env python | 
| Dave Borowitz | 1b46d67 | 2014-10-02 09:18:19 -0700 | [diff] [blame] | 2 | # Copyright (C) 2014 The Android Open Source Project | 
|  | 3 | # | 
|  | 4 | # Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 5 | # you may not use this file except in compliance with the License. | 
|  | 6 | # You may obtain a copy of the License at | 
|  | 7 | # | 
|  | 8 | # http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 9 | # | 
|  | 10 | # Unless required by applicable law or agreed to in writing, software | 
|  | 11 | # distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 13 | # See the License for the specific language governing permissions and | 
|  | 14 | # limitations under the License. | 
|  | 15 |  | 
|  | 16 | from __future__ import print_function | 
|  | 17 |  | 
|  | 18 | import argparse | 
|  | 19 | import collections | 
|  | 20 | import os | 
|  | 21 | import subprocess | 
|  | 22 | import sys | 
|  | 23 |  | 
|  | 24 |  | 
|  | 25 | def get_config(name): | 
|  | 26 | args = ['git', 'config', '--get', name] | 
|  | 27 | p = subprocess.Popen(args, stdout=subprocess.PIPE) | 
|  | 28 | out, _ = p.communicate() | 
|  | 29 | ret = p.poll() | 
|  | 30 | if ret not in (0, 1): | 
|  | 31 | raise subprocess.CalledProcessError(ret, ' '.join(args), output=out) | 
|  | 32 | return out.strip() | 
|  | 33 |  | 
|  | 34 |  | 
|  | 35 | def deref(name): | 
|  | 36 | p = subprocess.Popen( | 
|  | 37 | ['git', 'rev-parse', '--symbolic-full-name', name], | 
|  | 38 | stdout=subprocess.PIPE, stderr=subprocess.PIPE) | 
|  | 39 | out, _ = p.communicate() | 
|  | 40 | return out.strip() | 
|  | 41 |  | 
|  | 42 |  | 
|  | 43 | def main(argv): | 
|  | 44 | p = argparse.ArgumentParser(description='Push changes to Gerrit for review') | 
|  | 45 | p.add_argument('-r', '--remote', default='', metavar='REMOTE', | 
|  | 46 | help='remote name or URL to push to') | 
|  | 47 | p.add_argument('-b', '--branch', default='', metavar='BRANCH', | 
|  | 48 | help='remote branch name, refs/for/BRANCH') | 
| Dave Borowitz | 053b7a6e | 2016-09-22 09:20:13 +0200 | [diff] [blame] | 49 | p.add_argument('args', nargs='*', metavar='REVIEWER_OR_HASHTAG', | 
|  | 50 | help='reviewer names or aliases, or #hashtags') | 
| Dave Borowitz | 1b46d67 | 2014-10-02 09:18:19 -0700 | [diff] [blame] | 51 | p.add_argument('-t', '--topic', default='', metavar='TOPIC', | 
|  | 52 | help='topic for new changes') | 
|  | 53 | p.add_argument('--dry-run', action='store_true', | 
|  | 54 | help='dry run, print git command and exit') | 
|  | 55 | args = p.parse_args() | 
|  | 56 |  | 
|  | 57 | if not args.remote or not args.branch: | 
|  | 58 | hp = 'refs/heads/' | 
|  | 59 | upstream = deref('HEAD') | 
|  | 60 | while upstream.startswith(hp): | 
|  | 61 | upstream = deref(upstream[len(hp):] + '@{u}') | 
|  | 62 |  | 
|  | 63 | rp = 'refs/remotes/' | 
|  | 64 | if upstream.startswith(rp): | 
|  | 65 | def_remote, def_branch = upstream[len(rp):].split('/', 1) | 
|  | 66 | else: | 
|  | 67 | def_remote, def_branch = 'origin', 'master' | 
|  | 68 | args.remote = args.remote or def_remote | 
|  | 69 | args.branch = args.branch or def_branch | 
|  | 70 |  | 
| Dave Borowitz | 053b7a6e | 2016-09-22 09:20:13 +0200 | [diff] [blame] | 71 |  | 
| Dave Borowitz | 1b46d67 | 2014-10-02 09:18:19 -0700 | [diff] [blame] | 72 | opts = collections.defaultdict(list) | 
| Dave Borowitz | 053b7a6e | 2016-09-22 09:20:13 +0200 | [diff] [blame] | 73 | is_hashtag = lambda x: x.startswith('#') | 
|  | 74 | opts['r'].extend( | 
| Dave Borowitz | e7d88cd | 2016-10-04 11:47:33 -0400 | [diff] [blame] | 75 | (get_config('reviewer.' + r) or r) | 
|  | 76 | for r in args.args if not is_hashtag(r)) | 
| Dave Borowitz | 053b7a6e | 2016-09-22 09:20:13 +0200 | [diff] [blame] | 77 | opts['t'].extend(t[1:] for t in args.args if is_hashtag(t)) | 
| Dave Borowitz | 1b46d67 | 2014-10-02 09:18:19 -0700 | [diff] [blame] | 78 | if args.topic: | 
|  | 79 | opts['topic'].append(args.topic) | 
|  | 80 | opts_str = ','.join('%s=%s' % (k, v) for k in opts for v in opts[k]) | 
|  | 81 | if opts_str: | 
|  | 82 | opts_str = '%' + opts_str | 
|  | 83 |  | 
|  | 84 | git_args = ['git', 'push', args.remote, | 
|  | 85 | 'HEAD:refs/for/%s%s' % (args.branch, opts_str)] | 
|  | 86 | if args.dry_run: | 
|  | 87 | print(' '.join(git_args)) | 
|  | 88 | return 0 | 
|  | 89 | os.execvp('git', git_args) | 
|  | 90 |  | 
|  | 91 |  | 
|  | 92 | if __name__ == '__main__': | 
|  | 93 | sys.exit(main(sys.argv)) |