6321dc14a0702a98aba52a3bd76601c5ddddc0e5
[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 # Author: Chris Koeritz
7 # Author: Kevin Wentworth
8
9 source "$FEISTY_MEOW_SCRIPTS/core/launch_feisty_meow.sh"
10 source "$FEISTY_MEOW_SCRIPTS/tty/terminal_titler.sh"
11
12 #hmmm: we need to dump all the outputs in this script into splitter
13
14 ##############
15
16 # the maximum depth that the recursive functions will try to go below the starting directory.
17 export MAX_DEPTH=5
18
19 # use our splitter tool for lengthy output if it's available.
20 if [ ! -z "$(which splitter)" ]; then
21   TO_SPLITTER="$(which splitter)"
22 else
23   TO_SPLITTER=cat
24 fi
25
26 ##############
27
28 # one unpleasantry to take care of first; cygwin barfs aggressively if the TMP directory
29 # is a DOS path, but we need it to be a DOS path for our GFFS testing, so that blows.
30 # to get past this, TMP gets changed below to a hopefully generic and safe place.
31 if [[ "$TMP" =~ .:.* ]]; then
32   echo "making weirdo temporary directory for PCDOS-style path."
33   export TMP=/tmp/rev_control_$USER
34 fi
35 if [ ! -d "$TMP" ]; then
36   mkdir -p $TMP
37 fi
38 if [ ! -d "$TMP" ]; then
39   echo "could not create the temporary directory TMP in: $TMP"
40   echo "this script will not work properly without an existing TMP directory."
41 fi
42
43 ##############
44
45 # checks the directory provided into the revision control system repository it belongs to.
46 function do_checkin()
47 {
48   local directory="$1"; shift
49
50   save_terminal_title
51
52   # make a nice echoer since we want to use it inside conditions below.
53   local nicedir="$directory"
54   if [ $nicedir == "." ]; then
55     nicedir=$(\pwd)
56   fi
57   local blatt="echo checking in '$nicedir'..."
58
59   do_update "$directory"
60   test_or_die "repository update--this should be fixed before check-in."
61
62   pushd "$directory" &>/dev/null
63   if [ -f ".no-checkin" ]; then
64     echo "skipping check-in due to presence of .no-checkin sentinel file."
65   elif [ -d "CVS" ]; then
66     if test_writeable "CVS"; then
67       $blatt
68       cvs ci .
69       test_or_die "cvs checkin"
70     fi
71   elif [ -d ".svn" ]; then
72     if test_writeable ".svn"; then
73       $blatt
74       svn ci .
75       test_or_die "svn checkin"
76     fi
77   elif [ -d ".git" ]; then
78     if test_writeable ".git"; then
79       $blatt
80
81 # classic implementation, but only works with one master branch.
82 # fixes will be forthcoming from development branch.
83
84       # snag all new files.  not to everyone's liking.
85       git add --all .
86       test_or_die "git add all new files"
87       # tell git about all the files and get a check-in comment.
88       git commit .
89       test_or_die "git commit"
90       # upload the files to the server so others can see them.
91       git push 2>&1 | grep -v "X11 forwarding request failed"
92       if [ ${PIPESTATUS[0]} -ne 0 ]; then false; fi
93       test_or_die "git push"
94     fi
95   else
96     # nothing there.  it's not an error though.
97     echo no repository in $directory
98   fi
99   popd &>/dev/null
100
101   restore_terminal_title
102
103   true;
104 }
105
106 # shows the local changes in a repository.
107 function do_diff
108 {
109   local directory="$1"; shift
110
111   save_terminal_title
112
113   pushd "$directory" &>/dev/null
114
115   # only update if we see a repository living there.
116   if [ -d ".svn" ]; then
117     svn diff .
118     test_or_die "subversion diff"
119   elif [ -d ".git" ]; then
120     git diff 
121     test_or_die "git diff"
122   elif [ -d "CVS" ]; then
123     cvs diff .
124     test_or_die "cvs diff"
125   fi
126
127   popd &>/dev/null
128
129   restore_terminal_title
130
131   true;
132 }
133
134 # reports any files that are not already known to the upstream repository.
135 function do_report_new
136 {
137   local directory="$1"; shift
138
139   save_terminal_title
140
141   pushd "$directory" &>/dev/null
142
143   # only update if we see a repository living there.
144   if [ -f ".no-checkin" ]; then
145     echo "skipping reporting due to presence of .no-checkin sentinel file."
146   elif [ -d ".svn" ]; then
147     # this action so far only makes sense and is needed for svn.
148     bash $FEISTY_MEOW_SCRIPTS/rev_control/svnapply.sh \? echo
149     test_or_die "svn diff"
150   elif [ -d ".git" ]; then
151     git status -u
152     test_or_die "git status -u"
153   fi
154
155   popd &>/dev/null
156
157   restore_terminal_title
158
159   true
160 }
161
162 # checks in all the folders in a specified list.
163 function checkin_list()
164 {
165   # make the list of directories unique.
166   local list="$(uniquify $*)"
167
168   save_terminal_title
169
170   # turn repo list back into an array.
171   eval "repository_list=( ${REPOSITORY_LIST[*]} )"
172
173   local outer inner
174
175   for outer in "${repository_list[@]}"; do
176     # check the repository first, since it might be an absolute path.
177     if [[ $outer =~ /.* ]]; then
178       # yep, this path is absolute.  just handle it directly.
179       if [ ! -d "$outer" ]; then continue; fi
180       do_checkin $outer
181       test_or_die "running check-in (absolute) on path: $outer"
182       sep 28
183     else
184       for inner in $list; do
185         # add in the directory component to see if we can find the folder.
186         local path="$inner/$outer"
187         if [ ! -d "$path" ]; then continue; fi
188         do_checkin $path
189         test_or_die "running check-in (relative) on path: $path"
190         sep 28
191       done
192     fi
193   done
194
195   restore_terminal_title
196 }
197
198 # takes out the first few carriage returns that are in the input.
199 function squash_first_few_crs()
200 {
201   i=0
202   while read input_text; do
203     i=$((i+1))
204     if [ $i -le 5 ]; then
205       echo -n "$input_text  "
206     else
207       echo $input_text
208     fi
209   done
210   if [ $i -le 3 ]; then
211     # if we're still squashing eols, make sure we don't leave them hanging.
212     echo
213   fi
214 }
215
216 # a helpful method that reports the git branch for the current directory's
217 # git repository.
218 function my_branch_name()
219 {
220   echo "$(git branch | grep \* | cut -d ' ' -f2)"
221 }
222
223 # this reports the upstream branch for the current repo.
224 function parent_branch_name()
225 {
226   echo "$(git branch -vv | grep \* | cut -d ' ' -f2)"
227 }
228
229 # gets the latest versions of the assets from the upstream repository.
230 function do_update()
231 {
232   directory="$1"; shift
233
234   save_terminal_title
235
236   # make a nice echoer since we want to use it inside conditions below.
237   local nicedir="$directory"
238   if [ $nicedir == "." ]; then
239     nicedir=$(\pwd)
240   fi
241   local blatt="echo retrieving '$nicedir'..."
242
243   pushd "$directory" &>/dev/null
244   if [ -d "CVS" ]; then
245     if test_writeable "CVS"; then
246       $blatt
247       cvs update . | $TO_SPLITTER
248       test_or_die "cvs update"
249     fi
250   elif [ -d ".svn" ]; then
251     if test_writeable ".svn"; then
252       $blatt
253       svn update . | $TO_SPLITTER
254       test_or_die "svn update"
255     fi
256   elif [ -d ".git" ]; then
257     if test_writeable ".git"; then
258       $blatt
259
260 # classic implementation, but only works with one master branch.
261 # fixes will be forthcoming from development branch.
262
263       git pull 2>&1 | grep -v "X11 forwarding request failed" | $TO_SPLITTER
264       if [ ${PIPESTATUS[0]} -ne 0 ]; then false; fi
265       test_or_die "git pull"
266
267     fi
268   else
269     # this is not an error necessarily; we'll just pretend they planned this.
270     echo no repository in $directory
271   fi
272   popd &>/dev/null
273
274   restore_terminal_title
275
276   true
277 }
278
279 # gets all the updates for a list of folders under revision control.
280 function checkout_list()
281 {
282   local list="$(uniquify $*)"
283
284   save_terminal_title
285
286   # turn repo list back into an array.
287   eval "repository_list=( ${REPOSITORY_LIST[*]} )"
288
289   local outer inner
290
291   for outer in "${repository_list[@]}"; do
292     # check the repository first, since it might be an absolute path.
293     if [[ $outer =~ /.* ]]; then
294       # yep, this path is absolute.  just handle it directly.
295       if [ ! -d "$outer" ]; then continue; fi
296       do_update $outer
297       test_or_die "running update on: $path"
298       sep 28
299     else
300       for inner in $list; do
301         # add in the directory component to see if we can find the folder.
302         local path="$inner/$outer"
303         if [ ! -d "$path" ]; then continue; fi
304         do_update $path
305         test_or_die "running update on: $path"
306         sep 28
307       done
308     fi
309   done
310
311   restore_terminal_title
312 }
313
314 # provides a list of absolute paths of revision control directories
315 # that are located under the directory passed as the first parameter.
316 function generate_rev_ctrl_filelist()
317 {
318   local dir="$1"; shift
319   pushd "$dir" &>/dev/null
320   local dirhere="$( \cd "$(\dirname "$dir")" && /bin/pwd )"
321   local tempfile=$(mktemp /tmp/zz_checkins.XXXXXX)
322   echo >$tempfile
323   local additional_filter
324   find $dirhere -follow -maxdepth $MAX_DEPTH -type d -iname ".svn" -exec echo {}/.. ';' >>$tempfile 2>/dev/null
325   find $dirhere -follow -maxdepth $MAX_DEPTH -type d -iname ".git" -exec echo {}/.. ';' >>$tempfile 2>/dev/null
326   # CVS is not well behaved like git and (now) svn, and we seldom use it anymore.
327   popd &>/dev/null
328
329   # see if they've warned us not to try checking in within vendor hierarchies.
330   if [ ! -z "NO_CHECKIN_VENDOR" ]; then
331     sed -i -e '/.*\/vendor\/.*/d' "$tempfile"
332   fi
333
334   local sortfile=$(mktemp /tmp/zz_checkin_sort.XXXXXX)
335   sort <"$tempfile" >"$sortfile"
336   \rm "$tempfile"
337   echo "$sortfile"
338 }
339
340 # iterates across a list of directories contained in a file (first parameter).
341 # on each directory name, it performs the action (second parameter) provided.
342 function perform_revctrl_action_on_file()
343 {
344   local tempfile="$1"; shift
345   local action="$1"; shift
346
347   save_terminal_title
348
349   while read -u 3 dirname; do
350     if [ -z "$dirname" ]; then continue; fi
351     pushd "$dirname" &>/dev/null
352     echo "[$(pwd)]"
353     $action .
354     test_or_die "performing action $action on: $(pwd)"
355     sep 28
356     popd &>/dev/null
357   done 3<"$tempfile"
358
359   restore_terminal_title
360
361   rm $tempfile
362 }
363