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