enabling pulls again in dev branch
[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
95 #      # upload the files to the server so others can see them.
96 #      git push 2>&1 | grep -v "X11 forwarding request failed"
97 #      if [ ${PIPESTATUS[0]} -ne 0 ]; then false; fi
98 #      test_or_die "git push"
99
100       # catch if the diff-index failed somehow.
101       test_or_die "git diff-index"
102
103       # we continue on to the push, even if there were no changes this time, because
104       # there could already be committed changes that haven't been pushed yet.
105
106       local myself="$(my_branch_name)"
107       local parent="$(parent_branch_name)"
108
109       # upload any changes to the upstream repo so others can see them.
110       if [ "$myself" != "$parent" ]; then
111         git push origin "$(myself)" 2>&1 | grep -v "X11 forwarding request failed" | $TO_SPLITTER
112         test_or_die "git push to origin: $myself"
113       else
114         # this branch is the same as the parent, so just push.
115         git push 2>&1 | grep -v "X11 forwarding request failed" | $TO_SPLITTER
116         test_or_die "normal git push"
117       fi
118
119     fi
120   else
121     # nothing there.  it's not an error though.
122     echo no repository in $directory
123   fi
124   popd &>/dev/null
125
126   restore_terminal_title
127
128   true;
129 }
130
131 # shows the local changes in a repository.
132 function do_diff
133 {
134   local directory="$1"; shift
135
136   save_terminal_title
137
138   pushd "$directory" &>/dev/null
139
140   # only update if we see a repository living there.
141   if [ -d ".svn" ]; then
142     svn diff .
143     test_or_die "subversion diff"
144   elif [ -d ".git" ]; then
145     git diff 
146     test_or_die "git diff"
147   elif [ -d "CVS" ]; then
148     cvs diff .
149     test_or_die "cvs diff"
150   fi
151
152   popd &>/dev/null
153
154   restore_terminal_title
155
156   true;
157 }
158
159 # reports any files that are not already known to the upstream repository.
160 function do_report_new
161 {
162   local directory="$1"; shift
163
164   save_terminal_title
165
166   pushd "$directory" &>/dev/null
167
168   # only update if we see a repository living there.
169   if [ -f ".no-checkin" ]; then
170     echo "skipping reporting due to presence of .no-checkin sentinel file."
171   elif [ -d ".svn" ]; then
172     # this action so far only makes sense and is needed for svn.
173     bash $FEISTY_MEOW_SCRIPTS/rev_control/svnapply.sh \? echo
174     test_or_die "svn diff"
175   elif [ -d ".git" ]; then
176     git status -u
177     test_or_die "git status -u"
178   fi
179
180   popd &>/dev/null
181
182   restore_terminal_title
183
184   true
185 }
186
187 # checks in all the folders in a specified list.
188 function checkin_list()
189 {
190   # make the list of directories unique.
191   local list="$(uniquify $*)"
192
193   save_terminal_title
194
195   # turn repo list back into an array.
196   eval "repository_list=( ${REPOSITORY_LIST[*]} )"
197
198   local outer inner
199
200   for outer in "${repository_list[@]}"; do
201     # check the repository first, since it might be an absolute path.
202     if [[ $outer =~ /.* ]]; then
203       # yep, this path is absolute.  just handle it directly.
204       if [ ! -d "$outer" ]; then continue; fi
205       do_checkin $outer
206       test_or_die "running check-in (absolute) on path: $outer"
207       sep 28
208     else
209       for inner in $list; do
210         # add in the directory component to see if we can find the folder.
211         local path="$inner/$outer"
212         if [ ! -d "$path" ]; then continue; fi
213         do_checkin $path
214         test_or_die "running check-in (relative) on path: $path"
215         sep 28
216       done
217     fi
218   done
219
220   restore_terminal_title
221 }
222
223 # takes out the first few carriage returns that are in the input.
224 function squash_first_few_crs()
225 {
226   i=0
227   while read input_text; do
228     i=$((i+1))
229     if [ $i -le 5 ]; then
230       echo -n "$input_text  "
231     else
232       echo $input_text
233     fi
234   done
235   if [ $i -le 3 ]; then
236     # if we're still squashing eols, make sure we don't leave them hanging.
237     echo
238   fi
239 }
240
241 # a helpful method that reports the git branch for the current directory's
242 # git repository.
243 function my_branch_name()
244 {
245   echo "$(git branch | grep \* | cut -d ' ' -f2)"
246 }
247
248 # this reports the upstream branch for the current repo.
249 function parent_branch_name()
250 {
251   echo "$(git branch -vv | grep \* | cut -d ' ' -f2)"
252 }
253
254 # the git update process just gets more and more complex when you bring in
255 # branches, so we've moved this here to avoid having a ton of code in the
256 # do_checkin method.
257 function careful_git_update()
258 {
259   # first update all our remote branches to their current state from the repos.
260   git remote update
261   test_or_die "git remote update"
262
263 #hmmm: this should be a function:
264 # from: https://stackoverflow.com/questions/3258243/check-if-pull-needed-in-git
265 UPSTREAM=$(parent_branch_name)
266 #argh: original UPSTREAM='${1:-'\''@{u}'\''}'
267 LOCAL=$(git rev-parse @)
268 REMOTE=$(git rev-parse "$UPSTREAM")
269 BASE=$(git merge-base @ "$UPSTREAM")
270 var UPSTREAM LOCAL REMOTE BASE
271
272 if [ "$LOCAL" == "$REMOTE" ]; then
273     echo "Up-to-date"
274 elif [ "$LOCAL" == "$BASE" ]; then
275     echo "Need to pull"
276 elif [ "$REMOTE" == "$BASE" ]; then
277     echo "Need to push"
278 else
279     echo "Diverged"
280 fi
281
282   # now pull down any changes in our own origin in the repo, to stay in synch
283   # with any changes from others.
284   git pull --no-ff --all
285   test_or_die "git fetch origin"
286
287
288 echo The rest of pull is not being done yet.
289 return 1
290
291
292
293 # below has older shards of partial knowledge.
294
295 #      reslog=$(git log HEAD..origin/master --oneline)
296 #      if [[ "${reslog}" != "" ]] ; then
297 #        git merge origin/master
298
299 #      # from very helpful page:
300 #      # https://stackoverflow.com/questions/10312521/how-to-fetch-all-git-branches
301 #      for remote in $( git branch -r | grep -v -- '->' ); do
302 #        git branch --track ${remote#origin/} $remote 2>/dev/null
303 ##hmmm: ignoring errors from these, since they are continual.
304 ##hmmm: if we could find a way to not try to track with a local branch when there's already one present, that would be swell.  it's probably simple.
305 #      done
306 #
307 ##hmmm: well, one time it failed without the fetch.  i hope that's because the fetch is actually needed and not because the whole approach is fubar.
308 #      git fetch --all 2>&1 | grep -v "X11 forwarding request failed" | $TO_SPLITTER
309 #      test_or_die "git fetch"
310 #
311 #      git pull --all 2>&1 | grep -v "X11 forwarding request failed" | $TO_SPLITTER
312 #      test_or_die "git pull"
313
314 }
315
316 # gets the latest versions of the assets from the upstream repository.
317 function do_update()
318 {
319   directory="$1"; shift
320
321   save_terminal_title
322
323   # make a nice echoer since we want to use it inside conditions below.
324   local nicedir="$directory"
325   if [ $nicedir == "." ]; then
326     nicedir=$(\pwd)
327   fi
328   local blatt="echo retrieving '$nicedir'..."
329
330   pushd "$directory" &>/dev/null
331   if [ -d "CVS" ]; then
332     if test_writeable "CVS"; then
333       $blatt
334       cvs update . | $TO_SPLITTER
335       test_or_die "cvs update"
336     fi
337   elif [ -d ".svn" ]; then
338     if test_writeable ".svn"; then
339       $blatt
340       svn update . | $TO_SPLITTER
341       test_or_die "svn update"
342     fi
343   elif [ -d ".git" ]; then
344     if test_writeable ".git"; then
345       $blatt
346
347 # classic implementation, but only works with one master branch.
348 # fixes will be forthcoming from development branch.
349
350 #      git pull 2>&1 | grep -v "X11 forwarding request failed" | $TO_SPLITTER
351 #      if [ ${PIPESTATUS[0]} -ne 0 ]; then false; fi
352 #      test_or_die "git pull"
353
354 #any parms needed?
355       careful_git_update 
356
357     fi
358   else
359     # this is not an error necessarily; we'll just pretend they planned this.
360     echo no repository in $directory
361   fi
362   popd &>/dev/null
363
364   restore_terminal_title
365
366   true
367 }
368
369 # gets all the updates for a list of folders under revision control.
370 function checkout_list()
371 {
372   local list="$(uniquify $*)"
373
374   save_terminal_title
375
376   # turn repo list back into an array.
377   eval "repository_list=( ${REPOSITORY_LIST[*]} )"
378
379   local outer inner
380
381   for outer in "${repository_list[@]}"; do
382     # check the repository first, since it might be an absolute path.
383     if [[ $outer =~ /.* ]]; then
384       # yep, this path is absolute.  just handle it directly.
385       if [ ! -d "$outer" ]; then continue; fi
386       do_update $outer
387       test_or_die "running update on: $path"
388       sep 28
389     else
390       for inner in $list; do
391         # add in the directory component to see if we can find the folder.
392         local path="$inner/$outer"
393         if [ ! -d "$path" ]; then continue; fi
394         do_update $path
395         test_or_die "running update on: $path"
396         sep 28
397       done
398     fi
399   done
400
401   restore_terminal_title
402 }
403
404 # provides a list of absolute paths of revision control directories
405 # that are located under the directory passed as the first parameter.
406 function generate_rev_ctrl_filelist()
407 {
408   local dir="$1"; shift
409   pushd "$dir" &>/dev/null
410   local dirhere="$( \cd "$(\dirname "$dir")" && /bin/pwd )"
411   local tempfile=$(mktemp /tmp/zz_checkins.XXXXXX)
412   echo >$tempfile
413   local additional_filter
414   find $dirhere -follow -maxdepth $MAX_DEPTH -type d -iname ".svn" -exec echo {}/.. ';' >>$tempfile 2>/dev/null
415   find $dirhere -follow -maxdepth $MAX_DEPTH -type d -iname ".git" -exec echo {}/.. ';' >>$tempfile 2>/dev/null
416   # CVS is not well behaved like git and (now) svn, and we seldom use it anymore.
417   popd &>/dev/null
418
419   # see if they've warned us not to try checking in within vendor hierarchies.
420   if [ ! -z "NO_CHECKIN_VENDOR" ]; then
421     sed -i -e '/.*\/vendor\/.*/d' "$tempfile"
422   fi
423
424   local sortfile=$(mktemp /tmp/zz_checkin_sort.XXXXXX)
425   sort <"$tempfile" >"$sortfile"
426   \rm "$tempfile"
427   echo "$sortfile"
428 }
429
430 # iterates across a list of directories contained in a file (first parameter).
431 # on each directory name, it performs the action (second parameter) provided.
432 function perform_revctrl_action_on_file()
433 {
434   local tempfile="$1"; shift
435   local action="$1"; shift
436
437   save_terminal_title
438
439   while read -u 3 dirname; do
440     if [ -z "$dirname" ]; then continue; fi
441     pushd "$dirname" &>/dev/null
442     echo "[$(pwd)]"
443     $action .
444     test_or_die "performing action $action on: $(pwd)"
445     sep 28
446     popd &>/dev/null
447   done 3<"$tempfile"
448
449   restore_terminal_title
450
451   rm $tempfile
452 }
453