rev control now operates only when repo writable
[feisty_meow.git] / scripts / rev_control / version_control.sh
1 #!/bin/bash
2
3 # these are helper functions for doing localized revision control.
4 # this script should be sourced into other scripts that use it.
5
6 source "$FEISTY_MEOW_SCRIPTS/core/launch_feisty_meow.sh"
7 source "$FEISTY_MEOW_SCRIPTS/tty/terminal_titler.sh"
8
9 # the maximum depth that the recursive functions will try to go below the starting directory.
10 export MAX_DEPTH=5
11
12 #hmmm: re-address this code, since it doesn't make a lot of sense to me right now...
13 # one unpleasantry to take care of first; cygwin barfs aggressively if the TMP directory
14 # is a DOS path, but we need it to be a DOS path for our GFFS testing, so that blows.
15 # to get past this, TMP gets changed below to a hopefully generic and safe place.
16
17 if [[ "$TMP" =~ .:.* ]]; then
18   echo making weirdo temporary directory for DOS path.
19   export TMP=/tmp/rev_control_$USER
20 fi
21 if [ ! -d "$TMP" ]; then
22   mkdir -p $TMP
23 fi
24 if [ ! -d "$TMP" ]; then
25   echo "could not create the temporary directory TMP in: $TMP"
26   echo "this script will not work properly without an existing TMP directory."
27 fi
28
29 this_host=
30 # gets the machine's hostname and stores it in the variable "this_host".
31 function get_our_hostname()
32 {
33   if [ "$OS" == "Windows_NT" ]; then
34     this_host=$(hostname)
35   elif [ ! -z "$(echo $MACHTYPE | grep apple)" ]; then
36     this_host=$(hostname)
37   elif [ ! -z "$(echo $MACHTYPE | grep suse)" ]; then
38     this_host=$(hostname --long)
39   else
40     this_host=$(hostname)
41   fi
42   #echo "hostname is $this_host"
43 }
44
45 # this function sets a variable called "home_system" to "true" if the
46 # machine is considered one of fred's home machines.  if you are not
47 # fred, you may want to change the machine choices.
48 export home_system=
49 function is_home_system()
50 {
51   # load up the name of the host.
52   get_our_hostname
53   # reset the variable that we'll be setting.
54   home_system=
55   if [[ $this_host == *.gruntose.blurgh ]]; then
56     home_system=true
57 #temp code
58 elif [[ $this_host == buildy ]]; then
59 home_system=true
60 elif [[ $this_host == simmy ]]; then
61 home_system=true
62 #temp code
63   fi
64 }
65
66 #hmmm: move to core.
67 # makes sure that the "folder" is a directory and is writable.
68 # remember that bash successful returns are zeroes...
69 function test_writeable()
70 {
71   local folder="$1"; shift
72   if [ ! -d "$folder" -o ! -w "$folder" ]; then return 1; fi
73   return 0
74 }
75
76 # we only want to totally personalize this script if the user is right.
77 function check_user()
78 {
79   if [ "$USER" == "fred" ]; then
80     export SVNUSER=fred_t_hamster@
81     export EXTRA_PROTOCOL=+ssh
82   else
83     export SVNUSER=
84     export EXTRA_PROTOCOL=
85   fi
86 }
87
88 # calculates the right modifier for hostnames / repositories.
89 modifier=
90 function compute_modifier()
91 {
92   modifier=
93   directory="$1"; shift
94   in_or_out="$1"; shift
95   check_user
96   # some project specific overrides.
97   if [[ "$directory" == hoople* ]]; then
98     modifier="svn${EXTRA_PROTOCOL}://${SVNUSER}svn.code.sf.net/p/hoople2/svn/"
99   fi
100   if [[ "$directory" == yeti* ]]; then
101     modifier="svn${EXTRA_PROTOCOL}://${SVNUSER}svn.code.sf.net/p/yeti/svn/"
102   fi
103   # see if we're on one of fred's home machines.
104   is_home_system
105   # special override to pick local servers when at home.
106   if [ "$home_system" == "true" ]; then
107     if [ "$in_or_out" == "out" ]; then
108       # need the right home machine for modifier when checking out.
109 #huhhh?      modifier="svn://shaggy/"
110       modifier=
111     else 
112       # no modifier for checkin.
113       modifier=
114     fi
115   fi
116 }
117
118 # selects the method for check-in based on where we are.
119 function do_checkin()
120 {
121   local directory="$1"; shift
122
123   save_terminal_title
124
125   do_update "$directory"
126   if [ $? -ne 0 ]; then
127     echo "repository update failed; this should be fixed before check-in."
128     return 1
129   fi
130   pushd "$directory" &>/dev/null
131   local retval=0  # normally successful.
132   if [ -f ".no-checkin" ]; then
133     echo "skipping check-in due to presence of .no-checkin sentinel file."
134   elif [ -d "CVS" ]; then
135     if test_writeable "CVS"; then
136       cvs ci .
137       retval=$?
138     fi
139   elif [ -d ".svn" ]; then
140     if test_writeable ".svn"; then
141       svn ci .
142       retval=$?
143     fi
144   elif [ -d ".git" ]; then
145     if test_writeable ".git"; then
146       # snag all new files.  not to everyone's liking.
147       git add --all .
148       retval=$?
149       # tell git about all the files and get a check-in comment.
150       git commit .
151       retval+=$?
152       # upload the files to the server so others can see them.
153       git push 2>&1 | grep -v "X11 forwarding request failed"
154       retval+=$?
155     fi
156   else
157     echo no repository in $directory
158     retval=1
159   fi
160   popd &>/dev/null
161
162   restore_terminal_title
163
164   return $retval
165 }
166
167 function do_diff
168 {
169   local directory="$1"; shift
170
171   save_terminal_title
172
173   pushd "$directory" &>/dev/null
174   local retval=0  # normally successful.
175
176   # only update if we see a repository living there.
177   if [ -d ".svn" ]; then
178     svn diff .
179   elif [ -d ".git" ]; then
180     git diff 
181   elif [ -d "CVS" ]; then
182     cvs diff .
183   fi
184
185   popd &>/dev/null
186
187   restore_terminal_title
188
189   return $retval
190 }
191
192 function do_report_new
193 {
194   local directory="$1"; shift
195
196   save_terminal_title
197
198   pushd "$directory" &>/dev/null
199   local retval=0  # normally successful.
200
201   # only update if we see a repository living there.
202   if [ -f ".no-checkin" ]; then
203     echo "skipping reporting due to presence of .no-checkin sentinel file."
204   elif [ -d ".svn" ]; then
205     # this action so far only makes sense and is needed for svn.
206     bash $FEISTY_MEOW_SCRIPTS/rev_control/svnapply.sh \? echo
207     retval=$?
208   elif [ -d ".git" ]; then
209     git status -u
210     retval=$?
211   fi
212
213   popd &>/dev/null
214
215   restore_terminal_title
216
217   return $retval
218 }
219
220 # checks in all the folders in a specified list.
221 function checkin_list()
222 {
223   # make the list of directories unique.
224   local list="$(uniquify $*)"
225
226   save_terminal_title
227
228   # turn repo list back into an array.
229   eval "repository_list=( ${REPOSITORY_LIST[*]} )"
230
231   local outer inner
232
233   for outer in "${repository_list[@]}"; do
234     # check the repository first, since it might be an absolute path.
235     if [[ $outer =~ /.* ]]; then
236       # yep, this path is absolute.  just handle it directly.
237       if [ ! -d "$outer" ]; then continue; fi
238       echo "checking in '$outer'..."
239       do_checkin $outer
240       sep 7
241     else
242       for inner in $list; do
243         # add in the directory component to see if we can find the folder.
244         local path="$inner/$outer"
245         if [ ! -d "$path" ]; then continue; fi
246         echo "checking in '$path'..."
247         do_checkin $path
248         sep 7
249       done
250     fi
251   done
252
253   restore_terminal_title
254 }
255
256 # takes out the first few carriage returns that are in the input.
257 function squash_first_few_crs()
258 {
259   i=0
260   while read input_text; do
261     i=$((i+1))
262     if [ $i -le 5 ]; then
263       echo -n "$input_text  "
264     else
265       echo $input_text
266     fi
267   done
268   if [ $i -le 3 ]; then
269     # if we're still squashing eols, make sure we don't leave them hanging.
270     echo
271   fi
272 }
273
274 # selects the checkout method based on where we are (the host the script runs on).
275 function do_update()
276 {
277   directory="$1"; shift
278
279   save_terminal_title
280
281   local retval=0  # plan on success for now.
282   pushd "$directory" &>/dev/null
283   if [ -d "CVS" ]; then
284     if test_writeable "CVS"; then
285       cvs update . | squash_first_few_crs
286       retval=${PIPESTATUS[0]}
287     fi
288   elif [ -d ".svn" ]; then
289     if test_writeable ".svn"; then
290       svn update . | squash_first_few_crs
291       retval=${PIPESTATUS[0]}
292     fi
293   elif [ -d ".git" ]; then
294     if test_writeable ".git"; then
295       git pull 2>&1 | grep -v "X11 forwarding request failed" | squash_first_few_crs
296       retval=${PIPESTATUS[0]}
297     fi
298   else
299     # this is not an error necessarily; we'll just pretend they planned this.
300     echo no repository in $directory
301   fi
302   popd &>/dev/null
303
304   restore_terminal_title
305
306   return $retval
307 }
308
309 # gets all the updates for a list of folders under revision control.
310 function checkout_list()
311 {
312   local list="$(uniquify $*)"
313
314   save_terminal_title
315
316   # turn repo list back into an array.
317   eval "repository_list=( ${REPOSITORY_LIST[*]} )"
318
319   local outer inner
320
321   for outer in "${repository_list[@]}"; do
322     # check the repository first, since it might be an absolute path.
323     if [[ $outer =~ /.* ]]; then
324       # yep, this path is absolute.  just handle it directly.
325       if [ ! -d "$outer" ]; then continue; fi
326       echo "retrieving '$outer'..."
327       do_update $outer
328       sep 7
329     else
330       for inner in $list; do
331         # add in the directory component to see if we can find the folder.
332         local path="$inner/$outer"
333         if [ ! -d "$path" ]; then continue; fi
334         echo "retrieving '$path'..."
335         do_update $path
336         sep 7
337       done
338     fi
339   done
340
341   restore_terminal_title
342 }
343
344 # provides a list of absolute paths of revision control directories
345 # that are located under the directory passed as the first parameter.
346 function generate_rev_ctrl_filelist()
347 {
348   local dir="$1"; shift
349   pushd "$dir" &>/dev/null
350   local dirhere="$( \cd "$(\dirname "$dir")" && /bin/pwd )"
351   local tempfile=$(mktemp /tmp/zz_checkins.XXXXXX)
352   echo >$tempfile
353   find $dirhere -follow -maxdepth $MAX_DEPTH -type d -iname ".svn" -exec echo {}/.. ';' >>$tempfile 2>/dev/null
354   find $dirhere -follow -maxdepth $MAX_DEPTH -type d -iname ".git" -exec echo {}/.. ';' >>$tempfile 2>/dev/null
355   # CVS is not well behaved like git and (now) svn, and we seldom use it anymore.
356   popd &>/dev/null
357   local sortfile=$(mktemp /tmp/zz_checkin_sort.XXXXXX)
358   sort <"$tempfile" >"$sortfile"
359   \rm "$tempfile"
360   echo "$sortfile"
361 }
362
363 # iterates across a list of directories contained in a file (first parameter).
364 # on each directory name, it performs the action (second parameter) provided.
365 function perform_revctrl_action_on_file()
366 {
367
368 #hmmm: this doesn't capture any error returns!
369
370   local tempfile="$1"; shift
371   local action="$1"; shift
372
373   save_terminal_title
374
375   while read -u 3 dirname; do
376     if [ -z "$dirname" ]; then continue; fi
377     pushd "$dirname" &>/dev/null
378     echo "[$(pwd)]"
379     $action .
380     sep 7
381     popd &>/dev/null
382   done 3<"$tempfile"
383
384   restore_terminal_title
385
386   rm $tempfile
387 }
388
389