Merge lp:~cr3/checkbox/warning_prompt into lp:checkbox
- warning_prompt
- Merge into trunk
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 |
Related bugs: |
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
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 |
There's a lot of pep8 fixes but i'm happy with the skeleton of show_warning() in base checkbox/ user_interface. py.
Thanks