aboutsummaryrefslogtreecommitdiff
path: root/server/mrrepo
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2016-01-18 18:01:13 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2016-01-18 18:01:13 +0200
commitf697b300cc0b421b196193c090df54a121b1d398 (patch)
treea9fe24da2f1a4fec4f6d6df50cc46a1c60d316b1 /server/mrrepo
parentc74e6e00cf4125731e6f9d6a5472989be1c6d1d0 (diff)
Add script for mirroring, update creation script to support
Diffstat (limited to 'server/mrrepo')
-rwxr-xr-xserver/mrrepo149
1 files changed, 149 insertions, 0 deletions
diff --git a/server/mrrepo b/server/mrrepo
new file mode 100755
index 0000000..1210725
--- /dev/null
+++ b/server/mrrepo
@@ -0,0 +1,149 @@
+#! /usr/bin/env bash
+
+# Mirror repositories. For example:
+#
+# mrrepo -s git.example.org /var/scm
+#
+# 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.
+#
+# -v
+# Run verbose.
+#
+# -s
+# Use https rather than http to download the manifest (git protocol is still
+# used for mirroring).
+#
+# Notes:
+# - needs curl
+# - run from cron as user scm (which belongs to the group scm).
+#
+usage="usage: $0 [-v] [-s] <host> <path>"
+
+owd=`pwd`
+trap "{ cd $owd; exit 1; }" ERR
+set -o errtrace # Trap in functions.
+
+function info () { echo "$*" 1>&2; }
+function error () { info "$*"; exit 1; }
+
+prot=http
+host=
+path=
+verb=0
+
+while [ $# -gt 0 ]; do
+ case $1 in
+ -v)
+ verb=1
+ shift
+ ;;
+ -s)
+ prot=https
+ shift
+ ;;
+ *)
+ if [ -z "$host" ]; then
+ host=$1
+ elif [ -z "$path" ]; then
+ path=$1
+ else
+ error "$usage"
+ fi
+ shift
+ ;;
+ esac
+done
+
+if [ -z "$host" -o -z "$path" ]; then
+ error "$usage"
+fi
+
+if [ ! -d "$path" ]; then
+ error "$path is not a directory"
+fi
+
+cd $path
+
+curl_ops="-f" # Fail on HTTP errors.
+curl_ops+=" --max-time 10" # Finish in 10 seconds.
+
+if [ $verb -ge 1 ]; then
+ curl_ops+=" --progress-bar"
+else
+ curl_ops+=" -s -S" # Silent but show errors.
+fi
+
+function fetch () # <url> [<curl-options>]
+{
+ local u=$1; shift
+
+ if [ $verb -ge 1 ]; then
+ info "curl $curl_ops $* $u"
+ fi
+
+ curl $curl_ops $* $u
+}
+
+fetch $prot://$host/manifest -z manifest -o manifest
+
+new=()
+while read r || [ -n "$r" ]; do
+ new+=("$r")
+done <manifest
+
+# Find all existing repositories (directories that end with .git).
+#
+old=(`find . -type d -name '*.git' -print -prune | sed -e 's%^./%%' -`)
+
+git_ops=
+if [ $verb -eq 0 ]; then
+ git_ops+="-q"
+fi
+
+for r in ${new[@]}; do
+ if [ -d $r ]; then
+ if [ -z "$(ls -A $r)" ]; then
+ rm -r $r
+ fi
+ fi
+ if [ ! -d $r ]; then
+ if [ $verb -ge 1 ]; then
+ info "new repository $r in manifest, cloning"
+ info "git clone $git_ops --mirror git://$host/$r $r"
+ fi
+ mkdir -p $r
+ git clone $git_ops --mirror git://$host/$r $r
+
+ # Also copy the description file.
+ #
+ fetch $prot://$host/$r/description -o $r/description
+ else
+ if [ $verb -ge 1 ]; then
+ info "existing repository $r, fetching"
+ info "git -C $r fetch $git_ops --tags"
+ fi
+ git -C $r fetch $git_ops --tags
+ fi
+done
+
+# Remove old repositories.
+#
+for o in ${old[@]}; do
+ for n in ${new[@]}; do
+ if [ $o = $n ]; then
+ o=
+ break
+ fi
+ done
+
+ if [ -n "$o" ]; then
+ if [ $verb -ge 1 ]; then
+ info "repository $o is no longer in manifest, removing"
+ fi
+ rm -rf $o
+ fi
+done
+
+cd $owd