From 6c6826b7ba73f5d3a74da9fd64cab8fb95d7186e Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sat, 28 Sep 2019 03:22:16 -0400 Subject: [PATCH] cros-repo: rewrite in python --- .bin/cros-repo | 272 ++++++++++++++++++++++++++++++------------------- 1 file changed, 169 insertions(+), 103 deletions(-) diff --git a/.bin/cros-repo b/.bin/cros-repo index 8f8765b..474b1aa 100755 --- a/.bin/cros-repo +++ b/.bin/cros-repo @@ -1,103 +1,169 @@ -#!/bin/bash - -usage() { - cat <<-EOF - Usage: repo-cros [options] - - Options: - depot_tools clone depot_tools tree - int switch to internal tree - ext switch to external tree - -b switch branches (use "master" to get to ToT) - -r patch to reference repo (e.g. ~/chromiumos/) - -g - -m - -e - - Operates on the repo in ${PWD} - EOF - exit ${1:-1} -} - -v() { - printf '%s\n%s\n' "${PWD}" "$*" - "$@" -} - -email="vapier@chromium.org" -REF= -BRANCH= -MANIFEST= -MANIFEST_NAME= -RGROUPS=() -REPO_URL= -while [[ $# -gt 0 ]] ; do - case $1 in - depot_tools|dt) - exec git clone https://git.chromium.org/chromium/tools/depot_tools.git - ;; - int) - MANIFEST='https://chrome-internal.googlesource.com/chromeos/manifest-internal.git' - REPO_URL='https://chromium.googlesource.com/external/repo.git' - ;; - ext) - MANIFEST='https://chromium.googlesource.com/chromiumos/manifest.git' - REPO_URL='https://chromium.googlesource.com/external/repo.git' - ;; - -b) - BRANCH=$2 - shift - ;; - -r) - REF=$(realpath "${2:-$(echo ~/chromiumos)}") - shift - ;; - -g) - RGROUPS+=( "$2" ) - shift - ;; - -m) - MANIFEST_NAME="${2%.xml}.xml" - shift - ;; - -e) - email=$2 - shift - ;; - *) - usage - ;; - esac - shift -done - -if [[ ${#BRANCH} -eq 3 ]] && [[ -d ${REF} ]] ; then - BRANCH=$(git --git-dir="${REF}/.repo/manifests.git" branch -a | grep -o "release-${BRANCH}.*") -fi - -v repo init \ - ${MANIFEST:+-u "${MANIFEST}"} \ - ${REPO_URL:+--repo-url="${REPO_URL}"} \ - ${REF:+--reference "${REF}"} \ - ${MANIFEST_NAME:+-m "${MANIFEST_NAME}"} \ - ${RGROUPS:+-g "${RGROUPS[*]}"} \ - ${BRANCH:+-b "${BRANCH}"} - -rdir=$(realpath "`pwd`") -while [[ ! -d ${rdir}/.repo ]] ; do - rdir=${rdir%/*} - [[ ${rdir:-/} == "/" ]] && break -done -rdir+="/.repo" -if [[ -d ${rdir} ]] ; then - gcfg() { git --git-dir="$1" config user.email "${@:2}" ; } - if [[ $(gcfg "${rdir}/manifests.git") != "${email}" ]] ; then - echo "${rdir}: setting e-mail to ${email}" - find "${rdir}" -type d -name '*.git' | \ - while read d ; do - gcfg "${d}" ${email} - done - fi -fi - -exit 0 +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +"""Wrapper for syncing CrOS code. + +Actions: + depot_tools clone depot_tools tree + int switch to internal tree + ext switch to external tree + +Operates on the repo in the cwd. +""" + +import argparse +import fnmatch +import os +import subprocess +import sys + + +REPO_URL = 'https://chromium.googlesource.com/external/repo' +INT_MANIFEST = 'https://chrome-internal.googlesource.com/chromeos/manifest-internal' +EXT_MANIFEST = 'https://chromium.googlesource.com/chromiumos/manifest' + + +def run(cmd, **kwargs): + """Run with command tracing.""" + # Python 3.6 doesn't support capture_output. + if sys.version_info < (3, 7): + capture_output = kwargs.pop('capture_output', None) + if capture_output: + assert 'stdout' not in kwargs and 'stderr' not in kwargs + kwargs['stdout'] = subprocess.PIPE + kwargs['stderr'] = subprocess.PIPE + + print(kwargs.get('cwd', os.getcwd())) + print(' '.join(cmd)) + return subprocess.run(cmd, **kwargs) + + +def expand_branch(opts): + """Support branch shortnames.""" + url = INT_MANIFEST if opts.action == 'int' else EXT_MANIFEST + ret = run(['git', 'ls-remote', url, 'refs/heads/*'], capture_output=True, encoding='utf-8') + branches = [x.split()[-1].split('/')[-1] for x in ret.stdout.splitlines()] + ret = [] + for branch in branches: + if fnmatch.fnmatch(branch.lower(), f'*{opts.branch.lower()}*'): + ret.append(branch) + if not ret: + print(f'error: could not match branch {opts.branch}', file=sys.stderr) + print(f'Available branches:\n{" ".join(sorted(branches))}', file=sys.stderr) + sys.exit(1) + if len(ret) > 1: + print(f'error: too many branches match {opts.branch}:\n{" ".join(sorted(ret))}', + file=sys.stderr) + sys.exit(1) + print(f'Expanded branch {opts.branch} into {ret[0]}') + return ret[0] + + +def set_git_config(opts): + """Set .git/config settings in all the repos.""" + topdir = os.getcwd() + while True: + rdir = os.path.join(topdir, '.repo') + if os.path.exists(rdir): + break + topdir = os.path.dirname(topdir) + assert topdir != '/' + + def gcfg(path, *args): + cmd = ['git', f'--git-dir={path}', 'config', 'user.email'] + list(args) + ret = run(cmd, capture_output=True, encoding='utf-8') + return ret.stdout.strip() + + current_email = gcfg(os.path.join(rdir, 'manifests.git')) + if current_email == opts.email: + return + + print(f'Setting e-mail to {opts.email}') + for root, dirs, files in os.walk(rdir): + if root.endswith('.git') and not os.path.islink(os.path.join(root, 'config')): + gcfg(root, opts.email) + del dirs[:] + + +def init_repo(opts): + """Initialize CrOS checkout.""" + cmd = ['repo', 'init'] + + if opts.action == 'int': + cmd += ['-u', INT_MANIFEST] + cmd += ['--repo-url', REPO_URL] + elif opts.action == 'ext': + cmd += ['-u', EXT_MANIFEST] + cmd += ['--repo-url', REPO_URL] + + if opts.ref: + cmd += ['--reference', opts.ref] + + if opts.manifest: + cmd += ['-m', opts.manifest] + + if opts.group: + cmd += ['-g', opts.group] + + if opts.branch: + branch = expand_branch(opts) + cmd += ['-b', branch] + + ret = run(cmd) + if ret.returncode: + return ret.returncode + + set_git_config(opts) + + print('\ncros-repo: all done') + return 0 + + +def clone_depot_tools(): + """Clone depot_tools repo.""" + ret = run(['git', 'clone', 'https://chromium.googlesource.com/chromium/tools/depot_tools']) + return ret.returncode + + +def get_parser(): + """Get command line parser.""" + parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument('-b', '--branch', + help='Switch branches (use "master" to get to ToT)') + parser.add_argument('-r', '--ref', '--reference', default='~/chromiumos/', + help='Patch to reference repo (default: %(default)s)') + parser.add_argument('-g', '--group', + help='Manifest group to use (e.g. "minilayout")') + parser.add_argument('-m', '--manifest', + help='Manifest file name to use (e.g. "full.xml")') + parser.add_argument('-e', '--email', default='vapier@chromium.org', + help='E-mail address to force (default: %(default)s)') + parser.add_argument('action', nargs='?', + choices={'depot_tools', 'dt', 'int', 'ext'}, + help='What to do!') + return parser + + +def main(argv): + """The main func.""" + parser = get_parser() + opts = parser.parse_args(argv) + if opts.manifest: + if '/' in opts.manifest: + parser.error('manifest should be basename like "full.xml"') + if opts.manifest.endswith('.xml'): + opts.manifest = opts.manifest[:-4] + opts.manifest += '.xml' + if opts.ref: + opts.ref = os.path.expanduser(opts.ref) + + if opts.action in {'depot_tools', 'dt'}: + return clone_depot_tools() + else: + return init_repo(opts) + + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) -- 2.39.2