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
|
#!/bin/bash
# silly, but good-enough bugzilla monitoring
# jpokorny@redhat.com (will be pleased to know about further enhancements)
# licensed under GPLv2+ (note: this file only, not the bundled helper)
# usage:
# 1. optionally git clone git://git.fedorahosted.org/git/python-bugzilla
# (system-wide can also be used)
# 2. open ~/.watchbzrc for editing
# - set BUGZILLA_ROOT when using cloned python-bugzilla
# - optionally set STATUS and COMPONENT as per example
# (or pass such string as a 1st argument)
# - optionally set BZUSER to avoid the need to login manually before
# the "watch session"; you can set BZPASSWORD as well but be careful!
# 3. optionally install expect package (-> security++)
#
# make watch work with less in order to get scrolling feature seems to be
# impossible, this might be a way forward (a bit buggy when tested):
# https://github.com/jyapayne/UnixWatchCommandOutput
set -u
umask 077
HERE="$(dirname "$(readlink -f "$0")")"
BUGZILLA=$(which bugzilla 2>/dev/null)
BUGZILLA_ROOT=/usr
BUGZILLA_COOKIE=~/.watchbzcookies
BUGZILLA_LOGOUT=1
# example defaults, modify via ~/.watchbzrc
: ${WATCHBZ_DEBUG:=0}
COMPONENT=acpid,mc
STATUS=OPEN
REFRESH_INTERVAL=600 # [s], better not to drain bugzilla's power...
BZUSER=
BZPASSWORD=
# user configuration
[ -f ~/.watchbzrc ] && source ~/.watchbzrc
# Fedora and color-friendly watch: rhbz#801626
WATCHCMD=watch
PRECOLORIZE=cat
COLORIZE=cat
if watch --color -n0.1 -g date &>/dev/null; then
WATCHCMD='watch --color'
PRECOLORIZE="sed"
PRECOLORIZE+=" -e 's|\( [NAPMQDVRC] \)\(.*\)\([\{]${BZUSER}[\}]\)|\x1b[1;31m\1\x1b[0m\2|'"
COLORIZE="sed"
COLORIZE+=" -e 's|\([0-9.A-Z]\++[, ]\)|\x1b[1;32m\1\x1b[0m|g'"
COLORIZE+=" -e 's|\([0-9.A-Z]\+-[, ]\)|\x1b[33m\1\x1b[0m|g'"
COLORIZE+=" -e 's|\([0-9.A-Z]\+?[, ]\)|\x1b[37m\1\x1b[0m|g'"
COLORIZE+=" -e 's|\(I?[, ]\)|\x1b[1;36m\1\x1b[0m|g'"
COLORIZE+=" -e 's|\(!!!\)|\x1b[1;31m\1\x1b[0m|'"
fi
# guess correct paths
if [ -z "$BUGZILLA" ] || [ -n "${BUGZILLA_ROOT}" ]; then
# BUGZILLA_ROOT (path to local repo) should rather be set in ~/.watchbzrc
BUGZILLA="${BUGZILLA_ROOT}/bin/bugzilla"
PYTHONPATH=${PYTHONPATH:+:${PYTHONPATH}}
export PYTHONPATH="${BUGZILLA_ROOT}${PYTHONPATH}"
fi
# hardcoded for now (note the SEP - OUTPUT_FMT relationship)
SEP=@@@
WIDTH=$(( $(stty size | cut -d' ' -f2) - 1 ))
# arguments
if [ $# -ge 1 ]; then
if [[ "$1" = -* ]]; then
STATUS=$(echo "$1" | cut -c2-)
shift
fi
if [ $# -ge 1 ]; then
COMPONENT="$1"
fi
fi
# omit component if only single one queried
echo $COMPONENT | grep -q ','
if [ $? -eq 0 ]; then
OUTPUT_FMT="%{component}$SEP%{bug_id}$SEP%{product}$SEP%{priority}$SEP%{status}$SEP%{flags}$SEP%{short_desc}\ \{%{assigned_to}\}"
else
OUTPUT_FMT="%{bug_id}$SEP%{product}$SEP%{priority}$SEP%{status}$SEP%{flags}$SEP%{short_desc}\ \{%{assigned_to}\}"
fi
do_logout () {
rm "${BUGZILLA_COOKIE}" && echo "watch-bz: Authorization cookie removed"
}
do_init_login () {
if [ -z "$BZPASSWORD" ]; then
trap 'stty echo; exit' INT
trap return USR1
{
timeout 60 /bin/sh -c \
"while [ ! -f \"${BUGZILLA_COOKIE}\" ]; do \
sleep 1; \
done" \
&& echo "wow, cookie emerged"
kill -USR1 -$$
} & read -s -p 'Password (1 min timeout): ' BZPASSWORD \
|| return $?
trap '' USR1
trap '' INT
fi
rm -f -- ${BUGZILLA_COOKIE}.init
if which expect &>/dev/null; then
expect - <<-EOF
log_user 0
spawn $BUGZILLA --cookiefile=${BUGZILLA_COOKIE}.init login $BZUSER
expect "Password: "
send "${BZPASSWORD}\r"
send_user "wait a bit..."
expect eof
EOF
else
echo "Passing password through command-line argument is DANGEROUS"
local yn; read -p 'Continue? [yN]' yn
[ "${yn}" -ne "y" ] && exit
spawn $BUGZILLA --cookiefile=${BUGZILLA_COOKIE}.init login $BZUSER $BZPASSWORD
fi
if [ $? -ne 0 ]; then
echo "Cannot log in"
return 2
fi
cp -n -- ${BUGZILLA_COOKIE}{.init,}
rm -f -- ${BUGZILLA_COOKIE}.init
}
# exclusively using globals
do_init () {
# C-c handler to optionally remove cookie on exit
test $BUGZILLA_LOGOUT -ne 0 && trap do_logout INT
# login when appropriate
if [ -n "$BZUSER" ] && [ ! -f "${BUGZILLA_COOKIE}" ]; then
do_init_login || exit $?
fi
}
# exclusively using globals
do_watch () {
EXEC="${WATCHCMD} -t --interval $REFRESH_INTERVAL"
[ "${WATCHBZ_DEBUG}" -ne 0 ] && EXEC="sh -c"
TAIL="${HERE}/table-data $SEP | sort | ${PRECOLORIZE} | cut -c-$WIDTH | ${COLORIZE}"
[ "${WATCHBZ_DEBUG}" -ne 0 ] && TAIL="cat"
${EXEC} \
"$BUGZILLA --cookiefile="${BUGZILLA_COOKIE}" query -c $COMPONENT \
-t $STATUS --outputformat $OUTPUT_FMT \
| sed -u \
-e \"s|${SEP}Red Hat Enterprise Linux |${SEP}EL|\" \
-e \"s|${SEP}Fedora|${SEP} F |\" \
-e \"s|${SEP}NEW|${SEP}N|\" \
-e \"s|${SEP}ASSIGNED|${SEP}A|\" \
-e \"s|${SEP}POST|${SEP}P|\" \
-e \"s|${SEP}MODIFIED|${SEP}M|\" \
-e \"s|${SEP}ON_QA|${SEP}Q|\" \
-e \"s|${SEP}ON_DEV|${SEP}D|\" \
-e \"s|${SEP}VERIFIED|${SEP}V|\" \
-e \"s|${SEP}RELEASE_PENDING|${SEP}R|\" \
-e \"s|${SEP}CLOSED|${SEP}C|\" \
-e \"s|${SEP}urgent|${SEP}!!!|\" \
-e \"s|${SEP}high|${SEP}!!|\" \
-e \"s|${SEP}medium|${SEP} ! |\" \
-e \"s|${SEP}low|${SEP} ~ |\" \
-e \"s|${SEP}unspecified|${SEP} ? |\" \
-e \"s|qa_ack|QA|\" \
-e \"s|pm_ack|PM|\" \
-e \"s|devel_ack|D|\" \
-e \"s|needinfo|I|\" \
-e \"s|exception|E|\" \
-e \"s|blocker|BL|\" \
-e \"s|requires_release_note|RN|\" \
-e \"s|docs_scoped|DS|\" \
-e \"s|rhel-||g\" \
-e \"s|qe_test_coverage[?+-][,]\?||\" \
-e \"s|None||\" | ${TAIL}"
}
do_init
do_watch
|