Updated Swedish translation
[zeroinstall/zeroinstall-limyreth.git] / zeroinstall / 0launch-gui / bugs.py
blob62806a5255f1b1a74b5c936daf254925c8c593a6
1 # Copyright (C) 2009, Thomas Leonard
2 # See http://0install.net/0compile.html
4 import sys, os
5 import gtk, pango
6 import dialog
8 import zeroinstall
9 from zeroinstall import _
10 from zeroinstall import support
11 from zeroinstall.injector import selections
13 def report_bug(policy, iface):
14 assert iface
16 # TODO: Check the interface to decide where to send bug reports
18 issue_file = '/etc/issue'
19 if os.path.exists(issue_file):
20 issue = file(issue_file).read().strip()
21 else:
22 issue = "(file '%s' not found)" % issue_file
24 text = 'Problem with %s\n' % iface.uri
25 if iface.uri != policy.root:
26 text = ' (while attempting to run %s)\n' % policy.root
27 text += '\n'
29 text += 'Zero Install: Version %s, with Python %s\n' % (zeroinstall.version, sys.version)
31 text += '\nChosen implementations:\n'
33 if not policy.ready:
34 text += ' Failed to select all required implementations\n'
36 for chosen_iface_uri, impl in policy.solver.selections.selections.iteritems():
37 text += '\n Interface: %s\n' % chosen_iface_uri
38 if impl:
39 text += ' Version: %s\n' % impl.version
40 feed_url = impl.attrs['from-feed']
41 if feed_url != chosen_iface_uri:
42 text += ' From feed: %s\n' % feed_url
43 text += ' ID: %s\n' % impl.id
44 else:
45 chosen_iface = policy.config.iface_cache.get_interface(chosen_iface_uri)
46 impls = policy.solver.details.get(chosen_iface, None)
47 if impls:
48 best, reason = impls[0]
49 note = 'best was %s, but: %s' % (best, reason)
50 else:
51 note = 'not considered; %d available' % len(chosen_iface.implementations)
53 text += ' No implementation selected (%s)\n' % note
55 if hasattr(os, 'uname'):
56 text += '\nSystem:\n %s\n\nIssue:\n %s\n' % ('\n '.join(os.uname()), issue)
57 else:
58 text += '\nSystem without uname()\n'
60 if policy.solver.ready:
61 sels = selections.Selections(policy)
62 text += "\n" + sels.toDOM().toprettyxml(encoding = 'utf-8')
64 reporter = BugReporter(policy, iface, text)
65 reporter.show()
67 class BugReporter(dialog.Dialog):
68 def __init__(self, policy, iface, env):
69 dialog.Dialog.__init__(self)
71 self.sf_group_id = 76468
72 self.sf_artifact_id = 929902
74 self.set_title(_('Report a Bug'))
75 self.set_modal(True)
76 self.set_has_separator(False)
77 self.policy = policy
78 self.frames = []
80 vbox = gtk.VBox(False, 4)
81 vbox.set_border_width(10)
82 self.vbox.pack_start(vbox, True, True, 0)
84 self.set_default_size(gtk.gdk.screen_width() / 2, -1)
86 def frame(title, contents, buffer):
87 fr = gtk.Frame()
88 label = gtk.Label('')
89 label.set_markup('<b>%s</b>' % title)
90 fr.set_label_widget(label)
91 fr.set_shadow_type(gtk.SHADOW_NONE)
92 vbox.pack_start(fr, True, True, 0)
94 align = gtk.Alignment(0, 0, 1, 1)
95 align.set_padding(0, 0, 16, 0)
96 fr.add(align)
97 align.add(contents)
99 self.frames.append((title, buffer))
101 def text_area(text = None, mono = False):
102 swin = gtk.ScrolledWindow()
103 swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
104 swin.set_shadow_type(gtk.SHADOW_IN)
106 tv = gtk.TextView()
107 tv.set_wrap_mode(gtk.WRAP_WORD)
108 swin.add(tv)
109 if text:
110 tv.get_buffer().insert_at_cursor(text)
112 if mono:
113 tv.modify_font(pango.FontDescription('mono'))
115 tv.set_accepts_tab(False)
117 return swin, tv.get_buffer()
119 actual = text_area()
120 frame(_("What doesn't work?"), *actual)
122 expected = text_area()
123 frame(_('What did you expect to happen?'), *expected)
125 errors_box = gtk.VBox(False, 0)
126 errors_swin, errors_buffer = text_area(mono = True)
127 errors_box.pack_start(errors_swin, True, True, 0)
128 buttons = gtk.HButtonBox()
129 buttons.set_layout(gtk.BUTTONBOX_START)
130 errors_box.pack_start(buttons, False, True, 4)
131 get_errors = gtk.Button(_('Run it now and record the output'))
132 get_errors.connect('clicked', lambda button: self.collect_output(errors_buffer))
133 buttons.add(get_errors)
135 frame(_('Are any errors or warnings displayed?'), errors_box, errors_buffer)
137 if dialog.last_error:
138 errors_buffer.insert_at_cursor(str(dialog.last_error))
140 environ = text_area(env, mono = True)
141 frame(_('Information about your setup'), *environ)
143 browse_url = 'http://sourceforge.net/tracker/?group_id=%d&atid=%d' % (self.sf_group_id, self.sf_artifact_id)
144 location_hbox = gtk.HBox(False, 4)
145 location_hbox.pack_start(gtk.Label(_('Bugs reports will be sent to:')), False, True, 0)
146 if hasattr(gtk, 'LinkButton'):
147 import browser
148 url_box = gtk.LinkButton(browse_url)
149 url_box.connect('clicked', lambda button: browser.open_in_browser(browse_url))
150 else:
151 url_box = gtk.Label(browse_url)
152 url_box.set_selectable(True)
153 location_hbox.pack_start(url_box, False, True, 0)
154 vbox.pack_start(location_hbox, False, True, 0)
156 self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
157 self.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
158 self.set_default_response(gtk.RESPONSE_OK)
160 def resp(box, r):
161 if r == gtk.RESPONSE_OK:
162 text = ''
163 for title, buffer in self.frames:
164 start = buffer.get_start_iter()
165 end = buffer.get_end_iter()
166 text += '%s\n\n%s\n\n' % (title, buffer.get_text(start, end).strip())
167 title = _('Bug for %s') % iface.get_name()
168 self.report_bug(title, text)
169 self.destroy()
170 dialog.alert(self, _("Your bug report has been sent. Thank you."),
171 type = gtk.MESSAGE_INFO)
172 else:
173 self.destroy()
174 self.connect('response', resp)
176 self.show_all()
178 def collect_output(self, buffer):
179 iter = buffer.get_end_iter()
180 buffer.place_cursor(iter)
182 if not self.policy.ready:
183 missing = [iface.uri for iface in self.policy.implementation if self.policy.implementation[iface] is None]
184 buffer.insert_at_cursor("Can't run: no version has been selected for:\n- " +
185 "\n- ".join(missing))
186 return
187 uncached = self.policy.get_uncached_implementations()
188 if uncached:
189 buffer.insert_at_cursor("Can't run: the chosen versions have not been downloaded yet. I need:\n\n- " +
190 "\n\n- " . join(['%s version %s\n (%s)' %(x[0].uri, x[1].get_version(), x[1].id) for x in uncached]))
191 return
193 from zeroinstall.injector import selections
194 sels = selections.Selections(self.policy)
195 doc = sels.toDOM()
197 self.hide()
198 try:
199 gtk.gdk.flush()
200 iter = buffer.get_end_iter()
201 buffer.place_cursor(iter)
203 # Tell 0launch to run the program
204 doc.documentElement.setAttribute('run-test', 'true')
205 payload = doc.toxml('utf-8')
206 sys.stdout.write(('Length:%8x\n' % len(payload)) + payload)
207 sys.stdout.flush()
209 reply = support.read_bytes(0, len('Length:') + 9)
210 assert reply.startswith('Length:')
211 test_output = support.read_bytes(0, int(reply.split(':', 1)[1], 16))
213 # Cope with invalid UTF-8
214 import codecs
215 decoder = codecs.getdecoder('utf-8')
216 data = decoder(test_output, 'replace')[0]
218 buffer.insert_at_cursor(data)
219 finally:
220 self.show()
222 def report_bug(self, title, text):
223 try:
224 import urllib
225 from urllib2 import urlopen
227 stream = urlopen('http://sourceforge.net/tracker/index.php',
228 urllib.urlencode({
229 'group_id': str(self.sf_group_id),
230 'atid': str(self.sf_artifact_id),
231 'func': 'postadd',
232 'is_private': '0',
233 'summary': title,
234 'details': text}))
235 stream.read()
236 stream.close()
237 except:
238 # Write to stderr in the hope that it doesn't get lost
239 print >>sys.stderr, "Error sending bug report: %s\n\n%s" % (title, text)
240 raise