# of the diff correctness. It is not to be submitted. The script will
# not overwrite any file, but rather rename conflicting files.
#
-# Usage: fg-submit [<basename>]
+# Usage: fg-submit [-v] [<basename>]
+#
+# Options:
+# -v ... verbose output
#
# Example:
# $ cd $FG_ROOT/Aircraft/bo105
# to have the date in the archive name can conveniently achieve this
# by defining a shell alias in ~/.bashrc:
#
-# alias submit='fg-submit "${PWD/#*\/}-$(date +%Y-%m-%d)"'
+# alias submit='fg-submit "${PWD##*/}-$(date +%Y-%m-%d)"'
+#
#
#
# If the script finds an application named "fg-upload", then it calls
# this at the end with two arguments:
#
# $1 ... archive or compressed diff for submission
-# $2 ... accessory diff, *NOT* for submission!
+# $2 ... accessory uncompressed diff, *NOT* for submission!
#
# $1 and $2 are guaranteed not to contain spaces, only $1 is guaranteed
-# to actually exist. Such as script can be used to upload the file to an
+# to actually exist. Such a script can be used to upload the file to an
# ftp-/webserver, and/or to remove one or both files. Example using
-# KDE's kfmclient for upload (alternatives: ncftpput, gnomevfs-copy, ...):
+# KDE's kfmclient for upload (alternatives: ncftpput, gnomevfs-copy):
#
# $ cat ~/bin/fg-upload
# #!/bin/bash
# echo "uploading $1"
# if kfmclient copy $1 ftp://user:password@server.com; then
# echo "deleting $1 $2"
-# rm -rf $1 $2
+# rm -f $1 $2
+#
+# URL=ftp://server.com/$1
+#
+# # copy URL to KDE's clipboard, so that MMB-clicking pastes it
+# dcop klipper klipper setClipboardContents $URL
#
-# echo "Done. URL: ftp://server.com/$1"
+# echo "Done. --> $URL"
# else
-# echo "arghh ... HELP! HELP!"
+# echo "$0: uploading failed!"
# fi
+#
+#
+#
+# Whether a file should be included in the archive or not, is decided
+# by pattern rules. There is a set of reasonable default rules predefined,
+# but alternative settings can be defined in a hidden configuration file
+# named ".fg-submit". Such a file is searched in the current directory,
+# in its parent directory, in its grand-parent directory and so on,
+# and finally in the $HOME directory. The first found file is taken.
+#
+# A file can use a list of three keywords with arguments, each on a
+# separate line:
+#
+# ALLOW <pattern-list> ... accept & report matching file
+# DENY <pattern-list> ... reject & report matching file
+# IGNORE <pattern-list> ... silently reject matching file
+#
+# A <pattern-list> is a space-separated list of shell pattern.
+# It may also be empty, in which case it has no effect. Examples:
+#
+# DENY test.blend
+# ALLOW *.xcf *.blend
+#
+# The list of pattern is checked in the same order in which it was
+# built. The first match causes a file to be accepted or rejected.
+# Further matches are not considered. Comments using the hash
+# character '#' are allowed and ignored.
+#
+# Some default rules are always added at the end. If you want to
+# bypass them, then finish your configuration with an "ALLOW *"
+# or "DENY *", and no file will ever reach the default rules.
+#
+#
+# Example:
+#
+# DENY test.xcf # throw out the test image, but ...
+# ALLOW *.xcf # ... allow all other GIMP images (the default
+# # rules would otherwise throw them out)
+#
+# ALLOW not.old # add this file, but ...
+# IGNORE *.old # throw out all other "old" files (and don't
+# # report that to the terminal)
+#
+#
+# .fg-submit configuration files are "sourced" bash scripts, the
+# keywords are simple shell functions. That means that you can
+# also use other bash commands in that file, such as "echo", or
+# write several commands on one line, separated with semicolon.
+# You can even put all special rules in your ~/.fg-submit file,
+# with rules depending on the working directory:
+#
+# case "$PWD" in
+# */bo105*) DENY *.osg; ALLOW livery.xcf ;;
+# */ufo*) DENY *.tiff ;;
+# esac
+
+
+SELF=${0##*/}
+DIR=${PWD##*/}
+
+if [ "$1" == "-v" ]; then
+ DBG=1
+ shift
+fi
-SELF=${0/#*\/}
-DIR=${PWD/#*\/}
BASE=${1:-$DIR}
BASE=${BASE// /%20}
[ -x $CVS ] || CVS=cvs # http://www.hakubi.us/colorcvs/
UPLOAD=$(which fg-upload 2>/dev/null)
+CONFIG_FILE=".fg-submit"
ARCHIVE=$BASE.tar.bz2
DIFF=$BASE.diff
CDIFF=$DIFF.bz2
+# these rules are always prepended; the first letter decides if the
+# rule accepts (+), rejects (-), or ignores (!) a matching file.
+PREFIX_RULES="
+ !$DIFF* !$CDIFF* !$ARCHIVE*
+ !CVS/* !*/CVS/*
+"
+# these rules are always appended
+DEFAULT_RULES="
+ +.cvsignore +*/.cvsignore
+ -*~ -*. -*.bak -*.orig
+ -*.RGB -*.RGBA -*.MDL
+ -*.XCF -*.tga -*.TGA -*.bmp -*.BMP -*.PNG
+ -*.blend -*.blend[0-9] -*blend[0-9][0-9] -*.blend[0-9][0-9][0-9]
+ -*.gz -*.tgz -*.bz2 -*.zip -*.tar.gz* -*.tar.bz2*
+"
+POSTFIX_RULES="
+ !.* !*/.*
+ +*
+"
+
+
function ERROR { echo -e "\e[31;1m$*\e[m"; }
function LOG { echo -e "\e[35m$*\e[m"; }
function NEW { echo -e "\e[32m\t+ $*\e[m"; }
function CHANGED { echo -e "\e[36m\t+ $*\e[m"; }
function REJECT { echo -e "\e[31m\t- $*\e[m"; }
+function DEBUG { [ $DBG ] && echo -e "$*"; }
function diffstat {
# output diff statistics, similar to the "diffstat" utility
/^Index: / { dofile(); scan = bin = 0; file = $2; n++; next }
/^@@/ { scan = 1; next }
/^Binary/ { if (!scan) bin = 1; next }
- /^+/ { if (scan) a++; next }
+ /^\+/ { if (scan) a++; next }
/^-/ { if (scan) r++; next }
/^!/ { if (scan) c++; next }
END {
' <$1
}
+function backup_filename {
+ for ((i = 1; 1; i = i + 1)); do
+ name=$1.$i
+ if ! [ -a "$name" ]; then
+ touch $name
+ echo $name
+ return
+ fi
+ done
+}
+
+
+
+# set up accept/reject rules
+function ALLOW { for i in $*; do RULES="$RULES +$i"; done }
+function DENY { for i in $*; do RULES="$RULES -$i"; done }
+function IGNORE { for i in $*; do RULES="$RULES !$i"; done }
+
+
+function search_config {
+ file="$1/$CONFIG_FILE"
+ DEBUG "checking for config file $file"
+ if [ -f "$file" ]; then
+ CONFIG="$file"
+ return 0
+ elif [ "$1" ]; then
+ search_config ${1%/${1##*/}} # parent dir
+ return
+ fi
+ return 1
+}
+
+
+set -f
+RULES=
+if search_config "$PWD"; then
+ LOG "loading config file $CONFIG"
+ source "$CONFIG"
+elif [ -f ~/$CONFIG_FILE ]; then
+ DEBUG "loading config file ~/$CONFIG_FILE"
+ source ~/$CONFIG_FILE
+elif [ -f ~/${CONFIG_FILE}rc ]; then
+ DEBUG "loading config file ~/${CONFIG}rc"
+ source ~/${CONFIG_FILE}rc
+fi
+RULES="$PREFIX_RULES $RULES $DEFAULT_RULES $POSTFIX_RULES"
+set +f
+
-# create temporary dir that's automatcally removed on exit
-TMP=$(mktemp -d -t $SELF.$BASE.XXX) || (echo "$0: can't create temporary dir"; exit 1)
+if [ $DBG ]; then
+ DEBUG "using these rules: "
+ for i in $RULES; do echo -n "$i "; done
+ echo
+fi
+
+
+
+# create temporary dir that's automatically removed on exit
+TMP=$(mktemp -d /tmp/$SELF.$BASE.XXXXXX) || (echo "$0: can't create temporary dir"; exit 1)
trap "rm -rf $TMP" 0 1 2 3 13 15
-# move old files out of the way
+
+# move old files out of the way adding sequential suffixes
for i in $DIFF $CDIFF $ARCHIVE; do
- [ -f $i ] && mv $i $(mktemp $i.X)
+ [ -f $i ] && mv $i $(backup_filename $i)
done
+
LOG "updating and checking for new files ..."
-$CVS -q up -dP >$TMP/up
+$CVS -q up -dP >$TMP/up || exit 1
if grep "^C " $TMP/up &>/dev/null; then
fi
+
LOG "making diff ..."
if ! $CVS -q diff -up >$DIFF; then
LOG "diff statistics:"
fi
+
LOG "checking for files to submit ..."
if [ -f $TMP/files ]; then
cat $TMP/files|while read i; do
done
-# classify and filter files
+
+# filter files according to the pattern rules
if [ -f $TMP/check ]; then
for i in $(cat $TMP/check); do
- case "$i" in
- $ARCHIVE*|$DIFF*) # don't add files generated by the script
- ;;
- */.*|.*) # silently drop hidden files
- ;;
- *~|*.|*.bak|*.orig)
- REJECT "$i\t\t(backup file)"
- ;;
- CVS/*|*/CVS/*)
- REJECT "$i\t\t(CVS file)"
- ;;
- *.blend|*.blend[0-9]|*.blend[0-9][0-9])
- REJECT "$i\t\t(blender file)"
- ;;
- *.xcf|*.tga|*.bmp|*.BMP|*.png)
- REJECT "$i\t\t(graphics file)"
- ;;
- *)
- NEW "$i"
- echo "$i" >>$TMP/files
- ;;
- esac
+ DEBUG "checking whether file '$i' matches"
+ for r in $RULES; do
+ DEBUG "\t\trule $r"
+ class=${r:0:1}
+ rule=${r:1}
+ case "$i" in $rule)
+ case $class in
+ !) DEBUG "$i\t\t\"silently\" rejected\t\t$rule" ;;
+ -) REJECT "$i\t\t$rule" ;;
+ +) NEW "$i\t\t$rule" && echo "$i" >>$TMP/files ;;
+ esac
+ break
+ ;;
+ esac
+ done
done
fi
+
if ! [ -f $TMP/files ]; then
LOG "no changed or new files found"
exit 0
if [ -f $DIFF -a $numfiles == 1 ]; then
LOG "only changed non-binary files found"
LOG "creating compressed diff \e[1;37;40m$CDIFF\e[m\e[35m ..."
- bzip2 -k $DIFF
+ bzip2 --keep $DIFF
RESULT=$CDIFF
else
LOG "changed and/or new files found"
LOG "creating archive \e[1;37;40m$ARCHIVE\e[m\e[35m ..."
- tar -cjf $ARCHIVE --files-from $TMP/files
+ tar --create --bzip2 --file=$ARCHIVE --files-from $TMP/files
RESULT=$ARCHIVE
fi
-[ -x "$UPLOAD" -a -f $RESULT ] && $UPLOAD "$PWD" $RESULT $DIFF
-exit 0
+[ -x "$UPLOAD" -a -f $RESULT ] && $UPLOAD $RESULT $DIFF
+