3 # clcommit (GNU cvs-utils) version 0.11
4 # Written by Gary V. Vaughan <gary@gnu.org>
5 # and Alexandre Oliva <aoliva@redhat.com>
7 # Copyright (C) 1999, 2000, 2004, 2006 Free Software Foundation, Inc.
8 # This is free software; see the source for copying conditions. There is NO
9 # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 2 of the License, or
14 # (at your option) any later version.
16 # This program is distributed in the hope that it will be useful, but
17 # WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 # General Public License for more details.
21 # You should have received a copy of the GNU General Public License
22 # along with this program; if not, a copy can be downloaded from
23 # http://www.gnu.org/copyleft/gpl.html, or by writing to the Free
24 # Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
27 # Usage: $progname [-v] [-h] [-f] [-l] [-n] [-q] [-z N] [-C ChangeLog_file]
28 # [-m msg|-F msg_file|-1] [-s addr [--from addr]] [--] [file|dir ...]
30 # -C file --changelog=file extract commit message from specified ChangeLog
31 # -zN --compress=N set compression level (0-9, 0=none, 9=max)
32 # -n --dry-run don't commit anything
33 # --fast same as --force --first
34 # -F file --file=file read commit message from file
35 # -1 --first extract first entry from ChangeLog, no cvs diff
36 # -f --force don't check (unless *followed* by -n), and just
37 # display commit message instead of running $PAGER
38 # --from=addr override default from address in commit email
39 # -l --local don't descend into subdirectories
40 # -m msg --message=msg set commit message
41 # --msg=msg same as -m
42 # -q --quiet run cvs in quiet mode
43 # -s addr --sendmail=addr send a commit email of the differences to ADDR
44 # --signature[=file] add FILE to the end of the email (~/.signature)
45 # -v --version print version information
46 # -h,-? --help print short or long help message
48 # This script eases checking in changes to CVS-maintained projects
49 # with ChangeLog files. It will check that there have been no
50 # conflicting commits in the CVS repository and print which files it
51 # is going to commit to stderr. A list of files to compare and to
52 # check in can be given in the command line. If it is not given, all
53 # files in the current directory (and below, unless `-l' is given) are
54 # considered for check in.
56 # The commit message will be extracted from the differences between a
57 # file named ChangeLog* in the commit list, or named after -C, and the
58 # one in the repository (unless a message was specified with `-m' or
59 # `-F'). An empty message is not accepted (but a blank line is). If
60 # the message is acceptable, it will be presented for verification
61 # (and possible edition) using the $PAGER environment variable (or
62 # `more', if it is not set, or `cat', if the `-f' switch is given).
63 # If $PAGER exits successfully, the modified files (at that moment)
64 # are checked in, unless `-n' was specified, in which case nothing is
67 # Report bugs to <gary@gnu.org>
70 : ${MAILNOTIFY="./ltdl/config/mailnotify"}
71 : ${MKSTAMP="./ltdl/config/mkstamp"}
80 # Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
81 # is ksh but when the shell is invoked as "sh" and the current value of
82 # the _XPG environment variable is not equal to 1 (one), the special
83 # positional parameter $0, within a function call, is the name of the
87 # The name of this program:
88 progname
=`echo "$progpath" | $SED "$basename"`
106 # Locations for important files
108 log_file
="${TMPDIR-/tmp}/commitlog.$$"
111 trap '$RM "${log_file}*"; exit $EXIT_FAILURE' 1 2 15
117 # Echo program name prefixed message.
120 echo $progname: ${1+"$@"}
124 # Echo program name prefixed message to standard error.
127 echo $progname: ${1+"$@"} 1>&2
130 # func_fatal_error arg...
131 # Echo program name prefixed message to standard error, and exit.
138 # func_verbose arg...
139 # Echo program name prefixed message in verbose mode only.
142 $opt_verbose && func_error
${1+"$@"}
145 # func_fatal_help arg...
146 # Echo program name prefixed message to standard error, followed by
147 # a help hint, and exit.
151 func_fatal_error
"Try \`$progname --help' for more information."
154 # func_missing_arg argname
155 # Echo program name prefixed message to standard error and set global
159 func_error
"missing argument for $1"
164 # Echo short help message to standard output and exit.
167 $SED '/^# Usage:/,/# -h/ {
169 s/\$progname/'$progname'/;
173 echo "run \`$progname --help | more' for full usage"
178 # Echo long help message to standard output and exit.
181 $SED '/^# Usage:/,/# Report bugs to/ {
183 s/\$progname/'$progname'/;
190 # Echo version message to standard output and exit.
193 $SED '/^# '$PROGRAM' (GNU /,/# warranty; / {
195 s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/;
201 # Parse options once, thoroughly. This comes as soon as possible in
202 # the script to make things like `commit --version' happen quickly.
205 my_sed_single_opt
='1s/^\(..\).*$/\1/;q'
206 my_sed_single_rest
='1s/^..\(.*\)$/\1/;q'
207 my_sed_long_opt
='1s/^\(--[^=]*\)=.*/\1/;q'
208 my_sed_long_arg
='1s/^--[^=]*=//'
210 # this just eases exit handling
211 while test $# -gt 0; do
216 --fast) set -- --force --first ${1+"$@"} ;;
218 -f|
--force) opt_update
=false
; PAGER
=cat ;;
220 --from) test $# = 0 && func_missing_arg
$opt && break
225 -l|
--local) update_flags
="$update_flags -l"
226 commit_flags
="$commit_flags -l"
230 test $# = 0 && func_missing_arg
$opt && break
231 if $opt_first ||
test -f "$log_file"; then
232 func_error
"you can have at most one of -m, -F and -1"
235 echo "$1" > "$log_file"
239 -F|
--file) test $# = 0 && func_missing_arg
$opt && break
240 if $opt_first ||
test -f "$log_file"; then
241 func_error
"you can have at most one of -m, -F and -1"
244 if cat < "$1" > "$log_file"; then :; else
250 -1|
--first) if test -f "$log_File"; then
251 func_error
"you can have at most one of -m, -F and -1"
257 -C|
--[cC
]hange
[lL
]og
)
258 test $# = 0 && func_missing_arg
$opt && break
259 if test -f "$1"; then :; else
260 func_error
"ChangeLog file \`$1' does not exist"
267 -n|
--dry-run) opt_commit
=false
; opt_update
=: ;;
269 -q|
--quiet) cvs_flags
="$cvs_flags -q" ;;
271 -s|
--sendmail) test $# = 0 && func_missing_arg
$opt && break
276 --signature) test $# = 0 && func_missing_arg
$opt && break
277 signature_file
="$HOME/.signature"
280 *) signature_file
="$1"; shift ;;
282 if test -f "$signature_file"; then :; else
283 func_error
"\`$signature_file': file not found"
289 test $# = 0 && func_missing_arg
$opt && break
292 *) func_error
"invalid argument for $opt"
296 cvs_flags
="$cvs_flags -z$1"
300 # Separate optargs to long options:
301 --message=*|
--msg=*|
--from=*|
--file=*|
--[Cc
]hange
[Ll
]og
=*|
--compress=*|
--sendmail=*|
--signature=*)
302 arg
=`echo "$opt" | $SED "$my_sed_long_arg"`
303 opt
=`echo "$opt" | $SED "$my_sed_long_opt"`
304 set -- "$opt" "$arg" ${1+"$@"}
307 # Separate optargs to short options:
309 arg
=`echo "$opt" |$SED "$my_sed_single_rest"`
310 opt
=`echo "$opt" |$SED "$my_sed_single_opt"`
311 set -- "$opt" "$arg" ${1+"$@"}
314 # Separate non-argument short options:
316 rest
=`echo "$opt" |$SED "$my_sed_single_rest"`
317 opt
=`echo "$opt" |$SED "$my_sed_single_opt"`
318 set -- "$opt" "-$rest" ${1+"$@"}
321 -\?|
-h) func_usage
;;
323 --version) func_version
;;
325 -*) func_fatal_help
"unrecognized option \`$opt'" ;;
326 *) set -- "$opt" ${1+"$@"}; break ;;
330 if test -z "$sendmail_to"; then
332 # can't have a from address without a destination address
333 test -n "$sendmail_from" &&
334 func_error
"can't use --from without --sendmail." && exit_cmd
=exit
336 # can't use a signature file without a destination address
337 test -n "$signature_file" &&
338 func_error
"can't use --signature without --sendmail." && exit_cmd
=exit
341 # Bail if the options were screwed
342 $exit_cmd $EXIT_FAILURE
347 func_error
"$progname: checking for conflicts..."
348 if ( $CVS $cvs_flags -q -n update
$update_flags ${1+"$@"} |
353 ) 3>&1 >/dev
/null
; then
354 func_fatal_error
"some conflicts were found, aborting..."
358 if test -f "$log_file"; then :; else
359 if test -z "$ChangeLog"; then
360 for f
in ${1+"$@"}; do
362 ChangeLog
* |
*/ChangeLog
*)
363 if test -z "$ChangeLog"; then
366 func_fatal_error
"multiple ChangeLog files: $ChangeLog and $f"
373 func_error
"$progname: checking commit message..."
376 sed 's,^,+,' < ${ChangeLog-ChangeLog} |
379 "+") if $skipping; then skipping
=false
; else break; fi;;
381 func_error
"*** Warning: lines should start with tabs, not spaces; ignoring line:"
382 echo "$line" |
sed 's/^.//' >&2;;
384 $skipping ||
echo "$line" ;;
387 sed 's,^\+ ,,' > "$log_file" ||
exit $EXIT_FAILURE
389 $CVS $cvs_flags diff -u ${ChangeLog-ChangeLog} |
394 func_error
"*** Warning: the following line in ChangeLog diff is suspicious:"
395 echo "$line" |
sed 's/^.//' >&2;;
397 func_error
"*** Warning: lines should start with tabs, not spaces; ignoring line:"
398 echo "$line" |
sed 's/^.//' >&2;;
400 "+ "*) echo "$line";;
403 sed -e 's,\+ ,,' -e '/./p' -e '/./d' -e '1d' -e '$d' > "$log_file" \
404 ||
exit $EXIT_FAILURE
406 # The sed script above removes "+TAB" from the beginning of a line, then
407 # deletes the first and/or the last line, when they happen to be empty
410 grep '[^ ]' < "$log_file" > /dev
/null ||
411 func_fatal_error
"empty commit message, aborting"
413 if grep '^$' < "$log_file" > /dev
/null
; then
414 func_error
"*** Warning: blank lines should not appear within commit messages."
415 func_error
"*** They should be used to separate distinct commits."
418 ${PAGER-more} "$log_file" ||
exit $EXIT_FAILURE
420 sleep 1 # give the user some time for a ^C
422 filelist
=`cvs -nq up 2>/dev/null | grep '^[MAD] ' | sed 's/^. //'`
424 # Do not check for empty $log_file again, even though the user might have
425 # zeroed it out. If s/he did, it was probably intentional.
428 $CVS $cvs_flags commit
$commit_flags -F $log_file ${1+"$@"} ||
exit $EXIT_FAILURE
431 # Send a copy of the log_file if sendmail_to was set:
432 if test -n "$sendmail_to"; then
433 notify_file
="${log_file}.2"
434 func_error
"Mailing commit notification to $sendmail_to"
435 test $# -gt 0 && filelist
="$@"
439 echo "CVSROOT: `sed -e 's,.*:,,g' CVS/Root`"
441 echo "TIMESTAMP: `$SHELL $MKSTAMP < ./ChangeLog`"
442 test -f CVS
/Repository
&&
443 echo "Module name: `cat CVS/Repository`"
445 echo "Branch: `sed -e 's,^T,,;1q' CVS/Tag`"
447 echo "Changes by: `sed -e 's,:.*$,,g;s,^.*:,,' CVS/Root`"
450 sed -e 's,^, ,' "$log_file"
451 test -f "$signature_file" && cat "$signature_file"
454 if test -n "$sendmail_from"; then
455 $SHELL $MAILNOTIFY -F "$sendmail_from" -s "`echo $filelist`" -f "$notify_file" -m "text/plain" "$sendmail_to"
457 $SHELL $MAILNOTIFY -s "`echo $filelist`" -f "$notify_file" -m "text/plain" "$sendmail_to"