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, 2007 Free Software Foundation, Inc.
9 # This program is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <http://www.gnu.org/licenses/>.
22 # Usage: $progname [-v] [-h] [-f] [-l] [-n] [-q] [-z N] [-C ChangeLog_file]
23 # [-m msg|-F msg_file|-1] [-s addr [--from addr]] [--] [file|dir ...]
25 # -C file --changelog=file extract commit message from specified ChangeLog
26 # -zN --compress=N set compression level (0-9, 0=none, 9=max)
27 # -n --dry-run don't commit anything
28 # --fast same as --force --first
29 # -F file --file=file read commit message from file
30 # -1 --first extract first entry from ChangeLog, no cvs diff
31 # -f --force don't check (unless *followed* by -n), and just
32 # display commit message instead of running $PAGER
33 # --from=addr override default from address in commit email
34 # -l --local don't descend into subdirectories
35 # -m msg --message=msg set commit message
36 # --msg=msg same as -m
37 # -q --quiet run cvs in quiet mode
38 # -s addr --sendmail=addr send a commit email of the differences to ADDR
39 # --signature[=file] add FILE to the end of the email (~/.signature)
40 # -v --version print version information
41 # -h,-? --help print short or long help message
43 # This script eases checking in changes to CVS-maintained projects
44 # with ChangeLog files. It will check that there have been no
45 # conflicting commits in the CVS repository and print which files it
46 # is going to commit to stderr. A list of files to compare and to
47 # check in can be given in the command line. If it is not given, all
48 # files in the current directory (and below, unless `-l' is given) are
49 # considered for check in.
51 # The commit message will be extracted from the differences between a
52 # file named ChangeLog* in the commit list, or named after -C, and the
53 # one in the repository (unless a message was specified with `-m' or
54 # `-F'). An empty message is not accepted (but a blank line is). If
55 # the message is acceptable, it will be presented for verification
56 # (and possible edition) using the $PAGER environment variable (or
57 # `more', if it is not set, or `cat', if the `-f' switch is given).
58 # If $PAGER exits successfully, the modified files (at that moment)
59 # are checked in, unless `-n' was specified, in which case nothing is
62 # Report bugs to <gary@gnu.org>
65 : ${MAILNOTIFY="./ltdl/config/mailnotify"}
66 : ${MKSTAMP="./ltdl/config/mkstamp"}
75 # Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
76 # is ksh but when the shell is invoked as "sh" and the current value of
77 # the _XPG environment variable is not equal to 1 (one), the special
78 # positional parameter $0, within a function call, is the name of the
82 # The name of this program:
83 progname
=`echo "$progpath" | $SED "$basename"`
101 # Locations for important files
103 log_file
="${TMPDIR-/tmp}/commitlog.$$"
106 trap '$RM "${log_file}*"; exit $EXIT_FAILURE' 1 2 15
112 # Echo program name prefixed message.
115 echo $progname: ${1+"$@"}
119 # Echo program name prefixed message to standard error.
122 echo $progname: ${1+"$@"} 1>&2
125 # func_fatal_error arg...
126 # Echo program name prefixed message to standard error, and exit.
133 # func_verbose arg...
134 # Echo program name prefixed message in verbose mode only.
137 $opt_verbose && func_error
${1+"$@"}
140 # func_fatal_help arg...
141 # Echo program name prefixed message to standard error, followed by
142 # a help hint, and exit.
146 func_fatal_error
"Try \`$progname --help' for more information."
149 # func_missing_arg argname
150 # Echo program name prefixed message to standard error and set global
154 func_error
"missing argument for $1"
159 # Echo short help message to standard output and exit.
162 $SED '/^# Usage:/,/# -h/ {
164 s/\$progname/'$progname'/;
168 echo "run \`$progname --help | more' for full usage"
173 # Echo long help message to standard output and exit.
176 $SED '/^# Usage:/,/# Report bugs to/ {
178 s/\$progname/'$progname'/;
185 # Echo version message to standard output and exit.
188 $SED '/^# '$PROGRAM' (GNU /,/# warranty; / {
190 s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/;
196 # Parse options once, thoroughly. This comes as soon as possible in
197 # the script to make things like `commit --version' happen quickly.
200 my_sed_single_opt
='1s/^\(..\).*$/\1/;q'
201 my_sed_single_rest
='1s/^..\(.*\)$/\1/;q'
202 my_sed_long_opt
='1s/^\(--[^=]*\)=.*/\1/;q'
203 my_sed_long_arg
='1s/^--[^=]*=//'
205 # this just eases exit handling
206 while test $# -gt 0; do
211 --fast) set -- --force --first ${1+"$@"} ;;
213 -f|
--force) opt_update
=false
; PAGER
=cat ;;
215 --from) test $# = 0 && func_missing_arg
$opt && break
220 -l|
--local) update_flags
="$update_flags -l"
221 commit_flags
="$commit_flags -l"
225 test $# = 0 && func_missing_arg
$opt && break
226 if $opt_first ||
test -f "$log_file"; then
227 func_error
"you can have at most one of -m, -F and -1"
230 echo "$1" > "$log_file"
234 -F|
--file) test $# = 0 && func_missing_arg
$opt && break
235 if $opt_first ||
test -f "$log_file"; then
236 func_error
"you can have at most one of -m, -F and -1"
239 if cat < "$1" > "$log_file"; then :; else
245 -1|
--first) if test -f "$log_File"; then
246 func_error
"you can have at most one of -m, -F and -1"
252 -C|
--[cC
]hange
[lL
]og
)
253 test $# = 0 && func_missing_arg
$opt && break
254 if test -f "$1"; then :; else
255 func_error
"ChangeLog file \`$1' does not exist"
262 -n|
--dry-run) opt_commit
=false
; opt_update
=: ;;
264 -q|
--quiet) cvs_flags
="$cvs_flags -q" ;;
266 -s|
--sendmail) test $# = 0 && func_missing_arg
$opt && break
271 --signature) test $# = 0 && func_missing_arg
$opt && break
272 signature_file
="$HOME/.signature"
275 *) signature_file
="$1"; shift ;;
277 if test -f "$signature_file"; then :; else
278 func_error
"\`$signature_file': file not found"
284 test $# = 0 && func_missing_arg
$opt && break
287 *) func_error
"invalid argument for $opt"
291 cvs_flags
="$cvs_flags -z$1"
295 # Separate optargs to long options:
296 --message=*|
--msg=*|
--from=*|
--file=*|
--[Cc
]hange
[Ll
]og
=*|
--compress=*|
--sendmail=*|
--signature=*)
297 arg
=`echo "$opt" | $SED "$my_sed_long_arg"`
298 opt
=`echo "$opt" | $SED "$my_sed_long_opt"`
299 set -- "$opt" "$arg" ${1+"$@"}
302 # Separate optargs to short options:
304 arg
=`echo "$opt" |$SED "$my_sed_single_rest"`
305 opt
=`echo "$opt" |$SED "$my_sed_single_opt"`
306 set -- "$opt" "$arg" ${1+"$@"}
309 # Separate non-argument short options:
311 rest
=`echo "$opt" |$SED "$my_sed_single_rest"`
312 opt
=`echo "$opt" |$SED "$my_sed_single_opt"`
313 set -- "$opt" "-$rest" ${1+"$@"}
316 -\?|
-h) func_usage
;;
318 --version) func_version
;;
320 -*) func_fatal_help
"unrecognized option \`$opt'" ;;
321 *) set -- "$opt" ${1+"$@"}; break ;;
325 if test -z "$sendmail_to"; then
327 # can't have a from address without a destination address
328 test -n "$sendmail_from" &&
329 func_error
"can't use --from without --sendmail." && exit_cmd
=exit
331 # can't use a signature file without a destination address
332 test -n "$signature_file" &&
333 func_error
"can't use --signature without --sendmail." && exit_cmd
=exit
336 # Bail if the options were screwed
337 $exit_cmd $EXIT_FAILURE
342 func_error
"$progname: checking for conflicts..."
343 if ( $CVS $cvs_flags -q -n update
$update_flags ${1+"$@"} |
348 ) 3>&1 >/dev
/null
; then
349 func_fatal_error
"some conflicts were found, aborting..."
353 if test -f "$log_file"; then :; else
354 if test -z "$ChangeLog"; then
355 for f
in ${1+"$@"}; do
357 ChangeLog
* |
*/ChangeLog
*)
358 if test -z "$ChangeLog"; then
361 func_fatal_error
"multiple ChangeLog files: $ChangeLog and $f"
368 func_error
"$progname: checking commit message..."
371 sed 's,^,+,' < ${ChangeLog-ChangeLog} |
374 "+") if $skipping; then skipping
=false
; else break; fi;;
376 func_error
"*** Warning: lines should start with tabs, not spaces; ignoring line:"
377 echo "$line" |
sed 's/^.//' >&2;;
379 $skipping ||
echo "$line" ;;
382 sed 's,^\+ ,,' > "$log_file" ||
exit $EXIT_FAILURE
384 $CVS $cvs_flags diff -u ${ChangeLog-ChangeLog} |
389 func_error
"*** Warning: the following line in ChangeLog diff is suspicious:"
390 echo "$line" |
sed 's/^.//' >&2;;
392 func_error
"*** Warning: lines should start with tabs, not spaces; ignoring line:"
393 echo "$line" |
sed 's/^.//' >&2;;
395 "+ "*) echo "$line";;
398 sed -e 's,\+ ,,' -e '/./p' -e '/./d' -e '1d' -e '$d' > "$log_file" \
399 ||
exit $EXIT_FAILURE
401 # The sed script above removes "+TAB" from the beginning of a line, then
402 # deletes the first and/or the last line, when they happen to be empty
405 grep '[^ ]' < "$log_file" > /dev
/null ||
406 func_fatal_error
"empty commit message, aborting"
408 if grep '^$' < "$log_file" > /dev
/null
; then
409 func_error
"*** Warning: blank lines should not appear within commit messages."
410 func_error
"*** They should be used to separate distinct commits."
413 ${PAGER-more} "$log_file" ||
exit $EXIT_FAILURE
415 sleep 1 # give the user some time for a ^C
417 filelist
=`cvs -nq up 2>/dev/null | grep '^[MAD] ' | sed 's/^. //'`
419 # Do not check for empty $log_file again, even though the user might have
420 # zeroed it out. If s/he did, it was probably intentional.
423 $CVS $cvs_flags commit
$commit_flags -F $log_file ${1+"$@"} ||
exit $EXIT_FAILURE
426 # Send a copy of the log_file if sendmail_to was set:
427 if test -n "$sendmail_to"; then
428 notify_file
="${log_file}.2"
429 func_error
"Mailing commit notification to $sendmail_to"
430 test $# -gt 0 && filelist
="$@"
434 echo "CVSROOT: `sed -e 's,.*:,,g' CVS/Root`"
436 echo "TIMESTAMP: `$SHELL $MKSTAMP < ./ChangeLog`"
437 test -f CVS
/Repository
&&
438 echo "Module name: `cat CVS/Repository`"
440 echo "Branch: `sed -e 's,^T,,;1q' CVS/Tag`"
442 echo "Changes by: `sed -e 's,:.*$,,g;s,^.*:,,' CVS/Root`"
445 sed -e 's,^, ,' "$log_file"
446 test -f "$signature_file" && cat "$signature_file"
449 if test -n "$sendmail_from"; then
450 $SHELL $MAILNOTIFY -F "$sendmail_from" -s "`echo $filelist`" -f "$notify_file" -m "text/plain" "$sendmail_to"
452 $SHELL $MAILNOTIFY -s "`echo $filelist`" -f "$notify_file" -m "text/plain" "$sendmail_to"