Home | History | Annotate | Line # | Download | only in dist
      1  1.1  christos #! /bin/sh
      2  1.1  christos 
      3  1.1  christos # commit version 0.9.2
      4  1.1  christos 
      5  1.1  christos # Copyright (C) 1999, Free Software Foundation
      6  1.1  christos 
      7  1.1  christos # This script is Free Software, and it can be copied, distributed and
      8  1.1  christos # modified as defined in the GNU General Public License.  A copy of
      9  1.1  christos # its license can be downloaded from http://www.gnu.org/copyleft/gpl.html
     10  1.1  christos 
     11  1.1  christos # Originally by Gary V. Vaughan <gvaughan (at] oranda.demon.co.uk>
     12  1.1  christos # Heavily modified by Alexandre Oliva <oliva (at] dcc.unicamp.br>
     13  1.1  christos 
     14  1.1  christos # This scripts eases checking in changes to CVS-maintained projects
     15  1.1  christos # with ChangeLog files.  It will check that there have been no
     16  1.1  christos # conflicting commits in the CVS repository and print which files it
     17  1.1  christos # is going to commit to stderr.  A list of files to compare and to
     18  1.1  christos # check in can be given in the command line.  If it is not given, all
     19  1.1  christos # files in the current directory (and below, unless `-l' is given) are
     20  1.1  christos # considered for check in.
     21  1.1  christos 
     22  1.1  christos # The commit message will be extracted from the differences between
     23  1.1  christos # the local ChangeLog and the one in the repository (unless a message
     24  1.1  christos # was specified with `-m' or `-F').  An empty message is not accepted
     25  1.1  christos # (but a blank line is).  If the message is acceptable, it will be
     26  1.1  christos # presented for verification (and possible edition) using the $PAGER
     27  1.1  christos # environment variable (or `more', if it is not set, or `cat', if the
     28  1.1  christos # `-f' switch is given).  If $PAGER exits successfully, the modified
     29  1.1  christos # files (at that moment) are checked in, unless `-n' was specified, in
     30  1.1  christos # which case nothing is checked in.
     31  1.1  christos 
     32  1.1  christos # usage: commit [-v] [-h] [-f] [-l] [-n] [-q] [-z N]
     33  1.1  christos #               [-m msg|-F msg_file] [--] [file|dir ...]
     34  1.1  christos 
     35  1.1  christos # -f      --fast        don't check (unless *followed* by -n), and just
     36  1.1  christos #         --force       display commit message instead of running $PAGER
     37  1.1  christos # -l      --local       don't descend into subdirectories
     38  1.1  christos # -m msg  --message=msg set commit message
     39  1.1  christos #         --msg=msg     same as -m
     40  1.1  christos # -F file --file=file   read commit message from file
     41  1.1  christos # -n      --dry-run     don't commit anything
     42  1.1  christos # -q      --quiet       run cvs in quiet mode
     43  1.1  christos # -zN     --compress=N  set compression level (0-9, 0=none, 9=max)
     44  1.1  christos # -v      --version     print version information
     45  1.1  christos # -h,-?   --help        print short or long help message
     46  1.1  christos 
     47  1.1  christos name=commit
     48  1.1  christos cvsopt=
     49  1.1  christos updateopt=
     50  1.1  christos commitopt=
     51  1.1  christos dry_run=false
     52  1.1  christos commit=:
     53  1.1  christos update=:
     54  1.1  christos log_file="${TMPDIR-/tmp}/commitlog.$$"
     55  1.1  christos 
     56  1.1  christos rm -f "$log_file"
     57  1.1  christos trap 'rm -f "$log_file"; exit 1' 1 2 15
     58  1.1  christos 
     59  1.1  christos # this just eases exit handling
     60  1.1  christos main_repeat=":"
     61  1.1  christos while $main_repeat; do
     62  1.1  christos 
     63  1.1  christos repeat="test $# -gt 0"
     64  1.1  christos while $repeat; do
     65  1.1  christos     case "$1" in
     66  1.1  christos     -f|--force|--fast)
     67  1.1  christos 	update=false
     68  1.1  christos 	PAGER=cat
     69  1.1  christos 	shift
     70  1.1  christos 	;;
     71  1.1  christos     -l|--local)
     72  1.1  christos 	updateopt="$updateopt -l"
     73  1.1  christos 	commitopt="$commitopt -l"
     74  1.1  christos 	shift
     75  1.1  christos 	;;
     76  1.1  christos     -m|--message|--msg)
     77  1.1  christos 	if test $# = 1; then
     78  1.1  christos 	    echo "$name: missing argument for $1" >&2
     79  1.1  christos 	    break
     80  1.1  christos 	fi
     81  1.1  christos 	if test -f "$log_file"; then
     82  1.1  christos 	    echo "$name: you can have at most one of -m and -F" >&2
     83  1.1  christos 	    break
     84  1.1  christos 	fi
     85  1.1  christos 	shift
     86  1.1  christos 	echo "$1" > "$log_file"
     87  1.1  christos 	shift
     88  1.1  christos 	;;
     89  1.1  christos     -F|--file)
     90  1.1  christos 	if test -f "$log_file"; then
     91  1.1  christos 	    echo "$name: you can have at most one of -m and -F" >&2
     92  1.1  christos 	    break
     93  1.1  christos 	fi
     94  1.1  christos 	if test $# = 1; then
     95  1.1  christos 	    echo "$name: missing argument for $1" >&2
     96  1.1  christos 	    break
     97  1.1  christos 	fi
     98  1.1  christos 	shift
     99  1.1  christos 	if cat < "$1" > "$log_file"; then :; else
    100  1.1  christos 	    break
    101  1.1  christos 	fi
    102  1.1  christos 	shift
    103  1.1  christos 	;;
    104  1.1  christos     -n|--dry-run)
    105  1.1  christos 	commit=false
    106  1.1  christos 	update=true
    107  1.1  christos 	shift
    108  1.1  christos 	;;
    109  1.1  christos     -q|--quiet)
    110  1.1  christos 	cvsopt="$cvsopt -q"
    111  1.1  christos 	shift
    112  1.1  christos 	;;
    113  1.1  christos     -z|--compress)
    114  1.1  christos 	if test $# = 1; then
    115  1.1  christos 	    echo "$name: missing argument for $1" >&2
    116  1.1  christos 	    break
    117  1.1  christos 	fi
    118  1.1  christos 	case "$2" in
    119  1.1  christos 	[0-9]) :;;
    120  1.1  christos 	*)  echo "$name: invalid argument for $1" >&2
    121  1.1  christos 	    break
    122  1.1  christos 	    ;;
    123  1.1  christos 	esac
    124  1.1  christos 	cvsopt="$cvsopt -z$2"
    125  1.1  christos 	shift
    126  1.1  christos 	shift
    127  1.1  christos 	;;
    128  1.1  christos 
    129  1.1  christos     -m*|-F*|-z*)
    130  1.1  christos 	opt=`echo "$1" | sed '1s/^\(..\).*$/\1/;q'`
    131  1.1  christos 	arg=`echo "$1" | sed '1s/^-[a-zA-Z0-9]//'`
    132  1.1  christos 	shift
    133  1.1  christos 	set -- "$opt" "$arg" ${1+"$@"}
    134  1.1  christos 	;;
    135  1.1  christos     --message=*|--msg=*|--file=*|--compress=*)
    136  1.1  christos 	opt=`echo "$1" | sed '1s/^\(--[^=]*\)=.*/\1/;q'`
    137  1.1  christos     	arg=`echo "$1" | sed '1s/^--[^=]*=//'`
    138  1.1  christos 	shift
    139  1.1  christos 	set -- "$opt" "$arg" ${1+"$@"}
    140  1.1  christos 	;;
    141  1.1  christos 
    142  1.1  christos     -v|--version)
    143  1.1  christos 	sed '/^# '$name' version /,/^# Heavily modified by/ { s/^# //; p; }; d' < $0
    144  1.1  christos 	exit 0
    145  1.1  christos 	;;
    146  1.1  christos     -\?|-h)
    147  1.1  christos 	sed '/^# usage:/,/# -h/ { s/^# //; p; }; d' < $0 &&
    148  1.1  christos 	echo
    149  1.1  christos 	echo "run \`$name --help | more' for full usage"
    150  1.1  christos 	exit 0
    151  1.1  christos 	;;
    152  1.1  christos     --help)
    153  1.1  christos 	sed '/^# '$name' version /,/^[^#]/ { /^[^#]/ d; s/^# //; p; }; d' < $0
    154  1.1  christos 	exit 0
    155  1.1  christos 	;;
    156  1.1  christos     --)
    157  1.1  christos 	shift
    158  1.1  christos 	repeat=false
    159  1.1  christos 	;;
    160  1.1  christos     -*)
    161  1.1  christos 	echo "$name: invalid flag $1" >&2
    162  1.1  christos 	break
    163  1.1  christos 	;;
    164  1.1  christos     *)
    165  1.1  christos 	repeat=false
    166  1.1  christos 	;;
    167  1.1  christos     esac
    168  1.1  christos done
    169  1.1  christos # might have used break 2 within the previous loop, but so what
    170  1.1  christos $repeat && break
    171  1.1  christos 
    172  1.1  christos $update && \
    173  1.1  christos if echo "$name: checking for conflicts..." >&2
    174  1.1  christos    (cvs $cvsopt -q -n update $updateopt ${1+"$@"} 2>/dev/null \
    175  1.1  christos     | while read line; do
    176  1.1  christos 	echo "$line"
    177  1.1  christos 	echo "$line" >&3
    178  1.1  christos       done | grep '^C') 3>&1 >/dev/null; then
    179  1.1  christos   echo "$name: some conflicts were found, aborting..." >&2
    180  1.1  christos   break
    181  1.1  christos fi
    182  1.1  christos 
    183  1.1  christos if test ! -f "$log_file"; then
    184  1.1  christos   echo "$name: checking commit message..." >&2
    185  1.1  christos   cvs $cvsopt diff -u ChangeLog \
    186  1.1  christos   | while read line; do
    187  1.1  christos       case "$line" in
    188  1.1  christos       "--- ChangeLog"*) :;;
    189  1.1  christos       "-"*)
    190  1.1  christos 	echo "$name: *** Warning: the following line in ChangeLog diff is suspicious:" >&2
    191  1.1  christos 	echo "$line" | sed 's/^.//' >&2;;
    192  1.1  christos       "+ "*)
    193  1.1  christos 	echo "$name: *** Warning: lines should start with tabs, not spaces; ignoring line:" >&2
    194  1.1  christos 	echo "$line" | sed 's/^.//' >&2;;
    195  1.1  christos       "+") echo;;
    196  1.1  christos       "+	"*) echo "$line";;
    197  1.1  christos       esac
    198  1.1  christos     done \
    199  1.1  christos   | sed -e 's,\+	,,' -e '/./p' -e '/./d' -e '1d' -e '$d' > "$log_file" \
    200  1.1  christos   || break
    201  1.1  christos # The sed script above removes "+TAB" from the beginning of a line, then
    202  1.1  christos # deletes the first and/or the last line, when they happen to be empty
    203  1.1  christos fi
    204  1.1  christos 
    205  1.1  christos if grep '[^ 	]' < "$log_file" > /dev/null; then :; else
    206  1.1  christos   echo "$name: empty commit message, aborting" >&2
    207  1.1  christos   break
    208  1.1  christos fi
    209  1.1  christos 
    210  1.1  christos if grep '^$' < "$log_file" > /dev/null; then
    211  1.1  christos   echo "$name: *** Warning: blank lines should not appear within a commit messages." >&2
    212  1.1  christos   echo "$name: *** They should be used to separate distinct commits." >&2
    213  1.1  christos fi
    214  1.1  christos 
    215  1.1  christos ${PAGER-more} "$log_file" || break
    216  1.1  christos 
    217  1.1  christos sleep 1 # give the user some time for a ^C
    218  1.1  christos 
    219  1.1  christos # Do not check for empty $log_file again, even though the user might have
    220  1.1  christos # zeroed it out.  If s/he did, it was probably intentional.
    221  1.1  christos 
    222  1.1  christos if $commit; then
    223  1.1  christos   cvs $cvsopt commit $commitopt -F $log_file ${1+"$@"} || break
    224  1.1  christos fi
    225  1.1  christos 
    226  1.1  christos main_repeat=false
    227  1.1  christos done
    228  1.1  christos 
    229  1.1  christos rm -f "$log_file"
    230  1.1  christos 
    231  1.1  christos # if main_repeat was not set to `false', we failed
    232  1.1  christos $main_repeat && exit 1
    233  1.1  christos exit 0
    234