1
0
Fork 0
flightgear/scripts/tools/fg-submit
mfranz 5b683d1c8b yeah, yet another patch ... :-]
- fix config file name in $HOME; This didn't match the documentation.
  (doesn't cost us anything to check ~/.fg-submit first, and then ~/.fg-submitrc)
- don't use mktemp for the backup files. Some outdated distributions
  (Debian) come with a version that mandates six X, which is just too ugly.
  Just find the first free slot with sequential number. That isn't thread
  safe, but mktemp isn't either, so ...  (Should be using "lockfile", but
  its availability on CygWin is questionable. And it's not *that* important.)
- some more documentation
- some cleanup, too, of course
2007-03-09 19:15:54 +00:00

358 lines
9.7 KiB
Bash
Executable file

#!/bin/bash
#
# This script called in a CVS directory compares local files with
# the repository, and prepares an update package containing all
# changes and new files for submission to a CVS maintainer. If there
# are only changes in text files, then a compressed unified diff is
# made (foo.diff.bz2). If there are also changed binary or new files,
# then an archive is made instead (foo.tar.bz2). The base name ("foo")
# can be given as command line argument. Otherwise the directory name
# is used. The script also leaves a diff in uncompressed/unpackaged
# form. This is only for developer convenience -- for a quick check
# 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 [-v] [<basename>]
#
# Options:
# -v ... verbose output
#
# Example:
# $ cd $FG_ROOT/Aircraft/bo105
# $ fg-submit # -> bo105.diff.bz2 or bo105.tar.bz2
#
# $ fg-submit update # -> update.diff.bz2 or update.tar.bz2
#
#
# Spaces in the basename are replaced with "%20". People who prefer
# 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)"'
#
#
#
# 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!
#
# $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
# ftp-/webserver, and/or to remove one or both files. Example using
# KDE's kfmclient for upload (alternatives: ncftpput, gnomevfs-copy, wput):
#
# $ cat ~/bin/fg-upload
# #!/bin/bash
# echo "uploading $1"
# if kfmclient copy $1 ftp://user:password@server.com; then
# echo "deleting $1 $2"
# rm -f $1 $2
#
# echo "Done. URL: ftp://server.com/$1"
# else
# echo "arghh ... HELP! HELP!"
# 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 four 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
# DEFAULT ... adds default rules
#
# 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
#
# A config file that only contains the keyword DEFAULT causes the
# same behavior as no config file at all. A config file without
# DEFAULT drops the built-in default rules (with the exception of
# a few very basic ones, such as rejection of CVS files). Comments
# using the hash character '#' are allowed and ignored.
#
# The list of pattern is checked in the same in order in which it
# is built. The first match causes a file to be accepted or rejected.
# Further matches are not considered.
#
# Example:
#
# DENY test.xcf # throw out the test graphic, but ...
# ALLOW *.xcf # ... allow all other GIMP graphics (the following
# # DEFAULT keyword throws them out otherwise)
#
# DEFAULT # insert the default rules here
#
# ALLOW g.old # add this silly file :-)
# IGNORE *.old # throw out the 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
# DEFAULT
SELF=${0/#*\/}
DIR=${PWD/#*\/}
if [ "$1" == "-v" ]; then
DBG=1
shift
fi
BASE=${1:-$DIR}
BASE=${BASE// /%20}
CVS=/usr/bin/cvs # avoid colorcvs wrapper from
[ -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 leading ! makes silent rejects)
PREFIX_RULES="
!$DIFF* !$CDIFF* !$ARCHIVE*
!CVS/* !*/CVS/*
"
# these rules are used when no other rules are specified,
# and wherever the DEFAULT keyword is used
DEFAULT_RULES="
+.cvsignore +*/.cvsignore
-*~ -*. -*.bak -*.orig
-*.RGB -*.RGBA -*.MDL
-*.xcf -*.XCF -*.tga -*.TGA -*.bmp -*.BMP -*.png -*.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*
"
# these rules are always appended: ignore all hidden files that
# weren't explicitly allowed so far, and accept all the rest
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
awk '
function line(a, r, c, f) {
print "\t\033[32m"a"\033[m\t\033[31m"r"\033[m\t\033[34m"c"\033[m\t"f
}
function dofile() {
if (!file) {
return
}
if (bin) {
print "\t. . . . binary . . . . \033[36m"file"\033[m"
} else {
line(a, r, c, file)
at += a; rt += r; ct += c
}
a = r = c = 0
}
BEGIN {
print "\tadded---removed-changed----------------------------------------"
a = r = c = at = rt = ct = n = bin = 0
}
/^Index: / { dofile(); scan = bin = 0; file = $2; n++; next }
/^@@/ { scan = 1; next }
/^Binary/ { if (!scan) bin = 1; next }
/^\+/ { if (scan) a++; next }
/^-/ { if (scan) r++; next }
/^!/ { if (scan) c++; next }
END {
dofile()
print "\t----------------------------------------total------------------"
line(at, rt, ct, "\033[min "n" files")
}
' <$1
}
function backup_filename {
i=1
while true; do
name=$1.$i
if ! [ -a "$name" ]; then
touch $name
echo $name
return
fi
i=$(($i + 1))
done
}
# set up accept/reject rules
function DEFAULT { RULES="$RULES $DEFAULT_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 }
RULES=
HERE=$PWD
while true; do
if [ -f $CONFIG_FILE ]; then
CONFIG="$PWD/$CONFIG_FILE"
break
fi
cd ..
[ "$PWD" == "/" ] && break
done
cd "$HERE"
if [ "$CONFIG" ]; then
DEBUG "reading config $CONFIG"
source "$CONFIG"
elif [ -f ~/$CONFIG_FILE ]; then
DEBUG "reading config ~/$CONFIG_FILE"
source ~/$CONFIG_FILE
elif [ -f ~/${CONFIG_FILE}rc ]; then
DEBUG "reading config ~/${CONFIG_FILE}rc"
source ~/$CONFIG_FILE
else
DEBUG "no config file found; using default rules"
RULES="$RULES $DEFAULT_RULES"
fi
RULES="$PREFIX_RULES $RULES $POSTFIX_RULES"
DEBUG "using these rules: $RULES"
# 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 giving sequential suffixes
for i in $DIFF $CDIFF $ARCHIVE; do
[ -f $i ] && mv $i $(backup_filename $i)
done
LOG "updating and checking for new files ..."
$CVS -q up -dP >$TMP/up
if grep "^C " $TMP/up &>/dev/null; then
ERROR "there are conflicts with the following files:"
grep "^C " $TMP/up
exit 1
fi
LOG "making diff ..."
if ! $CVS -q diff -up >$DIFF; then
LOG "diff statistics:"
diffstat $DIFF
echo
# add diff file itself
echo $DIFF >>$TMP/files
# add changed binary files
awk '
/^Index: / { scan = 1; file = $2; next }
/^@@/ { scan = 0; next }
/^Binary/ { if (scan) { print file } }
' <$DIFF >>$TMP/files
else
rm -f $DIFF
fi
LOG "checking for files to submit ..."
if [ -f $TMP/files ]; then
cat $TMP/files|while read i; do
CHANGED "$i"
done
fi
grep "^? " $TMP/up|while read i; do
find ${i#? } -type f >>$TMP/check
done
# filter files according to the pattern rules
if [ -f $TMP/check ]; then
for i in $(cat $TMP/check); do
DEBUG "checking whether file '$i' matches"
for r in $RULES; do
DEBUG "\t\trule $r"
R=${r#?}
case "!$i" in $r)
DEBUG "\t\t\t\"silently\" rejected\t\t$R"
break
;;
esac
case "-$i" in $r)
REJECT "$i\t\t$R"
break
;;
esac
case "+$i" in $r)
NEW "$i\t\t$R"
echo "$i" >>$TMP/files
break
;;
esac
done
done
fi
if ! [ -f $TMP/files ]; then
LOG "no changed or new files found"
exit 0
fi
echo
numfiles=$(awk '//{n++}END{print n}' <$TMP/files)
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
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
RESULT=$ARCHIVE
fi
[ -x "$UPLOAD" -a -f $RESULT ] && $UPLOAD $RESULT $DIFF
exit 0