4 # for sending emails (-a option)
5 ADMINS="Thierry.Parmentelat@inria.fr baris@metin.org"
6 # the other end of the mirror (-r option)
7 REMOTE_GIT="git://git.planet-lab.org"
11 # local path to the reference (bare) repos
13 # local path to the working repos; can be trashed if needed
14 LOCAL_MIRROR_DIR="/git-mirror"
15 # a file in each repo to avoid too many notifications
16 NOTIFIED_FILE="NOTIFIED_ADMINS"
17 # global stamp to avoid multiple instances of this script
18 RUNNING_FILE=$LOCAL_MIRROR_DIR/RUNNING_MIRROR
19 # global list - errors to report
24 [ -n "$VERBOSE" ] && echo "--------------------" "$@"
28 [ -n "$QUIET" ] || echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "$@"
32 msg "Received signal - cleaning up $RUNNING_FILE and aborting"
39 local SUBJECT=$1; shift
41 verbose "error" $SUBJECT
43 # already notified within a half day ?
45 is_recent=$(find $REPO/$NOTIFIED_FILE -mmin -$GRACE 2> /dev/null)
46 # not there or less than 12 our old: don't notify
47 if [ -n "$is_recent" ] ; then
48 verbose "skipping recent notification -- $SUBJECT"
52 for admin in $ADMINS; do
53 echo -e "$BODY" | mail -s "$SUBJECT" $admin
55 touch $REPO/$NOTIFIED_FILE
58 # run directory command
59 # -or- to ignore errors
60 # run -i directory "command"
63 case "$1" in -i) IGNORE=true ; shift ;; esac
67 pushd ${REPO} > /dev/null
68 # quiet mode: record stdout and err for the mail
70 if [ -n "$QUIET" ] ; then
71 OUTPUT=$($COMMAND 2>&1) || ok=
72 TORECORD="[$REPO] $COMMAND\n$OUTPUT"
74 echo "[$REPO] Running $COMMAND"
81 # let's record the failure unless ignore is set
82 if [ -z "$IGNORE" ] ; then
83 FAILED_CMDS=("${FAILED_CMDS[@]}" "$TORECORD")
86 verbose "after run with $COMMAND" "ok=$ok" "#failed=${#FAILED_CMDS[@]}"
90 function merge_all_branches () {
91 local REPO_DIR=$1; shift
93 local REMOTE=$1; shift
95 pushd $REPO_DIR > /dev/null
96 BRANCHES=$(git branch -r | grep $REMOTE | grep -v HEAD | sed "s/.*\///g" | grep -v master)
99 run ${REPO_DIR} git checkout master
100 run ${REPO_DIR} git merge --ff $REMOTE/master
101 for BRANCH in $BRANCHES ; do
102 run -i ${REPO_DIR} git branch $BRANCH $REMOTE/$BRANCH
103 run ${REPO_DIR} git checkout $BRANCH
104 run ${REPO_DIR} git merge --ff $REMOTE/$BRANCH
108 function push_all_branches () {
109 local REPO_DIR=$1; shift
111 local PUSH_TO=$1; shift
112 local PUSH_FROM=$1; shift
114 pushd $REPO_DIR > /dev/null
115 BRANCHES=$(git branch -r | grep $PUSH_FROM | grep -v HEAD | sed "s/.*\///g" | grep -v master)
118 run ${REPO_DIR} git push $PUSH_TO master:master
119 for BRANCH in $BRANCHES ; do
120 run ${REPO_DIR} git push $PUSH_TO $BRANCH:$BRANCH
124 function mirror_repo () {
126 FAILED_CMDS=() # reset previous failure if any
128 NAME=$(basename ${repo} ".git")
130 REPO_DIR=${LOCAL_MIRROR_DIR}/${NAME}
131 REMOTE_REPO=${REMOTE_GIT}/${GIT_NAME}
132 MASTER_REPO=${MASTER_GIT}/${GIT_NAME}
134 # if there is no remote repository it may be that we only have
135 # the repository locally and don't need to mirror
136 git ls-remote $REMOTE_REPO &> /dev/null || return
138 if [ -d ${REPO_DIR} ] ; then
139 msg "pulling from ${NAME}"
140 run ${REPO_DIR} git fetch origin --tags
141 run ${REPO_DIR} git fetch origin
142 merge_all_branches $REPO_DIR $NAME origin
143 if [ -n "$FAILED_CMDS" ]; then
145 body="Can not fetch from ${MASTER_REPO}\n\n------------\n FAILED COMMANDS:\n"
146 for line in "${FAILED_CMDS[@]}"; do body="$body$line\n"; done
147 error $REPO_DIR "git-mirror.sh failed to merge remote with module ${NAME}" "$body"
151 msg "mirroring ${NAME} for the first time"
152 run ${LOCAL_MIRROR_DIR} git clone ${REMOTE_REPO}
153 run ${REPO_DIR} git remote add local_master ${MASTER_REPO}
156 msg "pushing ${NAME} to local master"
157 run ${REPO_DIR} git fetch local_master --tags
158 run ${REPO_DIR} git fetch local_master
159 merge_all_branches $REPO_DIR $NAME local_master
160 if [ -n "$FAILED_CMDS" ]; then
161 pushd ${REPO_DIR} > /dev/null
162 STATUS_OUT=$(git status)
165 body="STATUS in ${REPO_DIR}:\n${STATUS_OUT} \n\n------------\n FAILED COMMANDS:\n"
166 for line in "${FAILED_CMDS[@]}"; do body="$body$line\n"; done
167 error $REPO_DIR "git-mirror.sh failed on with module ${NAME}" "$body"
170 run ${REPO_DIR} git push --tags local_master
171 push_all_branches $REPO_DIR $NAME local_master origin
172 if [ -n "$FAILED_CMDS" ]; then
174 body="FAILED COMMANDS:\n"
175 for line in "${FAILED_CMDS[@]}"; do body="$body$line\n"; done
176 error $REPO_DIR "git-mirror.sh failed to push back with module ${NAME}" "$body"
179 # success, remove previous check file if any
180 rm -f $REPO_DIR/$NOTIFIED_FILE
184 echo "Usage $COMMAND [-a admin-mails] [-r remote-git-url] [-q] [-v] REPONAME*"
188 while getopts "a:r:qvh" opt; do
191 r) REMOTE_GIT=$OPTARG ;;
195 \?) echo "Invalid option: -$opt" >&2 ;;
200 # is the stamp older than an hour ?
203 is_old=$(find $RUNNING_FILE -mmin +$GRACE 2> /dev/null)
204 if [ -n "$is_old" ] ; then
205 msg "$RUNNING_FILE is older than $GRACE minutes - removing"
209 if [ -f $RUNNING_FILE ] ; then
210 msg "Found $RUNNING_FILE - another git-mirror seems to be running. Aborting... "
217 for gitrepo in "$@"; do mirror_repo $gitrepo ; done