Improve git-hg-sub-import to work with PROJRC and SUBPATHS
authorHugo Villeneuve <hugo@hugovil.com>
Thu, 17 Jul 2014 19:15:38 +0000 (15:15 -0400)
committerHugo Villeneuve <hugo@hugovil.com>
Thu, 17 Jul 2014 19:15:38 +0000 (15:15 -0400)
scripts/git-hg-sub-import

index 38f8621..4baf1bc 100755 (executable)
@@ -5,7 +5,10 @@ set -o errexit
 #   http://felipec.wordpress.com/2012/11/13/git-remote-hg-bzr-2/
 
 # Uncomment to have verbose debug output
-debug=1
+#debug=1
+
+PROJRC_COUNT=0
+SUBPATHS_COUNT=0
 
 print_usage()
 {
@@ -13,24 +16,118 @@ print_usage()
     echo "Usage: $(basename $0) [OPTIONS...]"
 }
 
-# git-remote-hg doesn't work with Mercurial subpaths extension,
-# so use it manually
-hg_subpaths_config() {
-    subpaths=$(hg showconfig | grep "subpaths" | grep "HG_REPO")
+# We parse the projrc file in the assembly (on the server), to check
+# for any projrc substitutions.
+#
+# Arg 1: repository (path and name)
+#
+# Return the substitution key/values in arrays:
+#  PROJRC_KEY
+#  PROJRC_VAL
+# PROJRC_COUNT will be greater than zero if any substitutions were found.
+hg_parse_projrc() {
+    if [ ${#} -lt 1 ]; then
+        echo "Missing repository name"
+    fi
+
+    # Repo name can have spaces in it, hence the use of ${*}
+    local repo_orig="${*}"
+    local repo="${*}"
 
-    echo "subpaths = ${subpaths}"
+    # Quote spaces
+    repo=${repo// /\\\\ }
 
-    if [ -n ${subpaths} ]; then
-        sp_src=${subpaths//subpaths./}
-        sp_src=${sp_src//=*/}
-        sp_src=${sp_src//\\/} # Remove windows separator (LSI)
-        sp_dst=${subpaths//*=/}
+    if [ -f "${repo}/.hg/projrc" ]; then
+        TMPF="/tmp/$(basename $0).projrc-$$.tmp"
 
-        if [ -n "${debug}" ]; then
-            echo "sp_src = $sp_src"
-            echo "sp_dst = $sp_dst"
-        fi
+        # Create temporary copy to replace backslashes with slashes.
+        # Make sure to only replace path backslashes, not backslashes for
+        # quoting spaces.
+        # \\[^ ]  Match a backslash, not followed by a space
+        cat "${repo}/.hg/projrc" | sed 's/\\\([^ ]\)/\/\1/g' > ${TMPF}
+
+        while read p; do
+            if echo ${p} | grep -q "\s=\s"; then
+                local key=$(echo ${p} | sed 's/^\(.*\) = .*/\1/')
+                local val=$(echo ${p} | sed 's/.* = \(.*\)/\1/')
+
+                PROJRC_KEY[${PROJRC_COUNT}]="${key}"
+                PROJRC_VAL[${PROJRC_COUNT}]="${val}"
+
+                if [ -n "${debug}" ]; then
+                    echo "Parsing PROJRC entry: ${p}"
+                    echo "  key: ${key}"
+                    echo "  val: ${val}"
+                fi
+
+                PROJRC_COUNT=$((PROJRC_COUNT + 1))
+            fi
+        done < ${TMPF}
+
+        rm ${TMPF}
+    fi
+}
+
+# We parse the Mercurial configuration, to check
+# for any SUBPATHS substitutions.
+#
+# Return the substitution key/values in arrays:
+#  SUBPATHS_KEY
+#  SUBPATHS_VAL
+# SUBPATHS_COUNT will be greater than zero if any substitutions were found.
+hg_parse_subpaths() {
+    subpaths=$(hg showconfig subpaths)
+
+    if [ -n "${subpaths}" ]; then
+        for p in ${subpaths}; do
+            local key=$(echo ${p} | sed 's/^subpaths\.\(.*\)=.*/\1/')
+            local val=$(echo ${p} | sed 's/.*=\(.*\)/\1/')
+
+            # Replace '\\' with '/'
+            key=${key//\\\\/\/}
+            #        ^^ replace multiple times
+
+            val=${val//\\\\/\/}
+
+            SUBPATHS_KEY[${SUBPATHS_COUNT}]="${key}"
+            SUBPATHS_VAL[${SUBPATHS_COUNT}]="${val}"
+
+            if [ -n "${debug}" ]; then
+                echo "Parsing SUBPATHS entry: ${p}"
+                echo "  key: ${key}"
+                echo "  val: ${val}"
+            fi
+
+            SUBPATHS_COUNT=$((SUBPATHS_COUNT + 1))
+        done
+    fi
+}
+
+# Replace the given path with either entries from PROJRC or SUBPATHS
+# Arg 1: path
+apply_substitutions() {
+    # Repo name can have spaces in it, hence the use of ${*}
+    local path="${*}"
+
+    if [ ${PROJRC_COUNT} -ne 0 ]; then
+        for s in $(seq 0 $((${PROJRC_COUNT} - 1))); do
+            local pattern=${PROJRC_KEY[${s}]}
+            local replacement=${PROJRC_VAL[${s}]}
+
+            path=${path/${pattern}/${replacement}}
+        done
     fi
+
+    if [ ${SUBPATHS_COUNT} -ne 0 ]; then
+        for s in $(seq 0 $((${SUBPATHS_COUNT} - 1))); do
+            local pattern=${SUBPATHS_KEY[${s}]}
+            local replacement=${SUBPATHS_VAL[${s}]}
+
+            path=${path/${pattern}/${replacement}}
+        done
+    fi
+
+    echo "${path}"
 }
 
 # git-remote-hg doesn't work with Mercurial projrc extension,
@@ -115,7 +212,15 @@ if [ ! -f .gitignore ]; then
     echo ".gitignore" > .gitignore
 fi
 
-hg_subpaths_config
+asm=$(cat .git/config | grep "hg::" | sed "s/.*url = hg::\(.*\)/\1/")
+hg_parse_projrc ${asm}
+
+hg_parse_subpaths
+
+HGSUB_TMP="/tmp/$(basename $0).hgsub-$$.tmp"
+
+# Create temporary copy to replace backslashes with slashes.
+cat .hgsub | sed 's/\\/\//g' > ${HGSUB_TMP}
 
 # Read lines from .hgsub
 while read sub; do
@@ -126,8 +231,12 @@ while read sub; do
         # Get subrepository URL
         src="${sub//*= /}"
 
-        # Replace using subpaths extension content
-        src=${src/${sp_src}/${sp_dst}}
+        # Replace using Mercurial subpaths substitutions (either projrc or from hgrc)
+        src=$(apply_substitutions ${src})
+
+        # Original name
+        repo=$(basename "${src}")
+        srcpath=$(dirname "${src}")
 
         # Get subrepository local alias or label
         dest="${sub// =*}"
@@ -138,20 +247,12 @@ while read sub; do
         # Get revision of subrepository (remove CR from .hgsubstate)
         rev=$(cat .hgsubstate | tr -d '\r' | grep "${id}" | sed "s/ .*//")
 
-        # Original name
-        repo=$(basename "${src}")
-        srcpath=$(dirname "${src}")
-
-        projrc_sub=$(hg_check_projrc_config "${src}")
-        src="${srcpath}/${projrc_sub}"
-
         if [ -n "${debug}" ]; then
             echo "repo: ${repo}"
-            echo "  path:   ${srcpath}"
-            echo "  id:     ${id}"
-            echo "  src:    ${projrc_sub}"
-            echo "  dest:   ${dest}"
-            echo "  rev:    ${rev}"
+            echo "  path:  ${srcpath}"
+            echo "  id:    ${id}"
+            echo "  local: ${dest}"
+            echo "  rev:   ${rev}"
         fi
 
         if [ ! -d "${dest}" ]; then
@@ -197,4 +298,7 @@ while read sub; do
             fi
         fi
     fi
-done < .hgsub
+done < ${HGSUB_TMP}
+
+rm ${HGSUB_TMP}
+