949234f72452baab2a271456cccc2bd44ee05081
[infrastructure.git] / scripts / git-mirror.sh
1 #!/bin/bash
2
3 ADMINS="Talip-Baris.Metin@inria.fr Thierry.Parmentelat@inria.fr"
4 MIRROR_GIT="git://git.planet-lab.org"
5 MASTER_GIT="/git"
6 LOCAL_MIRROR_DIR="/git-mirror"
7 QUIET=0
8 FAILED=0
9 FAILED_CMDS=""
10 NOTIFIED_FILE="NOTIFIED_ADMINS"
11
12 function msg () {
13     if [ $QUIET -eq 0 ]
14     then
15         echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx $@"
16     fi
17 }
18
19 function error () {
20     SUBJECT=$1
21     MSG=$2
22     CHECK_FILE=$3/$NOTIFIED_FILE
23
24     if [ -f $CHECK_FILE ]
25     then
26         return
27     fi
28
29     for admin in $ADMINS
30     do
31         echo -e "$MSG" | mail -s "$SUBJECT" $admin
32     done
33     touch $CHECK_FILE
34 }
35
36 function run () {
37     if [ $QUIET -eq 1 ]
38     then
39         COMMAND="$1 &> /dev/null"
40     else
41         COMMAND="$1"
42         msg $COMMAND
43     fi
44     REPO=$2
45
46     pushd ${REPO} > /dev/null
47     eval $COMMAND
48     if [ $? -ne 0 ]
49     then
50         FAILED=1
51         FAILED_CMDS="$FAILED_CMDS\n$COMMAND" 
52     fi
53     popd > /dev/null
54 }
55
56 function run_ignore_errors () {
57     OLD_FAILED=$FAILED
58     OLD_FAILED_CMDS=$FAILED_CMDS
59     run "$1" "$2"
60     FAILED=$OLD_FAILED
61     FAILED_CMDS=$OLD_FAILED_CMDS
62 }
63
64 function merge_all_branches () {
65     NAME=$1
66     REMOTE=$2
67     REPO_DIR=$3
68
69     pushd $REPO_DIR > /dev/null
70     BRANCHES=$(git branch -r | grep $REMOTE | grep -v HEAD | sed "s/.*\///g" | grep -v master)
71     popd > /dev/null
72
73     run "git checkout master" ${REPO_DIR}
74     run "git merge --ff $REMOTE/master" ${REPO_DIR}
75     for BRANCH in $BRANCHES ; do
76         run_ignore_errors "git branch $BRANCH $REMOTE/$BRANCH" ${REPO_DIR}
77         run "git checkout $BRANCH" ${REPO_DIR}
78         run "git merge --ff $REMOTE/$BRANCH" ${REPO_DIR}
79     done
80 }
81
82 function push_all_branches () {
83     NAME=$1
84     REMOTE=$2
85     REPO_DIR=$3
86
87     pushd $REPO_DIR > /dev/null
88     BRANCHES=$(git branch -r | grep $REMOTE | grep -v HEAD | sed "s/.*\///g" | grep -v master)
89     popd > /dev/null
90
91     run "git push $REMOTE master:master" ${REPO_DIR}
92     for BRANCH in $BRANCHES ; do
93         run "git push $REMOTE $BRANCH:$BRANCH" ${REPO_DIR}
94     done
95 }
96
97 function mirror () {
98     for arg in "$@" ; do
99         FAILED=0   # reset previous failure if any
100
101         NAME=$(basename ${arg} | sed s/.git$//g)
102         GIT_NAME=${NAME}.git
103         REPO_DIR=${LOCAL_MIRROR_DIR}/${NAME}
104         MIRROR_REPO=${MIRROR_GIT}/${GIT_NAME}
105         MASTER_REPO=${MASTER_GIT}/${GIT_NAME}
106
107
108         # if there is no remote repository it may be that we only have
109         # the repository locally and don't need to mirror
110         git ls-remote $MIRROR_REPO &> /dev/null
111         if [ $? -eq 0 ]
112         then
113             if [ -d ${REPO_DIR} ]
114             then
115                 msg "pulling from ${NAME}"
116                 run "git fetch origin --tags" ${REPO_DIR}
117                 run "git fetch origin" ${REPO_DIR}
118                 merge_all_branches $NAME origin $REPO_DIR
119                 if [ $? -ne 0 ]
120                 then
121                     error "git-mirror.sh failed" "Can not fetch from ${MASTER_REPO}" $REPO_DIR
122                 fi
123             else
124                 msg "mirroring ${NAME} for the first time"
125                 run "git clone ${MIRROR_REPO}" ${LOCAL_MIRROR_DIR}
126                 run "git remote add local_master ${MASTER_REPO}" ${REPO_DIR}
127             fi
128
129             msg "pushing ${NAME} to local master"
130             run "git fetch local_master --tags" ${REPO_DIR}
131             run "git fetch local_master" ${REPO_DIR}
132             merge_all_branches $NAME local_master $REPO_DIR
133             if [ $FAILED -ne 0 ]
134             then
135                 pushd ${REPO_DIR} > /dev/null
136                 STATUS_OUT=$(git status)
137                 popd > /dev/null                
138                 error "git-mirror.sh failed on ${MIRROR_REPO}" "STATUS:\n$STATUS_OUT \n\n------------\n FAILED COMMANDS:\n$FAILED_CMDS" $REPO_DIR
139             else
140                 run "git push --tags local_master" ${REPO_DIR}
141                 push_all_branches $NAME local_master $REPO_DIR
142
143                 # success, remove previous check file if any
144                 CHECK_FILE=$REPO_DIR/$NOTIFIED_FILE
145                 rm -f $CHECK_FILE
146             fi
147         fi
148     done
149 }
150
151
152 while getopts ":hq" opt
153 do
154   case $opt in
155       q)
156           QUIET=1
157           break
158           ;;
159       h)
160           echo "USAGE: $0 [-q] REPONAME*"
161           exit 1
162           ;;
163       \?)
164           echo "Invalid option: -$OPTARG" >&2
165           ;;
166   esac
167 done
168
169 shift $((OPTIND-1))
170 mirror $@
171