(sitka) [RT18017] Fixed sync using local instead of remote branch
[sitka/sitka-tools.git] / deployment / git-deploy.sh
1 #!/bin/bash
2
3 #TODO decide about sql files and other odd files
4
5 PROD_SERVERS=" app1-1 app1-2 app2-1 app2-2 app3-1 app3-2 stanns bibc-prod "
6 REPO='.'
7 PATHMAP_FILE='pathmap.ini'
8
9 function usage()
10 {
11     cat <<EOF
12 USAGE:
13 ./git-deploy.sh -g ~/evergreen/.git -r origin -b HEAD host1 [ host2 ... ]
14 ./git-deploy.sh -r origin -b user/lwhalen/rt15288 -P
15
16 This script is currently in testing.  By default it will echo the commands it would run to the screen.
17 If you wan to deploy something you need to use the -d option.
18
19 e.g. ./git-deploy.sh -r origin -b HEAD -d host1
20
21 As well, this script will not deploy to our production servers currently.  It will print out a message
22 saying so if you try to use a production server as a host option or if you use the -P option to deploy
23 to all production servers.
24
25 OPTIONS:
26     -g The location of the git repo
27     -r The remote to deploy from
28     -b The branch on the remote to deploy from
29     -c The config file with the path mapping between the repo and the server
30     -P Deploy to all production servers
31     -d Actually deploy.  While testing this option is needed to force the commands to execute
32     -s Sync the entire branch (as much as possible tt2, pm, js, maybe others?) with the server(s)
33     -h This help information
34 EOF
35 }
36
37 function get_hostname() {
38     HOST=$1
39     echo `echo $HOST | sed -e 's/^\([^.]*\).*$/\1/'`
40 }
41
42 function create_tmp_file() {
43     TMP_DIR=$1
44     FILENAME=$2
45     touch $TMP_DIR/$FILENAME
46     echo "$TMP_DIR/$FILENAME"
47 }
48
49 function does_file_exist() {
50     FILE=$1;
51     if [ `ls $FILE 2> /dev/null | wc -l` -eq 1 ]
52     then
53         return 0
54     else
55         return 1
56     fi
57 }
58     
59 function find_base_path() {
60     RELATIVE_PATH=$1
61     HOST=$2
62     HOST=`get_hostname $HOST` 
63
64     if does_file_exist ${HOST}'_'$PATHMAP_FILE
65     then
66         LOCAL_PATHMAP_FILE=${HOST}'_'$PATHMAP_FILE
67     elif does_file_exist $PATHMAP_FILE 
68     then
69         LOCAL_PATHMAP_FILE=$PATHMAP_FILE
70     else
71         echo "$PATHMAP file could not be found!" >&2
72         exit 4
73     fi
74
75     for COMPONENT in `$ACCESS_PATHMAP --config $LOCAL_PATHMAP_FILE`
76     do
77         BASE_PATH=`$ACCESS_PATHMAP --config $LOCAL_PATHMAP_FILE --component $COMPONENT --srcpath $RELATIVE_PATH`
78         if [[ $BASE_PATH ]]
79         then
80             echo $BASE_PATH
81             return
82         fi
83     done
84 }
85
86 function get_full_path() {
87     RELATIVE_PATH=$1
88     BASE_PATH=$2
89
90     if [[ $BASE_PATH ]]
91     then
92         #We extract the last directory in the base path so we can
93         #use parameter substitution to remove everything up to the
94         #last directory in the BASE_PATH from the RELATIVE_PATH
95         #this leaves us with the part of the git source tree path
96         #that needs to be appended to the base path in order to locate
97         #the file on the server
98         LAST_DIR_IN_BASE_PATH=`basename $BASE_PATH`
99         RELATIVE_PART=${RELATIVE_PATH/*$LAST_DIR_IN_BASE_PATH/}
100         echo $BASE_PATH$RELATIVE_PART
101         return
102     fi
103 }
104
105 function deployfile() {
106     REMOTE=$1
107     BRANCH=$2
108     BASE_PATH=$3
109     RELATIVE_PATH=$4
110     FILENAME=$5
111     TMP_DIR=$6
112     HOST=$7
113
114     PERL_FILE_RE='^.*.pm$'
115     SQL_FILE_RE='^.*.sql$'
116     TT2_FILE_RE='^Open-ILS/src/(templates)/(.*)$'
117     USER='opensrf'
118
119     if [[ $FILENAME =~ $PERL_FILE_RE ]]
120     then
121         USER='root'
122     elif [[ $FILENAME =~ $SQL_FILE_RE ]]
123     then
124         echo 'SQL file -- TAKE THE TIME TO LOAD THIS PROPERLY INTO THE DATABASE.  DO NOT FORGET TO WRAP IT IN BEGIN AND COMMIT'
125         return
126     else
127         USER='opensrf'
128     fi
129
130     FULL_PATH=`get_full_path $RELATIVE_PATH $BASE_PATH`
131
132     TEMPFILE=`create_tmp_file $TMP_DIR $FILENAME`
133     git --git-dir $REPO show $REMOTE/$BRANCH:$RELATIVE_PATH/$FILENAME > $TEMPFILE
134     
135     if [[ $PROD_SERVERS =~ " `echo $HOST | cut -d '.' -f 1` " ]]
136     then
137         echo "Cannot deploy `basename $TEMPFILE` to $HOST while testing.  Please use another server"
138     else 
139         COMMAND="deployfile.sh -f $TEMPFILE -p $FULL_PATH -u $USER -b $HOST"
140         if [[ -z "$DEPLOY" ]]
141         then
142             echo $COMMAND
143         else 
144             $COMMAND
145         fi
146     fi
147 }
148
149 while getopts ":g:r:b:c:Pdsh" opt
150 do
151     case $opt in
152         g ) REPO=$OPTARG;;
153         r ) REMOTE=$OPTARG;;
154         b ) BRANCH=$OPTARG;;
155         c ) PATHMAP_FILE=$OPTARG;;
156         P ) PROD="P";;
157         d ) DEPLOY="d";;
158         s ) SYNC="s";;
159         h ) usage && exit 0;;
160     esac
161 done
162
163 if [[ ! "$REPO" =~ .git$ ]]
164 then
165     REPO=$REPO"/.git"
166 fi
167
168 shift $(($OPTIND - 1))
169
170 if [[ -z "$PROD" ]]
171 then
172     HOST_LIST=$@
173 else
174     HOST_LIST=$@$PROD_SERVERS
175 fi
176
177 if [[ -z $HOST_LIST ]]
178 then
179     echo 'You must specify a host to deploy to in order to use this script' >&2
180     exit 1
181 fi
182
183 if [[ ! -z $SYNC ]]
184 then
185     read -p "Are you SURE you want to sync $HOST_LIST with $BRANCH (Yes/No): " ANSWER 2>&1
186     if [[ ! "$ANSWER" =~ [Yy]es ]]
187     then
188         echo "Aborting sync" >&2
189         exit 2;
190     fi
191 fi
192
193 #This line takes the host list and separates it into individual lines, then sorts it. Next it removes anything following the hostname with get_hostname
194 #(hopefully the domain name), then makes it a single line again with _ instead of ' '.
195 #It then uses parameter substitution to remove the last character from the string, which is a _ because sort places a newline at the end of the
196 #last server that gets translated into an unwanted _.  We need to sort the servers, so that they are used in a consistent manner for tracking
197 #deployment
198 HOST_LIST_FOR_DIR_NAME=`echo $HOST_LIST | tr ' ' '\n' | sort | while read SORTED_HOST_LIST ; do get_hostname $SORTED_HOST_LIST ; done | tr '\n' '_' | { read SORTED_HOST_LIST; echo ${SORTED_HOST_LIST%?}; }`
199 TMP_DIR='/tmp/'$BRANCH'/'$HOST_LIST_FOR_DIR_NAME'/'`date +%Y_%m_%d_%H_%M_%S`
200
201 mkdir -p $TMP_DIR
202
203 if [[ -z "$SYNC" ]]
204 then
205     LIST_BRANCH_FILES=`git --git-dir $REPO show $REMOTE/$BRANCH --name-only --oneline | awk '{if(NR!=1) {print}}'`
206 else
207     LIST_BRANCH_FILES=`cd $REPO && git ls-tree -r  --full-name $REMOTE/$BRANCH | cut -f 2`
208 fi
209
210 #Find access_pathmap.pl and if not found assume it is in current direcotry
211 ACCESS_PATHMAP=`which access_pathmap.pl`
212
213 if [[ -z $ACCESS_PATHMAP ]]
214 then
215     if does_file_exist access_pathmap.pl
216     then
217         ACCESS_PATHMAP='./access_pathmap.pl'
218     else
219         echo 'Could not locate access_pathmap.pl.  Either add access_pathmap.pl to your PATH or place it in the directory you are working in.' >&2
220         exit 3
221     fi
222 fi
223
224 for PATH_AND_FILENAME in $LIST_BRANCH_FILES
225 do
226     FILENAME=`basename $PATH_AND_FILENAME`
227     RELATIVE_PATH=`dirname $PATH_AND_FILENAME`
228     for DEPLOY_HOST in $HOST_LIST
229     do
230         BASE_PATH=`find_base_path $RELATIVE_PATH $DEPLOY_HOST`
231         if [[ $BASE_PATH ]]
232         then
233             deployfile $REMOTE $BRANCH $BASE_PATH $RELATIVE_PATH $FILENAME $TMP_DIR $DEPLOY_HOST
234         else
235             echo "Could not deploy $FILENAME to $DEPLOY_HOST because no mapping could be found in $PATHMAP_FILE or any host specific pathmap files" >&2
236         fi
237     done
238 done