From bd2e580b4d2f4fc4db54574fb82b8a1274a7918e Mon Sep 17 00:00:00 2001 From: Luca Stefani Date: Wed, 1 Jul 2020 12:23:29 +0200 Subject: [PATCH] repo_pull: Automatically extract gerrit instance from `repo manifest` Test: ./development/tools/repo_pull/repo_pull.py pull topic:hidl-vndk Change-Id: I44974ec5df65e404591d35c39238d58207001110 --- tools/repo_pull/gerrit.py | 67 +++++++++++++++++++++++++++++++++- tools/repo_pull/repo_patch.py | 15 ++++++-- tools/repo_pull/repo_pull.py | 56 +++++++--------------------- tools/repo_pull/repo_review.py | 8 ++++ 4 files changed, 97 insertions(+), 49 deletions(-) diff --git a/tools/repo_pull/gerrit.py b/tools/repo_pull/gerrit.py index aca5c0f93..1fecafb55 100755 --- a/tools/repo_pull/gerrit.py +++ b/tools/repo_pull/gerrit.py @@ -25,6 +25,7 @@ import base64 import json import os import sys +import xml.dom.minidom try: from urllib.error import HTTPError # PY3 @@ -47,6 +48,47 @@ except ImportError: from urlparse import urlparse # PY2 +try: + from subprocess import PIPE, run # PY3.5 +except ImportError: + from subprocess import CalledProcessError, PIPE, Popen + + class CompletedProcess(object): + """Process execution result returned by subprocess.run().""" + # pylint: disable=too-few-public-methods + + def __init__(self, args, returncode, stdout, stderr): + self.args = args + self.returncode = returncode + self.stdout = stdout + self.stderr = stderr + + def run(*args, **kwargs): + """Run a command with subprocess.Popen() and redirect input/output.""" + + check = kwargs.pop('check', False) + + try: + stdin = kwargs.pop('input') + assert 'stdin' not in kwargs + kwargs['stdin'] = PIPE + except KeyError: + stdin = None + + proc = Popen(*args, **kwargs) + try: + stdout, stderr = proc.communicate(stdin) + except: + proc.kill() + proc.wait() + raise + returncode = proc.wait() + + if check and returncode: + raise CalledProcessError(returncode, args, stdout) + return CompletedProcess(args, returncode, stdout, stderr) + + def load_auth_credentials_from_file(cookie_file): """Load credentials from an opened .gitcookies file.""" credentials = {} @@ -285,14 +327,28 @@ def get_patch(url_opener, gerrit_url, change_id, revision_id='current'): finally: response_file.close() +def find_gerrit_name(): + """Find the gerrit instance specified in the default remote.""" + manifest_cmd = ['repo', 'manifest'] + raw_manifest_xml = run(manifest_cmd, stdout=PIPE, check=True).stdout + + manifest_xml = xml.dom.minidom.parseString(raw_manifest_xml) + default_remote = manifest_xml.getElementsByTagName('default')[0] + default_remote_name = default_remote.getAttribute('remote') + for remote in manifest_xml.getElementsByTagName('remote'): + name = remote.getAttribute('name') + review = remote.getAttribute('review') + if review and name == default_remote_name: + return review + + raise ValueError('cannot find gerrit URL from manifest') def _parse_args(): """Parse command line options.""" parser = argparse.ArgumentParser() parser.add_argument('query', help='Change list query string') - parser.add_argument('-g', '--gerrit', required=True, - help='Gerrit review URL') + parser.add_argument('-g', '--gerrit', help='Gerrit review URL') parser.add_argument('--gitcookies', default=os.path.expanduser('~/.gitcookies'), @@ -307,6 +363,13 @@ def main(): """Main function""" args = _parse_args() + if not args.gerrit: + try: + args.gerrit = find_gerrit_name() + except: + print('gerrit instance not found, use [-g GERRIT]') + sys.exit(1) + # Query change lists url_opener = create_url_opener_from_args(args) change_lists = query_change_lists( diff --git a/tools/repo_pull/repo_patch.py b/tools/repo_pull/repo_patch.py index 393870609..e2a0453fc 100755 --- a/tools/repo_pull/repo_patch.py +++ b/tools/repo_pull/repo_patch.py @@ -24,16 +24,16 @@ from __future__ import print_function import argparse import os -from gerrit import create_url_opener_from_args, query_change_lists, get_patch - +from gerrit import ( + create_url_opener_from_args, find_gerrit_name, query_change_lists, get_patch +) def _parse_args(): """Parse command line options.""" parser = argparse.ArgumentParser() parser.add_argument('query', help='Change list query string') - parser.add_argument('-g', '--gerrit', required=True, - help='Gerrit review URL') + parser.add_argument('-g', '--gerrit', help='Gerrit review URL') parser.add_argument('--gitcookies', default=os.path.expanduser('~/.gitcookies'), @@ -48,6 +48,13 @@ def main(): """Main function""" args = _parse_args() + if not args.gerrit: + try: + args.gerrit = find_gerrit_name() + except: + print('gerrit instance not found, use [-g GERRIT]') + sys.exit(1) + # Query change lists url_opener = create_url_opener_from_args(args) change_lists = query_change_lists( diff --git a/tools/repo_pull/repo_pull.py b/tools/repo_pull/repo_pull.py index d42361128..67916155a 100755 --- a/tools/repo_pull/repo_pull.py +++ b/tools/repo_pull/repo_pull.py @@ -31,7 +31,10 @@ import re import sys import xml.dom.minidom -from gerrit import create_url_opener_from_args, query_change_lists +from gerrit import ( + create_url_opener_from_args, find_gerrit_name, query_change_lists, run +) +from subprocess import PIPE try: # pylint: disable=redefined-builtin @@ -50,46 +53,6 @@ except ImportError: """Quote a string if it contains special characters.""" return txt if _SHELL_SIMPLE_PATTERN.match(txt) else json.dumps(txt) -try: - from subprocess import PIPE, run # PY3.5 -except ImportError: - from subprocess import CalledProcessError, PIPE, Popen - - class CompletedProcess(object): - """Process execution result returned by subprocess.run().""" - # pylint: disable=too-few-public-methods - - def __init__(self, args, returncode, stdout, stderr): - self.args = args - self.returncode = returncode - self.stdout = stdout - self.stderr = stderr - - def run(*args, **kwargs): - """Run a command with subprocess.Popen() and redirect input/output.""" - - check = kwargs.pop('check', False) - - try: - stdin = kwargs.pop('input') - assert 'stdin' not in kwargs - kwargs['stdin'] = PIPE - except KeyError: - stdin = None - - proc = Popen(*args, **kwargs) - try: - stdout, stderr = proc.communicate(stdin) - except: - proc.kill() - proc.wait() - raise - returncode = proc.wait() - - if check and returncode: - raise CalledProcessError(returncode, args, stdout) - return CompletedProcess(args, returncode, stdout, stderr) - if bytes is str: def write_bytes(data, file): # PY2 @@ -404,8 +367,7 @@ def _parse_args(): help='Commands') parser.add_argument('query', help='Change list query string') - parser.add_argument('-g', '--gerrit', required=True, - help='Gerrit review URL') + parser.add_argument('-g', '--gerrit', help='Gerrit review URL') parser.add_argument('--gitcookies', default=os.path.expanduser('~/.gitcookies'), @@ -451,6 +413,14 @@ def _get_local_branch_name_from_args(args): def main(): """Main function""" args = _parse_args() + + if not args.gerrit: + try: + args.gerrit = find_gerrit_name() + except: + print('gerrit instance not found, use [-g GERRIT]') + sys.exit(1) + if args.command == 'json': _main_json(args) elif args.command == 'bash': diff --git a/tools/repo_pull/repo_review.py b/tools/repo_pull/repo_review.py index 24f5da6b9..535f5249f 100755 --- a/tools/repo_pull/repo_review.py +++ b/tools/repo_pull/repo_review.py @@ -187,6 +187,14 @@ def main(): # Parse and check the command line options args = _parse_args() + + if not args.gerrit: + try: + args.gerrit = find_gerrit_name() + except: + print('gerrit instance not found, use [-g GERRIT]') + sys.exit(1) + if not _has_task(args): print('error: Either --label, --message, --submit, --abandon, ' '--add-hashtag, --remove-hashtag, --set-topic, --delete-topic, '