]> git.mxchange.org Git - flightgear.git/blob - scripts/tools/fg-submit
Merge branch 'next' of gitorious.org:fg/flightgear into next
[flightgear.git] / scripts / tools / fg-submit
1 #!/bin/bash
2 #
3 # This script called in a CVS directory compares local files with
4 # the repository, and prepares an update package containing all
5 # changes and new files for submission to a CVS maintainer. If there
6 # are only changes in text files, then a compressed unified diff is
7 # made (foo.diff.bz2). If there are also changed binary or new files,
8 # then an archive is made instead (foo.tar.bz2). The base name ("foo")
9 # can be given as command line argument. Otherwise the directory name
10 # is used. The script also leaves a diff in uncompressed/unpackaged
11 # form. This is only for developer convenience -- for a quick check
12 # of the diff correctness. It is not to be submitted. The script will
13 # not overwrite any file, but rather rename conflicting files.
14 #
15 # Usage:  fg-submit [-v] [<basename>]
16 #
17 # Options:
18 #         -v ... verbose output
19 #
20 # Example:
21 #     $ cd $FG_ROOT/Aircraft/bo105
22 #     $ fg-submit                # -> bo105.diff.bz2 or bo105.tar.bz2
23 #
24 #     $ fg-submit update         # -> update.diff.bz2 or update.tar.bz2
25 #
26 #
27 # Spaces in the basename are replaced with "%20". People who prefer
28 # to have the date in the archive name can conveniently achieve this
29 # by defining a shell alias in ~/.bashrc:
30 #
31 #     alias submit='fg-submit "${PWD##*/}-$(date +%Y-%m-%d)"'
32 #
33 #
34 #
35 # If the script finds an application named "fg-upload", then it calls
36 # this at the end with two arguments:
37 #
38 #     $1 ... archive or compressed diff for submission
39 #     $2 ... accessory uncompressed diff, *NOT* for submission!
40 #
41 # $1 and $2 are guaranteed not to contain spaces, only $1 is guaranteed
42 # to actually exist. Such a script can be used to upload the file to an
43 # ftp-/webserver, and/or to remove one or both files. Example using
44 # KDE's kfmclient for upload (alternatives: ncftpput, gnomevfs-copy):
45 #
46 #     $ cat ~/bin/fg-upload
47 #     #!/bin/bash
48 #     echo "uploading $1"
49 #     if kfmclient copy $1 ftp://user:password@server.com; then
50 #             echo "deleting $1 $2"
51 #             rm -f $1 $2
52 #
53 #             URL=ftp://server.com/$1
54 #
55 #             # copy URL to KDE's clipboard, so that MMB-clicking pastes it
56 #             dcop klipper klipper setClipboardContents $URL
57 #
58 #             echo "Done.  -->  $URL"
59 #     else
60 #             echo "$0: uploading failed!"
61 #     fi
62 #
63 #
64 #
65 # Whether a file should be included in the archive or not, is decided
66 # by pattern rules. There is a set of reasonable default rules predefined,
67 # but alternative settings can be defined in a hidden configuration file
68 # named ".fg-submit". Such a file is searched in the current directory,
69 # in its parent directory, in its grand-parent directory and so on,
70 # and finally in the $HOME directory. The first found file is taken.
71 #
72 # A file can use a list of three keywords with arguments, each on a
73 # separate line:
74 #
75 #     ALLOW  <pattern-list>     ... accept & report matching file
76 #     DENY   <pattern-list>     ... reject & report matching file
77 #     IGNORE <pattern-list>     ... silently reject matching file
78 #
79 # A <pattern-list> is a space-separated list of shell pattern.
80 # It may also be empty, in which case it has no effect. Examples:
81 #
82 #     DENY   test.blend
83 #     ALLOW  *.xcf *.blend
84 #
85 # The list of pattern is checked in the same order in which it was
86 # built. The first match causes a file to be accepted or rejected.
87 # Further matches are not considered. Comments using the hash
88 # character '#' are allowed and ignored.
89 #
90 # Some default rules are always added at the end. If you want to
91 # bypass them, then finish your configuration with an "ALLOW *"
92 # or "DENY *", and no file will ever reach the default rules.
93 #
94 #
95 # Example:
96 #
97 #     DENY  test.xcf # throw out the test image, but ...
98 #     ALLOW *.xcf    # ... allow all other GIMP images (the default
99 #                    # rules would otherwise throw them out)
100 #
101 #     ALLOW  not.old # add this file, but ...
102 #     IGNORE *.old   # throw out all other "old" files (and don't
103 #                    # report that to the terminal)
104 #
105 #
106 # .fg-submit configuration files are "sourced" bash scripts, the
107 # keywords are simple shell functions. That means that you can
108 # also use other bash commands in that file, such as "echo", or
109 # write several commands on one line, separated with semicolon.
110 # You can even put all special rules in your ~/.fg-submit file,
111 # with rules depending on the working directory:
112 #
113 #     case "$PWD" in
114 #     */bo105*)  DENY *.osg; ALLOW livery.xcf ;;
115 #     */ufo*)    DENY *.tiff ;;
116 #     esac
117
118
119
120 SELF=${0##*/}
121 DIR=${PWD##*/}
122
123 if [ "$1" == "-v" ]; then
124         DBG=1
125         shift
126 fi
127
128 BASE=${1:-$DIR}
129 BASE=${BASE// /%20}
130
131 CVS=/usr/bin/cvs                 # avoid colorcvs wrapper from
132 [ -x $CVS ] || CVS=cvs           # http://www.hakubi.us/colorcvs/
133 UPLOAD=$(which fg-upload 2>/dev/null)
134
135 CONFIG_FILE=".fg-submit"
136 ARCHIVE=$BASE.tar.bz2
137 DIFF=$BASE.diff
138 CDIFF=$DIFF.bz2
139
140 # these rules are always prepended; the first letter decides if the
141 # rule accepts (+), rejects (-), or ignores (!) a matching file.
142 PREFIX_RULES="
143         !$DIFF* !$CDIFF* !$ARCHIVE*
144         !CVS/* !*/CVS/*
145 "
146 # these rules are always appended
147 DEFAULT_RULES="
148         +.cvsignore +*/.cvsignore
149         -*~ -*. -*.bak -*.orig
150         -*.RGB -*.RGBA -*.MDL
151         -*.XCF -*.tga -*.TGA -*.bmp -*.BMP -*.PNG
152         -*.blend -*.blend[0-9] -*blend[0-9][0-9] -*.blend[0-9][0-9][0-9]
153         -*.gz -*.tgz -*.bz2 -*.zip -*.tar.gz* -*.tar.bz2*
154 "
155 POSTFIX_RULES="
156         !.* !*/.*
157         +*
158 "
159
160
161
162 function ERROR   { echo -e "\e[31;1m$*\e[m";   }
163 function LOG     { echo -e "\e[35m$*\e[m";     }
164 function NEW     { echo -e "\e[32m\t+ $*\e[m"; }
165 function CHANGED { echo -e "\e[36m\t+ $*\e[m"; }
166 function REJECT  { echo -e "\e[31m\t- $*\e[m"; }
167 function DEBUG   { [ $DBG ] && echo -e "$*";   }
168
169 function diffstat {
170         # output diff statistics, similar to the "diffstat" utility
171         awk '
172                 function line(a, r, c, f) {
173                         print "\t\033[32m"a"\033[m\t\033[31m"r"\033[m\t\033[34m"c"\033[m\t"f
174                 }
175                 function dofile() {
176                         if (!file) {
177                                 return
178                         }
179                         if (bin) {
180                                 print "\t. . . . binary  . . . . \033[36m"file"\033[m"
181                         } else {
182                                 line(a, r, c, file)
183                                 at += a; rt += r; ct += c
184                         }
185                         a = r = c = 0
186                 }
187                 BEGIN      {
188                         print "\tadded---removed-changed----------------------------------------"
189                         a = r = c = at = rt = ct = n = bin = 0
190                 }
191                 /^Index: / { dofile(); scan = bin = 0; file = $2; n++; next }
192                 /^@@/      { scan = 1; next }
193                 /^Binary/  { if (!scan) bin = 1; next }
194                 /^\+/      { if (scan) a++; next }
195                 /^-/       { if (scan) r++; next }
196                 /^!/       { if (scan) c++; next }
197                 END        {
198                         dofile()
199                         print "\t----------------------------------------total------------------"
200                         line(at, rt, ct, "\033[min "n" files")
201                 }
202         ' <$1
203 }
204
205 function backup_filename {
206         for ((i = 1; 1; i = i + 1)); do
207                 name=$1.$i
208                 if ! [ -a "$name" ]; then
209                         touch $name
210                         echo $name
211                         return
212                 fi
213         done
214 }
215
216
217
218 # set up accept/reject rules
219 function ALLOW   { for i in $*; do RULES="$RULES +$i"; done }
220 function DENY    { for i in $*; do RULES="$RULES -$i"; done }
221 function IGNORE  { for i in $*; do RULES="$RULES !$i"; done }
222
223
224 function search_config {
225         file="$1/$CONFIG_FILE"
226         DEBUG "checking for config file $file"
227         if [ -f "$file" ]; then
228                 CONFIG="$file"
229                 return 0
230         elif [ "$1" ]; then
231                 search_config ${1%/${1##*/}} # parent dir
232                 return
233         fi
234         return 1
235 }
236
237
238 set -f
239 RULES=
240 if search_config "$PWD"; then
241         LOG "loading config file $CONFIG"
242         source "$CONFIG"
243 elif [ -f ~/$CONFIG_FILE ]; then
244         DEBUG "loading config file ~/$CONFIG_FILE"
245         source ~/$CONFIG_FILE
246 elif [ -f ~/${CONFIG_FILE}rc ]; then
247         DEBUG "loading config file ~/${CONFIG}rc"
248         source ~/${CONFIG_FILE}rc
249 fi
250 RULES="$PREFIX_RULES $RULES $DEFAULT_RULES $POSTFIX_RULES"
251 set +f
252
253
254 if [ $DBG ]; then
255         DEBUG "using these rules: "
256         for i in $RULES; do echo -n "$i "; done
257         echo
258 fi
259
260
261
262 # create temporary dir that's automatically removed on exit
263 TMP=$(mktemp -d /tmp/$SELF.$BASE.XXXXXX) || (echo "$0: can't create temporary dir"; exit 1)
264 trap "rm -rf $TMP" 0 1 2 3 13 15
265
266
267
268 # move old files out of the way adding sequential suffixes
269 for i in $DIFF $CDIFF $ARCHIVE; do
270         [ -f $i ] && mv $i $(backup_filename $i)
271 done
272
273
274
275 LOG "updating and checking for new files ..."
276 $CVS -q up -dP >$TMP/up || exit 1
277
278
279 if grep "^C " $TMP/up &>/dev/null; then
280         ERROR "there are conflicts with the following files:"
281         grep "^C " $TMP/up
282         exit 1
283 fi
284
285
286
287 LOG "making diff ..."
288 if ! $CVS -q diff -up >$DIFF; then
289         LOG "diff statistics:"
290         diffstat $DIFF
291         echo
292
293         # add diff file itself
294         echo $DIFF >>$TMP/files
295
296         # add changed binary files
297         awk '
298                 /^Index: / { scan = 1; file = $2; next }
299                 /^@@/      { scan = 0; next }
300                 /^Binary/  { if (scan) { print file } }
301         ' <$DIFF >>$TMP/files
302 else
303         rm -f $DIFF
304 fi
305
306
307
308 LOG "checking for files to submit ..."
309 if [ -f $TMP/files ]; then
310         cat $TMP/files|while read i; do
311                 CHANGED "$i"
312         done
313 fi
314
315 grep "^? " $TMP/up|while read i; do
316         find ${i#? } -type f >>$TMP/check
317 done
318
319
320
321 # filter files according to the pattern rules
322 if [ -f $TMP/check ]; then
323         for i in $(cat $TMP/check); do
324                 DEBUG "checking whether file '$i' matches"
325                 for r in $RULES; do
326                         DEBUG "\t\trule $r"
327                         class=${r:0:1}
328                         rule=${r:1}
329                         case "$i" in $rule)
330                                 case $class in
331                                 !) DEBUG "$i\t\t\"silently\" rejected\t\t$rule" ;;
332                                 -) REJECT "$i\t\t$rule" ;;
333                                 +) NEW "$i\t\t$rule" && echo "$i" >>$TMP/files ;;
334                                 esac
335                                 break
336                                 ;;
337                         esac
338                 done
339         done
340 fi
341
342
343
344 if ! [ -f $TMP/files ]; then
345         LOG "no changed or new files found"
346         exit 0
347 fi
348
349 echo
350 numfiles=$(awk '//{n++}END{print n}' <$TMP/files)
351 if [ -f $DIFF -a $numfiles == 1 ]; then
352         LOG "only changed non-binary files found"
353         LOG "creating compressed diff \e[1;37;40m$CDIFF\e[m\e[35m ..."
354         bzip2 --keep $DIFF
355         RESULT=$CDIFF
356 else
357         LOG "changed and/or new files found"
358         LOG "creating archive \e[1;37;40m$ARCHIVE\e[m\e[35m ..."
359         tar --create --bzip2 --file=$ARCHIVE --files-from $TMP/files
360         RESULT=$ARCHIVE
361 fi
362
363
364 [ -x "$UPLOAD" -a -f $RESULT ] && $UPLOAD $RESULT $DIFF
365
366