|  | #!/usr/bin/env python | 
|  | # Copyright (C) 2014 The Android Open Source Project | 
|  | # | 
|  | # Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | # you may not use this file except in compliance with the License. | 
|  | # You may obtain a copy of the License at | 
|  | # | 
|  | # http://www.apache.org/licenses/LICENSE-2.0 | 
|  | # | 
|  | # Unless required by applicable law or agreed to in writing, software | 
|  | # distributed under the License is distributed on an "AS IS" BASIS, | 
|  | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | # See the License for the specific language governing permissions and | 
|  | # limitations under the License. | 
|  |  | 
|  | from __future__ import print_function | 
|  |  | 
|  | import argparse | 
|  | import collections | 
|  | import os | 
|  | import subprocess | 
|  | import sys | 
|  |  | 
|  |  | 
|  | def get_config(name): | 
|  | args = ['git', 'config', '--get', name] | 
|  | p = subprocess.Popen(args, stdout=subprocess.PIPE) | 
|  | out, _ = p.communicate() | 
|  | ret = p.poll() | 
|  | if ret not in (0, 1): | 
|  | raise subprocess.CalledProcessError(ret, ' '.join(args), output=out) | 
|  | return out.strip() | 
|  |  | 
|  |  | 
|  | def deref(name): | 
|  | p = subprocess.Popen( | 
|  | ['git', 'rev-parse', '--symbolic-full-name', name], | 
|  | stdout=subprocess.PIPE, stderr=subprocess.PIPE) | 
|  | out, _ = p.communicate() | 
|  | return out.strip() | 
|  |  | 
|  |  | 
|  | def main(argv): | 
|  | p = argparse.ArgumentParser(description='Push changes to Gerrit for review') | 
|  | p.add_argument('-r', '--remote', default='', metavar='REMOTE', | 
|  | help='remote name or URL to push to') | 
|  | p.add_argument('-b', '--branch', default='', metavar='BRANCH', | 
|  | help='remote branch name, refs/for/BRANCH') | 
|  | p.add_argument('args', nargs='*', metavar='REVIEWER_OR_HASHTAG', | 
|  | help='reviewer names or aliases, or #hashtags') | 
|  | p.add_argument('-t', '--topic', default='', metavar='TOPIC', | 
|  | help='topic for new changes') | 
|  | p.add_argument('--dry-run', action='store_true', | 
|  | help='dry run, print git command and exit') | 
|  | args = p.parse_args() | 
|  |  | 
|  | if not args.remote or not args.branch: | 
|  | hp = 'refs/heads/' | 
|  | upstream = deref('HEAD') | 
|  | while upstream.startswith(hp): | 
|  | upstream = deref(upstream[len(hp):] + '@{u}') | 
|  |  | 
|  | rp = 'refs/remotes/' | 
|  | if upstream.startswith(rp): | 
|  | def_remote, def_branch = upstream[len(rp):].split('/', 1) | 
|  | else: | 
|  | def_remote, def_branch = 'origin', 'master' | 
|  | args.remote = args.remote or def_remote | 
|  | args.branch = args.branch or def_branch | 
|  |  | 
|  |  | 
|  | opts = collections.defaultdict(list) | 
|  | is_hashtag = lambda x: x.startswith('#') | 
|  | opts['r'].extend( | 
|  | (get_config('reviewer.' + r) or r) | 
|  | for r in args.args if not is_hashtag(r)) | 
|  | opts['t'].extend(t[1:] for t in args.args if is_hashtag(t)) | 
|  | if args.topic: | 
|  | opts['topic'].append(args.topic) | 
|  | opts_str = ','.join('%s=%s' % (k, v) for k in opts for v in opts[k]) | 
|  | if opts_str: | 
|  | opts_str = '%' + opts_str | 
|  |  | 
|  | git_args = ['git', 'push', args.remote, | 
|  | 'HEAD:refs/for/%s%s' % (args.branch, opts_str)] | 
|  | if args.dry_run: | 
|  | print(' '.join(git_args)) | 
|  | return 0 | 
|  | os.execvp('git', git_args) | 
|  |  | 
|  |  | 
|  | if __name__ == '__main__': | 
|  | sys.exit(main(sys.argv)) |