COMMAND=$(basename $0)
# for sending emails (-a option)
-ADMINS="Thierry.Parmentelat@inria.fr baris@metin.org"
+ADMINS="Thierry.Parmentelat@inria.fr"
# the other end of the mirror (-r option)
REMOTE_GIT="git://git.planet-lab.org"
-# -q option
+# options
QUIET=
+VERBOSE=
+FORCE=
# local path to the reference (bare) repos
MASTER_GIT="/git"
# local path to the working repos; can be trashed if needed
LOCAL_MIRROR_DIR="/git-mirror"
# a file in each repo to avoid too many notifications
-NOTIFIED_FILE="NOTIFIED_ADMINS"
+NOTIFIED_FILE="NOTIFIED"
# global stamp to avoid multiple instances of this script
-RUNNING_FILE=$LOCAL_MIRROR_DIR/RUNNING_MIRROR
+LOCKFILE=$LOCAL_MIRROR_DIR/LOCK
# global list - errors to report
FAILED_CMDS=()
-VERBOSE=
function verbose () {
[ -n "$VERBOSE" ] && echo "--------------------" "$@"
}
}
function failure () {
- msg "Received signal - cleaning up $RUNNING_FILE and aborting"
- rm -f $RUNNING_FILE
+ msg "Received signal - cleaning up $LOCKFILE and aborting"
+ rm -f $LOCKFILE
exit 1
}
-function error () {
- local REPO=$1; shift
+function notify () {
+ local REPO_DIR=$1; shift
local SUBJECT=$1; shift
local BODY=$1; shift
- verbose "error" $SUBJECT
+ verbose "notify" $SUBJECT
# already notified within a half day ?
GRACE=$((60*12))
- is_recent=$(find $REPO/$NOTIFIED_FILE -mmin -$GRACE 2> /dev/null)
+ is_recent=$(find $REPO_DIR/$NOTIFIED_FILE -mmin -$GRACE 2> /dev/null)
# not there or less than 12 our old: don't notify
if [ -n "$is_recent" ] ; then
verbose "skipping recent notification -- $SUBJECT"
for admin in $ADMINS; do
echo -e "$BODY" | mail -s "$SUBJECT" $admin
done
- touch $REPO/$NOTIFIED_FILE
+ touch $REPO_DIR/$NOTIFIED_FILE
+}
+
+function clear_notify () {
+ local REPO_DIR=$1; shift
+ rm -f $REPO_DIR/$NOTIFIED_FILE
}
# run directory command
function run () {
local IGNORE=""
case "$1" in -i) IGNORE=true ; shift ;; esac
- local REPO=$1; shift
+ local REPO_DIR=$1; shift
local COMMAND="$@"
- pushd ${REPO} > /dev/null
+ pushd ${REPO_DIR} > /dev/null
# quiet mode: record stdout and err for the mail
ok=true
if [ -n "$QUIET" ] ; then
OUTPUT=$($COMMAND 2>&1) || ok=
- TORECORD="[$REPO] $COMMAND\n$OUTPUT"
+ TORECORD="[$REPO_DIR] $COMMAND\n$OUTPUT"
else
- echo "[$REPO] Running $COMMAND"
- $COMMAND || ok=
- TORECORD="$COMMAND"
+ if [ -z "$IGNORE" ] ; then
+ echo "[$REPO_DIR] Running $COMMAND"
+ $COMMAND || ok=
+ TORECORD="$COMMAND"
+ else
+ echo "[$REPO_DIR] Running $COMMAND [ignored]"
+ $COMMAND >& /dev/null
+ fi
fi
# failed ?
pushd $REPO_DIR > /dev/null
BRANCHES=$(git branch -r | grep $REMOTE | grep -v HEAD | sed "s/.*\///g" | grep -v master)
+ HAS_MASTER=$(git branch -l | grep master)
popd > /dev/null
- run ${REPO_DIR} git checkout master
- run ${REPO_DIR} git merge --ff $REMOTE/master
+ [ -n "$HAS_MASTER" ] && run ${REPO_DIR} git checkout master
+ [ -n "$HAS_MASTER" ] && run ${REPO_DIR} git merge --ff $REMOTE/master
for BRANCH in $BRANCHES ; do
- run -i ${REPO_DIR} git branch $BRANCH $REMOTE/$BRANCH
+ run -i ${REPO_DIR} git branch $BRANCH $REMOTE/$BRANCH
run ${REPO_DIR} git checkout $BRANCH
run ${REPO_DIR} git merge --ff $REMOTE/$BRANCH
done
pushd $REPO_DIR > /dev/null
BRANCHES=$(git branch -r | grep $PUSH_FROM | grep -v HEAD | sed "s/.*\///g" | grep -v master)
+ HAS_MASTER=$(git branch -l | grep master)
popd > /dev/null
- run ${REPO_DIR} git push $PUSH_TO master:master
+ [ -n "$HAS_MASTER" ] && run ${REPO_DIR} git push $PUSH_TO master:master
for BRANCH in $BRANCHES ; do
run ${REPO_DIR} git push $PUSH_TO $BRANCH:$BRANCH
done
REMOTE_REPO=${REMOTE_GIT}/${GIT_NAME}
MASTER_REPO=${MASTER_GIT}/${GIT_NAME}
+ # if the local master is a symlink (like /git/vserver-reference.git -> sliceref.git)
+ # then skip it
+ # we use this for either aliases (like vserver-reference and sliceimage) or
+ # for repos managed in other locations (like /git-slave) but where
+ # the symlink is needed so they get served by git-daemon
+ [ -h ${MASTER_REPO} ] && return
+
# if there is no remote repository it may be that we only have
# the repository locally and don't need to mirror
git ls-remote $REMOTE_REPO &> /dev/null || return
# format mail body
body="Can not fetch from ${MASTER_REPO}\n\n------------\n FAILED COMMANDS:\n"
for line in "${FAILED_CMDS[@]}"; do body="$body$line\n"; done
- error $REPO_DIR "git-mirror.sh failed to merge remote with module ${NAME}" "$body"
+ notify $REPO_DIR "git-mirror.sh failed to merge remote with module ${NAME}" "$body"
return
fi
else
# format mail body
body="STATUS in ${REPO_DIR}:\n${STATUS_OUT} \n\n------------\n FAILED COMMANDS:\n"
for line in "${FAILED_CMDS[@]}"; do body="$body$line\n"; done
- error $REPO_DIR "git-mirror.sh failed on with module ${NAME}" "$body"
+ notify $REPO_DIR "git-mirror.sh failed on with module ${NAME}" "$body"
return
fi
run ${REPO_DIR} git push --tags local_master
# format mail body
body="FAILED COMMANDS:\n"
for line in "${FAILED_CMDS[@]}"; do body="$body$line\n"; done
- error $REPO_DIR "git-mirror.sh failed to push back with module ${NAME}" "$body"
+ notify $REPO_DIR "git-mirror.sh failed to push back with module ${NAME}" "$body"
return
fi
# success, remove previous check file if any
- rm -f $REPO_DIR/$NOTIFIED_FILE
+ clear_notify $REPO_DIR
+ # touch a stamp so it's easier to figure out where/if things get stuck
+ touch ${REPO_DIR}/MIRRORED.stamp
}
function usage () {
- echo "Usage $COMMAND [-a admin-mails] [-r remote-git-url] [-q] [-v] REPONAME*"
+ echo "Usage $COMMAND [options] REPONAME*"
+ echo " [-a admin-mails] : provide space-separated admins emails"
+ echo " [-r remote-git-url] : e.g. -r git://git.onelab.eu/"
+ echo " [-q] quiet mode for running under cron"
+ echo " [-v] verbose mode"
+ echo " [-f] force mode, runs even if the lock file is present"
+ echo " see also manage-git-mirror.sh"
exit 1
}
-while getopts "a:r:qvh" opt; do
+while getopts "a:r:s:qvfh" opt; do
case $opt in
a) ADMINS=$OPTARG ;;
r) REMOTE_GIT=$OPTARG ;;
q) QUIET=true ;;
v) VERBOSE=true ;;
+ f) FORCE=true ;;
h) usage ;;
\?) echo "Invalid option: -$opt" >&2 ;;
esac
done
shift $((OPTIND-1))
-# is the stamp older than an hour ?
-# in minutes
-GRACE=60
-is_old=$(find $RUNNING_FILE -mmin +$GRACE 2> /dev/null)
-if [ -n "$is_old" ] ; then
- msg "$RUNNING_FILE is older than $GRACE minutes - removing"
- rm -f $RUNNING_FILE
-fi
+# skip this if force is set
+# the natural usage of force is, manage-git-mirror.sh touches the lock file
+# which prevents the cron jobs from running during an hour
+# then you can use with -f which leaves the lock file as it is
+if [ -z "$FORCE" ] ; then
+ # is the stamp older than an hour ?
+ GRACE=60
+ is_old=$(find $LOCKFILE -mmin +$GRACE 2> /dev/null)
+ if [ -n "$is_old" ] ; then
+ msg "$LOCKFILE is older than $GRACE minutes - removing"
+ rm -f $LOCKFILE
+ fi
-if [ -f $RUNNING_FILE ] ; then
- msg "Found $RUNNING_FILE - another git-mirror seems to be running. Aborting... "
- exit 1
+ if [ -f $LOCKFILE ] ; then
+ msg "Found $LOCKFILE - another git-mirror seems to be running. Aborting... "
+ exit 1
+ fi
fi
trap failure INT
-date > $RUNNING_FILE
+# if force is set we leave the lock file as is
+[ -z "$FORCE" ] && date > $LOCKFILE
for gitrepo in "$@"; do mirror_repo $gitrepo ; done
-rm -f $RUNNING_FILE
+[ -z "$FORCE" ] && rm -f $LOCKFILE