3 flavours & 2 archs
[infrastructure.git] / scripts / git-mirror.sh
index 5dbc411..ff07de2 100755 (executable)
 #!/bin/bash
 
-MIRROR="git://git.planet-lab.org"
-LOCAL="/git"
+ADMINS="Talip-Baris.Metin@inria.fr Thierry.Parmentelat@inria.fr"
+MIRROR_GIT="git://git.planet-lab.org"
+MASTER_GIT="/git"
+LOCAL_MIRROR_DIR="/git-mirror"
+QUIET=0
+FAILED=0
+FAILED_CMDS=""
+NOTIFIED_FILE="NOTIFIED_ADMINS"
+RUNNING_FILE=$LOCAL_MIRROR_DIR/RUNNING_MIRROR
+
+function msg () {
+    if [ $QUIET -eq 0 ] ; then
+        echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "$@"
+    fi
+}
+
+function error () {
+    SUBJECT=$1
+    MSG=$2
+    CHECK_FILE=$3/$NOTIFIED_FILE
+
+    if [ -f $CHECK_FILE ];  then
+        return
+    fi
+
+    for admin in $ADMINS; do
+        echo -e "$MSG" | mail -s "$SUBJECT" $admin
+    done
+    touch $CHECK_FILE
+}
+
+function run () {
+    if [ $QUIET -eq 1 ]; then
+        COMMAND="$1 &> /dev/null"
+    else
+        COMMAND="$1"
+        msg $COMMAND
+    fi
+    REPO=$2
+
+    pushd ${REPO} > /dev/null
+    eval $COMMAND
+    if [ $? -ne 0 ]; then
+        FAILED=1
+        FAILED_CMDS="$FAILED_CMDS\n$COMMAND" 
+    fi
+    popd > /dev/null
+}
+
+function run_ignore_errors () {
+    OLD_FAILED=$FAILED
+    OLD_FAILED_CMDS=$FAILED_CMDS
+    run "$1" "$2"
+    FAILED=$OLD_FAILED
+    FAILED_CMDS=$OLD_FAILED_CMDS
+}
+
+function merge_all_branches () {
+    NAME=$1
+    REMOTE=$2
+    REPO_DIR=$3
+
+    pushd $REPO_DIR > /dev/null
+    BRANCHES=$(git branch -r | grep $REMOTE | grep -v HEAD | sed "s/.*\///g" | grep -v master)
+    popd > /dev/null
+
+    run "git checkout master" ${REPO_DIR}
+    run "git merge --ff $REMOTE/master" ${REPO_DIR}
+    for BRANCH in $BRANCHES ; do
+        run_ignore_errors "git branch $BRANCH $REMOTE/$BRANCH" ${REPO_DIR}
+        run "git checkout $BRANCH" ${REPO_DIR}
+        run "git merge --ff $REMOTE/$BRANCH" ${REPO_DIR}
+    done
+}
+
+function push_all_branches () {
+    NAME=$1
+    REMOTE=$2
+    REPO_DIR=$3
+
+    pushd $REPO_DIR > /dev/null
+    BRANCHES=$(git branch -r | grep $REMOTE | grep -v HEAD | sed "s/.*\///g" | grep -v master)
+    popd > /dev/null
+
+    run "git push $REMOTE master:master" ${REPO_DIR}
+    for BRANCH in $BRANCHES ; do
+        run "git push $REMOTE $BRANCH:$BRANCH" ${REPO_DIR}
+    done
+}
 
 function mirror () {
     for arg in "$@" ; do
-        REPO=${arg}
-        REPO_NAME=${REPO}.git
-        MIRROR_REPO=${MIRROR}/${REPO_NAME}
-        LOCAL_REPO=${LOCAL}/${REPO_NAME}
-
-        if [ -d ${REPO} ]
-        then
-           echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx pulling from ${REPO_NAME}"
-            pushd ${REPO}
-            git fetch --tags
-            git pull
-            popd
-        else
-            echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx mirroring in ${REPO_NAME} for the first time"
-            git clone ${MIRROR_REPO}
-            pushd ${REPO}
-            git remote add local_master ${LOCAL_REPO}
-            popd
-        fi
+        FAILED=0   # reset previous failure if any
+
+        NAME=$(basename ${arg} | sed s/.git$//g)
+        GIT_NAME=${NAME}.git
+        REPO_DIR=${LOCAL_MIRROR_DIR}/${NAME}
+        MIRROR_REPO=${MIRROR_GIT}/${GIT_NAME}
+        MASTER_REPO=${MASTER_GIT}/${GIT_NAME}
+
+
+        # 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 $MIRROR_REPO &> /dev/null
+        if [ $? -eq 0 ]; then
+            if [ -d ${REPO_DIR} ]; then
+               msg "pulling from ${NAME}"
+                run "git fetch origin --tags" ${REPO_DIR}
+               run "git fetch origin" ${REPO_DIR}
+                merge_all_branches $NAME origin $REPO_DIR
+                if [ $? -ne 0 ]; then
+                    error "git-mirror.sh failed" "Can not fetch from ${MASTER_REPO}" $REPO_DIR
+                fi
+            else
+                msg "mirroring ${NAME} for the first time"
+                run "git clone ${MIRROR_REPO}" ${LOCAL_MIRROR_DIR}
+                run "git remote add local_master ${MASTER_REPO}" ${REPO_DIR}
+            fi
 
-        echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx pushing ${REPO_NAME} to local master"
-        pushd ${REPO}
-        git fetch local_master --tags
-        git pull local_master
-            
-        git push local_master
-        git push --tags local_master
-        popd
+            msg "pushing ${NAME} to local master"
+            run "git fetch local_master --tags" ${REPO_DIR}
+            run "git fetch local_master" ${REPO_DIR}
+            merge_all_branches $NAME local_master $REPO_DIR
+            if [ $FAILED -ne 0 ]; then
+                pushd ${REPO_DIR} > /dev/null
+                STATUS_OUT=$(git status)
+                popd > /dev/null                
+                error "git-mirror.sh failed on ${MIRROR_REPO}" "STATUS:\n$STATUS_OUT \n\n------------\n FAILED COMMANDS:\n$FAILED_CMDS" $REPO_DIR
+            else
+                run "git push --tags local_master" ${REPO_DIR}
+                push_all_branches $NAME local_master $REPO_DIR
+
+                # success, remove previous check file if any
+                CHECK_FILE=$REPO_DIR/$NOTIFIED_FILE
+                rm -f $CHECK_FILE
+            fi
+        fi
     done
 }
 
-args="$@"
-[[ -z "$args" ]] && args=$(ls /svn)
 
-mirror $args
+function failure () {
+    msg "Received signal - cleaning up $RUNNING_FILE and aborting"
+    rm -f $RUNNING_FILE
+    exit 1
+}
+
+while getopts ":hq" opt
+do
+  case $opt in
+      q)
+          QUIET=1
+          break
+          ;;
+      h)
+          echo "Usage: $0 [-q] REPONAME*"
+          exit 1
+          ;;
+      \?)
+          echo "Invalid option: -$OPTARG" >&2
+          ;;
+  esac
+done
+
+
+# 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
+
+if [ -f $RUNNING_FILE ] ; then
+    msg "Found $RUNNING_FILE - another git-mirror seems to be running. Aborting... " 
+    exit 1
+fi
+
+trap failure ERR INT
 
+shift $((OPTIND-1))
+date > $RUNNING_FILE
+mirror $@
+rm -f $RUNNING_FILE