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