|
|
@@ -144,12 +144,26 @@ link_git_to_source() {
|
|
|
}
|
|
|
|
|
|
stage_and_commit() {
|
|
|
- local msg="$1"
|
|
|
- echo "[$(elapsed) s] Staging files..."
|
|
|
+ local subject="${1:-}"
|
|
|
+ local body="${2:-}"
|
|
|
+ local allow_empty="${3:-0}"
|
|
|
+ local display="${4:-$subject}"
|
|
|
+ [[ -z "$subject" ]] && subject="SVN snapshot"
|
|
|
git add -A
|
|
|
|
|
|
- echo "[$(elapsed) s] Creating commit: $msg"
|
|
|
- GIT_QUIET=1 git commit -q -m "$msg" || true
|
|
|
+ if (( allow_empty )); then
|
|
|
+ if [[ -n "$body" ]]; then
|
|
|
+ GIT_QUIET=1 git commit -q --allow-empty -m "$subject" -m "$body"
|
|
|
+ else
|
|
|
+ GIT_QUIET=1 git commit -q --allow-empty -m "$subject"
|
|
|
+ fi
|
|
|
+ else
|
|
|
+ if [[ -n "$body" ]]; then
|
|
|
+ GIT_QUIET=1 git commit -q -m "$subject" -m "$body"
|
|
|
+ else
|
|
|
+ GIT_QUIET=1 git commit -q -m "$subject"
|
|
|
+ fi
|
|
|
+ fi
|
|
|
}
|
|
|
|
|
|
# Validate history_count is numeric (default 0)
|
|
|
@@ -170,42 +184,74 @@ if (( history_count == 0 )); then
|
|
|
fi
|
|
|
|
|
|
# History mode: pull last N revisions into Git.
|
|
|
-head_rev="$(svn info --show-item revision 2>/dev/null || svn info | awk -F': ' '/^Revision:/ {print $2; exit}')"
|
|
|
-if [[ -z "$head_rev" ]]; then
|
|
|
- echo "Unable to determine HEAD revision" >&2
|
|
|
+SRC_URL="$(svn info --show-item url 2>/dev/null || svn info | awk -F': ' '/^URL:/ {print $2; exit}')"
|
|
|
+if [[ -z "$SRC_URL" ]]; then
|
|
|
+ echo "Unable to determine SVN URL" >&2
|
|
|
exit 1
|
|
|
fi
|
|
|
-start_rev=$(( head_rev - history_count + 1 ))
|
|
|
-if (( start_rev < 1 )); then start_rev=1; fi
|
|
|
+REPO_ROOT="$(svn info --show-item repos-root-url 2>/dev/null || svn info | awk -F': ' '/^Repository Root:/ {print $2; exit}')"
|
|
|
|
|
|
-echo "Including last $history_count revisions (r${start_rev}..r${head_rev})..."
|
|
|
+mapfile -t REV_LIST < <(svn log -q -r HEAD:1 --limit "$history_count" "$SRC_URL" | awk '/^r[0-9]+/ {sub(/^r/,"",$1); print $1}' | tac)
|
|
|
+if (( ${#REV_LIST[@]} == 0 )); then
|
|
|
+ echo "No SVN revisions found for path $SRC_URL" >&2
|
|
|
+ exit 1
|
|
|
+fi
|
|
|
+
|
|
|
+start_rev="${REV_LIST[0]}"
|
|
|
+head_rev="${REV_LIST[-1]}"
|
|
|
+echo "Including last ${#REV_LIST[@]} revisions affecting this path (r${start_rev}..r${head_rev})..."
|
|
|
|
|
|
-STAGE_DIR="$(mktemp -d "${MIRROR_ROOT}/.svn_git_sync_stage.XXXXXX")"
|
|
|
+WC_DIR="$(mktemp -d "${MIRROR_ROOT}/.svn_git_sync_wc.XXXXXX")"
|
|
|
mkdir -p "$DEST"
|
|
|
-cd "$DEST"
|
|
|
-init_git_repo
|
|
|
|
|
|
-for rev in $(seq "$start_rev" "$head_rev"); do
|
|
|
- echo "[$(elapsed) s] Exporting r${rev}..."
|
|
|
- rm -rf -- "$STAGE_DIR"
|
|
|
- mkdir -p "$STAGE_DIR"
|
|
|
- svn export --force --quiet -r "$rev" "$SRC_DIR" "$STAGE_DIR"
|
|
|
+sync_wc_to_dest() {
|
|
|
+ rsync -a --delete --exclude '.svn' --exclude '.git' "$WC_DIR"/ "$DEST"/
|
|
|
+ if [[ ! -e "$DEST/.gitignore" ]]; then
|
|
|
+ printf "*.pyc\n__pycache__/\n" > "$DEST/.gitignore"
|
|
|
+ fi
|
|
|
+}
|
|
|
|
|
|
- # Sync exported snapshot into repo working tree, preserving .git and .gitignore
|
|
|
- rsync -a --delete --exclude '.git' --exclude '.gitignore' "$STAGE_DIR"/ "$DEST"/
|
|
|
+echo "[$(elapsed) s] Checking out r${start_rev}..."
|
|
|
+svn checkout -q -r "$start_rev" "$SRC_URL" "$WC_DIR"
|
|
|
|
|
|
- # Ensure ignores persist
|
|
|
- if [[ ! -e .gitignore ]]; then
|
|
|
- printf "*.pyc\n__pycache__/\n" > .gitignore
|
|
|
- fi
|
|
|
+sync_wc_to_dest
|
|
|
|
|
|
- if [[ "$rev" -eq "$start_rev" ]]; then
|
|
|
- stage_and_commit "Import SVN r${rev}"
|
|
|
- else
|
|
|
- stage_and_commit "Update to SVN r${rev}"
|
|
|
+cd "$DEST"
|
|
|
+init_git_repo
|
|
|
+build_commit_msg() {
|
|
|
+ local rev="$1"
|
|
|
+ local svn_log author msg_body
|
|
|
+ svn_log="$(svn log -r "$rev" -l 1 "$SRC_URL")"
|
|
|
+ author="$(printf "%s\n" "$svn_log" | awk 'NR==2{split($0,a,"|"); gsub(/^ +| +$/,"",a[2]); print a[2]}')"
|
|
|
+ msg_body="$(printf "%s\n" "$svn_log" | sed '1,2d;/^---/,$d')"
|
|
|
+ if { [[ -z "$author" ]] || [[ -z "$msg_body" ]]; } && [[ -n "$REPO_ROOT" ]]; then
|
|
|
+ svn_log="$(svn log -r "$rev" -l 1 "$REPO_ROOT" 2>/dev/null || true)"
|
|
|
+ author="$(printf "%s\n" "$svn_log" | awk 'NR==2{split($0,a,"|"); gsub(/^ +| +$/,"",a[2]); print a[2]}')"
|
|
|
+ msg_body="$(printf "%s\n" "$svn_log" | sed '1,2d;/^---/,$d')"
|
|
|
fi
|
|
|
-done
|
|
|
+ msg_body="$(printf "%s" "$msg_body" | perl -0777 -pe 's/\A\s+//; s/\s+\z//; s/\n{2,}/\n\n/g')"
|
|
|
+ COMMIT_BODY="$msg_body"
|
|
|
+ COMMIT_BODY_FIRST="$(printf "%s" "$msg_body" | sed -n '1p')"
|
|
|
+ COMMIT_SUBJECT="SVN r${rev}"
|
|
|
+ [[ -n "$author" ]] && COMMIT_SUBJECT+=" by $author"
|
|
|
+ COMMIT_PROGRESS="$COMMIT_SUBJECT"
|
|
|
+ [[ -n "$COMMIT_BODY_FIRST" ]] && COMMIT_PROGRESS+=" — $COMMIT_BODY_FIRST"
|
|
|
+}
|
|
|
+
|
|
|
+build_commit_msg "$start_rev"
|
|
|
+echo "[$(elapsed) s] Preparing commit: $COMMIT_PROGRESS"
|
|
|
+stage_and_commit "$COMMIT_SUBJECT" "$COMMIT_BODY" 0 "$COMMIT_PROGRESS"
|
|
|
+
|
|
|
+if (( ${#REV_LIST[@]} > 1 )); then
|
|
|
+ for rev in "${REV_LIST[@]:1}"; do
|
|
|
+ svn update -q -r "$rev" "$WC_DIR"
|
|
|
+ sync_wc_to_dest
|
|
|
+ build_commit_msg "$rev"
|
|
|
+ echo "[$(elapsed) s] Preparing commit: $COMMIT_PROGRESS"
|
|
|
+ stage_and_commit "$COMMIT_SUBJECT" "$COMMIT_BODY" 1 "$COMMIT_PROGRESS"
|
|
|
+ done
|
|
|
+fi
|
|
|
|
|
|
-rm -rf -- "$STAGE_DIR"
|
|
|
+rm -rf -- "$WC_DIR"
|
|
|
|
|
|
link_git_to_source
|