1 | # -*- mode: tcl; indent-tabs-mode: nil -*- |
---|
2 | # ---------------------------------------------------------------------- |
---|
3 | # UTILITY: bugreport |
---|
4 | # |
---|
5 | # This redefines the usual Tcl bgerror command to install a nicer |
---|
6 | # looking bug handler. Bug reports can be submitted back to a |
---|
7 | # HUBzero-based site as support tickets. Additional information |
---|
8 | # can be obtained by defining procedures as bugreport::instrumented |
---|
9 | # proc (captures entrance/exit from proc) and by calling |
---|
10 | # bugreport::remark with extra info along the way. |
---|
11 | # ====================================================================== |
---|
12 | # AUTHOR: Michael McLennan, Purdue University |
---|
13 | # Copyright (c) 2004-2012 HUBzero Foundation, LLC |
---|
14 | # |
---|
15 | # See the file "license.terms" for information on usage and |
---|
16 | # redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. |
---|
17 | # ====================================================================== |
---|
18 | option add *BugReport*Label.font {Helvetica -12} startupFile |
---|
19 | option add *BugReport*banner*foreground white startupFile |
---|
20 | option add *BugReport*banner*background #a9a9a9 startupFile |
---|
21 | option add *BugReport*banner*highlightBackground #a9a9a9 startupFile |
---|
22 | option add *BugReport*banner.title.font {Helvetica -18 bold} startupFile |
---|
23 | option add *BugReport*xmit*wrapLength 3i startupFile |
---|
24 | option add *BugReport*expl.width 50 startupFile |
---|
25 | option add *BugReport*expl.font {Helvetica -12} startupFile |
---|
26 | option add *BugReport*expl.boldFont {Helvetica -12 bold} startupFile |
---|
27 | option add *BugReport*comments.l.font {Helvetica -12 italic} startupFile |
---|
28 | option add *BugReport*comments.info.text.font {Helvetica -12} startupFile |
---|
29 | option add *BugReport*details*font {Courier -12} startupFile |
---|
30 | |
---|
31 | namespace eval Rappture::bugreport { |
---|
32 | # details from the current trouble report, which user may decide to submit |
---|
33 | variable details |
---|
34 | |
---|
35 | # status from bugreport::instrumented/remark in case a bug occurs |
---|
36 | variable extraStack "" |
---|
37 | variable extraInfo "" |
---|
38 | |
---|
39 | # assume that if there's a problem launching a job, we should know it |
---|
40 | variable reportJobFailures 1 |
---|
41 | |
---|
42 | # submit these kinds of tickets by default |
---|
43 | variable settings |
---|
44 | set settings(user) $::tcl_platform(user) |
---|
45 | set settings(type) "automatic" |
---|
46 | set settings(group) "" |
---|
47 | set settings(category) "Rappture" |
---|
48 | } |
---|
49 | |
---|
50 | # ---------------------------------------------------------------------- |
---|
51 | # USAGE: install |
---|
52 | # |
---|
53 | # Called once in the main program to install this bug reporting |
---|
54 | # facility. Any unexpected errors after this call will be handled |
---|
55 | # by this mechanism. |
---|
56 | # ---------------------------------------------------------------------- |
---|
57 | proc Rappture::bugreport::install {} { |
---|
58 | ::proc ::bgerror {err} { ::Rappture::bugreport::activate $err } |
---|
59 | } |
---|
60 | |
---|
61 | # ---------------------------------------------------------------------- |
---|
62 | # USAGE: activate <error> |
---|
63 | # |
---|
64 | # Used internally to pop up the bug handler whenver a bug is |
---|
65 | # encountered. Tells the user that there is a bug and logs the |
---|
66 | # problem, so it can be fixed. |
---|
67 | # ---------------------------------------------------------------------- |
---|
68 | proc Rappture::bugreport::activate {err} { |
---|
69 | global env errorInfo |
---|
70 | variable details |
---|
71 | variable settings |
---|
72 | |
---|
73 | if {"@SHOWDETAILS" == $err} { |
---|
74 | pack propagate .bugreport yes |
---|
75 | pack forget .bugreport.expl |
---|
76 | pack forget .bugreport.xmit |
---|
77 | pack forget .bugreport.done |
---|
78 | pack forget .bugreport.cntls.show |
---|
79 | pack .bugreport.cntls -after .bugreport.banner -side bottom -fill x |
---|
80 | pack .bugreport.details -after .bugreport.banner \ |
---|
81 | -expand yes -fill both -padx 8 -pady 8 |
---|
82 | pack .bugreport.comments -after .bugreport.details \ |
---|
83 | -expand yes -fill both -padx 8 -pady {0 8} |
---|
84 | |
---|
85 | update idletasks |
---|
86 | set w [winfo reqwidth .bugreport] |
---|
87 | set h [winfo reqheight .bugreport] |
---|
88 | |
---|
89 | set x [winfo rootx .main] |
---|
90 | set y [winfo rooty .main] |
---|
91 | |
---|
92 | set mw [winfo width .main] |
---|
93 | if { $mw == 1 } { |
---|
94 | set mw [winfo reqwidth .main] |
---|
95 | } |
---|
96 | set mh [winfo height .main] |
---|
97 | if { $mh == 1 } { |
---|
98 | set mh [winfo reqwidth .main] |
---|
99 | } |
---|
100 | if { $mw > $w } { |
---|
101 | set x [expr { $x + (($mw-$w)/2) }] |
---|
102 | } |
---|
103 | if { $mh > $h } { |
---|
104 | set y [expr { $y + (($mh-$h)/2) }] |
---|
105 | } |
---|
106 | wm geometry .bugreport +$x+$y |
---|
107 | raise .bugreport |
---|
108 | return |
---|
109 | } |
---|
110 | |
---|
111 | # gather details so we can submit trouble reports later |
---|
112 | # do this now, before we do anything with "catch" down below |
---|
113 | # that might mask the errorInfo |
---|
114 | register $err |
---|
115 | |
---|
116 | pack propagate .bugreport yes |
---|
117 | pack forget .bugreport.details |
---|
118 | pack forget .bugreport.xmit |
---|
119 | pack forget .bugreport.done |
---|
120 | pack .bugreport.cntls.show -side right |
---|
121 | pack .bugreport.cntls -after .bugreport.banner -side bottom -fill x |
---|
122 | pack .bugreport.expl -after .bugreport.banner \ |
---|
123 | -expand yes -fill both -padx 8 -pady 8 |
---|
124 | pack .bugreport.comments -after .bugreport.expl \ |
---|
125 | -expand yes -fill both -padx 8 -pady {0 8} |
---|
126 | |
---|
127 | .bugreport.expl configure -state normal |
---|
128 | .bugreport.expl delete 1.0 end |
---|
129 | |
---|
130 | set url [Rappture::Tool::resources -huburl] |
---|
131 | if {"" != $url} { |
---|
132 | .bugreport.expl insert end "Something went wrong with this tool. Help us understand what happened by submitting a trouble report, so we can fix the problem. If you continue having trouble with this tool, please close it and restart." |
---|
133 | .bugreport.cntls.send configure -state normal |
---|
134 | focus .bugreport.cntls.send |
---|
135 | } else { |
---|
136 | .bugreport.expl insert end "Something went wrong with this tool. We would ask you to submit a trouble report about the error, but we can't tell what hub it should be submitted to. If you continue having trouble with this tool, please close it and restart." |
---|
137 | pack forget .bugreport.comments |
---|
138 | .bugreport.cntls.send configure -state disabled |
---|
139 | focus .bugreport.cntls.ok |
---|
140 | } |
---|
141 | fixTextHeight .bugreport.expl |
---|
142 | .bugreport.expl configure -state disabled |
---|
143 | |
---|
144 | .bugreport.details.info.text configure -state normal |
---|
145 | .bugreport.details.info.text delete 1.0 end |
---|
146 | .bugreport.details.info.text insert end " USER: $settings(user)\n" |
---|
147 | .bugreport.details.info.text insert end "HOSTNAME: $details(hostname)\n" |
---|
148 | .bugreport.details.info.text insert end "PLATFORM: $details(platform)\n" |
---|
149 | .bugreport.details.info.text insert end "CATEGORY: $details(category)\n" |
---|
150 | .bugreport.details.info.text insert end " TOOL: $details(referrer)\n" |
---|
151 | .bugreport.details.info.text insert end " SESSION: $details(session)\n" |
---|
152 | .bugreport.details.info.text insert end " SUMMARY: $details(summary)\n" |
---|
153 | .bugreport.details.info.text insert end "---------\n" |
---|
154 | .bugreport.details.info.text insert end $details(stackTrace) |
---|
155 | .bugreport.details.info.text configure -state disabled |
---|
156 | |
---|
157 | set w [winfo reqwidth .bugreport] |
---|
158 | set h [winfo reqheight .bugreport] |
---|
159 | |
---|
160 | set x [winfo rootx .main] |
---|
161 | set y [winfo rooty .main] |
---|
162 | |
---|
163 | set mw [winfo width .main] |
---|
164 | if { $mw == 1 } { |
---|
165 | set mw [winfo reqwidth .main] |
---|
166 | } |
---|
167 | set mh [winfo height .main] |
---|
168 | if { $mh == 1 } { |
---|
169 | set mh [winfo reqwidth .main] |
---|
170 | } |
---|
171 | |
---|
172 | if { $mw > $w } { |
---|
173 | set x [expr { $x + (($mw-$w)/2) }] |
---|
174 | } |
---|
175 | if { $mh > $h } { |
---|
176 | set y [expr { $y + (($mh-$h)/2) }] |
---|
177 | } |
---|
178 | |
---|
179 | wm geometry .bugreport +$x+$y |
---|
180 | wm deiconify .bugreport |
---|
181 | raise .bugreport |
---|
182 | |
---|
183 | catch {grab set .bugreport} |
---|
184 | update |
---|
185 | } |
---|
186 | |
---|
187 | # ---------------------------------------------------------------------- |
---|
188 | # USAGE: deactivate |
---|
189 | # |
---|
190 | # Used internally to take down the bug handler dialog. |
---|
191 | # ---------------------------------------------------------------------- |
---|
192 | proc Rappture::bugreport::deactivate {} { |
---|
193 | grab release .bugreport |
---|
194 | wm withdraw .bugreport |
---|
195 | |
---|
196 | # reset the grab in case it's hosed |
---|
197 | Rappture::grab::reset |
---|
198 | } |
---|
199 | |
---|
200 | # ---------------------------------------------------------------------- |
---|
201 | # USAGE: instrumented <what> <name> <arglist> <body> |
---|
202 | # |
---|
203 | # Used instead of the usual Tcl "proc" or itcl::body to define a |
---|
204 | # procedure that will automatically register information about its |
---|
205 | # execution in the bugreport mechanism. The <what> parameter should |
---|
206 | # be either "proc" or "itcl::body" or something like that. When the |
---|
207 | # procedure starts, it pushes its call information onto the stack, |
---|
208 | # then invokes the procedure body, then adds information about the |
---|
209 | # return code. |
---|
210 | # ---------------------------------------------------------------------- |
---|
211 | proc Rappture::bugreport::instrumented {what name arglist body} { |
---|
212 | set avals "" |
---|
213 | foreach term $arglist { |
---|
214 | set aname [lindex $term 0] |
---|
215 | append avals "\$$aname " |
---|
216 | } |
---|
217 | uplevel [list $what $name $arglist [format { |
---|
218 | Rappture::bugreport::remark -enter "PROC %s: %s" |
---|
219 | set __status [catch {%s} __result] |
---|
220 | Rappture::bugreport::remark -leave "PROC %s: code($__status) => $__result" |
---|
221 | switch -- $__status { |
---|
222 | 0 - 2 { |
---|
223 | return $__result |
---|
224 | } |
---|
225 | 3 { |
---|
226 | set __result "invoked \"break\" outside of a loop" |
---|
227 | } |
---|
228 | 4 { |
---|
229 | set __result "invoked \"continue\" outside of a loop" |
---|
230 | } |
---|
231 | } |
---|
232 | error $__result $::errorInfo |
---|
233 | } $name $avals $body $name]] |
---|
234 | } |
---|
235 | |
---|
236 | # ---------------------------------------------------------------------- |
---|
237 | # USAGE: remark ?-enter|-leave? <message> |
---|
238 | # |
---|
239 | # Adds the <message> to the current "extraInfo" being kept about the |
---|
240 | # program. This adds useful debugging info to the report that gets |
---|
241 | # sent back when an unexpected error is trapped. The -enter and -leave |
---|
242 | # options are used when a bugreport::instrumented proc starts/exits to |
---|
243 | # change the indent level for future messages. |
---|
244 | # ---------------------------------------------------------------------- |
---|
245 | proc Rappture::bugreport::remark {args} { |
---|
246 | variable extraStack |
---|
247 | variable extraInfo |
---|
248 | |
---|
249 | if {[llength $args] > 1} { |
---|
250 | set option [lindex $args 0] |
---|
251 | set args [lrange $args 1 end] |
---|
252 | switch -- $option { |
---|
253 | -enter { |
---|
254 | if {[llength $args] != 1} { |
---|
255 | error "wrong # args: should be \"remark -enter message\"" |
---|
256 | } |
---|
257 | set mesg [lindex $args 0] |
---|
258 | if {[llength $extraStack] == 0} { |
---|
259 | set extraInfo "" |
---|
260 | } |
---|
261 | append extraInfo [remark -indent ">> $mesg"] |
---|
262 | set extraStack [linsert $extraStack 0 $mesg] |
---|
263 | return |
---|
264 | } |
---|
265 | -leave { |
---|
266 | if {[llength $args] != 1} { |
---|
267 | error "wrong # args: should be \"remark -leave message\"" |
---|
268 | } |
---|
269 | set mesg [lindex $args 0] |
---|
270 | set extraStack [lrange $extraStack 1 end] |
---|
271 | append extraInfo [remark -indent "<< $mesg"] |
---|
272 | return |
---|
273 | } |
---|
274 | -indent { |
---|
275 | if {[llength $args] != 1} { |
---|
276 | error "wrong # args: should be \"remark -indent message\"" |
---|
277 | } |
---|
278 | } |
---|
279 | default { |
---|
280 | error "bad option \"$option\": should be -enter, -leave, -indent" |
---|
281 | } |
---|
282 | } |
---|
283 | } |
---|
284 | set mesg [lindex $args 0] |
---|
285 | set nlevel [llength $extraStack] |
---|
286 | set indent [string repeat { } [expr {2*$nlevel}]] |
---|
287 | foreach line [split $mesg \n] { |
---|
288 | append extraInfo "$indent$line\n" |
---|
289 | set prefix " " |
---|
290 | } |
---|
291 | } |
---|
292 | |
---|
293 | # ---------------------------------------------------------------------- |
---|
294 | # USAGE: sanitize <string> ?<replacement>? |
---|
295 | # |
---|
296 | # Removes any sensitive information in the bug report. This is useful |
---|
297 | # for things such as passwords that should be scrubbed out before any |
---|
298 | # ticket is filed. Replaces the <string> with an optional <replacement> |
---|
299 | # string (or ******** by default). This is usually called in some sort |
---|
300 | # of "catch" before forwarding the error on to the usual bgerror routine. |
---|
301 | # ---------------------------------------------------------------------- |
---|
302 | proc Rappture::bugreport::sanitize {str {repl ********}} { |
---|
303 | global errorInfo |
---|
304 | variable extraInfo |
---|
305 | |
---|
306 | set map [list $str $repl] |
---|
307 | set errorInfo [string map $map $errorInfo] |
---|
308 | set extraInfo [string map $map $extraInfo] |
---|
309 | } |
---|
310 | |
---|
311 | # ---------------------------------------------------------------------- |
---|
312 | # USAGE: attach <name> <string> |
---|
313 | # |
---|
314 | # Removes any sensitive information in the bug report. This is useful |
---|
315 | # for things such as passwords that should be scrubbed out before any |
---|
316 | # ticket is filed. Replaces the <string> with an optional <replacement> |
---|
317 | # string (or ******** by default). This is usually called in some sort |
---|
318 | # of "catch" before forwarding the error on to the usual bgerror routine. |
---|
319 | # ---------------------------------------------------------------------- |
---|
320 | proc Rappture::bugreport::attach {str {repl ********}} { |
---|
321 | global errorInfo |
---|
322 | variable extraInfo |
---|
323 | |
---|
324 | set map [list $str $repl] |
---|
325 | set errorInfo [string map $map $errorInfo] |
---|
326 | set extraInfo [string map $map $extraInfo] |
---|
327 | } |
---|
328 | |
---|
329 | |
---|
330 | # ---------------------------------------------------------------------- |
---|
331 | # USAGE: submit |
---|
332 | # |
---|
333 | # Takes details currently stored in the panel and registers them |
---|
334 | # as a support ticket on the hosting hub site. Pops up a panel |
---|
335 | # during the process and informs the user of the result. |
---|
336 | # ---------------------------------------------------------------------- |
---|
337 | proc Rappture::bugreport::submit {} { |
---|
338 | set info [.bugreport.details.info.text get 1.0 end] |
---|
339 | |
---|
340 | pack propagate .bugreport no |
---|
341 | pack forget .bugreport.details |
---|
342 | pack forget .bugreport.expl |
---|
343 | pack forget .bugreport.comments |
---|
344 | pack forget .bugreport.cntls |
---|
345 | pack .bugreport.xmit -after .bugreport.banner -padx 8 -pady 8 |
---|
346 | .bugreport.xmit.title configure -text "Sending trouble report to [Rappture::Tool::resources -hubname]..." |
---|
347 | |
---|
348 | # send off the trouble report... |
---|
349 | .bugreport.xmit.icon start |
---|
350 | set status [catch send result] |
---|
351 | .bugreport.xmit.icon stop |
---|
352 | |
---|
353 | pack propagate .bugreport yes |
---|
354 | pack forget .bugreport.xmit |
---|
355 | pack .bugreport.expl -after .bugreport.banner -padx 8 -pady 8 |
---|
356 | .bugreport.expl configure -state normal |
---|
357 | .bugreport.expl delete 1.0 end |
---|
358 | |
---|
359 | # handle the result |
---|
360 | if {$status != 0} { |
---|
361 | # add error to the details field, so we can see it with magic clicks |
---|
362 | .bugreport.details.info.text configure -state normal |
---|
363 | .bugreport.details.info.text insert 1.0 "Ticket submission failed:\n$result\n-----\n" |
---|
364 | .bugreport.details.info.text configure -state disabled |
---|
365 | |
---|
366 | .bugreport.expl insert end "Oops! Ticket submission failed:\n$result\n\nIf you want to report the original problem, you can file your own trouble report by going to the web site and clicking on the \"Help\" or \"Support\" link on the main navigation bar. If you continue having trouble with this tool, please close it and restart." |
---|
367 | } elseif {[regexp {Ticket #([0-9]*) +\((.*?)\) +([0-9]+) +times} $result match ticket extra times]} { |
---|
368 | .bugreport.expl insert end "This problem has been reported as " "" "Ticket #$ticket" bold " in our system." "" |
---|
369 | if {[string is integer $times] && $times > 1} { |
---|
370 | .bugreport.expl insert end " This particular problem has been reported $times times." |
---|
371 | } |
---|
372 | .bugreport.expl insert end "\n\nIf you continue having trouble with this tool, please close it and restart. Thanks for reporting the problem and helping us improve things!" |
---|
373 | } else { |
---|
374 | .bugreport.expl insert end "This problem has been reported. Here is the response from the hub, which may contain information about your ticket:\n" "" $result bold "\n\nIf you continue having trouble with this tool, please close it and restart. Thanks for reporting the problem and helping us improve things!" "" |
---|
375 | } |
---|
376 | fixTextHeight .bugreport.expl |
---|
377 | .bugreport.expl configure -state disabled |
---|
378 | pack .bugreport.done -side bottom -padx 8 -pady 8 |
---|
379 | focus .bugreport.done |
---|
380 | } |
---|
381 | |
---|
382 | # ---------------------------------------------------------------------- |
---|
383 | # USAGE: register <err> |
---|
384 | # |
---|
385 | # Low-level function used to capture information about a bug report |
---|
386 | # prior to calling "send", which actually sends the ticket. We usually |
---|
387 | # let the user preview the information and decide whether or not to |
---|
388 | # send the ticket. |
---|
389 | # ---------------------------------------------------------------------- |
---|
390 | proc Rappture::bugreport::register {err} { |
---|
391 | global errorInfo tcl_platform |
---|
392 | variable details |
---|
393 | variable settings |
---|
394 | variable extraInfo |
---|
395 | |
---|
396 | # |
---|
397 | # Figure out exactly what we'll send if the bug report is |
---|
398 | # submitted, so we can show the user. |
---|
399 | # |
---|
400 | set stackTrace "$err\n---------\n$errorInfo\n---------\n$extraInfo" |
---|
401 | if {![regexp {^([^\n]+)\n} $stackTrace match summary]} { |
---|
402 | if {[string length $stackTrace] == 0} { |
---|
403 | set summary "Unexpected error from Rappture" |
---|
404 | } else { |
---|
405 | set summary $stackTrace |
---|
406 | } |
---|
407 | } |
---|
408 | if {[string length $summary] > 200} { |
---|
409 | set summary "[string range $summary 0 200]..." |
---|
410 | } |
---|
411 | if {[string match {Problem launching job*} $summary]} { |
---|
412 | append summary " (in tool \"[Rappture::Tool::resources -appname]\")" |
---|
413 | set category "Tools" |
---|
414 | } else { |
---|
415 | set category $settings(category) |
---|
416 | } |
---|
417 | |
---|
418 | # make sure that the stack trace isn't too long |
---|
419 | set toolong 20000 |
---|
420 | if {[string length $stackTrace] > $toolong} { |
---|
421 | # |
---|
422 | # If this came from "Problem launching job", then it will have |
---|
423 | # a "== RAPPTURE INPUT ==" part somewhere in the middle. Try |
---|
424 | # to show the first part, this middle part, and the very last |
---|
425 | # part, cutting out whatever we have to in the middle. |
---|
426 | # |
---|
427 | if {[regexp -indices {\n== RAPPTURE INPUT ==\n} $stackTrace match]} { |
---|
428 | foreach {smid0 smid1} $match break |
---|
429 | set quarter [expr {$toolong/4}] |
---|
430 | set s0 $quarter |
---|
431 | set smid0 [expr {$smid0-$quarter}] |
---|
432 | set smid1 [expr {$smid1+$quarter}] |
---|
433 | set s1 [expr {[string length $stackTrace]-$quarter}] |
---|
434 | |
---|
435 | if {$smid0 < $s0} { |
---|
436 | # first part is short -- truncate last part |
---|
437 | set stackTrace "[string range $stackTrace 0 $smid1]\n...\n[string range $stackTrace [expr {[string length $stackTrace]-($toolong-$smid1)}] end]" |
---|
438 | } elseif {$smid1 > $s1} { |
---|
439 | # last part is short -- truncate first part |
---|
440 | set tailsize [expr {[string length $stackTrace]-$smid0}] |
---|
441 | set stackTrace "[string range $stackTrace 0 [expr {$toolong-$tailsize}]]\n...\n[string range $stackTrace $smid0 end]" |
---|
442 | } else { |
---|
443 | # rappture input line is right about in the middle |
---|
444 | set stackTrace "[string range $stackTrace 0 $s0]\n...\n[string range $stackTrace $smid0 $smid1]\n...\n[string range $stackTrace $s1 end]" |
---|
445 | } |
---|
446 | } else { |
---|
447 | # no Rappture input -- just show first part and last part |
---|
448 | set half [expr {$toolong/2}] |
---|
449 | set stackTrace "[string range $stackTrace 0 $half]\n...\n[string range $stackTrace [expr {[string length $stackTrace]-$half}] end]" |
---|
450 | } |
---|
451 | } |
---|
452 | |
---|
453 | set details(summary) $summary |
---|
454 | set details(category) $category |
---|
455 | set details(stackTrace) $stackTrace |
---|
456 | set details(hostname) [info hostname] |
---|
457 | set details(session) [Rappture::Tool::resources -session] |
---|
458 | set details(referrer) [Rappture::Tool::resources -appname] |
---|
459 | set details(platform) [array get tcl_platform] |
---|
460 | |
---|
461 | Rappture::Logger::log oops! $summary |
---|
462 | } |
---|
463 | |
---|
464 | # ---------------------------------------------------------------------- |
---|
465 | # USAGE: attachment <string> |
---|
466 | # |
---|
467 | # Low-level function used to capture information about a bug report |
---|
468 | # prior to calling "send", which actually sends the ticket. We usually |
---|
469 | # let the user preview the information and decide whether or not to |
---|
470 | # send the ticket. |
---|
471 | # ---------------------------------------------------------------------- |
---|
472 | proc Rappture::bugreport::attachment { string } { |
---|
473 | variable details |
---|
474 | set details(attachment) $string |
---|
475 | } |
---|
476 | |
---|
477 | # ---------------------------------------------------------------------- |
---|
478 | # USAGE: send |
---|
479 | # |
---|
480 | # Low-level function used to send bug reports back to the hub site. |
---|
481 | # Error details gathered by a previous call to "register" are sent |
---|
482 | # along as a support ticket. Returns a string of the following form, |
---|
483 | # representing details about the new or existing ticket: |
---|
484 | # Ticket #XX (XXXXXX) XX times |
---|
485 | # ---------------------------------------------------------------------- |
---|
486 | proc Rappture::bugreport::send {} { |
---|
487 | variable details |
---|
488 | variable settings |
---|
489 | |
---|
490 | package require http |
---|
491 | package require tls |
---|
492 | http::register https 443 [list ::tls::socket -tls1 1] |
---|
493 | |
---|
494 | set report $details(stackTrace) |
---|
495 | set cmts [string trim [.bugreport.comments.info.text get 1.0 end]] |
---|
496 | if {[string length $cmts] > 0} { |
---|
497 | set report "$cmts\n\n[string repeat = 72]\n$report" |
---|
498 | } |
---|
499 | set toolFile "" |
---|
500 | if { [info exists details(attachment)] } { |
---|
501 | set toolFile "/tmp/tool[pid].xml" |
---|
502 | set f [open $toolFile "w"] |
---|
503 | puts $f $details(attachment) |
---|
504 | close $f |
---|
505 | unset details(attachment) |
---|
506 | } |
---|
507 | set query [http::formatQuery \ |
---|
508 | option com_support \ |
---|
509 | controller tickets \ |
---|
510 | upload $toolFile \ |
---|
511 | task create \ |
---|
512 | no_html 1 \ |
---|
513 | report $report \ |
---|
514 | sesstoken $details(session) \ |
---|
515 | hostname $details(hostname) \ |
---|
516 | os $details(platform) \ |
---|
517 | category $details(category) \ |
---|
518 | summary $details(summary) \ |
---|
519 | referrer $details(referrer) \ |
---|
520 | login $settings(user) \ |
---|
521 | group $settings(group) \ |
---|
522 | type $settings(type) \ |
---|
523 | ] |
---|
524 | set url [Rappture::Tool::resources -huburl] |
---|
525 | if { $url == "" } { |
---|
526 | set url "http://hubzero.org" |
---|
527 | } |
---|
528 | if {[string index $url end] == "/"} { |
---|
529 | append url "index.php" |
---|
530 | } else { |
---|
531 | append url "/index.php" |
---|
532 | } |
---|
533 | |
---|
534 | set token [http::geturl $url -query $query -timeout 60000] |
---|
535 | |
---|
536 | if {[http::ncode $token] != 200} { |
---|
537 | error [http::code $token] |
---|
538 | } |
---|
539 | upvar #0 $token rval |
---|
540 | set info $rval(body) |
---|
541 | http::cleanup $token |
---|
542 | |
---|
543 | if { $toolFile != "" } { |
---|
544 | file delete $toolFile |
---|
545 | } |
---|
546 | if {[regexp {Ticket #[0-9]* +\(.*?\) +[0-9]+ +times} $info match]} { |
---|
547 | return $match |
---|
548 | } |
---|
549 | error "Report received, but ticket may not have been filed. Here's the result...\n$info" |
---|
550 | } |
---|
551 | |
---|
552 | # ---------------------------------------------------------------------- |
---|
553 | # USAGE: fixTextHeight <widget> |
---|
554 | # |
---|
555 | # Used internally to adjust the height of a text widget so it is just |
---|
556 | # tall enough to show the info within it. |
---|
557 | # ---------------------------------------------------------------------- |
---|
558 | proc Rappture::bugreport::fixTextHeight {widget} { |
---|
559 | # |
---|
560 | # HACK ALERT! In Tk8.5, we can count display lines directly. |
---|
561 | # But for earlier versions, we have to cook up something |
---|
562 | # similar. |
---|
563 | # |
---|
564 | if {[catch {$widget count -displaylines 1.0 end} h] == 0 && $h > 0} { |
---|
565 | $widget configure -height $h |
---|
566 | } else { |
---|
567 | for {set h 1} {$h < 15} {incr h} { |
---|
568 | $widget configure -height $h |
---|
569 | $widget see 1.0 |
---|
570 | update idletasks |
---|
571 | if {"" != [$widget bbox end-1char]} { |
---|
572 | break |
---|
573 | } |
---|
574 | } |
---|
575 | } |
---|
576 | } |
---|
577 | |
---|
578 | # ---------------------------------------------------------------------- |
---|
579 | # USAGE: shouldReport jobfailures <boolean> |
---|
580 | # USAGE: shouldReport for ?oops|jobs? |
---|
581 | # |
---|
582 | # Used internally to determine whether or not this system should |
---|
583 | # automatically report errors back to the hosting hub. Returns 1 |
---|
584 | # if the tool should, and 0 otherwise. The decision is made based |
---|
585 | # on whether this is a current tool in production, whether it is |
---|
586 | # being tested in a workspace, and whether the tool commonly generates |
---|
587 | # problems (by pilot error in its input deck). |
---|
588 | # ---------------------------------------------------------------------- |
---|
589 | proc Rappture::bugreport::shouldReport {option value} { |
---|
590 | global env |
---|
591 | |
---|
592 | switch -- $option { |
---|
593 | jobfailures { |
---|
594 | variable reportJobFailures |
---|
595 | if {![string is boolean $value]} { |
---|
596 | error "bad value \"$value\": should be boolean" |
---|
597 | } |
---|
598 | set reportJobFailures $value |
---|
599 | } |
---|
600 | for { |
---|
601 | # is it being run within a workspace? |
---|
602 | set appname [Rappture::Tool::resources -appname] |
---|
603 | if {[string match {[Ww]orkspace*} $appname]} { |
---|
604 | return 0 |
---|
605 | } |
---|
606 | |
---|
607 | # if this is a problem launching a job and the tool |
---|
608 | # expects this, then don't bother with automatic reports. |
---|
609 | variable reportJobFailures |
---|
610 | if {"jobs" == $value && !$reportJobFailures} { |
---|
611 | return 0 |
---|
612 | } |
---|
613 | |
---|
614 | # this is a real problem -- report it! |
---|
615 | return 1 |
---|
616 | } |
---|
617 | default { |
---|
618 | error "bad option \"$option\": should be jobfailures or for" |
---|
619 | } |
---|
620 | } |
---|
621 | } |
---|
622 | |
---|
623 | # ---------------------------------------------------------------------- |
---|
624 | # Build the bug reporting dialog |
---|
625 | # ---------------------------------------------------------------------- |
---|
626 | toplevel .bugreport -class BugReport -borderwidth 1 -relief solid |
---|
627 | wm overrideredirect .bugreport 1 |
---|
628 | wm withdraw .bugreport |
---|
629 | |
---|
630 | frame .bugreport.banner -background #a9a9a9 |
---|
631 | pack .bugreport.banner -side top -fill x |
---|
632 | label .bugreport.banner.icon -image [Rappture::icon alert] |
---|
633 | pack .bugreport.banner.icon -side left -padx 2 -pady 2 |
---|
634 | label .bugreport.banner.title -text "Oops! Internal Error" |
---|
635 | pack .bugreport.banner.title -side left -padx {0 8} -pady 2 |
---|
636 | |
---|
637 | # add these frustration bindings in case the "Dismiss" button is off screen |
---|
638 | bind .bugreport.banner.icon <Double-ButtonPress-1> \ |
---|
639 | Rappture::bugreport::deactivate |
---|
640 | bind .bugreport.banner.title <Double-ButtonPress-1> \ |
---|
641 | Rappture::bugreport::deactivate |
---|
642 | bind .bugreport <KeyPress-Escape> \ |
---|
643 | Rappture::bugreport::deactivate |
---|
644 | |
---|
645 | set bg [.bugreport cget -background] |
---|
646 | text .bugreport.expl -borderwidth 0 -highlightthickness 0 -background $bg \ |
---|
647 | -height 3 -wrap word |
---|
648 | .bugreport.expl tag configure bold \ |
---|
649 | -font [option get .bugreport.expl boldFont Font] |
---|
650 | # |
---|
651 | # HACK ALERT! We have problems with fixTextHeight working correctly |
---|
652 | # on Windows for Tk8.4 and earlier. To make it work properly, we |
---|
653 | # add the binding below. At some point, we'll ditch 8.4 and we can |
---|
654 | # use the new "count -displaylines" option in Tk8.5. |
---|
655 | # |
---|
656 | bind .bugreport.expl <Map> {Rappture::bugreport::fixTextHeight %W} |
---|
657 | |
---|
658 | frame .bugreport.comments |
---|
659 | label .bugreport.comments.l -text "What were you doing just before this error?" -anchor w |
---|
660 | pack .bugreport.comments.l -side top -anchor w |
---|
661 | Rappture::Scroller .bugreport.comments.info -xscrollmode none -yscrollmode auto |
---|
662 | text .bugreport.comments.info.text -width 30 -height 3 -wrap word |
---|
663 | .bugreport.comments.info contents .bugreport.comments.info.text |
---|
664 | bind .bugreport.comments.info.text <ButtonPress> {focus %W} |
---|
665 | pack .bugreport.comments.info -expand yes -fill both |
---|
666 | |
---|
667 | frame .bugreport.cntls |
---|
668 | pack .bugreport.cntls -side bottom -fill x |
---|
669 | button .bugreport.cntls.ok -text "Ignore" -command { |
---|
670 | Rappture::bugreport::deactivate |
---|
671 | } |
---|
672 | pack .bugreport.cntls.ok -side left -padx {4 20} -pady 8 |
---|
673 | button .bugreport.cntls.send -text "Send Trouble Report" -command { |
---|
674 | Rappture::bugreport::submit |
---|
675 | } |
---|
676 | pack .bugreport.cntls.send -side right -padx 4 -pady 8 |
---|
677 | |
---|
678 | button .bugreport.cntls.show -text "Show Details..." \ |
---|
679 | -command {Rappture::bugreport::activate @SHOWDETAILS} |
---|
680 | pack .bugreport.cntls.show -side right |
---|
681 | |
---|
682 | |
---|
683 | frame .bugreport.details |
---|
684 | Rappture::Scroller .bugreport.details.info -xscrollmode auto -yscrollmode auto |
---|
685 | text .bugreport.details.info.text -width 50 -height 15 -wrap none |
---|
686 | .bugreport.details.info contents .bugreport.details.info.text |
---|
687 | pack .bugreport.details.info -expand yes -fill both |
---|
688 | |
---|
689 | frame .bugreport.xmit |
---|
690 | Rappture::Animicon .bugreport.xmit.icon -images { |
---|
691 | circle-ball1 circle-ball2 circle-ball3 circle-ball4 |
---|
692 | circle-ball5 circle-ball6 circle-ball7 circle-ball8 |
---|
693 | } |
---|
694 | pack .bugreport.xmit.icon -side left |
---|
695 | label .bugreport.xmit.title -anchor w |
---|
696 | pack .bugreport.xmit.title -side left -expand yes -fill x |
---|
697 | |
---|
698 | button .bugreport.done -text "Done" \ |
---|
699 | -command Rappture::bugreport::deactivate |
---|
700 | |
---|
701 | # this binding keeps the bugreport window on top |
---|
702 | bind BugReportOnTop <ButtonPress> { |
---|
703 | wm deiconify %W |
---|
704 | raise %W |
---|
705 | } |
---|
706 | set btags [bindtags .bugreport] |
---|
707 | bindtags .bugreport [linsert $btags 0 BugReportOnTop] |
---|
708 | |
---|