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.
15 # Usage: fg-submit [-v] [<basename>]
18 # -v ... verbose output
21 # $ cd $FG_ROOT/Aircraft/bo105
22 # $ fg-submit # -> bo105.diff.bz2 or bo105.tar.bz2
24 # $ fg-submit update # -> update.diff.bz2 or update.tar.bz2
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:
31 # alias submit='fg-submit "${PWD##*/}-$(date +%Y-%m-%d)"'
35 # If the script finds an application named "fg-upload", then it calls
36 # this at the end with two arguments:
38 # $1 ... archive or compressed diff for submission
39 # $2 ... accessory diff, *NOT* for submission!
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, wput):
46 # $ cat ~/bin/fg-upload
49 # if kfmclient copy $1 ftp://user:password@server.com; then
50 # echo "deleting $1 $2"
53 # echo "Done. URL: ftp://server.com/$1"
55 # echo "arghh ... HELP! HELP!"
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.
67 # A file can use a list of three keywords with arguments, each on a
70 # ALLOW <pattern-list> ... accept & report matching file
71 # DENY <pattern-list> ... reject & report matching file
72 # IGNORE <pattern-list> ... silently reject matching file
74 # A <pattern-list> is a space-separated list of shell pattern.
75 # It may also be empty, in which case it has no effect. Examples:
80 # The list of pattern is checked in the same order in which it was
81 # built. The first match causes a file to be accepted or rejected.
82 # Further matches are not considered. Comments using the
83 # hash character '#' are allowed and ignored.
85 # Some default rules are always added at the end. If you want to
86 # bypass them, then just add "ALLOW *" or "DENY *" at the end of
87 # your configuration, and no file will ever reach the default rules.
92 # DENY test.xcf # throw out the test image, but ...
93 # ALLOW *.xcf # ... allow all other GIMP images (the default
94 # # rules would otherwise throw them out)
96 # ALLOW g.old # add this silly file, but ...
97 # IGNORE *.old # throw out all other "old" files (and don't
98 # # report that to the terminal)
101 # .fg-submit configuration files are "sourced" bash scripts, the
102 # keywords are simple shell functions. That means that you can
103 # also use other bash commands in that file, such as "echo", or
104 # write several commands on one line, separated with semicolon.
105 # You can even put all special rules in your ~/.fg-submit file,
106 # with rules depending on the working directory:
109 # */bo105*) DENY *.osg; ALLOW livery.xcf ;;
110 # */ufo*) DENY *.tiff ;;
118 if [ "$1" == "-v" ]; then
126 CVS=/usr/bin/cvs # avoid colorcvs wrapper from
127 [ -x $CVS ] || CVS=cvs # http://www.hakubi.us/colorcvs/
128 UPLOAD=$(which fg-upload 2>/dev/null)
130 CONFIG_FILE=".fg-submit"
131 ARCHIVE=$BASE.tar.bz2
135 # these rules are always prepended; the first letter decides if the
136 # rule accepts (+), rejects (-), or ignores (!) a matching file.
138 !$DIFF* !$CDIFF* !$ARCHIVE*
141 # these rules are always appended
143 +.cvsignore +*/.cvsignore
144 -*~ -*. -*.bak -*.orig
145 -*.RGB -*.RGBA -*.MDL
146 -*.xcf -*.XCF -*.tga -*.TGA -*.bmp -*.BMP -*.png -*.PNG
147 -*.blend -*.blend[0-9] -*blend[0-9][0-9] -*.blend[0-9][0-9][0-9]
148 -*.gz -*.tgz -*.bz2 -*.zip -*.tar.gz* -*.tar.bz2*
157 function ERROR { echo -e "\e[31;1m$*\e[m"; }
158 function LOG { echo -e "\e[35m$*\e[m"; }
159 function NEW { echo -e "\e[32m\t+ $*\e[m"; }
160 function CHANGED { echo -e "\e[36m\t+ $*\e[m"; }
161 function REJECT { echo -e "\e[31m\t- $*\e[m"; }
162 function DEBUG { [ $DBG ] && echo -e "$*"; }
165 # output diff statistics, similar to the "diffstat" utility
167 function line(a, r, c, f) {
168 print "\t\033[32m"a"\033[m\t\033[31m"r"\033[m\t\033[34m"c"\033[m\t"f
175 print "\t. . . . binary . . . . \033[36m"file"\033[m"
178 at += a; rt += r; ct += c
183 print "\tadded---removed-changed----------------------------------------"
184 a = r = c = at = rt = ct = n = bin = 0
186 /^Index: / { dofile(); scan = bin = 0; file = $2; n++; next }
187 /^@@/ { scan = 1; next }
188 /^Binary/ { if (!scan) bin = 1; next }
189 /^\+/ { if (scan) a++; next }
190 /^-/ { if (scan) r++; next }
191 /^!/ { if (scan) c++; next }
194 print "\t----------------------------------------total------------------"
195 line(at, rt, ct, "\033[min "n" files")
200 function backup_filename {
201 for ((i = 1; 1; i = i + 1)); do
203 if ! [ -a "$name" ]; then
213 # set up accept/reject rules
214 function ALLOW { for i in $*; do RULES="$RULES +$i"; done }
215 function DENY { for i in $*; do RULES="$RULES -$i"; done }
216 function IGNORE { for i in $*; do RULES="$RULES !$i"; done }
219 function search_config {
220 file="$1/$CONFIG_FILE"
221 DEBUG "checking for config file $file"
222 if [ -f "$file" ]; then
226 search_config ${1%/${1##*/}} # parent dir
235 if search_config "$PWD"; then
236 LOG "loading config file $CONFIG"
238 elif [ -f ~/$CONFIG_FILE ]; then
239 DEBUG "loading config file ~/$CONFIG_FILE"
240 source ~/$CONFIG_FILE
241 elif [ -f ~/${CONFIG_FILE}rc ]; then
242 DEBUG "loading config file ~/${CONFIG}rc"
243 source ~/${CONFIG_FILE}rc
245 RULES="$PREFIX_RULES $RULES $DEFAULT_RULES $POSTFIX_RULES"
250 DEBUG "using these rules: "
251 for i in $RULES; do echo -n "$i "; done
257 # create temporary dir that's automatically removed on exit
258 TMP=$(mktemp -d /tmp/$SELF.$BASE.XXXXXX) || (echo "$0: can't create temporary dir"; exit 1)
259 trap "rm -rf $TMP" 0 1 2 3 13 15
263 # move old files out of the way giving sequential suffixes
264 for i in $DIFF $CDIFF $ARCHIVE; do
265 [ -f $i ] && mv $i $(backup_filename $i)
270 LOG "updating and checking for new files ..."
271 $CVS -q up -dP >$TMP/up
274 if grep "^C " $TMP/up &>/dev/null; then
275 ERROR "there are conflicts with the following files:"
282 LOG "making diff ..."
283 if ! $CVS -q diff -up >$DIFF; then
284 LOG "diff statistics:"
288 # add diff file itself
289 echo $DIFF >>$TMP/files
291 # add changed binary files
293 /^Index: / { scan = 1; file = $2; next }
294 /^@@/ { scan = 0; next }
295 /^Binary/ { if (scan) { print file } }
296 ' <$DIFF >>$TMP/files
303 LOG "checking for files to submit ..."
304 if [ -f $TMP/files ]; then
305 cat $TMP/files|while read i; do
310 grep "^? " $TMP/up|while read i; do
311 find ${i#? } -type f >>$TMP/check
316 # filter files according to the pattern rules
317 if [ -f $TMP/check ]; then
318 for i in $(cat $TMP/check); do
319 DEBUG "checking whether file '$i' matches"
326 !) DEBUG "$i\t\t\"silently\" rejected\t\t$rule" ;;
327 -) REJECT "$i\t\t$rule" ;;
328 +) NEW "$i\t\t$rule" && echo "$i" >>$TMP/files ;;
339 if ! [ -f $TMP/files ]; then
340 LOG "no changed or new files found"
345 numfiles=$(awk '//{n++}END{print n}' <$TMP/files)
346 if [ -f $DIFF -a $numfiles == 1 ]; then
347 LOG "only changed non-binary files found"
348 LOG "creating compressed diff \e[1;37;40m$CDIFF\e[m\e[35m ..."
352 LOG "changed and/or new files found"
353 LOG "creating archive \e[1;37;40m$ARCHIVE\e[m\e[35m ..."
354 tar --create --bzip2 --file=$ARCHIVE --files-from $TMP/files
359 [ -x "$UPLOAD" -a -f $RESULT ] && $UPLOAD $RESULT $DIFF