aboutsummaryrefslogtreecommitdiffstats
path: root/Tools/scripts/close-pr
blob: b336c6d5a82b940bd698ed476d59333828dbd9be (plain) (blame)
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