From 7e4fea9d6203a056790e07d1e0200c5712dd6be8 Mon Sep 17 00:00:00 2001 From: Thierry Parmentelat Date: Thu, 13 Oct 2011 11:37:00 +0200 Subject: [PATCH] refactored for better logging, as well as command line options --- scripts/git-mirror.sh | 238 ++++++++++++++++++++++-------------------- 1 file changed, 122 insertions(+), 116 deletions(-) diff --git a/scripts/git-mirror.sh b/scripts/git-mirror.sh index 6be3b00..7768b48 100755 --- a/scripts/git-mirror.sh +++ b/scripts/git-mirror.sh @@ -1,171 +1,177 @@ #!/bin/bash +COMMAND=$(basename $0) -ADMINS="Talip-Baris.Metin@inria.fr Thierry.Parmentelat@inria.fr" -MIRROR_GIT="git://git.planet-lab.org" +# for sending emails (-a option) +ADMINS="Thierry.Parmentelat@inria.fr baris@metin.org" +# the other end of the mirror (-r option) +REMOTE_GIT="git://git.planet-lab.org" +# -q option +QUIET= + +# 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" -QUIET=0 -FAILED=0 -FAILED_CMDS="" +# a file in each repo to avoid too many notifications NOTIFIED_FILE="NOTIFIED_ADMINS" +# global stamp to avoid multiple instances of this script RUNNING_FILE=$LOCAL_MIRROR_DIR/RUNNING_MIRROR +# global list - errors to report +FAILED_CMDS=() function msg () { - if [ $QUIET -eq 0 ] ; then - echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "$@" - fi + [ -n "$QUIET" ] || echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "$@" +} + +function failure () { + msg "Received signal - cleaning up $RUNNING_FILE and aborting" + rm -f $RUNNING_FILE + exit 1 } function error () { - SUBJECT=$1 - MSG=$2 - CHECK_FILE=$3/$NOTIFIED_FILE + local REPO=$1; shift + local SUBJECT=$1; shift + local BODY=$1; shift - if [ -f $CHECK_FILE ]; then - return - fi + # already notified ? + [ -f $REPO/$NOTIFIED_FILE ] && return for admin in $ADMINS; do - echo -e "$MSG" | mail -s "$SUBJECT" $admin + echo -e "$BODY" | mail -s "$SUBJECT" $admin done - touch $CHECK_FILE + touch $REPO/$NOTIFIED_FILE } +# run directory command +# -or- to ignore errors +# run -i directory "command" function run () { - if [ $QUIET -eq 1 ]; then - COMMAND="$1 &> /dev/null" - else - COMMAND="$1" - msg $COMMAND - fi - REPO=$2 + local IGNORE="" + case "$1" in -i) IGNORE=true ; shift ;; esac + local REPO=$1; shift + local COMMAND="$@" pushd ${REPO} > /dev/null - eval $COMMAND - if [ $? -ne 0 ]; then - FAILED=1 - FAILED_CMDS="$FAILED_CMDS\n$COMMAND" + # quiet mode: record stdout and err for the mail + ok=true + if [ -n "$QUIET" ] ; then + OUTPUT=$($COMMAND 2>&1) || ok= + TORECORD="[$REPO] $OUTPUT" + else + echo "[$REPO] Running $COMMAND" + $COMMAND || ok= + TORECORD="$COMMAND" + fi + # failed ? + if [ -z "$ok" ]; then + # let's record the failure unless ignore is set + if [ -z "$IGNORE" ] ; then + FAILED_CMDS=("${FAILED_CMDS[@]}" "$TORECORD") + fi 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 + local REPO_DIR=$1; shift + local NAME=$1; shift + local REMOTE=$1; shift 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} + run ${REPO_DIR} git checkout master + run ${REPO_DIR} git merge --ff $REMOTE/master 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} + run -i ${REPO_DIR} git branch $BRANCH $REMOTE/$BRANCH + run ${REPO_DIR} git checkout $BRANCH + run ${REPO_DIR} git merge --ff $REMOTE/$BRANCH done } function push_all_branches () { - NAME=$1 - PUSH_TO=$2 - PUSH_FROM=$3 - REPO_DIR=$4 + local REPO_DIR=$1; shift + local NAME=$1; shift + local PUSH_TO=$1; shift + local PUSH_FROM=$1; shift pushd $REPO_DIR > /dev/null BRANCHES=$(git branch -r | grep $PUSH_FROM | grep -v HEAD | sed "s/.*\///g" | grep -v master) popd > /dev/null - run "git push $PUSH_TO master:master" ${REPO_DIR} + run ${REPO_DIR} git push $PUSH_TO master:master for BRANCH in $BRANCHES ; do - run "git push $PUSH_TO $BRANCH:$BRANCH" ${REPO_DIR} + run ${REPO_DIR} git push $PUSH_TO $BRANCH:$BRANCH done } -function mirror () { - for arg in "$@" ; do - 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 - - 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 origin $REPO_DIR - - # success, remove previous check file if any - CHECK_FILE=$REPO_DIR/$NOTIFIED_FILE - rm -f $CHECK_FILE - fi - fi - done -} +function mirror_repo () { + local repo=$1; shift + FAILED_CMDS=() # reset previous failure if any + + NAME=$(basename ${repo} ".git") + GIT_NAME=${NAME}.git + REPO_DIR=${LOCAL_MIRROR_DIR}/${NAME} + REMOTE_REPO=${REMOTE_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 $REMOTE_REPO &> /dev/null || return + + if [ -d ${REPO_DIR} ] ; then + msg "pulling from ${NAME}" + run ${REPO_DIR} git fetch origin --tags + run ${REPO_DIR} git fetch origin + merge_all_branches $REPO_DIR $NAME origin + if [ $? -ne 0 ]; then + error $REPO_DIR "git-mirror.sh failed with module ${NAME}" "Can not fetch from ${MASTER_REPO}" + fi + else + msg "mirroring ${NAME} for the first time" + run ${LOCAL_MIRROR_DIR} git clone ${REMOTE_REPO} + run ${REPO_DIR} git remote add local_master ${MASTER_REPO} + fi + msg "pushing ${NAME} to local master" + run ${REPO_DIR} git fetch local_master --tags + run ${REPO_DIR} git fetch local_master + merge_all_branches $REPO_DIR $NAME local_master + if [ -n "$FAILED_CMDS" ]; then + pushd ${REPO_DIR} > /dev/null + STATUS_OUT=$(git status) + popd > /dev/null + # 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 + else + run ${REPO_DIR} git push --tags local_master + push_all_branches $REPO_DIR $NAME local_master origin + + # success, remove previous check file if any + rm -f $REPO_DIR/$NOTIFIED_FILE + fi +} -function failure () { - msg "Received signal - cleaning up $RUNNING_FILE and aborting" - rm -f $RUNNING_FILE +function usage () { + echo "Usage $COMMAND [-a admin-mails] [-r remote-git-url] [-q] REPONAME*" exit 1 } -while getopts ":hq" opt -do +while getopts "a:r:qh" opt; do case $opt in - q) - QUIET=1 - break - ;; - h) - echo "Usage: $0 [-q] REPONAME*" - exit 1 - ;; - \?) - echo "Invalid option: -$OPTARG" >&2 - ;; + a) ADMINS=$OPTARG ;; + r) REMOTE_GIT=$OPTARG ;; + q) QUIET=true ;; + h) usage ;; + \?) echo "Invalid option: -$opt" >&2 ;; esac done - # is the stamp older than an hour ? # in minutes GRACE=60 @@ -184,5 +190,5 @@ trap failure ERR INT shift $((OPTIND-1)) date > $RUNNING_FILE -mirror $@ +for gitrepo in "$@"; do mirror_repo $gitrepo ; done rm -f $RUNNING_FILE -- 2.43.0