Merge lp:~sylvain-pineau/checkbox/whitelist_ordering_with_job_cache into lp:checkbox

Proposed by Sylvain Pineau
Status: Merged
Merged at revision: 1255
Proposed branch: lp:~sylvain-pineau/checkbox/whitelist_ordering_with_job_cache
Merge into: lp:checkbox
Diff against target: 169 lines (+51/-11)
4 files modified
checkbox/job.py (+2/-2)
checkbox/message.py (+17/-1)
checkbox/user_interface.py (+2/-2)
plugins/jobs_info.py (+30/-6)
To merge this branch: bzr merge lp:~sylvain-pineau/checkbox/whitelist_ordering_with_job_cache
Reviewer Review Type Date Requested Status
Marc Tardif (community) Approve
Sylvain Pineau (community) Needs Resubmitting
Review via email: mp+93080@code.launchpad.net

Description of the change

This branch brings two new features. A JobStore cache mechanism (thanks to Daniel Manrique) but entirely handled in message.py and the whitelist ordering proposal V2.0 (let's consider lp:~oem-qa/checkbox/patch_selection_dialog_sooner_and_whitelist_ordering as my first attempt).

This time, dependency checking is performed automatically and dependency jobs run in the whitelist order.

If errors are detected in the whitelist file or in jobs properties (doubled values, badly ordered dependencies, dependencies not found) they are all logged into the checkbox log file as warnings.

To post a comment you must log in.
1247. By Sylvain Pineau

Whitelist ordering

Revision history for this message
Sylvain Pineau (sylvain-pineau) wrote :

The ordering is now performed in plugins/jobs_info.py, much better.
Dependencies are ordered thanks to the JobStore.add call.
The ordering itself now relies on a simple cmp call, thanks cr3.

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

Looks good, thanks!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'checkbox/job.py'
2--- checkbox/job.py 2011-09-28 20:46:04 +0000
3+++ checkbox/job.py 2012-02-15 17:36:58 +0000
4@@ -122,7 +122,7 @@
5 if "depends" in job:
6 for depends in job["depends"]:
7 for filename in self._find_matching_messages():
8- message = self._read_message(filename)
9+ message = self._read_message(filename, cache=True)
10 if job["name"] in message.get("depends", []):
11 new_filename = self._get_next_message_filename()
12 os.rename(filename, new_filename)
13@@ -132,7 +132,7 @@
14 # TODO: Optimize by only searching backwards until a given condition
15 def _find_matching_messages(self, **kwargs):
16 for filename in self._walk_messages():
17- message = self._read_message(filename)
18+ message = self._read_message(filename,cache=True)
19 for key, value in kwargs.iteritems():
20 if message.get(key) != value:
21 break
22
23=== modified file 'checkbox/message.py'
24--- checkbox/message.py 2011-10-07 13:07:16 +0000
25+++ checkbox/message.py 2012-02-15 17:36:58 +0000
26@@ -20,6 +20,7 @@
27 import logging
28 import itertools
29 import posixpath
30+import sys
31
32 from checkbox.contrib import bpickle
33 from checkbox.lib.safe import safe_close
34@@ -40,6 +41,9 @@
35 class MessageStore(object):
36 """A message store which stores its messages in a file system hierarchy."""
37
38+ #This caches everything but a message's data, making it manageable to keep in memory.
39+ _message_cache = {}
40+
41 def __init__(self, persist, directory, directory_size=1000):
42 self._directory = directory
43 self._directory_size = directory_size
44@@ -240,7 +244,11 @@
45 def _dump_message(self, message):
46 return bpickle.dumps(message)
47
48- def _read_message(self, filename):
49+ def _read_message(self, filename, cache=False):
50+ #cache basically indicates whether the caller cares about having "data"
51+ if cache and filename in self._message_cache:
52+ return Message(self._message_cache[filename],filename)
53+
54 data = self._get_content(filename)
55 message = self._load_message(data)
56 return Message(message, filename)
57@@ -257,6 +265,14 @@
58
59 os.rename(filename + ".tmp", filename)
60
61+ #Strip the big data element and shove it in the cache
62+
63+ temp_message=dict(message)
64+ if "data" in temp_message:
65+ temp_message["data"] = None
66+
67+ self._message_cache[filename] = temp_message
68+
69 # For now we use the inode as the message id, as it will work
70 # correctly even faced with holding/unholding. It will break
71 # if the store is copied over for some reason, but this shouldn't
72
73=== modified file 'checkbox/user_interface.py'
74--- checkbox/user_interface.py 2012-02-13 01:44:19 +0000
75+++ checkbox/user_interface.py 2012-02-15 17:36:58 +0000
76@@ -27,8 +27,6 @@
77 import gettext
78 from gettext import gettext as _
79
80-from gi.repository import Gio
81-
82 from checkbox.contrib.REThread import REThread
83
84 from checkbox.lib.environ import add_variable, get_variable, remove_variable
85@@ -180,6 +178,8 @@
86 if os.getenv("DISPLAY") and \
87 subprocess.call(["pgrep", "-x", "-u", str(uid), "gnome-panel|gconfd-2"],
88 stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0:
89+ from gi.repository import Gio
90+
91 preferred_xml_app = Gio.app_info_get_default_for_type("application/xml",False)
92 if preferred_xml_app:
93 preferred_browser = preferred_xml_app.get_executable()
94
95=== modified file 'plugins/jobs_info.py'
96--- plugins/jobs_info.py 2012-02-07 18:30:21 +0000
97+++ plugins/jobs_info.py 2012-02-15 17:36:58 +0000
98@@ -54,16 +54,16 @@
99
100 # Space separated list of directories where job files are stored.
101 directories = List(Path(),
102- default_factory=lambda:"%(checkbox_share)s/jobs")
103+ default_factory=lambda: "%(checkbox_share)s/jobs")
104
105 # List of jobs to blacklist
106- blacklist = List(String(), default_factory=lambda:"")
107+ blacklist = List(String(), default_factory=lambda: "")
108
109 # Path to blacklist file
110 blacklist_file = Path(required=False)
111
112 # List of jobs to whitelist
113- whitelist = List(String(), default_factory=lambda:"")
114+ whitelist = List(String(), default_factory=lambda: "")
115
116 # Path to whitelist file
117 whitelist_file = Path(required=False)
118@@ -82,8 +82,8 @@
119 try:
120 file = open(filename)
121 except IOError, e:
122- error_message=(gettext.gettext("Failed to open file '%s': %s") %
123- (filename,e.strerror))
124+ error_message=(gettext.gettext("Failed to open file '%s': %s") %
125+ (filename, e.strerror))
126 logging.critical(error_message)
127 sys.stderr.write("%s\n" % error_message)
128 sys.exit(os.EX_NOINPUT)
129@@ -95,8 +95,15 @@
130
131 def gather(self):
132 # Register temporary handler for report-message events
133+ messages = []
134+
135 def report_message(message):
136- self._manager.reactor.fire("report-job", message)
137+ if self.whitelist_patterns:
138+ name = message["name"]
139+ if not [name for p in self.whitelist_patterns if p.match(name)]:
140+ return
141+
142+ messages.append(message)
143
144 # Set domain and message event handler
145 old_domain = gettext.textdomain()
146@@ -106,6 +113,23 @@
147 for directory in self.directories:
148 self._manager.reactor.fire("message-directory", directory)
149
150+ # Apply whitelist ordering
151+ def cmp_function(a, b):
152+ a_name = a["name"]
153+ b_name = b["name"]
154+ for pattern in self.whitelist_patterns:
155+ if pattern.match(a_name):
156+ a_index = self.whitelist_patterns.index(pattern)
157+ elif pattern.match(b_name):
158+ b_index = self.whitelist_patterns.index(pattern)
159+
160+ return cmp(a_index, b_index)
161+
162+ if self.whitelist_patterns:
163+ messages = sorted(messages, cmp=cmp_function)
164+ for message in messages:
165+ self._manager.reactor.fire("report-job", message)
166+
167 # Unset domain and event handler
168 self._manager.reactor.cancel_call(event_id)
169 gettext.textdomain(old_domain)

Subscribers

People subscribed via source and target branches