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
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
|
#!/bin/sh
# Program to edit problem reports for GNATS.
# Copyright (C) 1993, 1994, 1995, 1996, 1998 Free Software Foundation, Inc.
# Contributed by Jeffrey Osier (jeffrey@cygnus.com).
# Networking portion written by Alec Peterson (chuckie@panix.com).
# Local and networked versions combined by Rick Macdonald (rickm@vsl.com)
#
# This file is part of GNU GNATS.
#
# GNU GNATS is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# GNU GNATS is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU GNATS; see the file COPYING. If not, write to
# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
#
# This script handles both local and network GNATS editing.
# Execute with --mode=local or --mode=network
#
debug_print=false # or echo to get output.
DATE=`LC_TIME=C date`
GNATS_ROOT=${GNATS_ROOT:-/usr/local/share/gnats/gnats-db}; export GNATS_ROOT
LIBEXECDIR=/usr/local/libexec
GNATS_PORT=1529
EDIT_USER=anonymous
EDIT_PASSWD=guest
locked=
version=3.112
mode=local
usage="
local Usage: edit-pr [-V|--version] [-h|--help] PR
network Usage: nedit-pr [-V|--version] [-h|--help] [-d|--directory gnats_db_alias]
[-H|--host hostname] [-P|--port port_number]
[-v|--user userid] [-w|--passwd password] PR
"
# get current host name
if [ -z "$HOSTNAME" ]; then
if [ -f /bin/hostname ] ; then HOSTNAME=`/bin/hostname`
elif [ -f /usr/bin/hostname ] ; then HOSTNAME=`/usr/bin/hostname`
# Solaris et al.
elif [ -f /usr/ucb/hostname ] ; then HOSTNAME=`/usr/ucb/hostname`
# Irix
elif [ -f /usr/bsd/hostname ] ; then HOSTNAME=`/usr/bsd/hostname`
fi
fi
# GNATS_HOST defaults to current host if GNATS_SERVER is not set.
GNATS_HOST="gnats"
[ -z "$GNATS_HOST" ] && GNATS_HOST="$HOSTNAME"
# Newer config information? (Should the network version get this from gnatsd?)
[ -f ${GNATS_ROOT}/gnats-adm/config ] && . ${GNATS_ROOT}/gnats-adm/config
# Host-specific; must come after config file.
MAIL_AGENT="/usr/sbin/sendmail -oi -t"
# check to see if there is a $EDITOR; if not, use vi
[ -z "$VISUAL" ] &&
if [ -z "$EDITOR" ]; then
VISUAL=vi
else
VISUAL="$EDITOR"
fi
# Parse command line. For the non-flag argument, assume it's pr PR id.
if [ $# -eq 0 ]; then
echo "$usage" ; exit 1
fi
while [ $# -gt 0 ]; do
case "$1" in
-V|--version|--ve*)
echo "$version"; exit 0
;;
-m | --mode)
if [ $# -eq 1 ]; then echo "$usage"; exit 1; fi
shift ; mode="$1" ;;
-m=* | --mode=*) mode="`echo $1 | sed 's/^[-a-z]*=//'`" ;;
-d | --directory)
if [ $# -eq 1 ]; then echo "$usage"; exit 1; fi
shift ; GNATS_DB="$1" ;;
-d=* | --directory=*) GNATS_DB="`echo $1 | sed 's/^[-a-z]*=//'`" ;;
-H | --host)
if [ $# -eq 1 ]; then echo "$usage"; exit 1; fi
shift ; GNATS_HOST="$1" ;;
-H=* | --host=*) GNATS_HOST="`echo $1 | sed 's/^[-a-z]*=//'`" ;;
-P | --port)
if [ $# -eq 1 ]; then echo "$usage"; exit 1; fi
shift ; GNATS_PORT="$1" ;;
-P=* | --port=*) GNATS_PORT="`echo $1 | sed 's/^[-a-z]*=//'`" ;;
-v | --user)
if [ $# -eq 1 ]; then echo "$usage"; exit 1; fi
shift ; EDIT_USER="$1" ;;
-v=* | --user=*) EDIT_USER="`echo $1 | sed 's/^[-a-z]*=//'`" ;;
-w | --passwd)
if [ $# -eq 1 ]; then echo "$usage"; exit 1; fi
shift ; EDIT_PASSWD="$1" ;;
-w=* | --passwd=*) EDIT_PASSWD="`echo $1 | sed 's/^[-a-z]*=//'`" ;;
-h|--help*)
echo "$usage"; exit 0
;;
-*)
echo "$usage"; exit 1
;;
*)
if [ "`echo $1 | grep /`" != "" ]; then
pr=`echo $1 | awk -F"/" '{print $2}' -`
else
pr=$1
fi
prs="$prs $pr"
;;
esac
shift
done
for pr_id in $prs ; do
# set command here to always pass host and port, and directory if supplied
if [ "$mode" = "network" ]; then
prog="nedit-pr"
PR_ADDR="$LIBEXECDIR/gnats/npr-addr --host=$GNATS_HOST --port=$GNATS_PORT --user=$EDIT_USER --passwd=$EDIT_PASSWD"
PR_EDIT="$LIBEXECDIR/gnats/npr-edit --host=$GNATS_HOST --port=$GNATS_PORT --user=$EDIT_USER --passwd=$EDIT_PASSWD"
else
prog="edit-pr"
PR_ADDR="$LIBEXECDIR/gnats/pr-addr"
PR_EDIT="$LIBEXECDIR/gnats/pr-edit"
fi
if [ "$GNATS_DB" != "" ]; then
PR_ADDR="$PR_ADDR --directory=$GNATS_DB"
PR_EDIT="$PR_EDIT --directory=$GNATS_DB"
fi
# These traps take care of deleting all the /tmp files
trap 'rm -f $new $new.old $change_msg ; exit 0' 0
trap 'if [ "$locked" != "" ]; then \
$PR_EDIT --unlock $pr_id ; \
locked= ; \
fi ; \
rm -f $new $new.old $change_msg ; exit 1' 1 2 3 13 15
# find a user name
if [ "$USER" != "" ]; then
me=$USER
else
if [ "$LOGNAME" != "" ]; then
me=$LOGNAME
else
echo "$prog: no user name found---set LOGNAME." ; exit 1
fi
fi
if [ -n "$HOSTNAME" ]; then
full_me="$me@$HOSTNAME"
else
full_me="$me"
fi
# new = temp file to use for editing
new="/tmp/ep$$"
# lock the pr
$debug_print "Locking $pr_id."
lock=`$PR_EDIT --lock=$full_me $pr_id 2>&1 > $new`
locked=t
if [ "$lock" != "" ] ; then
echo $lock
exit 0
fi
# here's where we actually call the editor.
cp $new $new.old
/usr/bin/perl -pi -e "s|>State:.*|>State: closed|" $new
if cmp -s $new.old $new ; then
echo "$prog: PR not changed"
$PR_EDIT --unlock $pr_id
continue
fi
# error-check output by calling pr-edit --check; if mistakes exist,
# call $VISUAL or exit
checking=t
while [ "$checking" != "" ]; do
errors="`$PR_EDIT --check < $new 2>&1`"
if [ "$errors" != "" ]; then
echo "Hit \`return\` to fix the following errors, or type \'quit\' to quit:"
echo "$errors"
read fixme
case "$fixme" in
q* | Q*)
echo "PR $pr_id not updated: changed file is in $new.changed"
mv $new $new.changed
$PR_EDIT --unlock $pr_id
exit 0
;;
esac
$VISUAL $new
else
checking=
fi
done
# now that we have a clean new PR:
# - check for changes in Responsible or State
# - add audit trail
# - mail changes to relevant parties
old_state="`sed -n '/^>State:/{s,^>[-a-zA-Z]*: *,,;p;q;}' $new.old`"
new_state="`sed -n '/^>State:/{s,^>[-a-zA-Z]*: *,,;p;q;}' $new`"
old_resp="`sed -n '/^>Responsible:/{s,^>[-a-zA-Z]*: *,,;s, *(.*,,g;p;q;}' $new.old`"
new_resp="`sed -n '/^>Responsible:/{s,^>[-a-zA-Z]*: *,,;s, *(.*,,g;p;q;}' $new`"
old_synopsis="`sed -n '/^>Synopsis:/{s,^>[-a-zA-Z]*: *,,;p;q;}' $new.old`"
new_synopsis="`sed -n '/^>Synopsis:/{s,^>[-a-zA-Z]*: *,,;p;q;}' $new`"
old_class="`sed -n '/^>Class:/{s,^>[-a-zA-Z]*: *,,;p;q;}' $new.old`"
new_class="`sed -n '/^>Class:/{s,^>[-a-zA-Z]*: *,,;p;q;}' $new`"
full_id="`sed -n '/^>Category:/{s,^>[-a-zA-Z]*: *,,;p;q;}' $new`/$pr_id"
# If you can read this, you may have a future in sed(1) programming.
reply_to="`sed -n \
-e '/^$/{g;s/ / /g;s/\n/ /g;s/^.*: *//;s/ *(.*) *//;s/.*<//;s/>.*//;p;q;}' \
-e '/^Reply-To:/h' \
-e '/^Reply-To:/,/^[^ ]/{s/^[^ ].*//;H;}' \
-e '/^Reply-To:/,$b' \
-e '/^From:/h' \
-e '/^From:/,/^[^ ]/{s/^[^ ].*//;H;}' \
$new.old`"
x_gnats_notify="`sed -n \
-e '/^$/{g;s/ / /g;s/\n/ /g;s/^.*: *//;s/ *(.*) *//;s/.*<//;s/>.*//;p;q;}' \
-e '/^X-GNATS-Notify:/h' \
-e '/^X-GNATS-Notify:/,/^[^ ]/{s/^[^ ].*//;H;}' \
-e '/^X-GNATS-Notify:/,$b' \
$new.old`"
change_msg=/tmp/ed_pr_ch$$
# the following could stand to be cleaned up...
if [ "$old_state" != "$new_state" ]; then
state_change=yes
fi
if [ "$old_resp" != "$new_resp" ]; then
resp_change=yes
fi
if [ "$old_class" != "$new_class" ]; then
class_change=yes
fi
if [ ! -z "$state_change" ] || [ ! -z "$resp_change" ] || \
[ ! -z "$class_change" ]; then
# we've got a change
mail_to="$me"
if [ ! -z "$state_change" ]; then
$debug_print "Doing state change."
echo State-Changed-From-To: "$old_state"'->'"$new_state" >> $change_msg
echo State-Changed-By: $me >> $change_msg
echo State-Changed-When: $DATE >> $change_msg
echo "State-Changed-Why: " >> $change_msg
if [ -e /tmp/chng.$$ ]; then
echo "Re-use last message (y/n)?"
read yesno
if [ "$yesno" != "y" ]; then
cat /home/gnats/gnats-adm/edit-pr-msg > /tmp/chng.$$
fi
else
cat /home/gnats/gnats-adm/edit-pr-msg > /tmp/chng.$$
fi
$VISUAL /tmp/chng.$$
sed '/^GNATS:/d' /tmp/chng.$$ >> $change_msg
to_old=1
to_subm=1
if [ ! -z "$class_change" ] || [ ! -z "$resp_change" ]; then
echo "" >> $change_msg
echo "" >> $change_msg
fi
fi
if [ ! -z "$class_change" ]; then
$debug_print "Doing class change."
echo Class-Changed-From-To: "$old_class"'->'"$new_class" >> $change_msg
echo Class-Changed-By: $me >> $change_msg
echo Class-Changed-When: $DATE >> $change_msg
echo "Class-Changed-Why: " >> $change_msg
echo 'Why did the class change? (Ctrl-D to end)'
cat >> $change_msg
to_old=1
to_new=1
if [ ! -z "$resp_change" ]; then
echo "" >> $change_msg
echo "" >> $change_msg
fi
fi
if [ ! -z "$resp_change" ]; then
$debug_print "Doing responsible change."
echo Responsible-Changed-From-To: "$old_resp"'->'"$new_resp" >> $change_msg
echo Responsible-Changed-By: $me >> $change_msg
echo Responsible-Changed-When: $DATE >> $change_msg
echo "Responsible-Changed-Why: " >> $change_msg
echo 'Why did the responsible person change? (Ctrl-D to end)'
cat >> $change_msg
to_old=1
to_new=1
fi
echo "" >> $change_msg
echo "http://www.freebsd.org/cgi/query-pr.cgi?pr=$pr_id" >> $change_msg
if [ -n "$to_subm" ]; then mail_to="${reply_to}, ${mail_to}" ; fi
if [ -n "$x_gnats_notify" ]; then mail_to="${x_gnats_notify}, ${mail_to}" ; fi
if [ -n "$to_old" ] ; then mail_to="${mail_to}, `$PR_ADDR ${old_resp}`" ; fi
if [ -n "$to_new" ] ; then mail_to="${mail_to}, `$PR_ADDR ${new_resp}`" ; fi
# We have to quote the end of each line in the change_msg, so that sed
# won't try to use it as a new command.
$debug_print "Quoting lines in $change_msg."
sed -e "/^>Unformatted:/i\\
`sed -e 's/$/ \\\\/g' $change_msg`
" $new > $new.tmp
mv -f $new.tmp $new
$MAIL_AGENT << __EOF__
To: $mail_to
From: $me
Subject: Re: $full_id: $new_synopsis
`if [ "$old_synopsis" != "$new_synopsis" ]; then
echo Old Synopsis: "$old_synopsis"
echo New Synopsis: "$new_synopsis"
else
echo Synopsis: "$old_synopsis"
fi`
`cat $change_msg`
__EOF__
fi
echo "$prog: filing PR $full_id back into the database..."
# call PR_EDIT on the new file and clean up
$PR_EDIT < $new
$PR_EDIT --unlock $pr_id
done
exit 0
|