From d629fb40849ddc046a8255f5407ef588f49e32d8 Mon Sep 17 00:00:00 2001 From: "agable@chromium.org" Date: Wed, 1 Oct 2014 09:40:10 +0000 Subject: [PATCH] Introduct git-auto-svn This tool can automatically set up the necessary git-svn metadata for our repos that live in SVN but are mirrored to Chrome. R=iannucci@chromium.org, tandrii@chromium.org BUG=418973 Review URL: https://codereview.chromium.org/611253003 git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@292241 0039d316-1c4b-4281-b951-d872f2087c98 --- git-auto-svn | 9 + git_auto_svn.py | 96 +++ git_common.py | 20 +- git_footers.py | 2 + man/html/git-auto-svn.html | 837 ++++++++++++++++++++++++++ man/man1/git-auto-svn.1 | 113 ++++ man/src/_git-auto-svn_desc.helper.txt | 1 + man/src/git-auto-svn.txt | 69 +++ man/src/make_docs.sh | 1 + 9 files changed, 1139 insertions(+), 9 deletions(-) create mode 100755 git-auto-svn create mode 100755 git_auto_svn.py create mode 100644 man/html/git-auto-svn.html create mode 100644 man/man1/git-auto-svn.1 create mode 100644 man/src/_git-auto-svn_desc.helper.txt create mode 100644 man/src/git-auto-svn.txt diff --git a/git-auto-svn b/git-auto-svn new file mode 100755 index 000000000..b7da01492 --- /dev/null +++ b/git-auto-svn @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# git_map_branches.py -- a git-command for presenting a graphical view of git +# branches in the current repo, and their relationships to each other. + +. $(type -P python_git_runner.sh) diff --git a/git_auto_svn.py b/git_auto_svn.py new file mode 100755 index 000000000..8a35143c5 --- /dev/null +++ b/git_auto_svn.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Performs all git-svn setup steps necessary for 'git svn dcommit' to work. + +Assumes that trunk of the svn remote maps to master of the git remote. + +Example: +git clone https://chromium.googlesource.com/chromium/tools/depot_tools +cd depot_tools +git auto-svn +""" + +import argparse +import os +import sys +import urlparse + +import subprocess2 + +from git_common import run as run_git +from git_common import run_stream as run_git_stream +from git_common import set_config, root, ROOT +from git_footers import parse_footers, get_unique, GIT_SVN_ID_PATTERN + + +SVN_EXE = ROOT+'\\svn.bat' if sys.platform.startswith('win') else 'svn' + + +def run_svn(*cmd, **kwargs): + """Runs an svn command. + + Returns (stdout, stderr) as a pair of strings. + + Raises subprocess2.CalledProcessError on nonzero return code. + """ + kwargs.setdefault('stdin', subprocess2.PIPE) + kwargs.setdefault('stdout', subprocess2.PIPE) + kwargs.setdefault('stderr', subprocess2.PIPE) + + cmd = (SVN_EXE,) + cmd + proc = subprocess2.Popen(cmd, **kwargs) + ret, err = proc.communicate() + retcode = proc.wait() + if retcode != 0: + raise subprocess2.CalledProcessError(retcode, cmd, os.getcwd(), ret, err) + + return ret, err + + +def main(argv): + # No command line flags. Just use the parser to prevent people from trying + # to pass flags that don't do anything, and to provide 'usage'. + parser = argparse.ArgumentParser( + description='Automatically set up git-svn for a repo mirrored from svn.') + parser.parse_args(argv[1:]) + + upstream = root() + message = run_git('log', '-1', '--format=%B', upstream) + footers = parse_footers(message) + git_svn_id = get_unique(footers, 'git-svn-id') + match = GIT_SVN_ID_PATTERN.match(git_svn_id) + assert match, 'No valid git-svn-id footer found on %s.' % upstream + print 'Found git-svn-id footer %s on %s' % (match.group(1), upstream) + + parsed_svn = urlparse.urlparse(match.group(1)) + path_components = parsed_svn.path.split('/') + svn_repo = None + svn_path = None + for i in xrange(len(path_components)): + try: + maybe_repo = '%s://%s%s' % ( + parsed_svn.scheme, parsed_svn.netloc, '/'.join(path_components[:i+1])) + print 'Checking ', maybe_repo + run_svn('info', maybe_repo) + svn_repo = maybe_repo + svn_path = '/'.join(path_components[i+1:]) + break + except subprocess2.CalledProcessError: + continue + assert svn_repo is not None, 'Unable to find svn repo for %s' % match.group(1) + print 'Found upstream svn repo %s and path %s' % (svn_repo, svn_path) + + prefix = upstream.rsplit('/')[0] + run_git('svn', 'init', '--prefix=%s' % prefix, '-T', svn_path, svn_repo) + set_config('svn-remote.svn.fetch', + '%s:refs/remotes/%s' % (svn_path, upstream)) + print 'Configured metadata, running "git svn fetch". This may take some time.' + for line in run_git_stream('svn', 'fetch').xreadlines(): + print line.strip() + + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/git_common.py b/git_common.py index 2e268da0f..99ed53cc4 100644 --- a/git_common.py +++ b/git_common.py @@ -319,15 +319,6 @@ def branches(*args): yield line.split()[-1] -def run_with_retcode(*cmd, **kwargs): - """Run a command but only return the status code.""" - try: - run(*cmd, **kwargs) - return 0 - except subprocess2.CalledProcessError as cpe: - return cpe.returncode - - def config(option, default=None): try: return run('config', '--get', option) or default @@ -551,6 +542,15 @@ def run(*cmd, **kwargs): return run_with_stderr(*cmd, **kwargs)[0] +def run_with_retcode(*cmd, **kwargs): + """Run a command but only return the status code.""" + try: + run(*cmd, **kwargs) + return 0 + except subprocess2.CalledProcessError as cpe: + return cpe.returncode + + def run_stream(*cmd, **kwargs): """Runs a git command. Returns stdout as a PIPE (file-like object). @@ -600,6 +600,7 @@ def set_branch_config(branch, option, value, scope='local'): def set_config(option, value, scope='local'): run('config', '--' + scope, option, value) + def squash_current_branch(header=None, merge_base=None): header = header or 'git squash commit.' merge_base = merge_base or get_or_create_merge_base(current_branch()) @@ -723,6 +724,7 @@ def upstream(branch): except subprocess2.CalledProcessError: return None + def get_git_version(): """Returns a tuple that contains the numeric components of the current git version.""" diff --git a/git_footers.py b/git_footers.py index 6e8136b35..fe72e18a9 100755 --- a/git_footers.py +++ b/git_footers.py @@ -11,10 +11,12 @@ from collections import defaultdict import git_common as git + FOOTER_PATTERN = re.compile(r'^\s*([\w-]+): (.*)$') CHROME_COMMIT_POSITION_PATTERN = re.compile(r'^([\w/-]+)@{#(\d+)}$') GIT_SVN_ID_PATTERN = re.compile('^([^\s@]+)@(\d+)') + def normalize_name(header): return '-'.join([ word.title() for word in header.strip().split('-') ]) diff --git a/man/html/git-auto-svn.html b/man/html/git-auto-svn.html new file mode 100644 index 000000000..24445d033 --- /dev/null +++ b/man/html/git-auto-svn.html @@ -0,0 +1,837 @@ + + + + + +git-auto-svn(1) + + + + + +
+
+

SYNOPSIS

+
+
+
git auto-svn
+
+
+
+
+
+

DESCRIPTION

+
+

git auto-svn automatically sets up git-svn metadata and runs git-svn fetch for +repos that are homed in SVN but mirrored to Git (such as depot_tools itself).

+

It determines the metadata to use by inspecting the git-svn-id footer of the +HEAD of the remote upstream ref (by default, origin/master). git-svn-id +footers look like this:

+
+
+
git-svn-id: svn://some.host.org/repo/path/to/a/sub/folder@123456 0039d316-1c4b-4281-b951-d872f2087c98
+
+

git auto-svn extracts the repository url +(svn://some.host.org/repo/path/to/a/sub/folder) from the git-svn-id, and +splits it into the root repository (svn://some.host.org/repo) and the path +within that repository (/path/to/a/sub/folder).

+

It then sets up the following stanza in .git/config:

+
+
+
[svn-remote "svn"]
+    url = svn://some.host.org/repo
+    fetch = path/to/a/sub/folder:refs/remotes/origin/master
+
+

Finally, it runs git svn fetch to pull in the data from the svn remote.

+
+
+
+

CONFIGURATION VARIABLES

+
+
+

svn-remote.svn.url

+

This is the url of the root of the remote svn repository.

+
+
+

svn-remote.svn.fetch

+

This looks like a git refspec, but maps a subdirectory of the svn repository +to a single ref in the git remote.

+
+
+
+
+

EXAMPLE

+
+
+
+
git clone https://chromium.googlesource.com/chromium/tools/depot_tools
+cd depot_tools
+git auto-svn
+
+

This results in the following stanza in depot_tools/.git/config:

+
+
+
[svn-remote "svn"]
+    url = svn://svn.chromium.org/chrome
+    fetch = trunk/tools/depot_tools:refs/remotes/origin/master
+
+
+
+
+

CHROMIUM DEPOT_TOOLS

+
+

Part of the chromium depot_tools(7) suite. These tools are meant to +assist with the development of chromium and related projects. Download the tools +from here.

+
+
+
+

+ + + diff --git a/man/man1/git-auto-svn.1 b/man/man1/git-auto-svn.1 new file mode 100644 index 000000000..84e238bb4 --- /dev/null +++ b/man/man1/git-auto-svn.1 @@ -0,0 +1,113 @@ +'\" t +.\" Title: git-auto-svn +.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] +.\" Generator: DocBook XSL Stylesheets v1.78.1 +.\" Date: 09/30/2014 +.\" Manual: Chromium depot_tools Manual +.\" Source: depot_tools 2bbacdc +.\" Language: English +.\" +.TH "GIT\-AUTO\-SVN" "1" "09/30/2014" "depot_tools 2bbacdc" "Chromium depot_tools Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +git-auto-svn \- Automatically set up git\-svn metadata for a repo mirrored from SVN\&. +.SH "SYNOPSIS" +.sp +.nf +\fIgit auto\-svn\fR +.fi +.sp +.SH "DESCRIPTION" +.sp +git auto\-svn automatically sets up git\-svn metadata and runs git\-svn fetch for repos that are homed in SVN but mirrored to Git (such as depot_tools itself)\&. +.sp +It determines the metadata to use by inspecting the git\-svn\-id footer of the HEAD of the remote upstream ref (by default, origin/master)\&. git\-svn\-id footers look like this: +.sp +.if n \{\ +.RS 4 +.\} +.nf +git\-svn\-id: svn://some\&.host\&.org/repo/path/to/a/sub/folder@123456 0039d316\-1c4b\-4281\-b951\-d872f2087c98 +.fi +.if n \{\ +.RE +.\} +.sp +git auto\-svn extracts the repository url (svn://some\&.host\&.org/repo/path/to/a/sub/folder) from the git\-svn\-id, and splits it into the root repository (svn://some\&.host\&.org/repo) and the path within that repository (/path/to/a/sub/folder)\&. +.sp +It then sets up the following stanza in \&.git/config: +.sp +.if n \{\ +.RS 4 +.\} +.nf +[svn\-remote "svn"] + url = svn://some\&.host\&.org/repo + fetch = path/to/a/sub/folder:refs/remotes/origin/master +.fi +.if n \{\ +.RE +.\} +.sp +Finally, it runs git svn fetch to pull in the data from the svn remote\&. +.SH "CONFIGURATION VARIABLES" +.SS "svn\-remote\&.svn\&.url" +.sp +This is the url of the root of the remote svn repository\&. +.SS "svn\-remote\&.svn\&.fetch" +.sp +This looks like a git refspec, but maps a subdirectory of the svn repository to a single ref in the git remote\&. +.SH "EXAMPLE" +.sp +.if n \{\ +.RS 4 +.\} +.nf +git clone https://chromium\&.googlesource\&.com/chromium/tools/depot_tools +cd depot_tools +git auto\-svn +.fi +.if n \{\ +.RE +.\} +.sp +This results in the following stanza in depot_tools/\&.git/config: +.sp +.if n \{\ +.RS 4 +.\} +.nf +[svn\-remote "svn"] + url = svn://svn\&.chromium\&.org/chrome + fetch = trunk/tools/depot_tools:refs/remotes/origin/master +.fi +.if n \{\ +.RE +.\} +.SH "CHROMIUM DEPOT_TOOLS" +.sp +Part of the chromium \fBdepot_tools\fR(7) suite\&. These tools are meant to assist with the development of chromium and related projects\&. Download the tools from \m[blue]\fBhere\fR\m[]\&\s-2\u[1]\d\s+2\&. +.SH "NOTES" +.IP " 1." 4 +here +.RS 4 +\%https://chromium.googlesource.com/chromium/tools/depot_tools.git +.RE diff --git a/man/src/_git-auto-svn_desc.helper.txt b/man/src/_git-auto-svn_desc.helper.txt new file mode 100644 index 000000000..eabe443d7 --- /dev/null +++ b/man/src/_git-auto-svn_desc.helper.txt @@ -0,0 +1 @@ +Automatically set up git-svn metadata for a repo mirrored from SVN. diff --git a/man/src/git-auto-svn.txt b/man/src/git-auto-svn.txt new file mode 100644 index 000000000..9aa780d33 --- /dev/null +++ b/man/src/git-auto-svn.txt @@ -0,0 +1,69 @@ +git-auto-svn(1) +=============== + +NAME +---- +git-auto-svn - +include::_git-auto-svn_desc.helper.txt[] + +SYNOPSIS +-------- +[verse] +'git auto-svn' + +DESCRIPTION +----------- + +`git auto-svn` automatically sets up git-svn metadata and runs git-svn fetch for +repos that are homed in SVN but mirrored to Git (such as depot_tools itself). + +It determines the metadata to use by inspecting the `git-svn-id` footer of the +HEAD of the remote upstream ref (by default, `origin/master`). `git-svn-id` +footers look like this: + + git-svn-id: svn://some.host.org/repo/path/to/a/sub/folder@123456 0039d316-1c4b-4281-b951-d872f2087c98 + +`git auto-svn` extracts the repository url +(svn://some.host.org/repo/path/to/a/sub/folder) from the `git-svn-id`, and +splits it into the root repository (svn://some.host.org/repo) and the path +within that repository (/path/to/a/sub/folder). + +It then sets up the following stanza in .git/config: + + [svn-remote "svn"] + url = svn://some.host.org/repo + fetch = path/to/a/sub/folder:refs/remotes/origin/master + +Finally, it runs `git svn fetch` to pull in the data from the svn remote. + +CONFIGURATION VARIABLES +----------------------- + +svn-remote.svn.url +~~~~~~~~~~~~~~~~~~ + +This is the url of the root of the remote svn repository. + +svn-remote.svn.fetch +~~~~~~~~~~~~~~~~~~~~ + +This looks like a git refspec, but maps a subdirectory of the svn repository +to a single ref in the git remote. + +EXAMPLE +------- + + git clone https://chromium.googlesource.com/chromium/tools/depot_tools + cd depot_tools + git auto-svn + +This results in the following stanza in `depot_tools/.git/config`: + + [svn-remote "svn"] + url = svn://svn.chromium.org/chrome + fetch = trunk/tools/depot_tools:refs/remotes/origin/master + + +include::_footer.txt[] + +// vim: ft=asciidoc: diff --git a/man/src/make_docs.sh b/man/src/make_docs.sh index 73d76e248..d7af87d77 100755 --- a/man/src/make_docs.sh +++ b/man/src/make_docs.sh @@ -23,6 +23,7 @@ ensure_in_path() { } ensure_in_path xmlto +ensure_in_path hg DFLT_CATALOG_PATH="/usr/local/etc/xml/catalog" if [[ ! $XML_CATALOG_FILES && -f "$DFLT_CATALOG_PATH" ]]