aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xserver/mrrepo84
1 files changed, 81 insertions, 3 deletions
diff --git a/server/mrrepo b/server/mrrepo
index 5e7d0fb..aae1e54 100755
--- a/server/mrrepo
+++ b/server/mrrepo
@@ -6,7 +6,23 @@
#
# Will first download (via http or https if -s specified) the manifest file
# from git.example.org which should list all publicly available repositories.
-# It will then mirror each repository in /var/scm using the git protocol.
+# It will then mirror each remote repository in /var/scm locally, using the
+# git protocol.
+#
+# Afterwards it may mirror it further to a remote repository that can be
+# specified in the manifest file. If mirroring via https, then you also most
+# likely need to provide credentials for the remote https URLs in the
+# mrrepo-config file. This file should be placed next to and will be sourced
+# by the mrrepo script (remember to adjust its permissions).
+#
+# The manifest file line format (lines starting with # are ignored):
+#
+# <repository-path>[ <remote-mirror-url>]
+#
+# To specify another credential for a URL add the following line to
+# mrrepo-config:
+#
+# credentials['<https-url-prefix>']='<user>:<password>'
#
# -v
# Run verbose.
@@ -68,6 +84,19 @@ if [ ! -d "$path" ]; then
error "$path is not a directory"
fi
+declare -A credentials
+config="$(realpath "${BASH_SOURCE[0]}")-config"
+
+if [ -f "$config" ]; then
+ source "$config"
+
+ for p in "${!credentials[@]}"; do
+ if [ "${p:0:8}" != "https://" ]; then
+ error "https protocol is expected for '$p' in '$config'"
+ fi
+ done
+fi
+
cd "$path"
curl_ops=()
@@ -93,10 +122,44 @@ function fetch () # <url> [<curl-options>]
fetch "$prot://$host/manifest" -z manifest -o manifest
+function field () # <line> <num> [<name>]
+{
+ local r
+ r="$(echo "$1 " | cut -d ' ' -f "$2")"
+
+ if [ "$3" -a -z "$r" ]; then
+ error "field <$3> (#$2) missing in '$1'"
+ fi
+ echo "$r"
+}
+
+# Collect new repositories (in the new array) and while at it fix up remote
+# URLs with credentials (in the remotes map).
+#
new=()
-while read r || [ -n "$r" ]; do
+declare -A remotes
+
+while read l || [ -n "$l" ]; do
+ r=$(field "$l" 1 'path')
+ u=$(field "$l" 2)
+
new+=("$r")
-done <manifest
+
+ # If the remote URL is specified then add credentials into it, if found.
+ # Note that currently we only support adding credentials for https URLs.
+ #
+ if [ -n "$u" ]; then
+ for p in "${!credentials[@]}"; do
+ if [[ "$u" == "$p"* ]]; then
+ c="${credentials[$p]}"
+ u="$(echo "$u" | sed 's%^\(https://\)\(.*\)$%\1'"$c"'@\2%')"
+ break;
+ fi
+ done
+
+ remotes["$r"]="$u"
+ fi
+done < <(sed -e '/^\s*#/d;/^\s*$/d;s/\s\s*/ /g' manifest)
# Find all the existing repositories (directories that end with .git).
#
@@ -135,6 +198,21 @@ for r in "${new[@]}"; do
#
fetch "$prot://$host/$r/description" -z "$r/description" -o "$r/description"
fi
+
+ # Mirror to the remote URL, if present.
+ #
+ u="${remotes[$r]}"
+ if [ -n "$u" ]; then
+ if [ "$verb" -ge 1 ]; then
+ info "remote URL $u for repository $r, pushing"
+ info git -C "$r" push "${git_ops[@]}" --mirror "$u"
+ fi
+
+ # Disable prompting for username/password if credentials are missing for
+ # the remote URL and fail instead.
+ #
+ GIT_TERMINAL_PROMPT=0 git -C "$r" push "${git_ops[@]}" --mirror "$u"
+ fi
done
# Remove old repositories.