don't commit with no mods
[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
88       # see if there are any changes in the local repository.
89       if ! git diff-index --quiet HEAD --; then
90         # tell git about all the files and get a check-in comment.
91         git commit .
92         test_or_die "git commit"
93       fi
94       # upload the files to the server so others can see them.
95       git push 2>&1 | grep -v "X11 forwarding request failed"
96       if [ ${PIPESTATUS[0]} -ne 0 ]; then false; fi
97       test_or_die "git push"
98     fi
99   else
100     # nothing there.  it's not an error though.
101     echo no repository in $directory
102   fi
103   popd &>/dev/null
104
105   restore_terminal_title
106
107   true;
108 }
109
110 # shows the local changes in a repository.
111 function do_diff
112 {
113   local directory="$1"; shift
114
115   save_terminal_title
116
117   pushd "$directory" &>/dev/null
118
119   # only update if we see a repository living there.
120   if [ -d ".svn" ]; then
121     svn diff .
122     test_or_die "subversion diff"
123   elif [ -d ".git" ]; then
124     git diff 
125     test_or_die "git diff"
126   elif [ -d "CVS" ]; then
127     cvs diff .
128     test_or_die "cvs diff"
129   fi
130
131   popd &>/dev/null
132
133   restore_terminal_title
134
135   true;
136 }
137
138 # reports any files that are not already known to the upstream repository.
139 function do_report_new
140 {
141   local directory="$1"; shift
142
143   save_terminal_title
144
145   pushd "$directory" &>/dev/null
146
147   # only update if we see a repository living there.
148   if [ -f ".no-checkin" ]; then
149     echo "skipping reporting due to presence of .no-checkin sentinel file."
150   elif [ -d ".svn" ]; then
151     # this action so far only makes sense and is needed for svn.
152     bash $FEISTY_MEOW_SCRIPTS/rev_control/svnapply.sh \? echo
153     test_or_die "svn diff"
154   elif [ -d ".git" ]; then
155     git status -u
156     test_or_die "git status -u"
157   fi
158
159   popd &>/dev/null
160
161   restore_terminal_title
162
163   true
164 }
165
166 # checks in all the folders in a specified list.
167 function checkin_list()
168 {
169   # make the list of directories unique.
170   local list="$(uniquify $*)"
171
172   save_terminal_title
173
174   # turn repo list back into an array.
175   eval "repository_list=( ${REPOSITORY_LIST[*]} )"
176
177   local outer inner
178
179   for outer in "${repository_list[@]}"; do
180     # check the repository first, since it might be an absolute path.
181     if [[ $outer =~ /.* ]]; then
182       # yep, this path is absolute.  just handle it directly.
183       if [ ! -d "$outer" ]; then continue; fi
184       do_checkin $outer
185       test_or_die "running check-in (absolute) on path: $outer"
186       sep 28
187     else
188       for inner in $list; do
189         # add in the directory component to see if we can find the folder.
190         local path="$inner/$outer"
191         if [ ! -d "$path" ]; then continue; fi
192         do_checkin $path
193         test_or_die "running check-in (relative) on path: $path"
194         sep 28
195       done
196     fi
197   done
198
199   restore_terminal_title
200 }
201
202 # takes out the first few carriage returns that are in the input.
203 function squash_first_few_crs()
204 {
205   i=0
206   while read input_text; do
207     i=$((i+1))
208     if [ $i -le 5 ]; then
209       echo -n "$input_text  "
210     else
211       echo $input_text
212     fi
213   done
214   if [ $i -le 3 ]; then
215     # if we're still squashing eols, make sure we don't leave them hanging.
216     echo
217   fi
218 }
219
220 # a helpful method that reports the git branch for the current directory's
221 # git repository.
222 function my_branch_name()
223 {
224   echo "$(git branch | grep \* | cut -d ' ' -f2)"
225 }
226
227 # this reports the upstream branch for the current repo.
228 function parent_branch_name()
229 {
230   echo "$(git branch -vv | grep \* | cut -d ' ' -f2)"
231 }
232
233 # gets the latest versions of the assets from the upstream repository.
234 function do_update()
235 {
236   directory="$1"; shift
237
238   save_terminal_title
239
240   # make a nice echoer since we want to use it inside conditions below.
241   local nicedir="$directory"
242   if [ $nicedir == "." ]; then
243     nicedir=$(\pwd)
244   fi
245   local blatt="echo retrieving '$nicedir'..."
246
247   pushd "$directory" &>/dev/null
248   if [ -d "CVS" ]; then
249     if test_writeable "CVS"; then
250       $blatt
251       cvs update . | $TO_SPLITTER
252       test_or_die "cvs update"
253     fi
254   elif [ -d ".svn" ]; then
255     if test_writeable ".svn"; then
256       $blatt
257       svn update . | $TO_SPLITTER
258       test_or_die "svn update"
259     fi
260   elif [ -d ".git" ]; then
261     if test_writeable ".git"; then
262       $blatt
263
264 # classic implementation, but only works with one master branch.
265 # fixes will be forthcoming from development branch.
266
267       git pull 2>&1 | grep -v "X11 forwarding request failed" | $TO_SPLITTER
268       if [ ${PIPESTATUS[0]} -ne 0 ]; then false; fi
269       test_or_die "git pull"
270
271     fi
272   else
273     # this is not an error necessarily; we'll just pretend they planned this.
274     echo no repository in $directory
275   fi
276   popd &>/dev/null
277
278   restore_terminal_title
279
280   true
281 }
282
283 # gets all the updates for a list of folders under revision control.
284 function checkout_list()
285 {
286   local list="$(uniquify $*)"
287
288   save_terminal_title
289
290   # turn repo list back into an array.
291   eval "repository_list=( ${REPOSITORY_LIST[*]} )"
292
293   local outer inner
294
295   for outer in "${repository_list[@]}"; do
296     # check the repository first, since it might be an absolute path.
297     if [[ $outer =~ /.* ]]; then
298       # yep, this path is absolute.  just handle it directly.
299       if [ ! -d "$outer" ]; then continue; fi
300       do_update $outer
301       test_or_die "running update on: $path"
302       sep 28
303     else
304       for inner in $list; do
305         # add in the directory component to see if we can find the folder.
306         local path="$inner/$outer"
307         if [ ! -d "$path" ]; then continue; fi
308         do_update $path
309         test_or_die "running update on: $path"
310         sep 28
311       done
312     fi
313   done
314
315   restore_terminal_title
316 }
317
318 # provides a list of absolute paths of revision control directories
319 # that are located under the directory passed as the first parameter.
320 function generate_rev_ctrl_filelist()
321 {
322   local dir="$1"; shift
323   pushd "$dir" &>/dev/null
324   local dirhere="$( \cd "$(\dirname "$dir")" && /bin/pwd )"
325   local tempfile=$(mktemp /tmp/zz_checkins.XXXXXX)
326   echo >$tempfile
327   local additional_filter
328   find $dirhere -follow -maxdepth $MAX_DEPTH -type d -iname ".svn" -exec echo {}/.. ';' >>$tempfile 2>/dev/null
329   find $dirhere -follow -maxdepth $MAX_DEPTH -type d -iname ".git" -exec echo {}/.. ';' >>$tempfile 2>/dev/null
330   # CVS is not well behaved like git and (now) svn, and we seldom use it anymore.
331   popd &>/dev/null
332
333   # see if they've warned us not to try checking in within vendor hierarchies.
334   if [ ! -z "NO_CHECKIN_VENDOR" ]; then
335     sed -i -e '/.*\/vendor\/.*/d' "$tempfile"
336   fi
337
338   local sortfile=$(mktemp /tmp/zz_checkin_sort.XXXXXX)
339   sort <"$tempfile" >"$sortfile"
340   \rm "$tempfile"
341   echo "$sortfile"
342 }
343
344 # iterates across a list of directories contained in a file (first parameter).
345 # on each directory name, it performs the action (second parameter) provided.
346 function perform_revctrl_action_on_file()
347 {
348   local tempfile="$1"; shift
349   local action="$1"; shift
350
351   save_terminal_title
352
353   while read -u 3 dirname; do
354     if [ -z "$dirname" ]; then continue; fi
355     pushd "$dirname" &>/dev/null
356     echo "[$(pwd)]"
357     $action .
358     test_or_die "performing action $action on: $(pwd)"
359     sep 28
360     popd &>/dev/null
361   done 3<"$tempfile"
362
363   restore_terminal_title
364
365   rm $tempfile
366 }
367