fixed up wording in recursives
[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   # make a nice echoer since we want to use it inside conditions below.
126   local nicedir="$directory"
127   if [ $nicedir == "." ]; then
128     nicedir=$(\pwd)
129   fi
130   local blatt="echo checking in '$nicedir'..."
131
132   do_update "$directory"
133   if [ $? -ne 0 ]; then
134     echo "repository update failed; this should be fixed before check-in."
135     return 1
136   fi
137   pushd "$directory" &>/dev/null
138   local retval=0  # normally successful.
139   if [ -f ".no-checkin" ]; then
140     echo "skipping check-in due to presence of .no-checkin sentinel file."
141   elif [ -d "CVS" ]; then
142     if test_writeable "CVS"; then
143       $blatt
144       cvs ci .
145       retval=$?
146     fi
147   elif [ -d ".svn" ]; then
148     if test_writeable ".svn"; then
149       $blatt
150       svn ci .
151       retval=$?
152     fi
153   elif [ -d ".git" ]; then
154     if test_writeable ".git"; then
155       $blatt
156       # snag all new files.  not to everyone's liking.
157       git add --all .
158       retval=$?
159       # tell git about all the files and get a check-in comment.
160       git commit .
161       retval+=$?
162       # upload the files to the server so others can see them.
163       git push 2>&1 | grep -v "X11 forwarding request failed"
164       retval+=$?
165     fi
166   else
167     echo no repository in $directory
168     retval=1
169   fi
170   popd &>/dev/null
171
172   restore_terminal_title
173
174   return $retval
175 }
176
177 function do_diff
178 {
179   local directory="$1"; shift
180
181   save_terminal_title
182
183   pushd "$directory" &>/dev/null
184   local retval=0  # normally successful.
185
186   # only update if we see a repository living there.
187   if [ -d ".svn" ]; then
188     svn diff .
189   elif [ -d ".git" ]; then
190     git diff 
191   elif [ -d "CVS" ]; then
192     cvs diff .
193   fi
194
195   popd &>/dev/null
196
197   restore_terminal_title
198
199   return $retval
200 }
201
202 function do_report_new
203 {
204   local directory="$1"; shift
205
206   save_terminal_title
207
208   pushd "$directory" &>/dev/null
209   local retval=0  # normally successful.
210
211   # only update if we see a repository living there.
212   if [ -f ".no-checkin" ]; then
213     echo "skipping reporting due to presence of .no-checkin sentinel file."
214   elif [ -d ".svn" ]; then
215     # this action so far only makes sense and is needed for svn.
216     bash $FEISTY_MEOW_SCRIPTS/rev_control/svnapply.sh \? echo
217     retval=$?
218   elif [ -d ".git" ]; then
219     git status -u
220     retval=$?
221   fi
222
223   popd &>/dev/null
224
225   restore_terminal_title
226
227   return $retval
228 }
229
230 # checks in all the folders in a specified list.
231 function checkin_list()
232 {
233   # make the list of directories unique.
234   local list="$(uniquify $*)"
235
236   save_terminal_title
237
238   # turn repo list back into an array.
239   eval "repository_list=( ${REPOSITORY_LIST[*]} )"
240
241   local outer inner
242
243   for outer in "${repository_list[@]}"; do
244     # check the repository first, since it might be an absolute path.
245     if [[ $outer =~ /.* ]]; then
246       # yep, this path is absolute.  just handle it directly.
247       if [ ! -d "$outer" ]; then continue; fi
248       do_checkin $outer
249       sep 7
250     else
251       for inner in $list; do
252         # add in the directory component to see if we can find the folder.
253         local path="$inner/$outer"
254         if [ ! -d "$path" ]; then continue; fi
255         do_checkin $path
256         sep 7
257       done
258     fi
259   done
260
261   restore_terminal_title
262 }
263
264 # takes out the first few carriage returns that are in the input.
265 function squash_first_few_crs()
266 {
267   i=0
268   while read input_text; do
269     i=$((i+1))
270     if [ $i -le 5 ]; then
271       echo -n "$input_text  "
272     else
273       echo $input_text
274     fi
275   done
276   if [ $i -le 3 ]; then
277     # if we're still squashing eols, make sure we don't leave them hanging.
278     echo
279   fi
280 }
281
282 # selects the checkout method based on where we are (the host the script runs on).
283 function do_update()
284 {
285   directory="$1"; shift
286
287   save_terminal_title
288
289   # make a nice echoer since we want to use it inside conditions below.
290   local nicedir="$directory"
291   if [ $nicedir == "." ]; then
292     nicedir=$(\pwd)
293   fi
294   local blatt="echo retrieving '$nicedir'..."
295
296   local retval=0  # plan on success for now.
297   pushd "$directory" &>/dev/null
298   if [ -d "CVS" ]; then
299     if test_writeable "CVS"; then
300       $blatt
301       cvs update . | squash_first_few_crs
302       retval=${PIPESTATUS[0]}
303     fi
304   elif [ -d ".svn" ]; then
305     if test_writeable ".svn"; then
306       $blatt
307       svn update . | squash_first_few_crs
308       retval=${PIPESTATUS[0]}
309     fi
310   elif [ -d ".git" ]; then
311     if test_writeable ".git"; then
312       $blatt
313       git pull 2>&1 | grep -v "X11 forwarding request failed" | squash_first_few_crs
314       retval=${PIPESTATUS[0]}
315     fi
316   else
317     # this is not an error necessarily; we'll just pretend they planned this.
318     echo no repository in $directory
319   fi
320   popd &>/dev/null
321
322   restore_terminal_title
323
324   return $retval
325 }
326
327 # gets all the updates for a list of folders under revision control.
328 function checkout_list()
329 {
330   local list="$(uniquify $*)"
331
332   save_terminal_title
333
334   # turn repo list back into an array.
335   eval "repository_list=( ${REPOSITORY_LIST[*]} )"
336
337   local outer inner
338
339   for outer in "${repository_list[@]}"; do
340     # check the repository first, since it might be an absolute path.
341     if [[ $outer =~ /.* ]]; then
342       # yep, this path is absolute.  just handle it directly.
343       if [ ! -d "$outer" ]; then continue; fi
344       do_update $outer
345       sep 7
346     else
347       for inner in $list; do
348         # add in the directory component to see if we can find the folder.
349         local path="$inner/$outer"
350         if [ ! -d "$path" ]; then continue; fi
351         do_update $path
352         sep 7
353       done
354     fi
355   done
356
357   restore_terminal_title
358 }
359
360 # provides a list of absolute paths of revision control directories
361 # that are located under the directory passed as the first parameter.
362 function generate_rev_ctrl_filelist()
363 {
364   local dir="$1"; shift
365   pushd "$dir" &>/dev/null
366   local dirhere="$( \cd "$(\dirname "$dir")" && /bin/pwd )"
367   local tempfile=$(mktemp /tmp/zz_checkins.XXXXXX)
368   echo >$tempfile
369   find $dirhere -follow -maxdepth $MAX_DEPTH -type d -iname ".svn" -exec echo {}/.. ';' >>$tempfile 2>/dev/null
370   find $dirhere -follow -maxdepth $MAX_DEPTH -type d -iname ".git" -exec echo {}/.. ';' >>$tempfile 2>/dev/null
371   # CVS is not well behaved like git and (now) svn, and we seldom use it anymore.
372   popd &>/dev/null
373   local sortfile=$(mktemp /tmp/zz_checkin_sort.XXXXXX)
374   sort <"$tempfile" >"$sortfile"
375   \rm "$tempfile"
376   echo "$sortfile"
377 }
378
379 # iterates across a list of directories contained in a file (first parameter).
380 # on each directory name, it performs the action (second parameter) provided.
381 function perform_revctrl_action_on_file()
382 {
383
384 #hmmm: this doesn't capture any error returns!
385
386   local tempfile="$1"; shift
387   local action="$1"; shift
388
389   save_terminal_title
390
391   while read -u 3 dirname; do
392     if [ -z "$dirname" ]; then continue; fi
393     pushd "$dirname" &>/dev/null
394     echo "[$(pwd)]"
395     $action .
396     sep 7
397     popd &>/dev/null
398   done 3<"$tempfile"
399
400   restore_terminal_title
401
402   rm $tempfile
403 }
404
405