]> git.mxchange.org Git - flightgear.git/blob - scripts/tools/fg-submit
- rules can be defined in optional .fg-submit config files, via commands
[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 diff, *NOT* for submission!
40 #
41 # $1 and $2 are guaranteed not to contain spaces, only $1 is guaranteed
42 # to actually exist. Such as 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, wput):
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 #             echo "Done.  URL: ftp://server.com/$1"
54 #     else
55 #             echo "arghh ... HELP! HELP!"
56 #     fi
57 #
58 #
59 #
60 # Whether a file should be included in the archive or not, is decided
61 # by pattern rules. There is a set of reasonable default rules predefined,
62 # but alternative settings can be defined in a hidden configuration file
63 # named ".fg-submit". Such a file is searched in the current directory,
64 # in its parent directory, in its grand-parent directory and so on,
65 # and finally in the $HOME directory. The first found file is taken.
66 #
67 # A file can use a list of four keywords with arguments, each on a
68 # separate line:
69 #
70 #     ALLOW   <pattern-list>     ... accept & report matching file
71 #     DENY    <pattern-list>     ... reject & report matching file
72 #     IGNORE  <pattern-list>     ... silently reject matching file
73 #     DEFAULT                    ... adds default rules
74 #
75 # A <pattern-list> is a space-separated list of shell pattern.
76 # It may also be empty, in which case it has no effect. Examples:
77 #
78 #     DENY   test.blend
79 #     ALLOW  *.xcf *.blend
80 #
81 # A config file that only contains the keyword DEFAULT causes the
82 # same behavior as no config file at all. A config file without
83 # DEFAULT drops the built-in default rules (with the exception of
84 # a few very basic ones, such as rejection of CVS files). Comments
85 # using the hash character '#' are allowed and ignored.
86 #
87 # The list of pattern is checked in the same in order in which it
88 # is built. The first match causes a file to be accepted or rejected.
89 # Further matches are not considered.
90 #
91 # Example:
92 #
93 #     DENY  test.xcf # throw out the test graphic, but ...
94 #     ALLOW *.xcf    # ... allow all other GIMP graphics (the following
95 #                    # DEFAULT keyword throws them out otherwise)
96 #
97 #     DEFAULT        # insert the default rules here
98 #
99 #     ALLOW  g.old   # add this silly file :-)
100 #     IGNORE *.old   # throw out the old files (and don't report
101 #                    # that to the terminal)
102 #
103 # .fg-submit configuration files are sourced bash scripts, the
104 # keywords are simple shell functions. That means that you can
105 # also use other bash commands in that file, such as "echo".
106
107
108
109 SELF=${0/#*\/}
110 DIR=${PWD/#*\/}
111
112 if [ "$1" == "-v" ]; then
113         DBG=1
114         shift
115 fi
116
117 BASE=${1:-$DIR}
118 BASE=${BASE// /%20}
119
120 CVS=/usr/bin/cvs                 # avoid colorcvs wrapper from
121 [ -x $CVS ] || CVS=cvs           # http://www.hakubi.us/colorcvs/
122 UPLOAD=$(which fg-upload 2>/dev/null)
123
124 ARCHIVE=$BASE.tar.bz2
125 DIFF=$BASE.diff
126 CDIFF=$DIFF.bz2
127
128 # these rules are always prepended (the leading ! makes silent rejects)
129 PREFIX_RULES="
130         !$DIFF* !$CDIFF* !$ARCHIVE*
131         !CVS/* !*/CVS/*
132 "
133 # these rules are used when no other rules are specified,
134 # and wherever the DEFAULT keyword is used
135 DEFAULT_RULES="
136         +.cvsignore +*/.cvsignore
137         -*~ -*. -*.bak -*.orig
138         -*.RGB -*.RGBA -*.MDL
139         -*.xcf -*.XCF -*.tga -*.TGA -*.bmp -*.BMP -*.png -*.PNG
140         -*.blend -*.blend[0-9] -*blend[0-9][0-9] -*.blend[0-9][0-9][0-9]
141         -*.gz -*.tgz -*.bz2 -*.zip -*.tar.gz* -*.tar.bz2*
142 "
143 # these rules are always appended; the last one accepts anything
144 # (throw out all hidden files that weren't explicitly allowed, and
145 # accept the rest)
146 POSTFIX_RULES="
147         !.* !*/.*
148         +*
149 "
150
151
152 function ERROR   { echo -e "\e[31;1m$*\e[m";   }
153 function LOG     { echo -e "\e[35m$*\e[m";     }
154 function NEW     { echo -e "\e[32m\t+ $*\e[m"; }
155 function CHANGED { echo -e "\e[36m\t+ $*\e[m"; }
156 function REJECT  { echo -e "\e[31m\t- $*\e[m"; }
157 function DEBUG   { [ $DBG ] && echo -e "$*";   }
158
159 function diffstat {
160         # output diff statistics, similar to the "diffstat" utility
161         awk '
162                 function line(a, r, c, f) {
163                         print "\t\033[32m"a"\033[m\t\033[31m"r"\033[m\t\033[34m"c"\033[m\t"f
164                 }
165                 function dofile() {
166                         if (!file) {
167                                 return
168                         }
169                         if (bin) {
170                                 print "\t. . . . binary  . . . . \033[36m"file"\033[m"
171                         } else {
172                                 line(a, r, c, file)
173                                 at += a; rt += r; ct += c
174                         }
175                         a = r = c = 0
176                 }
177                 BEGIN      {
178                         print "\tadded---removed-changed----------------------------------------"
179                         a = r = c = at = rt = ct = n = bin = 0
180                 }
181                 /^Index: / { dofile(); scan = bin = 0; file = $2; n++; next }
182                 /^@@/      { scan = 1; next }
183                 /^Binary/  { if (!scan) bin = 1; next }
184                 /^\+/       { if (scan) a++; next }
185                 /^-/       { if (scan) r++; next }
186                 /^!/       { if (scan) c++; next }
187                 END        {
188                         dofile()
189                         print "\t----------------------------------------total------------------"
190                         line(at, rt, ct, "\033[min "n" files")
191                 }
192         ' <$1
193 }
194
195
196 # set up accept/reject rules
197 function DEFAULT { RULES="$RULES $DEFAULT_RULES"; }
198 function ALLOW   { for i in $*; do RULES="$RULES +$i"; done }
199 function DENY    { for i in $*; do RULES="$RULES -$i"; done }
200 function IGNORE  { for i in $*; do RULES="$RULES !$i"; done }
201
202 RULES=
203 HERE=$PWD
204 while true; do
205         if [ -f .fg-submit ]; then
206                 CONFIG="$PWD/.fg-submit"
207                 break
208         fi
209         cd ..
210         [ "$PWD" == "/" ] && break
211 done
212 cd "$HERE"
213
214 if [ "$CONFIG" ]; then
215         DEBUG "reading config $CONFIG"
216         source "$CONFIG"
217 elif [ -f ~/.fg-submitrc ]; then
218         DEBUG "reading config ~/.fg-submitrc"
219         source ~/.fg-submitrc
220 else
221         DEBUG "no config file found; using default rules"
222         RULES="$RULES $DEFAULT_RULES"
223 fi
224 RULES="$PREFIX_RULES $RULES $POSTFIX_RULES"
225 DEBUG "using these rules: $RULES"
226
227
228 # create temporary dir that's automatically removed on exit
229 TMP=$(mktemp -d /tmp/$SELF.$BASE.XXXXXX) || (echo "$0: can't create temporary dir"; exit 1)
230 trap "rm -rf $TMP" 0 1 2 3 13 15
231
232
233 # move old files out of the way
234 for i in $DIFF $CDIFF $ARCHIVE; do
235         [ -f $i ] && mv $i $(mktemp $i.XXXXXX)
236 done
237
238
239 LOG "updating and checking for new files ..."
240 $CVS -q up -dP >$TMP/up
241
242
243 if grep "^C " $TMP/up &>/dev/null; then
244         ERROR "there are conflicts with the following files:"
245         grep "^C " $TMP/up
246         exit 1
247 fi
248
249
250 LOG "making diff ..."
251 if ! $CVS -q diff -up >$DIFF; then
252         LOG "diff statistics:"
253         diffstat $DIFF
254         echo
255
256         # add diff file itself
257         echo $DIFF >>$TMP/files
258
259         # add changed binary files
260         awk '
261                 /^Index: / { scan = 1; file = $2; next }
262                 /^@@/      { scan = 0; next }
263                 /^Binary/  { if (scan) { print file } }
264         ' <$DIFF >>$TMP/files
265 else
266         rm -f $DIFF
267 fi
268
269
270 LOG "checking for files to submit ..."
271 if [ -f $TMP/files ]; then
272         cat $TMP/files|while read i; do
273                 CHANGED "$i"
274         done
275 fi
276
277 grep "^? " $TMP/up|while read i; do
278         find ${i#? } -type f >>$TMP/check
279 done
280
281
282 # classify and filter files
283 if [ -f $TMP/check ]; then
284         for i in $(cat $TMP/check); do
285                 DEBUG "checking whether file '$i' matches"
286                 for r in $RULES; do
287                         DEBUG "\t\trule $r"
288                         R=${r#?}
289                         case "!$i" in $r)
290                                 DEBUG "\t\t\t\"silently\" rejected\t\t(rule $R)"
291                                 break
292                                 ;;
293                         esac
294                         case "-$i" in $r)
295                                 REJECT "$i\t\t(rule $R)"
296                                 break
297                                 ;;
298                         esac
299                         case "+$i" in $r)
300                                 NEW "$i\t\t(rule $R)"
301                                 echo "$i" >>$TMP/files
302                                 break
303                                 ;;
304                         esac
305                 done
306         done
307 fi
308
309
310 if ! [ -f $TMP/files ]; then
311         LOG "no changed or new files found"
312         exit 0
313 fi
314
315 echo
316 numfiles=$(awk '//{n++}END{print n}' <$TMP/files)
317 if [ -f $DIFF -a $numfiles == 1 ]; then
318         LOG "only changed non-binary files found"
319         LOG "creating compressed diff \e[1;37;40m$CDIFF\e[m\e[35m ..."
320         bzip2 -k $DIFF
321         RESULT=$CDIFF
322 else
323         LOG "changed and/or new files found"
324         LOG "creating archive \e[1;37;40m$ARCHIVE\e[m\e[35m ..."
325         tar -cjf $ARCHIVE --files-from $TMP/files
326         RESULT=$ARCHIVE
327 fi
328
329 [ -x "$UPLOAD" -a -f $RESULT ] && $UPLOAD $RESULT $DIFF
330
331 exit 0
332