>From 3dbfff128c125f9d3307dff1e5b44f8135620f2b Mon Sep 17 00:00:00 2001
From: Maxim Kuvyrkov <maxim.kuvyrkov@linaro.org>
Date: Tue, 14 May 2019 13:12:36 +0000
Subject: [PATCH] [Contrib] SVN -> Git conversion scripts

	* svn-git-repo.sh, svn-list-branches.sh, svn-git-branch.sh: New scripts.

Change-Id: I437d70c3bc431261bde5eec29e7207d4ebb0fe01
---
 contrib/svn-git-branch.sh    |  92 +++++++++++++++++++++++++++++
 contrib/svn-git-repo.sh      |  57 ++++++++++++++++++
 contrib/svn-list-branches.sh | 108 +++++++++++++++++++++++++++++++++++
 3 files changed, 257 insertions(+)
 create mode 100755 contrib/svn-git-branch.sh
 create mode 100755 contrib/svn-git-repo.sh
 create mode 100755 contrib/svn-list-branches.sh

diff --git a/contrib/svn-git-branch.sh b/contrib/svn-git-branch.sh
new file mode 100755
index 00000000000..70f8deb0a4f
--- /dev/null
+++ b/contrib/svn-git-branch.sh
@@ -0,0 +1,92 @@
+#!/bin/bash
+
+set -euf -o pipefail
+
+svntop="svn+ssh://gcc.gnu.org/svn/gcc"
+verbose=0
+
+while test $# -gt 0; do
+    case "$1" in
+	--svntop) svntop="$2"; shift ;;
+	--verbose) verbose=$(($verbose+1)) ;;
+	--) shift; break ;;
+	*) break ;;
+    esac
+    shift
+done
+
+info ()
+{
+    if [ $verbose -ge 1 ]; then
+	echo "INFO: $@" >&2
+    fi
+}
+
+if [ $verbose -ge 2 ]; then
+    set -x
+fi
+
+info "converting $@"
+
+spec="$1"
+shift 1
+
+branch=$(echo "$spec" | cut -d@ -f 1)
+rev=$(echo "$spec" | cut -s -d@ -f 2)
+
+for parent in "$@"; do
+    parent_branch=$(echo "$parent" | cut -d@ -f 1)
+    parent_rev=$(echo "$parent" | cut -s -d@ -f 2)
+
+    sha1=$(git rev-parse refs/remotes/svn/$parent)
+    mkdir -p $(dirname .git/refs/remotes/svn/$branch@$parent_rev)
+    echo $sha1 > .git/refs/remotes/svn/$branch@$parent_rev
+done
+
+sha1=""
+for i in origin extra; do
+    if git rev-parse refs/remotes/$i/${branch#branches/} >/dev/null 2>&1; then
+	sha1=$(git rev-parse refs/remotes/$i/${branch#branches/})
+    fi
+done
+
+if [ x"$sha1" != x"" ]; then
+    if ! git rev-parse refs/remotes/cache/$branch >/dev/null 2>&1 \
+	   || [ x"$rev" != x"" ]; then
+	mkdir -p $(dirname .git/refs/remotes/cache/$branch)
+	echo $sha1 > .git/refs/remotes/cache/$branch
+
+	cat >> .git/config <<EOF
+
+[svn-remote "cache-$branch"]
+	url = svn+ssh://gcc.gnu.org/svn/gcc
+	fetch = $branch:refs/remotes/cache/$branch
+EOF
+	git svn fetch --log-window-size=10000 "cache-$branch"
+
+	if [ x"$rev" != x"" ]; then
+	    sha1=$(git svn find-rev --before r$rev refs/remotes/cache/$branch)
+	else
+	    sha1=$(git rev-parse refs/remotes/cache/$branch)
+	fi
+
+	head -n -4 .git/config > .git/newconfig
+	mv .git/newconfig .git/config
+    else
+	sha1=$(git rev-parse refs/remotes/cache/$branch)
+    fi
+
+    mkdir -p $(dirname .git/refs/remotes/svn/$spec)
+    echo $sha1 > .git/refs/remotes/svn/$spec
+fi
+
+cat >> .git/config <<EOF
+
+[svn-remote "$spec"]
+	url = svn+ssh://gcc.gnu.org/svn/gcc
+	fetch = $branch:refs/remotes/svn/$spec
+EOF
+
+git svn fetch ${rev:+-r BASE:$rev} --log-window-size=10000 "$spec"
+head -n -4 .git/config > .git/newconfig
+mv .git/newconfig .git/config
diff --git a/contrib/svn-git-repo.sh b/contrib/svn-git-repo.sh
new file mode 100755
index 00000000000..bdabd079c67
--- /dev/null
+++ b/contrib/svn-git-repo.sh
@@ -0,0 +1,57 @@
+#!/bin/bash
+
+set -euf -o pipefail
+
+branchfile=""
+giturl=https://gcc.gnu.org/git/gcc.git
+reference=""
+repo=""
+svnpaths=()
+svntop=svn+ssh://gcc.gnu.org/svn/gcc
+
+while test $# -gt 0; do
+    case "$1" in
+	--branchfile) branchfile="$2"; shift ;;
+	--giturl) giturl="$2"; shift ;;
+	--reference) reference="$2"; shift ;;
+	--repo) repo="$2"; shift ;;
+	--svnpath) svnpaths+=("$2"); shift ;;
+	--svntop) svntop="$2"; shift ;;
+	--verbose) set -x ;;
+	*) echo "ERROR: wrong argument: $1"; exit 1 ;;
+    esac
+    shift
+done
+
+top=$(cd $(dirname "$0"); pwd)
+
+if [ x"$repo" = x"" ]; then
+    echo "ERROR: no --repo /path/to/repo"
+    exit 1
+elif [ -d "$repo" ]; then
+    echo "ERROR: directory $repo exists"
+    echo "       rename it to $repo.bak if it is a good starting point"
+    exit 1
+fi
+
+if [ -d "$repo.bak" ]; then
+    rsync -a --del "$repo.bak/" "$repo/"
+else
+    git clone ${reference:+--reference "$reference"} "$giturl" "$repo"
+    git -C "$repo" config --add remote.origin.fetch '+refs/remotes/*:refs/remotes/extra/*'
+    git -C "$repo" remote update -p
+    rsync -a --del "$repo/" "$repo.bak/"
+fi
+
+(
+    if [ x"$branchfile" = x"" ]; then
+	branchfile=$(mktemp)
+	$top/svn-list-branches.sh --svntop "$svntop" "${svnpaths[@]}" > "$branchfile" &
+    fi
+    tail -f -n +1 "$branchfile"
+) | while read -a params; do
+    (
+	cd "$repo"
+	$top/svn-git-branch.sh --svntop "$svntop" "${params[@]}" < /dev/null
+    )
+done
diff --git a/contrib/svn-list-branches.sh b/contrib/svn-list-branches.sh
new file mode 100755
index 00000000000..1a3378f27b8
--- /dev/null
+++ b/contrib/svn-list-branches.sh
@@ -0,0 +1,108 @@
+#!/bin/bash
+
+set -euf -o pipefail
+
+svntop="svn+ssh://gcc.gnu.org/svn/gcc"
+verbose=0
+
+while test $# -gt 0; do
+    case "$1" in
+	--svntop) svntop="$2"; shift ;;
+	--verbose) verbose=$(($verbose+1)) ;;
+	--) shift; break ;;
+	*) break ;;
+    esac
+    shift
+done
+
+info ()
+{
+    if [ $verbose -ge 1 ]; then
+	echo "INFO: $@" >&2
+    fi
+}
+
+error ()
+{
+    echo "ERROR: $@" >&2
+    exit 1
+}
+
+if [ $verbose -ge 2 ]; then
+    set -x
+fi
+
+queue=()
+for i in "$@"; do
+    i=$(echo "$i" | sed -e "s#^/*##g" -e "s#/*\$##g")
+    queue=("$i")
+done
+
+tmp=$(mktemp)
+
+declare -A printed
+
+while [ "${#queue[@]}" -gt 0 ]; do
+    path="${queue[0]}"
+    queue=("${queue[@]:1}")
+
+    info "Processing $path"
+
+    svn ls "$svntop/$path" > $tmp
+    if grep -v -q "/\$" $tmp; then
+	copy_log=$(svn log -v --stop-on-copy "$svntop/$path" \
+		       | grep -A3 -e "------------------------------------------------------------------------" \
+		       | tail -n3 \
+		       | grep "^   A /.* (from /.*:[0-9]*)\$" \
+		       | tail -n 1)
+	if [ x"$copy_log" != x"" ]; then
+	    realpath="$(echo "$copy_log" | sed -e "s#^   A /\(.*\) (from /\(.*\):\([0-9]*\))\$#\1#")"
+	    parent="$(echo "$copy_log" | sed -e "s#^   A /\(.*\) (from /\(.*\):\([0-9]*\))\$#\2#")"
+	    parent_rev="$(echo "$copy_log" | sed -e "s#^   A /\(.*\) (from /\(.*\):\([0-9]*\))\$#\3#")"
+
+	    parent="$parent@$parent_rev"
+	    if [ x"${printed[$parent]+set}" != x"set" ]; then
+		queue=("$parent" "$path" "${queue[@]}")
+		info "Backtracking to $parent"
+		continue
+	    fi
+
+	    if [ x"$realpath" != x"${path%@*}" ]; then
+		rev=$(echo "$path" | cut -s -d@ -f 2)
+		if [ x"$rev" != x"" ]; then
+		    error "path $path is versioned and not a branch"
+		fi
+		path="$realpath"
+	    fi
+	fi
+
+	if [ x"${printed[$path]+set}" != x"set" ]; then
+	    printed[$path]=1
+
+	    printf "$path"
+	    while true; do
+		copy_log=$(svn log -v --stop-on-copy "$svntop/$path" \
+			       | grep -A3 -e "------------------------------------------------------------------------" \
+			       | tail -n3 \
+			       | grep "^   A /.* (from /.*:[0-9]*)\$" \
+			       | tail -n 1)
+		if [ x"$copy_log" = x"" ]; then
+		    break
+		fi
+
+		parent="$(echo "$copy_log" | sed -e "s#^   A /\(.*\) (from /\(.*\):\([0-9]*\))\$#\2#")"
+		parent_rev="$(echo "$copy_log" | sed -e "s#^   A /\(.*\) (from /\(.*\):\([0-9]*\))\$#\3#")"
+
+		path="$parent@$parent_rev"
+
+		printf " $path"
+	    done
+	    printf "\n"
+	fi
+    else
+	while read newpath; do
+	    newpath=$(echo "$path/$newpath" | sed -e "s#^/##g" -e "s#/\$##g")
+	    queue=("${queue[@]}" "$newpath")
+	done < $tmp
+    fi
+done
-- 
2.17.1

