commit revision 1.1 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