Merge lp:~cr3/checkbox/warning_prompt into lp:checkbox

Proposed by Marc Tardif
Status: Merged
Approved by: Sylvain Pineau
Approved revision: 1781
Merged at revision: 1785
Proposed branch: lp:~cr3/checkbox/warning_prompt
Merge into: lp:checkbox
Diff against target: 395 lines (+168/-85)
3 files modified
checkbox/user_interface.py (+98/-70)
plugins/jobs_info.py (+35/-15)
plugins/warning_prompt.py (+35/-0)
To merge this branch: bzr merge lp:~cr3/checkbox/warning_prompt
Reviewer Review Type Date Requested Status
Sylvain Pineau Approve
Review via email: mp+130193@code.launchpad.net

Commit message

Merged warning_prompt plugin for whitelist validation warnings by cr3.

Description of the change

Added warning_prompt plugin to prevent the reactor from stopping on some warnings when run non-interactively.

To post a comment you must log in.
Revision history for this message
Sylvain Pineau (sylvain-pineau) wrote :

There's a lot of pep8 fixes but i'm happy with the skeleton of show_warning() in base checkbox/user_interface.py.

Thanks

review: Approve
Revision history for this message
Marc Tardif (cr3) wrote :

Thanks, you can now work on having a nice user interface for Qt specifically at your leisure by overriding the show_warning method in the qt interface class.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'checkbox/user_interface.py'
2--- checkbox/user_interface.py 2012-07-23 20:50:14 +0000
3+++ checkbox/user_interface.py 2012-10-17 19:06:24 +0000
4@@ -29,10 +29,20 @@
5
6 from checkbox.contrib.REThread import REThread
7
8-from checkbox.lib.environ import add_variable, get_variable, remove_variable
9+from checkbox.lib.environ import (
10+ add_variable,
11+ get_variable,
12+ remove_variable,
13+ )
14
15-from checkbox.job import (FAIL, PASS, UNINITIATED,
16- UNRESOLVED, UNSUPPORTED, UNTESTED)
17+from checkbox.job import (
18+ FAIL,
19+ PASS,
20+ UNINITIATED,
21+ UNRESOLVED,
22+ UNSUPPORTED,
23+ UNTESTED,
24+ )
25 from checkbox.reactor import StopAllException
26
27
28@@ -83,13 +93,22 @@
29 logging.info(text)
30 return default
31
32- def show_error(self, primary_text,
33- secondary_text=None, detailed_text=None):
34+ def show_error(
35+ self, primary_text, secondary_text=None, detailed_text=None):
36 text = filter(None, [primary_text, secondary_text, detailed_text])
37 text = '\n'.join(text)
38 logging.error(text)
39 raise StopAllException("Error: %s" % text)
40
41+ def show_warning(
42+ self, primary_text, secondary_text=None, detailed_text=None):
43+ try:
44+ self.show_error(primary_text, secondary_text, detailed_text)
45+ except StopAllException:
46+ # The only difference with show_error for now is that warnings
47+ # don't stop the reactor.
48+ pass
49+
50 def show_progress(self, message, function, *args, **kwargs):
51 self.show_progress_start(message)
52
53@@ -138,8 +157,8 @@
54
55 Display an error dialog if everything fails."""
56
57- # If we are called through sudo, determine the real user id and run the
58- # browser with it to get the user's web browser settings.
59+ # If we are called through sudo, determine the real user id and
60+ # run the browser with it to get the user's web browser settings.
61 try:
62 uid = int(get_variable("SUDO_UID"))
63 gid = int(get_variable("SUDO_GID"))
64@@ -149,67 +168,78 @@
65 gid = None
66 sudo_prefix = []
67
68- # figure out appropriate web browser
69- try:
70- # if ksmserver is running, try kfmclient
71- try:
72- if os.getenv("DISPLAY") and \
73- subprocess.call(["pgrep", "-x", "-u", str(uid), "ksmserver"],
74- stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0:
75- subprocess.Popen(sudo_prefix + ["kfmclient", "openURL", url])
76- return
77- except OSError:
78- pass
79-
80- # if gnome-session is running, try gnome-open; special-case firefox
81- # (and more generally, mozilla browsers) and epiphany to open a new window
82- # with respectively -new-window and --new-window; special-case chromium-browser
83- # to allow file:// URLs as needed by the checkbox report.
84- try:
85- if os.getenv("DISPLAY") and \
86- subprocess.call(["pgrep", "-x", "-u", str(uid), "gnome-panel|gconfd-2"],
87- stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0:
88- from gi.repository import Gio
89-
90- preferred_xml_app = Gio.app_info_get_default_for_type("application/xml",False)
91- if preferred_xml_app:
92- preferred_browser = preferred_xml_app.get_executable()
93- browser = re.match("((firefox|seamonkey|flock)[^\s]*)", preferred_browser)
94- if browser:
95- subprocess.Popen(sudo_prefix + [browser.group(0), "-new-window", url])
96- return
97-
98- browser = re.match("(epiphany[^\s]*)", preferred_browser)
99- if browser:
100- subprocess.Popen(sudo_prefix + [browser.group(0), "--new-window", url])
101- return
102-
103- browser = re.match("(chromium-browser[^\s]*)", preferred_browser)
104- if browser:
105- subprocess.Popen(sudo_prefix + [browser.group(0), "--allow-file-access-from-files", url])
106- return
107-
108- subprocess.Popen(sudo_prefix + [preferred_browser % url], shell=True)
109- return
110-
111- subprocess.Popen(sudo_prefix + ["gnome-open", url])
112- return
113- except OSError:
114- pass
115-
116- # fall back to webbrowser
117- if uid and gid:
118- os.setgroups([gid])
119- os.setgid(gid)
120- os.setuid(uid)
121- remove_variable("SUDO_USER")
122- add_variable("HOME", pwd.getpwuid(uid).pw_dir)
123-
124- webbrowser.open(url, new=True, autoraise=True)
125- return
126-
127- except Exception as e:
128- pass
129+ # if ksmserver is running, try kfmclient
130+ try:
131+ if (os.getenv("DISPLAY") and
132+ subprocess.call(
133+ ["pgrep", "-x", "-u", str(uid), "ksmserver"],
134+ stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0):
135+ subprocess.Popen(sudo_prefix + ["kfmclient", "openURL", url])
136+ return
137+ except OSError:
138+ pass
139+
140+ # if gnome-session is running, try gnome-open; special-case
141+ # firefox (and more generally, mozilla browsers) and epiphany
142+ # to open a new window with respectively -new-window and
143+ # --new-window; special-case chromium-browser to allow file://
144+ # URLs as needed by the checkbox report.
145+ try:
146+ if (os.getenv("DISPLAY") and
147+ subprocess.call(
148+ ["pgrep", "-x", "-u", str(uid), "gnome-panel|gconfd-2"],
149+ stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0):
150+ from gi.repository import Gio
151+
152+ preferred_xml_app = Gio.app_info_get_default_for_type(
153+ "application/xml", False)
154+ if preferred_xml_app:
155+ preferred_browser = preferred_xml_app.get_executable()
156+ browser = re.match(
157+ "((firefox|seamonkey|flock)[^\s]*)",
158+ preferred_browser)
159+ if browser:
160+ subprocess.Popen(
161+ sudo_prefix +
162+ [browser.group(0), "-new-window", url])
163+ return
164+
165+ browser = re.match("(epiphany[^\s]*)", preferred_browser)
166+ if browser:
167+ subprocess.Popen(
168+ sudo_prefix +
169+ [browser.group(0), "--new-window", url])
170+ return
171+
172+ browser = re.match(
173+ "(chromium-browser[^\s]*)", preferred_browser)
174+ if browser:
175+ subprocess.Popen(
176+ sudo_prefix +
177+ [browser.group(0),
178+ "--allow-file-access-from-files", url])
179+ return
180+
181+ subprocess.Popen(
182+ sudo_prefix +
183+ [preferred_browser % url], shell=True)
184+ return
185+
186+ subprocess.Popen(sudo_prefix + ["gnome-open", url])
187+ return
188+ except OSError:
189+ pass
190+
191+ # fall back to webbrowser
192+ if uid and gid:
193+ os.setgroups([gid])
194+ os.setgid(gid)
195+ os.setuid(uid)
196+ remove_variable("SUDO_USER")
197+ add_variable("HOME", pwd.getpwuid(uid).pw_dir)
198+
199+ webbrowser.open(url, new=True, autoraise=True)
200+ return
201
202 def show_report(self, text, results):
203 """
204@@ -225,5 +255,3 @@
205 about each job.
206 """
207 pass
208-
209-
210
211=== modified file 'plugins/jobs_info.py'
212--- plugins/jobs_info.py 2012-06-26 14:07:30 +0000
213+++ plugins/jobs_info.py 2012-10-17 19:06:24 +0000
214@@ -16,18 +16,29 @@
215 # You should have received a copy of the GNU General Public License
216 # along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
217 #
218-import os, sys, re
219+import os
220+import re
221+import sys
222+
223 import difflib
224 import gettext
225 import logging
226
227 from collections import defaultdict
228+from gettext import gettext as _
229
230 from checkbox.lib.resolver import Resolver
231
232 from checkbox.arguments import coerce_arguments
233-from checkbox.properties import Float, Int, List, Map, Path, String
234 from checkbox.plugin import Plugin
235+from checkbox.properties import (
236+ Float,
237+ Int,
238+ List,
239+ Map,
240+ Path,
241+ String,
242+ )
243
244
245 job_schema = Map({
246@@ -76,14 +87,17 @@
247 def register(self, manager):
248 super(JobsInfo, self).register(manager)
249
250- self.whitelist_patterns = self.get_patterns(self.whitelist, self.whitelist_file)
251- self.blacklist_patterns = self.get_patterns(self.blacklist, self.blacklist_file)
252+ self.whitelist_patterns = self.get_patterns(
253+ self.whitelist, self.whitelist_file)
254+ self.blacklist_patterns = self.get_patterns(
255+ self.blacklist, self.blacklist_file)
256 self.selected_jobs = defaultdict(list)
257
258 self._manager.reactor.call_on("prompt-begin", self.prompt_begin)
259 self._manager.reactor.call_on("gather", self.gather)
260 if logging.getLogger().getEffectiveLevel() <= logging.DEBUG:
261- self._manager.reactor.call_on("prompt-gather", self.post_gather, 90)
262+ self._manager.reactor.call_on(
263+ "prompt-gather", self.post_gather, 90)
264 self._manager.reactor.call_on("report-job", self.report_job, -100)
265
266 def prompt_begin(self, interface):
267@@ -92,7 +106,8 @@
268 to display errors
269 """
270 self.interface = interface
271- self.unused_patterns = self.whitelist_patterns + self.blacklist_patterns
272+ self.unused_patterns = (
273+ self.whitelist_patterns + self.blacklist_patterns)
274
275 def check_ordered_messages(self, messages):
276 """Return whether the list of messages are ordered or not."""
277@@ -113,8 +128,8 @@
278 try:
279 file = open(filename)
280 except IOError as e:
281- error_message=(gettext.gettext("Failed to open file '%s': %s") %
282- (filename, e.strerror))
283+ error_message = (_("Failed to open file '%s': %s")
284+ % (filename, e.strerror))
285 logging.critical(error_message)
286 sys.stderr.write("%s\n" % error_message)
287 sys.exit(os.EX_NOINPUT)
288@@ -148,7 +163,9 @@
289 def report_message(message):
290 if self.whitelist_patterns:
291 name = message["name"]
292- if not [name for p in self.whitelist_patterns if p.match(name)]:
293+ names = [name for p in self.whitelist_patterns
294+ if p.match(name)]
295+ if not names:
296 return
297
298 messages.append(message)
299@@ -156,7 +173,8 @@
300 # Set domain and message event handler
301 old_domain = gettext.textdomain()
302 gettext.textdomain(self.domain)
303- event_id = self._manager.reactor.call_on("report-message", report_message, 100)
304+ event_id = self._manager.reactor.call_on(
305+ "report-message", report_message, 100)
306
307 for directory in self.directories:
308 self._manager.reactor.fire("message-directory", directory)
309@@ -182,7 +200,8 @@
310 messages = sorted(messages, key=key_function)
311
312 if not self.check_ordered_messages(messages):
313- old_message_names = [message["name"] + "\n" for message in messages]
314+ old_message_names = [
315+ message["name"] + "\n" for message in messages]
316 resolver = Resolver(key_func=lambda m: m["name"])
317 for message in messages:
318 resolver.add(
319@@ -192,7 +211,8 @@
320 # Check if messages are already topologically ordered
321 if (self.whitelist_patterns and
322 logging.getLogger().getEffectiveLevel() <= logging.DEBUG):
323- new_message_names = [message["name"] + "\n" for message in messages]
324+ new_message_names = [
325+ message["name"] + "\n" for message in messages]
326 detailed_text = "".join(
327 difflib.unified_diff(
328 old_message_names,
329@@ -200,7 +220,7 @@
330 "old whitelist",
331 "new whitelist"))
332 self._manager.reactor.fire(
333- "prompt-error",
334+ "prompt-warning",
335 self.interface,
336 "Whitelist not topologically ordered",
337 "Jobs will be reordered to fix broken dependencies",
338@@ -231,7 +251,7 @@
339 'Please make sure that the patterns you used are up-to-date\n'
340 .format('\n'.join(['- {0}'.format(tc)
341 for tc in orphan_test_cases])))
342- self._manager.reactor.fire('prompt-error', self.interface,
343+ self._manager.reactor.fire('prompt-warning', self.interface,
344 'Orphan test cases detected',
345 "Some test cases aren't included "
346 'in any test suite',
347@@ -244,7 +264,7 @@
348 "Please make sure that the patterns you used are up-to-date\n"
349 .format('\n'.join(['- {0}'.format(p.pattern[1:-1])
350 for p in self.unused_patterns])))
351- self._manager.reactor.fire('prompt-error', self.interface,
352+ self._manager.reactor.fire('prompt-warning', self.interface,
353 'Unused patterns',
354 'Please make sure that the patterns '
355 'you used are up-to-date',
356
357=== added file 'plugins/warning_prompt.py'
358--- plugins/warning_prompt.py 1970-01-01 00:00:00 +0000
359+++ plugins/warning_prompt.py 2012-10-17 19:06:24 +0000
360@@ -0,0 +1,35 @@
361+#
362+# This file is part of Checkbox.
363+#
364+# Copyright 2012 Canonical Ltd.
365+#
366+# Checkbox is free software: you can redistribute it and/or modify
367+# it under the terms of the GNU General Public License as published by
368+# the Free Software Foundation, either version 3 of the License, or
369+# (at your option) any later version.
370+#
371+# Checkbox is distributed in the hope that it will be useful,
372+# but WITHOUT ANY WARRANTY; without even the implied warranty of
373+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
374+# GNU General Public License for more details.
375+#
376+# You should have received a copy of the GNU General Public License
377+# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
378+#
379+from checkbox.plugin import Plugin
380+
381+
382+class WarningPrompt(Plugin):
383+
384+ def register(self, manager):
385+ super(WarningPrompt, self).register(manager)
386+
387+ self._manager.reactor.call_on("prompt-warning",
388+ self.prompt_warning)
389+
390+ def prompt_warning(self, interface,
391+ primary_text, secondary_text=None, detailed_text=None):
392+ interface.show_warning(primary_text, secondary_text, detailed_text)
393+
394+
395+factory = WarningPrompt

Subscribers

People subscribed via source and target branches