git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Eddy Petrișor" <eddy.petrisor@gmail.com>
To: git@vger.kernel.org
Cc: Eddy Petrisor <eddy@epetrisor.dsd.ro>
Subject: [PATCH] First crude implementation of git-svn-externals
Date: Fri, 29 Aug 2008 03:02:58 +0300	[thread overview]
Message-ID: <1219968179-14156-2-git-send-email-eddy.petrisor@gmail.com> (raw)
In-Reply-To: <1219968179-14156-1-git-send-email-eddy.petrisor@gmail.com>

From: Eddy Petrisor <eddy@epetrisor.dsd.ro>

Current functionality:
 - fetches all the externals of an already svn-fetched repo
 - support for svn:externals refresh
 - if the location of the external has changed, the current working
   copy will be placed aside and a new directory will be created
   instead
 - if the remote URI is the same (maybe a verison bump, there will
   be a 'git svn rebase'
 - remove support (useful for testing purposes or clean restarts)
 - avoid zombie externals at all costs - in some repos empty
   svn:externals might exist; svn ignores such externals, so git should
   do the same

TODO:
 - take into account the revision of an external, if it exists
 - do not do deep svn cloning, to avoid legthy operations, just pull HEAD
 - add shallow copies to git svn repos (one revision should be enough
   for most externals)
 - use submodules for externals
---
 .gitignore           |    1 +
 Makefile             |    1 +
 git-svn-externals.sh |  158 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 160 insertions(+), 0 deletions(-)
 create mode 100755 git-svn-externals.sh

diff --git a/.gitignore b/.gitignore
index bbaf9de..cd2c47d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -123,6 +123,7 @@ git-status
 git-stripspace
 git-submodule
 git-svn
+git-svn-externals
 git-symbolic-ref
 git-tag
 git-tar-tree
diff --git a/Makefile b/Makefile
index bf400e6..b130244 100644
--- a/Makefile
+++ b/Makefile
@@ -265,6 +265,7 @@ SCRIPT_SH += git-sh-setup.sh
 SCRIPT_SH += git-stash.sh
 SCRIPT_SH += git-submodule.sh
 SCRIPT_SH += git-web--browse.sh
+SCRIPT_SH += git-svn-externals.sh
 
 SCRIPT_PERL += git-add--interactive.perl
 SCRIPT_PERL += git-archimport.perl
diff --git a/git-svn-externals.sh b/git-svn-externals.sh
new file mode 100755
index 0000000..38b7af6
--- /dev/null
+++ b/git-svn-externals.sh
@@ -0,0 +1,158 @@
+#!/bin/sh
+
+set -e
+
+GIT_SVN_LAST_DIR="$(pwd)"
+trap "cd '$GIT_SVN_LAST_DIR'" INT EXIT KILL
+
+
+USAGE='[help|init|refresh|show]'
+
+LONG_USAGE='git svn externals help
+	print this long help message.
+git svn externals init [<pathspec>...]
+	pull all externals according to current repo state.
+git svn externals refresh [<pathspec>...]
+	removes current externals and repulls them.
+'
+
+
+SUBDIRECTORY_OK=Sometimes
+OPTIONS_SPEC=
+. git-sh-setup
+cd_to_toplevel
+# this should never fail
+require_work_tree
+
+
+GIT_SVN_TOP_DIR="$(pwd)"
+
+svn_revision_to_numrevision ()
+#$1 - repository URI
+#$2 - the revision to be transformed
+{
+	local REVSPEC
+	[ "$2" ] && REVSPEC="-r $2" || REVSPEC=''
+	[ "$1" ] || die "Internal error: no repository given in svn_revision_to_numrevision"
+	LANG=C svn info "$1" "$REVSPEC" | grep 'Revision' | cut -f 2 -d ':' | sed 's#^\ \ *##g'
+}
+
+prune_inital_slashes ()
+{
+	echo "$1" | sed 's#^//*##g'
+}
+
+git_svn_externals_remove ()
+{
+	local LASTDIR="$(pwd)"
+	cd_to_toplevel && TOPLEVELDIR="$(pwd)"
+	git svn show-externals | grep -vE '^(#.*|)$' | while read EXT_DIR REV EXT_SRC ; do
+		if [ -z "$REV" ] ; then
+			echo "Skipping illegal external '$EXT_DIR' which has no value" >&2
+			continue
+		fi
+		EXT_DIR="$(prune_inital_slashes "$EXT_DIR")"
+
+		if [ -z "$EXT_SRC" ] ; then
+			EXT_SRC="$REV"
+			REV="-rHEAD"
+		fi
+		REV=${REV#-r}
+
+		echo "Removing local copy for external '$EXT_DIR' ( $EXT_SRC@$REV )"
+		rm -fr "$EXT_DIR"
+	done
+
+	cd "$LASTDIR"
+}
+
+git_svn_init_dir_repo ()
+# assumes is ran from the parent dir of the repo
+# $1 EXT_DIR
+# $2 EXT_SRC
+# $3 REV
+{
+	local LASTDIR="$(pwd)"
+
+	mkdir -p "$1"
+	cd "$1"
+	git svn init "$2"
+	git svn fetch
+
+	cd "$LASTDIR"
+}
+
+git_svn_externals_refresh_external ()
+#$1 directory where the external is locally
+#$2 remote url
+#$3 revision at which the external is pinned at
+{
+	local LASTDIR="$GIT_SVN_TOP_DIR"
+
+	local EXT_SRC="$2"
+	local EXT_DIR="$1"
+
+	if cd "$EXT_DIR" 2>/dev/null; then
+		local OLDDIREXISTS=yes
+		local OLD_EXT_SRC=$(git config --get svn-remote.svn.url)
+		local OLD_EXT_REV=$(git config --get svn-remote.svn.revision || svn_revision_to_numrevision $OLD_EXT_SRC HEAD)
+		cd -
+	else
+		local OLDDIREXISTS=no
+		local OLD_EXT_SRC="${EXT_SRC}"
+		local OLD_EXT_REV=$(svn_revision_to_numrevision $EXT_SRC HEAD)
+	fi
+
+	if [ "$OLD_EXT_SRC" != "$EXT_SRC" ] ; then
+		echo "External URI definition changed. Moving away the old repo and pulling a new one."
+		cd "$LASTDIR"
+		local SUBDIR="$(basename "$EXT_DIR")"
+		local DIRNAME="$(dirname "$EXT_DIR")"
+		NEWDIR="$(mktemp -p "$DIRNAME" "$SUBDIR.obsolete.XXXXXX")" && rm -f "$NEWDIR"
+		mv "$EXT_DIR" "$NEWDIR"
+		echo "  Old copy moved to '$NEWDIR'."
+		git_svn_init_dir_repo "$EXT_DIR" "$EXT_SRC" "$REV"
+	elif [ "$OLDDIREXISTS" = "no" ] ; then
+		git_svn_init_dir_repo "$EXT_DIR" "$EXT_SRC" "$REV"
+	else
+		cd "$EXT_DIR"
+		git svn rebase
+	fi
+
+	cd "$LASTDIR"
+	return 0
+}
+
+git_svn_externals_refresh ()
+{
+	git svn show-externals | grep -vE '^(#.*|)$' | while read EXT_DIR REV EXT_SRC ; do
+		if [ -z "$REV" ] ; then
+			echo "Skipping illegal external '$EXT_DIR' which has no value" >&2
+			continue
+		fi
+		EXT_DIR="$(prune_inital_slashes "$EXT_DIR")"
+
+		if [ -z "$EXT_SRC" ] ; then
+			EXT_SRC="$REV"
+			REV="-rHEAD"
+		fi
+		REV=${REV#-r}
+
+		echo "Refreshing local copy for external '$EXT_DIR' ( $EXT_SRC@$REV )"
+		cd "$GIT_SVN_TOP_DIR"
+		git_svn_externals_refresh_external "$EXT_DIR" "$EXT_SRC" "$REV"
+	done
+
+	cd "$GIT_SVN_TOP_DIR"
+}
+
+
+case $1 in
+	--remove)
+		git_svn_externals_remove
+		;;
+	-r|--refresh|*)
+		git_svn_externals_refresh
+		;;
+esac
+
-- 
1.5.6.3

  reply	other threads:[~2008-08-29  0:04 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-08-29  0:02 [PATCH 0/3] git-svn-externals PoC (in a sh script) Eddy Petrișor
2008-08-29  0:02 ` [PATCH] git svn: should not display zombie externals Eddy Petrișor
2008-08-29  0:02   ` Eddy Petrișor [this message]
2008-08-29  0:02     ` [PATCH] added a test frame for git-svn-externals.sh Eddy Petrișor
2008-08-29  0:16 ` [PATCH 0/3] git-svn-externals PoC (in a sh script) Eddy Petrișor
2008-08-29  9:29 ` Eric Wong
2008-09-01  6:20   ` RFH: git-svn and submodules Eric Wong
2008-09-10 13:56   ` [PATCH 0/3] git-svn-externals PoC (in a sh script) Eddy Petrișor
2008-09-10 13:59     ` Eddy Petrișor

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1219968179-14156-2-git-send-email-eddy.petrisor@gmail.com \
    --to=eddy.petrisor@gmail.com \
    --cc=eddy@epetrisor.dsd.ro \
    --cc=git@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).