summaryrefslogtreecommitdiff
path: root/commit
blob: e52b40a9fd2237b92f1921962017eeae38edbcdc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
#! /bin/sh

# commit version 0.9.2

# Copyright (C) 1999, Free Software Foundation

# This script is Free Software, and it can be copied, distributed and
# modified as defined in the GNU General Public License.  A copy of
# its license can be downloaded from http://www.gnu.org/copyleft/gpl.html

# Originally by Gary V. Vaughan <gvv@techie.com>
# Heavily modified by Alexandre Oliva <oliva@dcc.unicamp.br>

# This scripts eases checking in changes to CVS-maintained projects
# with ChangeLog files.  It will check that there have been no
# conflicting commits in the CVS repository and print which files it
# is going to commit to stderr.  A list of files to compare and to
# check in can be given in the command line.  If it is not given, all
# files in the current directory (and below, unless `-l' is given) are
# considered for check in.

# The commit message will be extracted from the differences between
# the local ChangeLog and the one in the repository (unless a message
# was specified with `-m' or `-F').  An empty message is not accepted
# (but a blank line is).  If the message is acceptable, it will be
# presented for verification (and possible edition) using the $PAGER
# environment variable (or `more', if it is not set, or `cat', if the
# `-f' switch is given).  If $PAGER exits successfully, the modified
# files (at that moment) are checked in, unless `-n' was specified, in
# which case nothing is checked in.

# usage: commit [-v] [-h] [-f] [-l] [-n] [-q] [-z N]
#               [-m msg|-F msg_file] [--] [file|dir ...]

# -f      --fast        don't check (unless *followed* by -n), and just 
#         --force       display commit message instead of running $PAGER
# -l      --local       don't descend into subdirectories
# -m msg  --message=msg set commit message
#         --msg=msg     same as -m
# -F file --file=file   read commit message from file
# -n      --dry-run     don't commit anything
# -q      --quiet       run cvs in quiet mode
# -zN     --compress=N  set compression level (0-9, 0=none, 9=max)
# -v      --version     print version information
# -h,-?   --help        print short or long help message

name=commit
cvsopt=
updateopt=
commitopt=
dry_run=false
commit=:
update=:
log_file="${TMPDIR-/tmp}/commitlog.$$"

rm -f "$log_file"
trap 'rm -f "$log_file"; exit 1' 1 2 15

# this just eases exit handling
main_repeat=":"
while $main_repeat; do

repeat="test $# -gt 0"
while $repeat; do
    case "$1" in
    -f|--force|--fast)
	update=false
	PAGER=cat
	shift
	;;
    -l|--local)
	updateopt="$updateopt -l"
	commitopt="$commitopt -l"
	shift
	;;
    -m|--message|--msg)
	if test $# = 1; then
	    echo "$name: missing argument for $1" >&2
	    break
	fi
	if test -f "$log_file"; then
	    echo "$name: you can have at most one of -m and -F" >&2
	    break
	fi
	shift
	echo "$1" > "$log_file"
	shift
	;;
    -F|--file)
	if test -f "$log_file"; then
	    echo "$name: you can have at most one of -m and -F" >&2
	    break
	fi
	if test $# = 1; then
	    echo "$name: missing argument for $1" >&2
	    break
	fi
	shift
	if cat < "$1" > "$log_file"; then :; else
	    break
	fi
	shift
	;;
    -n|--dry-run)
	commit=false
	update=true
	shift
	;;
    -q|--quiet)
	cvsopt="$cvsopt -q"
	shift
	;;
    -z|--compress)
	if test $# = 1; then
	    echo "$name: missing argument for $1" >&2
	    break
	fi
	case "$2" in
	[0-9]) :;;
	*)  echo "$name: invalid argument for $1" >&2
	    break
	    ;;
	esac
	cvsopt="$cvsopt -z$2"
	shift
	shift
	;;

    -m*|-F*|-z*)
	opt=`echo "$1" | sed '1s/^\(..\).*$/\1/;q'`
	arg=`echo "$1" | sed '1s/^-[a-zA-Z0-9]//'`
	shift
	set -- "$opt" "$arg" ${1+"$@"}
	;;
    --message=*|--msg=*|--file=*|--compress=*)
	opt=`echo "$1" | sed '1s/^\(--[^=]*\)=.*/\1/;q'`
    	arg=`echo "$1" | sed '1s/^--[^=]*=//'`
	shift
	set -- "$opt" "$arg" ${1+"$@"}
	;;

    -v|--version)
	sed '/^# '$name' version /,/^# Heavily modified by/ { s/^# //; p; }; d' < $0
	exit 0
	;;
    -\?|-h)
	sed '/^# usage:/,/# -h/ { s/^# //; p; }; d' < $0 &&
	echo
	echo "run \`$name --help | more' for full usage"
	exit 0
	;;
    --help)
	sed '/^# '$name' version /,/^[^#]/ { /^[^#]/ d; s/^# //; p; }; d' < $0
	exit 0
	;;
    --)
	shift
	repeat=false
	;;
    -*)
	echo "$name: invalid flag $1" >&2
	break
	;;
    *)
	repeat=false
	;;
    esac
done
# might have used break 2 within the previous loop, but so what
$repeat && break

$update && \
if echo "$name: checking for conflicts..." >&2
   (cvs $cvsopt -q -n update $updateopt ${1+"$@"} 2>/dev/null \
    | while read line; do
	echo "$line"
	echo "$line" >&3
      done | grep '^C') 3>&1 >/dev/null; then
  echo "$name: some conflicts were found, aborting..." >&2
  break
fi

if test ! -f "$log_file"; then
  echo "$name: checking commit message..." >&2
  cvs $cvsopt diff -u ChangeLog \
  | while read line; do
      case "$line" in
      "--- ChangeLog"*) :;;
      "-"*)
	echo "$name: *** Warning: the following line in ChangeLog diff is suspicious:" >&2
	echo "$line" | sed 's/^.//' >&2;;
      "+ "*)
	echo "$name: *** Warning: lines should start with tabs, not spaces; ignoring line:" >&2
	echo "$line" | sed 's/^.//' >&2;;
      "+") echo;;
      "+	"*) echo "$line";;
      esac
    done \
  | sed -e 's,\+	,,' -e '/./p' -e '/./d' -e '1d' -e '$d' > "$log_file" \
  || break
# The sed script above removes "+TAB" from the beginning of a line, then
# deletes the first and/or the last line, when they happen to be empty
fi

if grep '[^ 	]' < "$log_file" > /dev/null; then :; else
  echo "$name: empty commit message, aborting" >&2
  break
fi

if grep '^$' < "$log_file" > /dev/null; then
  echo "$name: *** Warning: blank lines should not appear within a commit messages." >&2
  echo "$name: *** They should be used to separate distinct commits." >&2
fi

${PAGER-more} "$log_file" || break

sleep 1 # give the user some time for a ^C

# Do not check for empty $log_file again, even though the user might have
# zeroed it out.  If s/he did, it was probably intentional.

if $commit; then
  cvs $cvsopt commit $commitopt -F $log_file ${1+"$@"} || break
fi

main_repeat=false
done

rm -f "$log_file"

# if main_repeat was not set to `false', we failed
$main_repeat && exit 1
exit 0