Merge lp:~brendan-donegan/ubuntu/raring/checkbox/0.15.4 into lp:ubuntu/raring/checkbox
- Raring (13.04)
- 0.15.4
- Merge into raring
Proposed by
Brendan Donegan
Status: | Merged |
---|---|
Merged at revision: | 1880 |
Proposed branch: | lp:~brendan-donegan/ubuntu/raring/checkbox/0.15.4 |
Merge into: | lp:ubuntu/raring/checkbox |
Diff against target: |
7070 lines (+2426/-817) 170 files modified
Vagrantfile (+14/-9) checkbox/parsers/tests/test_submission.py (+2/-2) checkbox/parsers/udevadm.py (+21/-0) debian/changelog (+18/-0) debian/po/ast.po (+2/-2) debian/po/cs.po (+2/-2) debian/po/de.po (+2/-2) debian/po/en_AU.po (+2/-2) debian/po/en_GB.po (+2/-2) debian/po/es.po (+2/-2) debian/po/fr.po (+2/-2) debian/po/gl.po (+2/-2) debian/po/he.po (+2/-2) debian/po/hu.po (+2/-2) debian/po/id.po (+2/-2) debian/po/it.po (+2/-2) debian/po/ja.po (+2/-2) debian/po/nl.po (+2/-2) debian/po/oc.po (+2/-2) debian/po/pl.po (+2/-2) debian/po/pt_BR.po (+2/-2) debian/po/ro.po (+2/-2) debian/po/ru.po (+2/-2) debian/po/tr.po (+2/-2) debian/po/uk.po (+2/-2) debian/po/zh_CN.po (+2/-2) debian/po/zh_TW.po (+2/-2) jobs/graphics.txt.in (+2/-1) jobs/input.txt.in (+1/-0) jobs/optical.txt.in (+4/-4) jobs/suspend.txt.in (+1/-1) plainbox/docs/changelog.rst (+32/-0) plainbox/docs/dev/architecture.rst (+337/-0) plainbox/docs/dev/index.rst (+14/-0) plainbox/docs/dev/intro.rst (+238/-0) plainbox/docs/dev/reference.rst (+154/-0) plainbox/docs/glossary.rst (+104/-0) plainbox/docs/index.rst (+46/-6) plainbox/docs/usage.rst (+69/-0) plainbox/plainbox/__init__.py (+4/-4) plainbox/plainbox/abc.py (+2/-4) plainbox/plainbox/impl/__init__.py (+6/-4) plainbox/plainbox/impl/box.py (+55/-14) plainbox/plainbox/impl/checkbox.py (+9/-9) plainbox/plainbox/impl/commands/__init__.py (+6/-6) plainbox/plainbox/impl/commands/selftest.py (+6/-6) plainbox/plainbox/impl/depmgr.py (+17/-15) plainbox/plainbox/impl/exporter/__init__.py (+20/-9) plainbox/plainbox/impl/exporter/json.py (+5/-6) plainbox/plainbox/impl/exporter/rfc822.py (+6/-6) plainbox/plainbox/impl/exporter/test_init.py (+16/-12) plainbox/plainbox/impl/exporter/text.py (+6/-6) plainbox/plainbox/impl/integration_tests.py (+20/-4) plainbox/plainbox/impl/job.py (+18/-8) plainbox/plainbox/impl/mock_job.py (+36/-0) plainbox/plainbox/impl/resource.py (+7/-7) plainbox/plainbox/impl/result.py (+42/-12) plainbox/plainbox/impl/rfc822.py (+10/-7) plainbox/plainbox/impl/runner.py (+76/-19) plainbox/plainbox/impl/session.py (+115/-52) plainbox/plainbox/impl/test_box.py (+110/-14) plainbox/plainbox/impl/test_job.py (+3/-3) plainbox/plainbox/impl/test_result.py (+22/-18) plainbox/plainbox/impl/test_runner.py (+5/-5) plainbox/plainbox/impl/test_session.py (+188/-14) plainbox/plainbox/impl/testing_utils.py (+18/-6) plainbox/plainbox/impl/utils.py.moved (+0/-58) plainbox/plainbox/public.py (+2/-2) plainbox/plainbox/testing_utils/__init__.py (+2/-4) plainbox/plainbox/testing_utils/cwd.py (+2/-2) plainbox/plainbox/testing_utils/io.py (+2/-2) plainbox/plainbox/testing_utils/testcases.py (+3/-3) plainbox/plainbox/tests.py (+2/-4) plainbox/plainbox/vendor/__init__.py (+28/-0) plainbox/plainbox/vendor/extcmd/__init__.py (+2/-2) plainbox/setup.py (+3/-0) po/ace.po (+4/-4) po/af.po (+4/-4) po/am.po (+4/-4) po/ar.po (+4/-4) po/ast.po (+4/-4) po/az.po (+4/-4) po/be.po (+4/-4) po/bg.po (+4/-4) po/bn.po (+4/-4) po/bo.po (+4/-4) po/br.po (+4/-4) po/bs.po (+4/-4) po/ca.po (+4/-4) po/ca@valencia.po (+4/-4) po/ckb.po (+4/-4) po/cs.po (+4/-4) po/cy.po (+4/-4) po/da.po (+4/-4) po/de.po (+5/-5) po/dv.po (+4/-4) po/el.po (+4/-4) po/en_AU.po (+4/-4) po/en_CA.po (+4/-4) po/en_GB.po (+4/-4) po/eo.po (+4/-4) po/es.po (+4/-4) po/et.po (+4/-4) po/eu.po (+4/-4) po/fa.po (+4/-4) po/fi.po (+4/-4) po/fr.po (+4/-4) po/ga.po (+4/-4) po/gd.po (+4/-4) po/gl.po (+4/-4) po/he.po (+4/-4) po/hi.po (+4/-4) po/hr.po (+4/-4) po/hu.po (+4/-4) po/hy.po (+4/-4) po/id.po (+4/-4) po/is.po (+4/-4) po/it.po (+4/-4) po/ja.po (+4/-4) po/jbo.po (+4/-4) po/ka.po (+4/-4) po/kk.po (+4/-4) po/km.po (+4/-4) po/kn.po (+4/-4) po/ko.po (+4/-4) po/ku.po (+4/-4) po/ky.po (+4/-4) po/lt.po (+4/-4) po/lv.po (+4/-4) po/mk.po (+4/-4) po/ml.po (+4/-4) po/mr.po (+4/-4) po/ms.po (+4/-4) po/my.po (+4/-4) po/nb.po (+4/-4) po/nds.po (+4/-4) po/ne.po (+4/-4) po/nl.po (+4/-4) po/nn.po (+4/-4) po/oc.po (+4/-4) po/pl.po (+4/-4) po/ps.po (+4/-4) po/pt.po (+4/-4) po/pt_BR.po (+4/-4) po/ro.po (+4/-4) po/ru.po (+4/-4) po/sd.po (+4/-4) po/shn.po (+4/-4) po/si.po (+4/-4) po/sk.po (+4/-4) po/sl.po (+4/-4) po/sq.po (+4/-4) po/sr.po (+4/-4) po/sv.po (+4/-4) po/ta.po (+4/-4) po/te.po (+4/-4) po/th.po (+4/-4) po/tr.po (+22/-7) po/ug.po (+4/-4) po/uk.po (+4/-4) po/ur.po (+4/-4) po/uz.po (+4/-4) po/vi.po (+4/-4) po/zh_CN.po (+4/-4) po/zh_HK.po (+4/-4) po/zh_TW.po (+4/-4) scripts/network_device_info (+56/-35) scripts/udev_resource (+1/-1) test (+4/-0) test-in-vagrant.sh (+9/-1) |
To merge this branch: | bzr merge lp:~brendan-donegan/ubuntu/raring/checkbox/0.15.4 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Daniel Manrique (community) | Approve | ||
Review via email: mp+152211@code.launchpad.net |
Commit message
Description of the change
checkbox (0.15.4) raring; urgency=low
* New upstream release (LP: #1152223)
[ Daniel Manrique ]
* Added pipefail option to a few jobs using ansi_parser (LP: #1131598)
[ Jeff Marcom ]
* jobs/input.txt.in Added job requirement for accelerometer test (LP: #1135832)
[Sylvain Pineau]
* scripts/
checkbox/
of lspci (LP: #1091633)
-- Brendan Donegan <email address hidden> Thu, 07 Mar 2013 15:43:13 +0000
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'Vagrantfile' |
2 | --- Vagrantfile 2013-02-22 16:26:25 +0000 |
3 | +++ Vagrantfile 2013-03-07 16:10:38 +0000 |
4 | @@ -5,24 +5,29 @@ |
5 | |
6 | # Define a Ubuntu Server image (cloud) for the 12.10 release (quantal) |
7 | config.vm.define :quantal do |quantal_config| |
8 | - quantal_config.vm.box = "quantal-cloud-amd64" |
9 | - quantal_config.vm.box_url = "http://cloud-images.ubuntu.com/vagrant/quantal/current/quantal-server-cloudimg-amd64-vagrant-disk1.box" |
10 | + quantal_config.vm.box = "quantal-cloud-i386" |
11 | + quantal_config.vm.box_url = "http://cloud-images.ubuntu.com/vagrant/quantal/current/quantal-server-cloudimg-i386-vagrant-disk1.box" |
12 | end |
13 | |
14 | # Define a Ubuntu Server image (cloud) for the 12.04 release (precise) |
15 | config.vm.define :precise do |precise_config| |
16 | - precise_config.vm.box = "precise-cloud-amd64" |
17 | - precise_config.vm.box_url = "http://cloud-images.ubuntu.com/vagrant/precise/current/precise-server-cloudimg-amd64-vagrant-disk1.box" |
18 | + precise_config.vm.box = "precise-cloud-i386" |
19 | + precise_config.vm.box_url = "http://cloud-images.ubuntu.com/vagrant/precise/current/precise-server-cloudimg-i386-vagrant-disk1.box" |
20 | end |
21 | |
22 | # For debugging and later future GUI testing |
23 | # config.vm.boot_mode = :gui |
24 | |
25 | - # Update to have the latest packages |
26 | - # Commented out for now, we don't really need it |
27 | - # config.vm.provision :shell, :inline => "apt-get update && apt-get dist-upgrade" |
28 | + # Update to have the latest packages, this is needed because the image comes |
29 | + # with an old (and no longer working) apt cache and links to many packages no |
30 | + # longer work. |
31 | + config.vm.provision :shell, :inline => "apt-get update && apt-get dist-upgrade --yes" |
32 | # Install dependencies from native packages |
33 | - config.vm.provision :shell, :inline => "apt-get install --yes python3-setuptools python3-yaml python3-lxml" |
34 | + config.vm.provision :shell, :inline => "apt-get install --yes python3-setuptools python3-lxml" |
35 | + # Install python3-mock so that we can create mock objects for testing |
36 | + config.vm.provision :shell, :inline => "apt-get install --yes python3-mock" |
37 | + # Install policykit-1 so that we have pkexec |
38 | + config.vm.provision :shell, :inline => "apt-get install --yes policykit-1" |
39 | # Install some checkbox script dependencies: |
40 | # Later on those could be installed on demand to test how we behave without |
41 | # them but for now that's good enough. Little by little... |
42 | @@ -38,5 +43,5 @@ |
43 | # Develop plainbox so that we have it in $PATH |
44 | config.vm.provision :shell, :inline => "cd /vagrant/plainbox/ && python3 setup.py develop" |
45 | # Create a cool symlink so that everyone knows where to go to |
46 | - config.vm.provision :shell, :inline => "ln -s /vagrant /home/vagrant/checkbox" |
47 | + config.vm.provision :shell, :inline => "ln -fs /vagrant /home/vagrant/checkbox" |
48 | end |
49 | |
50 | === modified file 'checkbox/parsers/tests/test_submission.py' |
51 | --- checkbox/parsers/tests/test_submission.py 2012-10-12 21:39:01 +0000 |
52 | +++ checkbox/parsers/tests/test_submission.py 2013-03-07 16:10:38 +0000 |
53 | @@ -153,13 +153,13 @@ |
54 | """Device states can be in the udev element.""" |
55 | result = self.getResult("submission_udev.xml") |
56 | self.assertTrue("device_states" in result) |
57 | - self.assertEquals(len(result["device_states"]), 77) |
58 | + self.assertEquals(len(result["device_states"]), 82) |
59 | |
60 | def test_device_udevadm(self): |
61 | """Device states can be in a udevadm info element.""" |
62 | result = self.getResult("submission_info_udevadm.xml") |
63 | self.assertTrue("device_states" in result) |
64 | - self.assertEquals(len(result["device_states"]), 77) |
65 | + self.assertEquals(len(result["device_states"]), 82) |
66 | |
67 | def test_device_dmidecode(self): |
68 | """Device states can be in a dmidecode info element.""" |
69 | |
70 | === modified file 'checkbox/parsers/udevadm.py' |
71 | --- checkbox/parsers/udevadm.py 2012-11-12 09:59:00 +0000 |
72 | +++ checkbox/parsers/udevadm.py 2013-03-07 16:10:38 +0000 |
73 | @@ -92,8 +92,15 @@ |
74 | @property |
75 | def category(self): |
76 | if "IFINDEX" in self._environment: |
77 | + if "DEVTYPE" in self._environment: |
78 | + devtype = self._environment["DEVTYPE"] |
79 | + if devtype == "wlan": |
80 | + return "WIRELESS" |
81 | return "NETWORK" |
82 | |
83 | + if self.bus == "sound": |
84 | + return "AUDIO" |
85 | + |
86 | if self.bus == "ieee80211": |
87 | return "WIRELESS" |
88 | |
89 | @@ -383,6 +390,9 @@ |
90 | if self.driver == "floppy": |
91 | return "Platform Device" |
92 | |
93 | + if "ID_MODEL_FROM_DATABASE" in self._environment: |
94 | + return self._environment["ID_MODEL_FROM_DATABASE"] |
95 | + |
96 | return None |
97 | |
98 | @property |
99 | @@ -407,6 +417,17 @@ |
100 | and "ID_VENDOR_ENC" in self._environment: |
101 | return decode_id(self._environment["ID_VENDOR_ENC"]) |
102 | |
103 | + if "ID_VENDOR_FROM_DATABASE" in self._environment: |
104 | + return self._environment["ID_VENDOR_FROM_DATABASE"] |
105 | + |
106 | + return None |
107 | + |
108 | + @property |
109 | + def interface(self): |
110 | + if self.category in ("NETWORK", "WIRELESS") \ |
111 | + and "INTERFACE" in self._environment: |
112 | + return self._environment["INTERFACE"] |
113 | + |
114 | return None |
115 | |
116 | |
117 | |
118 | === modified file 'debian/changelog' |
119 | --- debian/changelog 2013-02-22 16:41:55 +0000 |
120 | +++ debian/changelog 2013-03-07 16:10:38 +0000 |
121 | @@ -1,7 +1,25 @@ |
122 | +checkbox (0.15.4) raring; urgency=low |
123 | + |
124 | + * New upstream release (LP: #1152223) |
125 | + |
126 | + [ Daniel Manrique ] |
127 | + * Added pipefail option to a few jobs using ansi_parser (LP: #1131598) |
128 | + |
129 | + [ Jeff Marcom ] |
130 | + * jobs/input.txt.in Added job requirement for accelerometer test (LP: #1135832) |
131 | + |
132 | + [Sylvain Pineau] |
133 | + * scripts/network_device_info, scripts/udev_resource, |
134 | + checkbox/parsers/udevadm.py: Use udev to categorise network devices instead |
135 | + of lspci (LP: #1091633) |
136 | + |
137 | + -- Brendan Donegan <brendan.donegan@ubuntu.com> Thu, 07 Mar 2013 15:43:13 +0000 |
138 | + |
139 | checkbox (0.15.3) raring; urgency=low |
140 | |
141 | * New upstream release (LP: #1131801) |
142 | |
143 | + [ Daniel Manrique ] |
144 | * scripts/pts_run: modified to output the full log from phoronix-test-suite |
145 | (LP: #1102819) |
146 | |
147 | |
148 | === modified file 'debian/po/ast.po' |
149 | --- debian/po/ast.po 2013-02-22 16:26:25 +0000 |
150 | +++ debian/po/ast.po 2013-03-07 16:10:38 +0000 |
151 | @@ -14,8 +14,8 @@ |
152 | "MIME-Version: 1.0\n" |
153 | "Content-Type: text/plain; charset=UTF-8\n" |
154 | "Content-Transfer-Encoding: 8bit\n" |
155 | -"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n" |
156 | -"X-Generator: Launchpad (build 16491)\n" |
157 | +"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n" |
158 | +"X-Generator: Launchpad (build 16506)\n" |
159 | |
160 | #. Type: string |
161 | #. Description |
162 | |
163 | === modified file 'debian/po/cs.po' |
164 | --- debian/po/cs.po 2013-02-22 16:26:25 +0000 |
165 | +++ debian/po/cs.po 2013-03-07 16:10:38 +0000 |
166 | @@ -14,8 +14,8 @@ |
167 | "MIME-Version: 1.0\n" |
168 | "Content-Type: text/plain; charset=UTF-8\n" |
169 | "Content-Transfer-Encoding: 8bit\n" |
170 | -"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n" |
171 | -"X-Generator: Launchpad (build 16491)\n" |
172 | +"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n" |
173 | +"X-Generator: Launchpad (build 16506)\n" |
174 | |
175 | #. Type: string |
176 | #. Description |
177 | |
178 | === modified file 'debian/po/de.po' |
179 | --- debian/po/de.po 2013-02-22 16:26:25 +0000 |
180 | +++ debian/po/de.po 2013-03-07 16:10:38 +0000 |
181 | @@ -14,8 +14,8 @@ |
182 | "MIME-Version: 1.0\n" |
183 | "Content-Type: text/plain; charset=UTF-8\n" |
184 | "Content-Transfer-Encoding: 8bit\n" |
185 | -"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n" |
186 | -"X-Generator: Launchpad (build 16491)\n" |
187 | +"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n" |
188 | +"X-Generator: Launchpad (build 16506)\n" |
189 | |
190 | #. Type: string |
191 | #. Description |
192 | |
193 | === modified file 'debian/po/en_AU.po' |
194 | --- debian/po/en_AU.po 2013-02-22 16:26:25 +0000 |
195 | +++ debian/po/en_AU.po 2013-03-07 16:10:38 +0000 |
196 | @@ -14,8 +14,8 @@ |
197 | "MIME-Version: 1.0\n" |
198 | "Content-Type: text/plain; charset=UTF-8\n" |
199 | "Content-Transfer-Encoding: 8bit\n" |
200 | -"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n" |
201 | -"X-Generator: Launchpad (build 16491)\n" |
202 | +"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n" |
203 | +"X-Generator: Launchpad (build 16506)\n" |
204 | |
205 | #. Type: string |
206 | #. Description |
207 | |
208 | === modified file 'debian/po/en_GB.po' |
209 | --- debian/po/en_GB.po 2013-02-22 16:26:25 +0000 |
210 | +++ debian/po/en_GB.po 2013-03-07 16:10:38 +0000 |
211 | @@ -14,8 +14,8 @@ |
212 | "MIME-Version: 1.0\n" |
213 | "Content-Type: text/plain; charset=UTF-8\n" |
214 | "Content-Transfer-Encoding: 8bit\n" |
215 | -"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n" |
216 | -"X-Generator: Launchpad (build 16491)\n" |
217 | +"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n" |
218 | +"X-Generator: Launchpad (build 16506)\n" |
219 | |
220 | #. Type: string |
221 | #. Description |
222 | |
223 | === modified file 'debian/po/es.po' |
224 | --- debian/po/es.po 2013-02-22 16:26:25 +0000 |
225 | +++ debian/po/es.po 2013-03-07 16:10:38 +0000 |
226 | @@ -14,8 +14,8 @@ |
227 | "MIME-Version: 1.0\n" |
228 | "Content-Type: text/plain; charset=UTF-8\n" |
229 | "Content-Transfer-Encoding: 8bit\n" |
230 | -"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n" |
231 | -"X-Generator: Launchpad (build 16491)\n" |
232 | +"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n" |
233 | +"X-Generator: Launchpad (build 16506)\n" |
234 | |
235 | #. Type: string |
236 | #. Description |
237 | |
238 | === modified file 'debian/po/fr.po' |
239 | --- debian/po/fr.po 2013-02-22 16:26:25 +0000 |
240 | +++ debian/po/fr.po 2013-03-07 16:10:38 +0000 |
241 | @@ -14,8 +14,8 @@ |
242 | "MIME-Version: 1.0\n" |
243 | "Content-Type: text/plain; charset=UTF-8\n" |
244 | "Content-Transfer-Encoding: 8bit\n" |
245 | -"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n" |
246 | -"X-Generator: Launchpad (build 16491)\n" |
247 | +"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n" |
248 | +"X-Generator: Launchpad (build 16506)\n" |
249 | |
250 | #. Type: string |
251 | #. Description |
252 | |
253 | === modified file 'debian/po/gl.po' |
254 | --- debian/po/gl.po 2013-02-22 16:26:25 +0000 |
255 | +++ debian/po/gl.po 2013-03-07 16:10:38 +0000 |
256 | @@ -14,8 +14,8 @@ |
257 | "MIME-Version: 1.0\n" |
258 | "Content-Type: text/plain; charset=UTF-8\n" |
259 | "Content-Transfer-Encoding: 8bit\n" |
260 | -"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n" |
261 | -"X-Generator: Launchpad (build 16491)\n" |
262 | +"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n" |
263 | +"X-Generator: Launchpad (build 16506)\n" |
264 | |
265 | #. Type: string |
266 | #. Description |
267 | |
268 | === modified file 'debian/po/he.po' |
269 | --- debian/po/he.po 2013-02-22 16:26:25 +0000 |
270 | +++ debian/po/he.po 2013-03-07 16:10:38 +0000 |
271 | @@ -14,8 +14,8 @@ |
272 | "MIME-Version: 1.0\n" |
273 | "Content-Type: text/plain; charset=UTF-8\n" |
274 | "Content-Transfer-Encoding: 8bit\n" |
275 | -"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n" |
276 | -"X-Generator: Launchpad (build 16491)\n" |
277 | +"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n" |
278 | +"X-Generator: Launchpad (build 16506)\n" |
279 | |
280 | #. Type: string |
281 | #. Description |
282 | |
283 | === modified file 'debian/po/hu.po' |
284 | --- debian/po/hu.po 2013-02-22 16:26:25 +0000 |
285 | +++ debian/po/hu.po 2013-03-07 16:10:38 +0000 |
286 | @@ -14,8 +14,8 @@ |
287 | "MIME-Version: 1.0\n" |
288 | "Content-Type: text/plain; charset=UTF-8\n" |
289 | "Content-Transfer-Encoding: 8bit\n" |
290 | -"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n" |
291 | -"X-Generator: Launchpad (build 16491)\n" |
292 | +"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n" |
293 | +"X-Generator: Launchpad (build 16506)\n" |
294 | |
295 | #. Type: string |
296 | #. Description |
297 | |
298 | === modified file 'debian/po/id.po' |
299 | --- debian/po/id.po 2013-02-22 16:26:25 +0000 |
300 | +++ debian/po/id.po 2013-03-07 16:10:38 +0000 |
301 | @@ -14,8 +14,8 @@ |
302 | "MIME-Version: 1.0\n" |
303 | "Content-Type: text/plain; charset=UTF-8\n" |
304 | "Content-Transfer-Encoding: 8bit\n" |
305 | -"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n" |
306 | -"X-Generator: Launchpad (build 16491)\n" |
307 | +"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n" |
308 | +"X-Generator: Launchpad (build 16506)\n" |
309 | |
310 | #. Type: string |
311 | #. Description |
312 | |
313 | === modified file 'debian/po/it.po' |
314 | --- debian/po/it.po 2013-02-22 16:26:25 +0000 |
315 | +++ debian/po/it.po 2013-03-07 16:10:38 +0000 |
316 | @@ -14,8 +14,8 @@ |
317 | "MIME-Version: 1.0\n" |
318 | "Content-Type: text/plain; charset=UTF-8\n" |
319 | "Content-Transfer-Encoding: 8bit\n" |
320 | -"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n" |
321 | -"X-Generator: Launchpad (build 16491)\n" |
322 | +"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n" |
323 | +"X-Generator: Launchpad (build 16506)\n" |
324 | |
325 | #. Type: string |
326 | #. Description |
327 | |
328 | === modified file 'debian/po/ja.po' |
329 | --- debian/po/ja.po 2013-02-22 16:26:25 +0000 |
330 | +++ debian/po/ja.po 2013-03-07 16:10:38 +0000 |
331 | @@ -14,8 +14,8 @@ |
332 | "MIME-Version: 1.0\n" |
333 | "Content-Type: text/plain; charset=UTF-8\n" |
334 | "Content-Transfer-Encoding: 8bit\n" |
335 | -"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n" |
336 | -"X-Generator: Launchpad (build 16491)\n" |
337 | +"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n" |
338 | +"X-Generator: Launchpad (build 16506)\n" |
339 | |
340 | #. Type: string |
341 | #. Description |
342 | |
343 | === modified file 'debian/po/nl.po' |
344 | --- debian/po/nl.po 2013-02-22 16:26:25 +0000 |
345 | +++ debian/po/nl.po 2013-03-07 16:10:38 +0000 |
346 | @@ -14,8 +14,8 @@ |
347 | "MIME-Version: 1.0\n" |
348 | "Content-Type: text/plain; charset=UTF-8\n" |
349 | "Content-Transfer-Encoding: 8bit\n" |
350 | -"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n" |
351 | -"X-Generator: Launchpad (build 16491)\n" |
352 | +"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n" |
353 | +"X-Generator: Launchpad (build 16506)\n" |
354 | |
355 | #. Type: string |
356 | #. Description |
357 | |
358 | === modified file 'debian/po/oc.po' |
359 | --- debian/po/oc.po 2013-02-22 16:26:25 +0000 |
360 | +++ debian/po/oc.po 2013-03-07 16:10:38 +0000 |
361 | @@ -14,8 +14,8 @@ |
362 | "MIME-Version: 1.0\n" |
363 | "Content-Type: text/plain; charset=UTF-8\n" |
364 | "Content-Transfer-Encoding: 8bit\n" |
365 | -"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n" |
366 | -"X-Generator: Launchpad (build 16491)\n" |
367 | +"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n" |
368 | +"X-Generator: Launchpad (build 16506)\n" |
369 | |
370 | #. Type: string |
371 | #. Description |
372 | |
373 | === modified file 'debian/po/pl.po' |
374 | --- debian/po/pl.po 2013-02-22 16:26:25 +0000 |
375 | +++ debian/po/pl.po 2013-03-07 16:10:38 +0000 |
376 | @@ -14,8 +14,8 @@ |
377 | "MIME-Version: 1.0\n" |
378 | "Content-Type: text/plain; charset=UTF-8\n" |
379 | "Content-Transfer-Encoding: 8bit\n" |
380 | -"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n" |
381 | -"X-Generator: Launchpad (build 16491)\n" |
382 | +"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n" |
383 | +"X-Generator: Launchpad (build 16506)\n" |
384 | |
385 | #. Type: string |
386 | #. Description |
387 | |
388 | === modified file 'debian/po/pt_BR.po' |
389 | --- debian/po/pt_BR.po 2013-02-22 16:26:25 +0000 |
390 | +++ debian/po/pt_BR.po 2013-03-07 16:10:38 +0000 |
391 | @@ -14,8 +14,8 @@ |
392 | "MIME-Version: 1.0\n" |
393 | "Content-Type: text/plain; charset=UTF-8\n" |
394 | "Content-Transfer-Encoding: 8bit\n" |
395 | -"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n" |
396 | -"X-Generator: Launchpad (build 16491)\n" |
397 | +"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n" |
398 | +"X-Generator: Launchpad (build 16506)\n" |
399 | |
400 | #. Type: string |
401 | #. Description |
402 | |
403 | === modified file 'debian/po/ro.po' |
404 | --- debian/po/ro.po 2013-02-22 16:26:25 +0000 |
405 | +++ debian/po/ro.po 2013-03-07 16:10:38 +0000 |
406 | @@ -14,8 +14,8 @@ |
407 | "MIME-Version: 1.0\n" |
408 | "Content-Type: text/plain; charset=UTF-8\n" |
409 | "Content-Transfer-Encoding: 8bit\n" |
410 | -"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n" |
411 | -"X-Generator: Launchpad (build 16491)\n" |
412 | +"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n" |
413 | +"X-Generator: Launchpad (build 16506)\n" |
414 | |
415 | #. Type: string |
416 | #. Description |
417 | |
418 | === modified file 'debian/po/ru.po' |
419 | --- debian/po/ru.po 2013-02-22 16:26:25 +0000 |
420 | +++ debian/po/ru.po 2013-03-07 16:10:38 +0000 |
421 | @@ -14,8 +14,8 @@ |
422 | "MIME-Version: 1.0\n" |
423 | "Content-Type: text/plain; charset=UTF-8\n" |
424 | "Content-Transfer-Encoding: 8bit\n" |
425 | -"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n" |
426 | -"X-Generator: Launchpad (build 16491)\n" |
427 | +"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n" |
428 | +"X-Generator: Launchpad (build 16506)\n" |
429 | |
430 | #. Type: string |
431 | #. Description |
432 | |
433 | === modified file 'debian/po/tr.po' |
434 | --- debian/po/tr.po 2013-02-22 16:26:25 +0000 |
435 | +++ debian/po/tr.po 2013-03-07 16:10:38 +0000 |
436 | @@ -14,8 +14,8 @@ |
437 | "MIME-Version: 1.0\n" |
438 | "Content-Type: text/plain; charset=UTF-8\n" |
439 | "Content-Transfer-Encoding: 8bit\n" |
440 | -"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n" |
441 | -"X-Generator: Launchpad (build 16491)\n" |
442 | +"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n" |
443 | +"X-Generator: Launchpad (build 16506)\n" |
444 | |
445 | #. Type: string |
446 | #. Description |
447 | |
448 | === modified file 'debian/po/uk.po' |
449 | --- debian/po/uk.po 2013-02-22 16:26:25 +0000 |
450 | +++ debian/po/uk.po 2013-03-07 16:10:38 +0000 |
451 | @@ -14,8 +14,8 @@ |
452 | "MIME-Version: 1.0\n" |
453 | "Content-Type: text/plain; charset=UTF-8\n" |
454 | "Content-Transfer-Encoding: 8bit\n" |
455 | -"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n" |
456 | -"X-Generator: Launchpad (build 16491)\n" |
457 | +"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n" |
458 | +"X-Generator: Launchpad (build 16506)\n" |
459 | |
460 | #. Type: string |
461 | #. Description |
462 | |
463 | === modified file 'debian/po/zh_CN.po' |
464 | --- debian/po/zh_CN.po 2013-02-22 16:26:25 +0000 |
465 | +++ debian/po/zh_CN.po 2013-03-07 16:10:38 +0000 |
466 | @@ -14,8 +14,8 @@ |
467 | "MIME-Version: 1.0\n" |
468 | "Content-Type: text/plain; charset=UTF-8\n" |
469 | "Content-Transfer-Encoding: 8bit\n" |
470 | -"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n" |
471 | -"X-Generator: Launchpad (build 16491)\n" |
472 | +"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n" |
473 | +"X-Generator: Launchpad (build 16506)\n" |
474 | |
475 | #. Type: string |
476 | #. Description |
477 | |
478 | === modified file 'debian/po/zh_TW.po' |
479 | --- debian/po/zh_TW.po 2013-02-22 16:26:25 +0000 |
480 | +++ debian/po/zh_TW.po 2013-03-07 16:10:38 +0000 |
481 | @@ -14,8 +14,8 @@ |
482 | "MIME-Version: 1.0\n" |
483 | "Content-Type: text/plain; charset=UTF-8\n" |
484 | "Content-Transfer-Encoding: 8bit\n" |
485 | -"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n" |
486 | -"X-Generator: Launchpad (build 16491)\n" |
487 | +"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n" |
488 | +"X-Generator: Launchpad (build 16506)\n" |
489 | |
490 | #. Type: string |
491 | #. Description |
492 | |
493 | === modified file 'jobs/graphics.txt.in' |
494 | --- jobs/graphics.txt.in 2012-12-12 12:59:22 +0000 |
495 | +++ jobs/graphics.txt.in 2013-03-07 16:10:38 +0000 |
496 | @@ -170,7 +170,7 @@ |
497 | plugin: shell |
498 | name: graphics/screenshot |
499 | requires: package.name == 'fswebcam' |
500 | -command: camera_test still --device=/dev/external_webcam -f ${CHECKBOX_DATA}/screenshot.jpg -q 2>&1 | ansi_parser |
501 | +command: set -o pipefail; camera_test still --device=/dev/external_webcam -f ${CHECKBOX_DATA}/screenshot.jpg -q 2>&1 | ansi_parser |
502 | _description: |
503 | PURPOSE: |
504 | Take a screengrab of the current screen (logged on Unity desktop) |
505 | @@ -191,6 +191,7 @@ |
506 | command: |
507 | dbus-launch gsettings set org.gnome.totem repeat true |
508 | totem --fullscreen ${CHECKBOX_SHARE}/data/video/Ogg_Theora_Video.ogv 2>/dev/null & |
509 | + set -o pipefail |
510 | sleep 15 && camera_test still --device=/dev/external_webcam -f ${CHECKBOX_DATA}/screenshot_fullscreen_video.jpg -q 2>&1 | ansi_parser |
511 | sleep 5 && totem --quit 2>/dev/null |
512 | dbus-launch gsettings set org.gnome.totem repeat false |
513 | |
514 | === modified file 'jobs/input.txt.in' |
515 | --- jobs/input.txt.in 2013-02-22 16:26:25 +0000 |
516 | +++ jobs/input.txt.in 2013-03-07 16:10:38 +0000 |
517 | @@ -44,6 +44,7 @@ |
518 | plugin: user-interact |
519 | name: input/accelerometer |
520 | user: root |
521 | +requires: module.name in ['hdaps', 'hp_accel'] |
522 | command: accelerometer_test -m |
523 | _description: |
524 | PURPOSE: |
525 | |
526 | === modified file 'jobs/optical.txt.in' |
527 | --- jobs/optical.txt.in 2012-10-11 20:48:55 +0000 |
528 | +++ jobs/optical.txt.in 2013-03-07 16:10:38 +0000 |
529 | @@ -58,7 +58,7 @@ |
530 | name: optical/cdrom-write_`ls /sys$path/block` |
531 | requires: device.path == "$path" |
532 | user: root |
533 | - command: optical_write_test /dev/`ls /sys$path/block` | ansi_parser |
534 | + command: set -o pipefail; optical_write_test /dev/`ls /sys$path/block` | ansi_parser |
535 | description: |
536 | PURPOSE: |
537 | This test will check your system's $product CD writing capabilities. This test requires a blank CD-R or CD+R. If you do not have a blank disk, skip this test. |
538 | @@ -80,7 +80,7 @@ |
539 | name: optical/cdrom-write-automated_`ls /sys$path/block` |
540 | requires: device.path == "$path" |
541 | user: root |
542 | - command: optical_write_test /dev/`ls /sys$path/block` | ansi_parser |
543 | + command: set -o pipefail; optical_write_test /dev/`ls /sys$path/block` | ansi_parser |
544 | description: |
545 | This is an automated version of optical/cdrom-write. It assumes you have already inserted a data CD into your optical drive prior to running Checkbox. |
546 | EOF |
547 | @@ -116,7 +116,7 @@ |
548 | name: optical/dvd-write_`ls /sys$path/block` |
549 | requires: device.path == "$path" |
550 | user: root |
551 | - command: optical_write_test /dev/`ls /sys$path/block` | ansi_parser |
552 | + command: set -o pipefail; optical_write_test /dev/`ls /sys$path/block` | ansi_parser |
553 | description: |
554 | PURPOSE: |
555 | This test will check your system's $product writing capabilities. This test requires a blank DVD-R or DVD+R. If you do not have a blank DVD disk, skip this test. |
556 | @@ -140,7 +140,7 @@ |
557 | name: optical/dvd-write-automated_`ls /sys$path/block` |
558 | requires: device.path == "$path" |
559 | user: root |
560 | - command: optical_write_test /dev/`ls /sys$path/block` | ansi_parser |
561 | + command: set -o pipefail; optical_write_test /dev/`ls /sys$path/block` | ansi_parser |
562 | description: |
563 | This is an automated version of optical/dvd-write. It assumes you have already inserted a data DVD into your optical drive prior to running Checkbox. |
564 | EOF |
565 | |
566 | === modified file 'jobs/suspend.txt.in' |
567 | --- jobs/suspend.txt.in 2013-01-30 21:43:05 +0000 |
568 | +++ jobs/suspend.txt.in 2013-03-07 16:10:38 +0000 |
569 | @@ -790,7 +790,7 @@ |
570 | name: suspend/screenshot_after_suspend |
571 | depends: suspend/suspend_advanced_auto |
572 | requires: package.name == 'fswebcam' |
573 | -command: camera_test still --device=/dev/external_webcam -f ${CHECKBOX_DATA}/screenshot_after_suspend.jpg -q 2>&1 | ansi_parser |
574 | +command: set -o pipefail; camera_test still --device=/dev/external_webcam -f ${CHECKBOX_DATA}/screenshot_after_suspend.jpg -q 2>&1 | ansi_parser |
575 | _description: |
576 | PURPOSE: |
577 | Take a screengrab of the current screen after suspend (logged on Unity desktop) |
578 | |
579 | === added file 'plainbox/docs/changelog.rst' |
580 | --- plainbox/docs/changelog.rst 1970-01-01 00:00:00 +0000 |
581 | +++ plainbox/docs/changelog.rst 2013-03-07 16:10:38 +0000 |
582 | @@ -0,0 +1,32 @@ |
583 | +ChangeLog |
584 | +========= |
585 | + |
586 | +.. note:: |
587 | + This changelog contains only a summary of changes. For a more accurate |
588 | + accounting of development history please inspect the source history |
589 | + directly. |
590 | + |
591 | +PlainBox 0.3 (Unreleased) |
592 | +^^^^^^^^^^^^^^^^^^^^^^^^^ |
593 | + |
594 | +* Added support for all job types (manual, user-interact, user-verify, attachment, local) |
595 | +* Added support for running as another user |
596 | +* Added support for creating session checkpoints and resuming testing across reboots |
597 | +* Added support for exporting test results to JSON, plain text and XML |
598 | +* Added support for handling binary data (eg, binary attachments) |
599 | +* Added support for using sub-commands to the main plainbox executable |
600 | +* Added documentation to the project |
601 | +* Numerous internal re-factorings, changes and improvements. |
602 | +* Improved unit and integration testing coverage |
603 | + |
604 | +PlainBox 0.2 |
605 | +^^^^^^^^^^^^ |
606 | + |
607 | +* Last release made from the standalone github tree. |
608 | +* Added support for discovering dependencies and automatic dependency |
609 | + resolution (for both job dependencies and resource dependencies) |
610 | + |
611 | +PlainBox 0.1 |
612 | +^^^^^^^^^^^^ |
613 | + |
614 | +* Initial release |
615 | |
616 | === added directory 'plainbox/docs/dev' |
617 | === added file 'plainbox/docs/dev/architecture.rst' |
618 | --- plainbox/docs/dev/architecture.rst 1970-01-01 00:00:00 +0000 |
619 | +++ plainbox/docs/dev/architecture.rst 2013-03-07 16:10:38 +0000 |
620 | @@ -0,0 +1,337 @@ |
621 | +PlainBox Architecture |
622 | +===================== |
623 | + |
624 | +This document explains the architecture of PlainBox internals. It should be |
625 | +always up-to-date and accurate to the extent of the scope of this overview. |
626 | + |
627 | +General design considerations |
628 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
629 | + |
630 | +PlainBox is a reimplementation of CheckBox that replaces a reactor / event / |
631 | +plugin architecture with a monolithic core and tightly integrated components. |
632 | + |
633 | +The implementation models a few of the externally-visible concepts such as |
634 | +jobs, resources and resource programs but also has some additional design that |
635 | +was not present in CheckBox before. |
636 | + |
637 | +The goal of the rewrite is to provide the right model and APIs for user |
638 | +interfaces in order to build the kind of end-user solution that we could not |
639 | +build with CheckBox. |
640 | + |
641 | +This is expressed by additional functionality that is there only to provide the |
642 | +higher layers with the right data (failure reason, descriptions, etc.). The |
643 | +code is also intended to be highly testable. Test coverage at the time of |
644 | +writing this document was exceeding 80% |
645 | + |
646 | +The core requirement for the current phase of PlainBox development is feature |
647 | +parity with CheckBox and gradual shift from one to another in the daily |
648 | +responsibilities of the Hardware Certification team. Currently PlainBox |
649 | +implements a large chunk of core / essential features from CheckBox. While not |
650 | +all features are present the core is considered almost feature complete at this |
651 | +stage. |
652 | + |
653 | +Application Skeleton |
654 | +^^^^^^^^^^^^^^^^^^^^ |
655 | + |
656 | +This skeleton represents a typical application based on PlainBox. It enumerates |
657 | +the essential parts of the APIs from the point of view of an application |
658 | +developer. |
659 | + |
660 | +1. Instantiate :class:`plainbox.impl.checkbox.CheckBox` then call |
661 | + :meth:`plainbox.impl.checkbox.CheckBox.get_builtin_jobs()` to discover all |
662 | + known jobs. In the future this might be replaced by a step that obtains jobs |
663 | + from a named provider. |
664 | + |
665 | +3. Instantiate :class:`plainbox.impl.runner.JobRunner` so that we can run jobs |
666 | + |
667 | +4. Instantiate :class:`plainbox.impl.session.SessionState` so that we can keep |
668 | + track of application state. |
669 | + |
670 | + - Potentially restore an earlier, interrupted, testing session by calling |
671 | + :meth:`plainbox.impl.session.SessionState.restore()` |
672 | + |
673 | + - Potentially remove an earlier, interrupted, testing session by calling |
674 | + :meth:`plainbox.impl.session.SessionState.discard()` |
675 | + |
676 | + - Potentially start a new test session by calling |
677 | + :meth:`plainbox.impl.session.SessionState.open()` |
678 | + |
679 | +5. Allow the user to select jobs that should be executed and update session |
680 | + state by calling |
681 | + :meth:`plainbox.impl.session.SessionState.update_desired_job_list()` |
682 | + |
683 | +6. For each job in :attr:`plainbox.impl.SessionState.run_list`: |
684 | + |
685 | + 1. Check if we want to run the job (if we have a result for it from previous |
686 | + runs) or if we must run it (for jobs that cannot be persisted across |
687 | + suspend) |
688 | + |
689 | + 2. Check if the job can be started by looking at |
690 | + :meth:`plainbox.impl.session.JobState.can_start()` |
691 | + |
692 | + - optionally query for additional data on why a job cannot be started and |
693 | + present that to the user. |
694 | + |
695 | + - optionally abort the sequence and go to step 5 or the outer loop. |
696 | + |
697 | + 3. Call :meth:`plainbox.impl.runner.JobRunner.run_job()` with the current |
698 | + job and store the result. |
699 | + |
700 | + - optionally ask the user to perform some manipulation |
701 | + |
702 | + - optionally ask the user to qualify the outcome |
703 | + |
704 | + - optionally ask the user for additional comments |
705 | + |
706 | + 4. Call :meth:`plainbox.impl.session.SessionState.update_job_result()` to |
707 | + update readiness of jobs that depend on the outcome or output of current |
708 | + job. |
709 | + |
710 | + 5. Call :meth:`plainbox.impl.session.SessionState.checkpoint()` to ensure |
711 | + that testing can resume after system crash or shutdown. |
712 | + |
713 | +7. Instantiate the selected state exporter, for example |
714 | + :class:`plainbox.impl.exporters.json.JSONSessionStateExporter` so that we |
715 | + can use it to save test results. |
716 | + |
717 | + - optionally pass configuration options to customize the subset and the |
718 | + presentation of the session state |
719 | + |
720 | +8. Call |
721 | + :meth:`plainbox.impl.exporters.SessionStateExporterBase.get_session_data_subset()` |
722 | + followed by :meth:`plainbox.impl.exporters.SessionStateExporterBase.dump()` |
723 | + to save results to a file. |
724 | + |
725 | +9. Call :meth:`plainbox.impl.session.SessionState.close()` to remove any |
726 | + nonvolatile temporary storage that was needed for the session. |
727 | + |
728 | +Essential classes |
729 | +================= |
730 | + |
731 | +:class:`~plainbox.impl.session.SessionState` |
732 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
733 | + |
734 | +Class representing all state needed during a single program session. |
735 | + |
736 | +Usage |
737 | +----- |
738 | + |
739 | +The general idea is that you feed the session with a list of known jobs and |
740 | +a subset of jobs that you want to run and in return get an ordered list of |
741 | +jobs to run. |
742 | + |
743 | +It is expected that the user will select / deselect and run jobs. This |
744 | +class can react to both actions by recomputing the dependency graph and |
745 | +updating the read states accordingly. |
746 | + |
747 | +As the user runs subsequent jobs the results of those jobs are exposed to |
748 | +the session with :meth:`update_job_result()`. This can cause subsequent |
749 | +jobs to become available (not inhibited by anything). Note that there is no |
750 | +notification of changes at this time. |
751 | + |
752 | +The session does almost nothing by itself, it learns about everything by |
753 | +observing job results coming from the job runner |
754 | +(:class:`plainbox.impl.runner.JobRunner`) that applications need to |
755 | +instantiate. |
756 | + |
757 | +Suspend and resume |
758 | +------------------ |
759 | + |
760 | +The session can save check-point data after each job is executed. This |
761 | +allows the system to survive and continue after a catastrophic failure |
762 | +(broken suspend, power failure) or continue across tests that require the |
763 | +machine to reboot. |
764 | + |
765 | +.. todo:: |
766 | + |
767 | + Create a section on suspend/resume design |
768 | + |
769 | +Implementation notes |
770 | +-------------------- |
771 | + |
772 | +Internally it ties into :class:`plainbox.impl.depmgr.DependencySolver` for |
773 | +resolving dependencies. The way the session objects are used allows them to |
774 | +return various problems back to the UI level - those are all the error |
775 | +classes from :mod:`plainbox.impl.depmgr`: |
776 | + |
777 | + - :class:`plainbox.impl.depmgr.DependencyCycleError` |
778 | + |
779 | + - :class:`plainbox.impl.depmgr.DependencyDuplicateError` |
780 | + |
781 | + - :class:`plainbox.impl.depmgr.DependencyMissingError` |
782 | + |
783 | +Normally *none* of those errors should ever happen, they are only provided |
784 | +so that we don't choke when a problem really happens. Everything is checked |
785 | +and verified early before starting a job so typical unit and integration |
786 | +testing should capture broken job definitions (for example, with cyclic |
787 | +dependencies) being added to the repository. |
788 | + |
789 | +Implementation issues |
790 | +--------------------- |
791 | + |
792 | +There are two issues that are known at this time: |
793 | + |
794 | +* There is too much checkbox-specific knowledge which really belongs |
795 | + elsewhere. We are working to remove that so that non-checkbox jobs |
796 | + can be introduced later. There is a branch in progress that entirely |
797 | + removes that and moves it to a new concept called SessionController. |
798 | + In that design the session delegates understanding of results to a |
799 | + per-job session controller and exposes some APIs to alter the state |
800 | + that was previously internal (most notably a way to add new jobs and |
801 | + resources). |
802 | + |
803 | +* The way jobs are currently selected is unfortunate because of local jobs |
804 | + that can add new jobs to the system. This causes considerable complexity |
805 | + at the application level where the application must check if each |
806 | + executed job is a 'local' job and re-compute the desired_job_list. This |
807 | + should be replaced by a matcher function that can be passed to |
808 | + SessionState once so that desired_job_list is re-evaluated internally |
809 | + whenever job_list changes. |
810 | + |
811 | + |
812 | +:class:`~plainbox.impl.job.JobDefinition` |
813 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
814 | + |
815 | +:term:`CheckBox` has a concept of a :term:`job`. Jobs are named units of |
816 | +testing work that can be executed. Typical jobs range from automated CPU power |
817 | +management checks, BIOS tests, semi-automated peripherals testing to all manual |
818 | +validation by following a script (intended for humans). |
819 | + |
820 | +Jobs are distributed in plain text files, formated as a loose RFC822 documents |
821 | +where typically a single text file contains a few dozen different jobs that |
822 | +belong to one topic, for example, all bluetooth tests. |
823 | + |
824 | +Tests have a number of properties that will not be discussed in detail here, |
825 | +they are all documented in :class:`plainbox.impl.job.JobDefinition`. From the |
826 | +architecture point of view the four essential properties of a job are *name*, |
827 | +*plugin* and *requires* and *depends*. Those are discussed in detail below. |
828 | + |
829 | +JobDefinition.name |
830 | +------------------ |
831 | + |
832 | +The *name* field must be unique and is referred to by other parts of the system |
833 | +(such as whitelists). Typically jobs follow a simple naming pattern |
834 | +'category/detail', eg, 'networking/modem_connection'. The name must be _unique_ |
835 | +and this is enforced by the core. |
836 | + |
837 | +JobDefinition.plugin |
838 | +-------------------- |
839 | + |
840 | +The *plugin* field is an archaism from CheckBox and a misnomer (as PlainBox |
841 | +does not have any plugins). In the CheckBox architecture it would instruct the |
842 | +core which plugin should process that job. In PlainBox it is a way to encode |
843 | +what type of a job is being processed. There is a finite set of types that are |
844 | +documented below. |
845 | + |
846 | +plugin == "shell" |
847 | +################# |
848 | + |
849 | +This value is used for fully automated jobs. Everything the job needs to do is |
850 | +automated (preparation, execution, verification) and fully handled by the |
851 | +command that is associated with a job. |
852 | + |
853 | +plugin == "manual" |
854 | +################## |
855 | + |
856 | +This value is used for fully manual jobs. It has no special handling in the core |
857 | +apart from requiring a human-provided outcome (pass/fail classification) |
858 | + |
859 | +plugin == "local" |
860 | +################# |
861 | + |
862 | +This value is used for special job generator jobs. The output of such jobs is |
863 | +interpreted as additional jobs and is identical in effect to loading such jobs |
864 | +from a job definition file. |
865 | + |
866 | +There are two practical uses for such jobs: |
867 | + |
868 | +* Some local jobs are used to generate a number of jobs for each object. |
869 | + This is needed where the tested machine may have a number of such objects |
870 | + and each requires unique testing. A good example is a computer where all |
871 | + network tests are explicitly "instantiated" for each network card |
872 | + present. |
873 | + |
874 | + This is a valid use case but is rather unfortunate for architecture of |
875 | + PlainBox and there is a desire to replace it with equally-expressive |
876 | + pattern jobs. The advantage is that unlike local jobs (which cannot be |
877 | + "discovered" without enduring any potential side effects that may be |
878 | + caused by the job script command) pattern jobs would allow the core to |
879 | + determine the names of jobs that can be generated and, for example, |
880 | + automatically determine that a pattern job needs to be executed as a |
881 | + dependency of a phantom (yet undetermined) job with a given name. |
882 | + |
883 | + The solution with "pattern" jobs may be executed in future phases of |
884 | + PlainBox development. Currently there is no support for that at all. |
885 | + |
886 | + Currently PlainBox cannot determine job dependencies across local jobs. |
887 | + That is, unless a local job is explicitly requested (in the desired job |
888 | + list) PlainBox will not be able to run a job that is generated by a local |
889 | + job at all and will treat it as if that job never existed. |
890 | + |
891 | +* Some local jobs are used to create a form of informal "category". |
892 | + Typically all such jobs have a leading and trailing double underscore, |
893 | + for example '__audio__'. This is currently being used by CheckBox for |
894 | + building a hierarchical tree of tests that the user may select. |
895 | + |
896 | + Since this has the same flaws as described above (for pattern jobs) it |
897 | + will likely be replaced by an explicit category field that can be |
898 | + specified each job. |
899 | + |
900 | +plugin == "resource" |
901 | +#################### |
902 | + |
903 | +This value is used for special "data" or "environment" jobs. Their output is |
904 | +parsed as a list of RFC822 records and is kept by the core during a testing session. |
905 | + |
906 | +They are primarily used to determine if a given job can be started. For |
907 | +example, a particular bluetooth test may use the _requires_ field to indicate |
908 | +that it depends (via a resource dependency) on a job that enumerates devices |
909 | +and that one of those devices must be a bluetooth device. |
910 | + |
911 | +plugin == "user-interact" |
912 | +######################### |
913 | + |
914 | +For all intents and purposes it is equivalent to "manual". The actual |
915 | +difference is that a user is expected to perform some physical manipulation |
916 | +before an automated test. |
917 | + |
918 | +plugin == "user-verify" |
919 | +####################### |
920 | + |
921 | +For all intents and purposes it is equivalent to "manual". The actual |
922 | +difference is that a user is expected to perform manual verification after an |
923 | +automated test. |
924 | + |
925 | +JobDefinition.depends |
926 | +--------------------- |
927 | + |
928 | +The *depends* field is used to express dependencies between two jobs. If job A |
929 | +has depends on job B then A cannot start if B is not both finished and |
930 | +successful. PlainBox understands this dependency and can automatically sort and |
931 | +execute jobs in proper order. In many places of the code this is referred to as |
932 | +a "direct dependency" (in contrast to "resource dependency") |
933 | + |
934 | +The actual syntax is not strictly specified, PlainBox interprets this field as |
935 | +a list of tokens delimited by comma or any whitespace (including newlines). |
936 | + |
937 | +A job may depend on any number of other jobs. There are a number of failure |
938 | +modes associated with this feature, all of which are detected and handled by |
939 | +PlainBox. Typically they only arise when during CheckBox job development |
940 | +(editing actual job files) and are always a sign of a human error. No released |
941 | +version of CheckBox or PlainBox should ever encounter any of those issues. |
942 | + |
943 | +The actual problems are: |
944 | + |
945 | +* dependency cycles, where job either directly or indirectly depends on |
946 | + itself |
947 | + |
948 | +* missing dependencies where some job refers to a job that is not defined |
949 | + anywhere. |
950 | + |
951 | +* duplicate jobs where two jobs with the same name (but different |
952 | + definition) are being introduced to the system. |
953 | + |
954 | +In all of those cases the core removes the offending job and tries to work |
955 | +regardless of the problem. This is intended more as a development aid rather |
956 | +than a reliability feature as no released versions of either project should |
957 | +cause this problem. |
958 | |
959 | === added file 'plainbox/docs/dev/index.rst' |
960 | --- plainbox/docs/dev/index.rst 1970-01-01 00:00:00 +0000 |
961 | +++ plainbox/docs/dev/index.rst 2013-03-07 16:10:38 +0000 |
962 | @@ -0,0 +1,14 @@ |
963 | +Developers |
964 | +========== |
965 | + |
966 | +The PlainBox project hopes to be a friendly developer environment. We invested |
967 | +in a lot of tools to make your life easier. Despite being a business-centric |
968 | +software project we welcome and encourage contributions from both Canonical and |
969 | +Community members. |
970 | + |
971 | +.. toctree:: |
972 | + :maxdepth: 3 |
973 | + |
974 | + intro.rst |
975 | + architecture.rst |
976 | + reference.rst |
977 | |
978 | === added file 'plainbox/docs/dev/intro.rst' |
979 | --- plainbox/docs/dev/intro.rst 1970-01-01 00:00:00 +0000 |
980 | +++ plainbox/docs/dev/intro.rst 2013-03-07 16:10:38 +0000 |
981 | @@ -0,0 +1,238 @@ |
982 | +Getting started with development |
983 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
984 | + |
985 | +PlainBox uses python3 for development. The core is really system independent |
986 | +but you will need Ubuntu to really make the best of it and experience it as we |
987 | +do. We encourage everyone to use the most recent Ubuntu release for |
988 | +development. Usually this brings the best, most recent tools without having to |
989 | +search for software on the Internet. |
990 | + |
991 | +PlainBox has almost no dependencies itself, almost, because we depend on the |
992 | +mighty :term:`CheckBox` project to provide us with a lot of existing |
993 | +infrastructure. Testing PlainBox requires additional packages and some |
994 | +non-packaged software. You will typically want to install it and take advantage |
995 | +of the integration we provide. |
996 | + |
997 | +.. note:: |
998 | + |
999 | + If you are working with the source please be aware that PlainBox requires |
1000 | + an installed copy of CheckBox. CheckBox in turns is has many scripts that |
1001 | + depend on various system packages, including python packages that cannot be |
1002 | + installed from pypi. If you were planning on using :command:`virtualenv` |
1003 | + then please make sure to create it with the ``--system-site-packages`` |
1004 | + option. |
1005 | + |
1006 | +Get the tools |
1007 | +------------- |
1008 | + |
1009 | +First, you need to install the basic development tools: |
1010 | + |
1011 | +.. code-block:: bash |
1012 | + |
1013 | + $ sudo apt-get install bzr python3-setuptools python3-dev python3-doc python3-sphinx python-virtualenv |
1014 | + |
1015 | +While developing PlainBox you will often need to run potentially dangerous |
1016 | +commands on your system, such as asking it to suspend and wake up |
1017 | +automatically. We also need to support a range of Ubuntu releases, going all |
1018 | +the way back to Ubuntu 12.04. This may cause compatibility issues that are |
1019 | +unnoticed all until they hit our CI system. To minimize this PlainBox uses |
1020 | +:term:`Vagrant` to create lightweight execution environments that transparently |
1021 | +share your source tree and allow you to quickly create and share testing |
1022 | +environment that can be deployed by any developer in minutes. Vagrant uses |
1023 | +:term:`VirtualBox` and while both are packaged in Ubuntu, unless you are |
1024 | +running Ubuntu 13.04 you should download and install the software from their |
1025 | +upstream projects. |
1026 | + |
1027 | +If you are running Ubuntu 13.04 |
1028 | + |
1029 | +.. code-block:: bash |
1030 | + |
1031 | + $ sudo apt-get install vagrant |
1032 | + |
1033 | +If you are running earlier version of Ubuntu follow those two links to get started: |
1034 | + |
1035 | + * http://downloads.vagrantup.com/ |
1036 | + * https://www.virtualbox.org/wiki/Downloads |
1037 | + |
1038 | +If you have not installed VirtualBox before, you must add yourself to the |
1039 | +``vboxusers`` group, log out and log back in again. |
1040 | + |
1041 | +.. code-block:: bash |
1042 | + |
1043 | + $ sudo usermod -G vboxusers -a $USER |
1044 | + |
1045 | +Get the source |
1046 | +-------------- |
1047 | + |
1048 | +Now that you have all the tools, you can get the source: |
1049 | + |
1050 | +.. code-block:: bash |
1051 | + |
1052 | + $ bzr branch lp:checkbox |
1053 | + |
1054 | +.. note:: |
1055 | + If you would rather use ``git`` you can also do that (and in fact, some of |
1056 | + us already do). Head to `git-lp homepage <http://zyga.github.com/git-lp/>`_ |
1057 | + and follow the guide there to use git-lp with this project. |
1058 | + |
1059 | +Initialize virtualenv |
1060 | +--------------------- |
1061 | + |
1062 | +PlainBox will use a few unpackaged and bleeding-edge releases from :term:`pypi` |
1063 | +those are installed by additional script. By default the script assumes you |
1064 | +have a /ramdisk directory but you can pass any path as an argument for an |
1065 | +alternate location. |
1066 | + |
1067 | +.. code-block:: bash |
1068 | + |
1069 | + $ ./mk-venv.sh |
1070 | + |
1071 | +After everything is set up you can activate the virtualenv environment with the |
1072 | +dot command. Note that there *is* a space between the dot and the forward |
1073 | +slash. You can repeat this command in as many shells as you like. |
1074 | + |
1075 | +.. code-block:: bash |
1076 | + |
1077 | + $ . /ramdisk/venv/bin/activate |
1078 | + |
1079 | +Once virtualenv is activated your shell prompt will be changed to reflect that. |
1080 | +You should now be able to run :command:`plainbox --help` to ensure everything |
1081 | +is working properly. |
1082 | + |
1083 | +Initialize vagrant |
1084 | +------------------ |
1085 | + |
1086 | +Vagrant allows us to ship a tiny text file :file:`Vagrantfile` that describes |
1087 | +the development and testing environment. This file tells :command:`vagrant` how |
1088 | +to prepare a virtual machine for testing. If you never used it before you may |
1089 | +want to keep a tab open on `vagrant getting started guide |
1090 | +<http:`http://docs.vagrantup.com/v1/docs/getting-started/index.html>`_ |
1091 | + |
1092 | +We did all the hard work so that you don't have to, to get everything ready |
1093 | +just run one command: |
1094 | + |
1095 | +.. code-block:: bash |
1096 | + |
1097 | + $ vagrant up |
1098 | + |
1099 | +This will download vanilla Ubuntu cloud images, initialize VirtualBox, |
1100 | +provision virtual machines (one for each supported Ubuntu release) and allow |
1101 | +you to ssh into them for testing with one command. |
1102 | + |
1103 | +This will take a moment, depending on the speed of your network. Once that is |
1104 | +done you should be able to log into, say, ``precise`` and run |
1105 | +:command:`plainbox --help` to see if everything is all right. |
1106 | + |
1107 | +.. code-block:: bash |
1108 | + |
1109 | + $ vagrant ssh precise |
1110 | + vagrant@vagrant-ubuntu-precise-32:~$ plainbox --help |
1111 | + usage: plainbox [-h] [-v] {run,special,self-test} ... |
1112 | + |
1113 | + positional arguments: |
1114 | + {run,special,self-test} |
1115 | + run run a test job |
1116 | + special special/internal commands |
1117 | + self-test run integration tests |
1118 | + |
1119 | + optional arguments: |
1120 | + -h, --help show this help message and exit |
1121 | + -v, --version show program's version number and exit |
1122 | + $ exit |
1123 | + |
1124 | +Running PlainBox tests |
1125 | +^^^^^^^^^^^^^^^^^^^^^^ |
1126 | + |
1127 | +PlainBox is designed to be testable so it would be silly if it was hard to run |
1128 | +tests. Actually, there are many different ways to run tests. They all run the |
1129 | +same code so don't worry. |
1130 | + |
1131 | +To test the current code you are working on you can: |
1132 | + |
1133 | +- Run the :command:`./test-in-vagrant.sh` from the plainbox directory. This |
1134 | + will take the longes but will go over *all* the tests on *all* the supported |
1135 | + versions of Ubuntu. It will run CheckBox unit-tests, PlainBox unit-tests and |
1136 | + it will even run integration tests that actually execute jobs. |
1137 | + |
1138 | +- Run :command:`plainbox self-test --unit-tests` or |
1139 | + :command:`plainbox self-test --integration-tests`. This will execute all the |
1140 | + tests right on your machine, without any virtualization (well, unless you do |
1141 | + that after running :command:`vagrant ssh`). Typically you would run unit |
1142 | + tests while being in a ``virtualenv`` with the ``plainbox`` package in |
1143 | + development mode, as created by running :command:`python setup.py develop` |
1144 | + |
1145 | +- Run :command:`./setup.py test` this will install any required test |
1146 | + dependencies from pypi and run unit tests. |
1147 | + |
1148 | +- Run the script :command:`test-with-coverage.sh` while being in a virtualenv. |
1149 | + This will also compute testing code coverage and is very much recommended |
1150 | + while working on new code and tests. |
1151 | + |
1152 | +Submitting Patches |
1153 | +^^^^^^^^^^^^^^^^^^ |
1154 | + |
1155 | +We use `Launchpad <https://launchpad.net>`_ for most of our project management. |
1156 | +All code changes should be submitted as merge requests. Launchpad has |
1157 | +`extensive documentation <https://help.launchpad.net/>`_ on how to use various |
1158 | +facilities it provides. |
1159 | + |
1160 | +In general we are open to contributions but we reserve the right to reject |
1161 | +patches if they don't fit into the needs of the :term:`Hardware Certification`. |
1162 | +If you have an idea go and talk to us on :abbr:`IRC (Internet Relay Chat)` on |
1163 | +the `#ubuntu-quality <irc://freenode.net:8001/#ubuntu-quality>`_ channel. |
1164 | + |
1165 | +We have some basic rules patch acceptance: |
1166 | + |
1167 | +0. Be prepare to alter your changes. |
1168 | + |
1169 | + This is a meta-rule. One of the points of code reviews is to improve the |
1170 | + proposal. That implies the proposal may need to change. You must be prepared |
1171 | + and able to change your code after getting feedback. |
1172 | + |
1173 | + To do that efficiently you must structure your work in a way where each |
1174 | + committed change works for you rather than against you. The rules listed |
1175 | + below are a reflection of this. |
1176 | + |
1177 | +1. Each patch should be a single logical change that can be applied. |
1178 | + |
1179 | + Don't clump lots of changes into one big patch. That will only delay review, |
1180 | + make accepting feedback difficult and annoying. This may mean that the history |
1181 | + has many small patches that can land in trunk in a FIFO mode. The oldest patch |
1182 | + of your branch may be allowed to land and should make sense. This has |
1183 | + implications on how general code editing should be performed. If you break some |
1184 | + APIs then firsts introduce a working replacement, then change usage of the API |
1185 | + and lastly remove any dead code. |
1186 | + |
1187 | +2. Don't keep junk patches in your branch. |
1188 | + |
1189 | + Don't keep patches such as "fix typo" in your branch, that makes the review |
1190 | + process more difficult as some reviewers will read your patches one by one. |
1191 | + This is especially important if your changes are substantial. |
1192 | + |
1193 | +3. Don't merge with trunk, rebase on trunk. |
1194 | + |
1195 | + This way you can keep your local delta as a collection of meaningful, |
1196 | + readable patches. Reading the full diff and following the complex merge |
1197 | + history (especially for long-lived branches) is difficult in practice. |
1198 | + |
1199 | +4. Keep unrelated changes in separate branches. |
1200 | + |
1201 | + If you ware working on something and found a bug that needed immediate |
1202 | + fixing, typo or anything else that is small and quick to fix, do it. Then |
1203 | + take that patch out of your development branch and into a dedicated branch |
1204 | + and propose it. As the small change is reviewed and lands you can remove |
1205 | + that patch from your development branch. |
1206 | + |
1207 | + This is intended to help both the developer and the reviewer. Seemingly |
1208 | + trivial patches may turn out to be more complicated than initially assumed |
1209 | + (and may have their own feedback cycle and iterations). The reviewer can |
1210 | + focus on logical changes and not on a collection of unrelated alterations. |
1211 | + Lastly we may need to apply some fixes to other supported branches and |
1212 | + release those. |
1213 | + |
1214 | +5. Don't propose untested code. |
1215 | + |
1216 | + We generally like tests for new code. This is not a super-strict requirement |
1217 | + but unless writing tests is incredibly hard we'd rather wait. If testing is |
1218 | + hard we'd rather invest some time in refactoring the code or building |
1219 | + required support infrastructure. |
1220 | |
1221 | === added file 'plainbox/docs/dev/reference.rst' |
1222 | --- plainbox/docs/dev/reference.rst 1970-01-01 00:00:00 +0000 |
1223 | +++ plainbox/docs/dev/reference.rst 2013-03-07 16:10:38 +0000 |
1224 | @@ -0,0 +1,154 @@ |
1225 | +.. _code_reference: |
1226 | + |
1227 | +.. toctree:: |
1228 | + :maxdepth: 2 |
1229 | + |
1230 | +Code reference |
1231 | +============== |
1232 | + |
1233 | +.. note:: |
1234 | + |
1235 | + Unless stated otherwise all API is unstable. PlainBox does not offer |
1236 | + general API stability at this time. |
1237 | + |
1238 | +.. automodule:: plainbox |
1239 | + :members: |
1240 | + :undoc-members: |
1241 | + :show-inheritance: |
1242 | + |
1243 | +.. automodule:: plainbox.public |
1244 | + :members: |
1245 | + :undoc-members: |
1246 | + :show-inheritance: |
1247 | + |
1248 | +.. automodule:: plainbox.abc |
1249 | + :members: |
1250 | + :undoc-members: |
1251 | + :show-inheritance: |
1252 | + |
1253 | +.. automodule:: plainbox.tests |
1254 | + :members: |
1255 | + :undoc-members: |
1256 | + :show-inheritance: |
1257 | + |
1258 | +.. automodule:: plainbox.testing_utils |
1259 | + :members: |
1260 | + :undoc-members: |
1261 | + :show-inheritance: |
1262 | + |
1263 | +.. automodule:: plainbox.testing_utils.cwd |
1264 | + :members: |
1265 | + :undoc-members: |
1266 | + :show-inheritance: |
1267 | + |
1268 | +.. automodule:: plainbox.testing_utils.io |
1269 | + :members: |
1270 | + :undoc-members: |
1271 | + :show-inheritance: |
1272 | + |
1273 | +.. automodule:: plainbox.testing_utils.testcases |
1274 | + :members: |
1275 | + :undoc-members: |
1276 | + :show-inheritance: |
1277 | + |
1278 | +.. automodule:: plainbox.vendor |
1279 | + :members: |
1280 | + |
1281 | +.. automodule:: plainbox.vendor.extcmd |
1282 | + :members: |
1283 | + :undoc-members: |
1284 | + :show-inheritance: |
1285 | + |
1286 | +.. automodule:: plainbox.impl |
1287 | + :members: |
1288 | + :undoc-members: |
1289 | + :show-inheritance: |
1290 | + |
1291 | +.. automodule:: plainbox.impl.commands |
1292 | + :members: |
1293 | + :undoc-members: |
1294 | + :show-inheritance: |
1295 | + |
1296 | +.. automodule:: plainbox.impl.commands.selftest |
1297 | + :members: |
1298 | + :undoc-members: |
1299 | + :show-inheritance: |
1300 | + |
1301 | +.. automodule:: plainbox.impl.exporter |
1302 | + :members: |
1303 | + :undoc-members: |
1304 | + :show-inheritance: |
1305 | + |
1306 | +.. automodule:: plainbox.impl.exporter.json |
1307 | + :members: |
1308 | + :undoc-members: |
1309 | + :show-inheritance: |
1310 | + |
1311 | +.. automodule:: plainbox.impl.exporter.rfc822 |
1312 | + :members: |
1313 | + :undoc-members: |
1314 | + :show-inheritance: |
1315 | + |
1316 | +.. automodule:: plainbox.impl.exporter.text |
1317 | + :members: |
1318 | + :undoc-members: |
1319 | + :show-inheritance: |
1320 | + |
1321 | +.. automodule:: plainbox.impl.box |
1322 | + :members: |
1323 | + :undoc-members: |
1324 | + :show-inheritance: |
1325 | + |
1326 | +.. automodule:: plainbox.impl.checkbox |
1327 | + :members: |
1328 | + :undoc-members: |
1329 | + :show-inheritance: |
1330 | + |
1331 | +.. automodule:: plainbox.impl.depmgr |
1332 | + :members: |
1333 | + :undoc-members: |
1334 | + :show-inheritance: |
1335 | + |
1336 | +.. automodule:: plainbox.impl.integration_tests |
1337 | + :members: |
1338 | + :undoc-members: |
1339 | + :show-inheritance: |
1340 | + |
1341 | +.. automodule:: plainbox.impl.job |
1342 | + :members: |
1343 | + :undoc-members: |
1344 | + :show-inheritance: |
1345 | + |
1346 | +.. automodule:: plainbox.impl.mock_job |
1347 | + :members: |
1348 | + :undoc-members: |
1349 | + :show-inheritance: |
1350 | + |
1351 | +.. automodule:: plainbox.impl.resource |
1352 | + :members: |
1353 | + :undoc-members: |
1354 | + :show-inheritance: |
1355 | + |
1356 | +.. automodule:: plainbox.impl.result |
1357 | + :members: |
1358 | + :undoc-members: |
1359 | + :show-inheritance: |
1360 | + |
1361 | +.. automodule:: plainbox.impl.rfc822 |
1362 | + :members: |
1363 | + :show-inheritance: |
1364 | + |
1365 | +.. automodule:: plainbox.impl.runner |
1366 | + :members: |
1367 | + :undoc-members: |
1368 | + :show-inheritance: |
1369 | + |
1370 | +.. automodule:: plainbox.impl.session |
1371 | + :members: |
1372 | + :undoc-members: |
1373 | + :show-inheritance: |
1374 | + |
1375 | +.. automodule:: plainbox.impl.testing_utils |
1376 | + :members: |
1377 | + :undoc-members: |
1378 | + :show-inheritance: |
1379 | |
1380 | === added file 'plainbox/docs/glossary.rst' |
1381 | --- plainbox/docs/glossary.rst 1970-01-01 00:00:00 +0000 |
1382 | +++ plainbox/docs/glossary.rst 2013-03-07 16:10:38 +0000 |
1383 | @@ -0,0 +1,104 @@ |
1384 | +Glossary |
1385 | +======== |
1386 | + |
1387 | +.. glossary:: |
1388 | + |
1389 | + hardware certification |
1390 | + |
1391 | + A process of ensuring that a specific device works well with Ubuntu. |
1392 | + For more details see our certification program: |
1393 | + |
1394 | + http://www.canonical.com/engineering-services/certification/hardware-certification |
1395 | + |
1396 | + hardware certification team |
1397 | + |
1398 | + A team inside Canonical working on :term:`Hardware Certification`. |
1399 | + |
1400 | + CheckBox |
1401 | + |
1402 | + CheckBox is a hardware testing tool developed by Canonical for |
1403 | + certifying hardware with Ubuntu. CheckBox is free software and is |
1404 | + available at http://launchpad.net/checkbox. The ``checkbox`` package is |
1405 | + pre-installed on all Ubuntu systems |
1406 | + |
1407 | + PlainBox |
1408 | + |
1409 | + PlainBox is a rewrite of CheckBox with the aim of improving internal |
1410 | + architecture, testability, robustness, quality and speed. It is |
1411 | + currently under active development. It is not pre-installed on Ubuntu. |
1412 | + It is developed inside CheckBox code repository. |
1413 | + |
1414 | + white list |
1415 | + |
1416 | + White lists are text files used by CheckBox to select Jobs for |
1417 | + execution. They can include simple regular expressions to match and |
1418 | + pick many similar jobs at once. |
1419 | + |
1420 | + job |
1421 | + |
1422 | + Jobs are smallest units of testing that can be performed by either |
1423 | + CheckBox or PlainBox. All jobs have an unique name. There are many |
1424 | + types of jobs, some are fully automated others are fully manual. Some |
1425 | + jobs are only an implementation detail and a part of the internal |
1426 | + architecture of CheckBox |
1427 | + |
1428 | + resources |
1429 | + |
1430 | + Resources are collections of key-value data sets that are generated by |
1431 | + special resource jobs. They are extensively used to indicate hardware |
1432 | + or software dependencies. For example a bluetooth test may indicate it |
1433 | + requires bluetooth hardware and appropriate software packages |
1434 | + installed. |
1435 | + |
1436 | + requirement program |
1437 | + |
1438 | + Requirement programs are small (one to few lines) programs that use a |
1439 | + subset of python to execute some code against resources. They are what |
1440 | + actually describes the relationship of a Job to some Resources. For |
1441 | + example a resource program ``package.name == "bluez"`` indicates that |
1442 | + at least one resource generated by the ``package`` job has a key |
1443 | + ``name`` equal to the string ``bluez``. |
1444 | + |
1445 | + attachment |
1446 | + |
1447 | + Attachments are a special type of a Job that can creates an attachment |
1448 | + record in the submission.xml file. They are commonly used to include |
1449 | + basic system information files and output of certain commands which can |
1450 | + aid in system certification. |
1451 | + |
1452 | + certification website |
1453 | + |
1454 | + The website https://certification.canonical.com/ |
1455 | + |
1456 | + Canonical ID |
1457 | + |
1458 | + A number assigned to the specific device (laptop, desktop or server) by |
1459 | + Canonical. This number is used on the Certification Website and by the |
1460 | + Hardware Certification Team. It is an internal bookkeeping identifier |
1461 | + used in our labs. |
1462 | + |
1463 | + Secure ID |
1464 | + |
1465 | + An identifier, similar to Canonical ID, used for hardware |
1466 | + certification. This identifier is used when interacting with the |
1467 | + Certification Website, it does not reveal anything about the actual |
1468 | + hardware (like the manufacturer name or device name) |
1469 | + |
1470 | + pypi |
1471 | + |
1472 | + The Python Package Index where any developer can share their python |
1473 | + programs and libraries. Pypi is available at: |
1474 | + https://pypi.python.org/pypi. |
1475 | + |
1476 | + Vagrant |
1477 | + |
1478 | + Vagrant is command line program intended for software developers to |
1479 | + quickly create portable virtual environments for testing their software |
1480 | + in a production operating system. Vagrant is free software and is |
1481 | + available at http://www.vagrantup.com/ |
1482 | + |
1483 | + VirtualBox |
1484 | + |
1485 | + VirtualBox is a free, powerful desktop vitalization software. |
1486 | + VirtualBox is available in the Ubuntu Software Center and at |
1487 | + https://www.virtualbox.org/ |
1488 | |
1489 | === modified file 'plainbox/docs/index.rst' |
1490 | --- plainbox/docs/index.rst 2013-02-22 16:26:25 +0000 |
1491 | +++ plainbox/docs/index.rst 2013-03-07 16:10:38 +0000 |
1492 | @@ -3,15 +3,56 @@ |
1493 | You can adapt this file completely to your liking, but it should at least |
1494 | contain the root `toctree` directive. |
1495 | |
1496 | -Welcome to PlainBox's documentation! |
1497 | -==================================== |
1498 | - |
1499 | -Contents: |
1500 | +PlainBox |
1501 | +======== |
1502 | + |
1503 | +:term:`PlainBox` is a hardware testing tool useful for certifying laptops, |
1504 | +desktops and servers with Ubuntu. It is a replacement for the current |
1505 | +certification tool, :term:`CheckBox`. |
1506 | + |
1507 | +PlainBox *complements* CheckBox. It uses all the hardware test definitions, |
1508 | +scripts and libraries from CheckBox. PlainBox is currently in **alpha** stages, |
1509 | +having mostly but not entirely complete core and a developer-centric command |
1510 | +line interface. |
1511 | + |
1512 | +Installation |
1513 | +^^^^^^^^^^^^ |
1514 | + |
1515 | +PlainBox can be installed from a :abbr:`PPA (Personal Package Archive)` |
1516 | +(recommended) or :abbr:`pypi (python package index)` on Ubuntu Precise (12.04) |
1517 | +or newer. |
1518 | + |
1519 | +.. code-block:: bash |
1520 | + |
1521 | + $ sudo add-apt-repository ppa:checkbox-dev/ppa && sudo apt-get update && sudo apt-get install plainbox |
1522 | + |
1523 | + |
1524 | +Testing your hardware |
1525 | +^^^^^^^^^^^^^^^^^^^^^ |
1526 | + |
1527 | +To test your hardware with the default set of tests run this command. |
1528 | + |
1529 | +.. code-block:: bash |
1530 | + |
1531 | + $ plainbox run --whitelist=default --output-format=xml --output-file=submission.xml |
1532 | + |
1533 | +The :file:`submission.xml` you get in the end can be submitted to the |
1534 | +:term:`certification website`. For more details see :ref:`usage` |
1535 | + |
1536 | +.. todo:: |
1537 | + This example is bad because it is fake. We should improve the core so that |
1538 | + a whitelist can referred to by name alone (not by a full path). |
1539 | + |
1540 | +Table of contents |
1541 | +================= |
1542 | |
1543 | .. toctree:: |
1544 | :maxdepth: 2 |
1545 | |
1546 | - |
1547 | + usage.rst |
1548 | + dev/index.rst |
1549 | + glossary.rst |
1550 | + changelog.rst |
1551 | |
1552 | Indices and tables |
1553 | ================== |
1554 | @@ -19,4 +60,3 @@ |
1555 | * :ref:`genindex` |
1556 | * :ref:`modindex` |
1557 | * :ref:`search` |
1558 | - |
1559 | |
1560 | === added file 'plainbox/docs/usage.rst' |
1561 | --- plainbox/docs/usage.rst 1970-01-01 00:00:00 +0000 |
1562 | +++ plainbox/docs/usage.rst 2013-03-07 16:10:38 +0000 |
1563 | @@ -0,0 +1,69 @@ |
1564 | +.. _usage: |
1565 | + |
1566 | +Usage |
1567 | +===== |
1568 | + |
1569 | +Currently :term:`PlainBox` has no graphical user interface. To use it you need |
1570 | +to use the command line. |
1571 | + |
1572 | +Basically there is just one command that does everything we can do so far, that |
1573 | +is :command:`plainbox run`. It has a number of options that tell it which |
1574 | +:term:`job` to run and what to do with results. |
1575 | + |
1576 | +PlainBox has built-in help system so running :command:`plainbox run --help` |
1577 | +will give you instant information about all the various arguments and options |
1578 | +that are available. This document is not intended to replace that. |
1579 | + |
1580 | +Running a specific job |
1581 | +^^^^^^^^^^^^^^^^^^^^^^ |
1582 | + |
1583 | +To run a specific :term:`job` pass it to the ``--include-pattern`` or ``-i`` |
1584 | +option. |
1585 | + |
1586 | +For example, to run the ``cpu/scaling_test`` job: |
1587 | + |
1588 | +.. code-block:: bash |
1589 | + |
1590 | + $ plainbox run -i cpu/scaling_test |
1591 | + |
1592 | +.. note:: |
1593 | + |
1594 | + The option ``-i`` can be provided any number of times. |
1595 | + |
1596 | +Running jobs related to a specific area |
1597 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
1598 | + |
1599 | +PlainBox has no concept of job categories but you can simulate that by |
1600 | +running all jobs that follow a specific naming pattern. For example, to run |
1601 | +all of the USB tests you can run the following command: |
1602 | + |
1603 | +.. code-block:: bash |
1604 | + |
1605 | + $ plainbox run -i 'usb/' |
1606 | + |
1607 | +Running a white list |
1608 | +^^^^^^^^^^^^^^^^^^^^ |
1609 | + |
1610 | +To run a :term:`white list` pass the ``--whitelist`` or ``-w`` option. |
1611 | + |
1612 | +For example, to run the default white list run: |
1613 | + |
1614 | +.. code-block:: bash |
1615 | + |
1616 | + $ plainbox run -w default |
1617 | + |
1618 | +Saving test results as XML |
1619 | +^^^^^^^^^^^^^^^^^^^^^^^^^^ |
1620 | + |
1621 | +To send test results to the :term:`certification website` you need to pass two |
1622 | +additional options: |
1623 | + |
1624 | +1. ``--output-format=xml`` |
1625 | +2. ``--output-file=NAME`` where *NAME* is a file name |
1626 | + |
1627 | +For example, to get the default certification tests ready to be submitted |
1628 | +run this command: |
1629 | + |
1630 | +.. code-block:: bash |
1631 | + |
1632 | + $ plainbox run -w default -f xml -o submission.xml |
1633 | |
1634 | === modified file 'plainbox/plainbox/__init__.py' |
1635 | --- plainbox/plainbox/__init__.py 2012-11-29 00:59:03 +0000 |
1636 | +++ plainbox/plainbox/__init__.py 2013-03-07 16:10:38 +0000 |
1637 | @@ -18,13 +18,13 @@ |
1638 | # along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
1639 | |
1640 | """ |
1641 | -plainbox |
1642 | -======== |
1643 | +:mod:`plainbox` -- main package |
1644 | +=============================== |
1645 | |
1646 | Simple checkbox redesign, without the complex message passing |
1647 | |
1648 | -All public API is in the 'public' module. |
1649 | -All abstract base classes are in the 'abc' module. |
1650 | +All public API is in :mod:`plainbox.public`. |
1651 | +All abstract base classes are in :mod:`plainbox.abc`. |
1652 | """ |
1653 | |
1654 | import sys |
1655 | |
1656 | === modified file 'plainbox/plainbox/abc.py' |
1657 | --- plainbox/plainbox/abc.py 2012-11-29 18:40:46 +0000 |
1658 | +++ plainbox/plainbox/abc.py 2013-03-07 16:10:38 +0000 |
1659 | @@ -18,10 +18,8 @@ |
1660 | # along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
1661 | |
1662 | """ |
1663 | -plainbox.abc |
1664 | -============ |
1665 | - |
1666 | -Abstract base classes used by plainbox |
1667 | +:mod:`plainbox.abc` -- abstract base classes |
1668 | +============================================ |
1669 | |
1670 | Those classes are actually implemented in the plainbox.impl package. This |
1671 | module is here so that the essential API concepts are in a single spot and are |
1672 | |
1673 | === modified file 'plainbox/plainbox/impl/__init__.py' |
1674 | --- plainbox/plainbox/impl/__init__.py 2012-11-19 10:45:46 +0000 |
1675 | +++ plainbox/plainbox/impl/__init__.py 2013-03-07 16:10:38 +0000 |
1676 | @@ -18,10 +18,12 @@ |
1677 | # along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
1678 | |
1679 | """ |
1680 | -plainbox.impl |
1681 | -============= |
1682 | - |
1683 | - * THIS MODULE DOES NOT HAVE STABLE PUBLIC API * |
1684 | +:mod:`plainbox.impl` -- implementation package |
1685 | +============================================== |
1686 | + |
1687 | +.. warning:: |
1688 | + |
1689 | + THIS MODULE DOES NOT HAVE STABLE PUBLIC API |
1690 | """ |
1691 | |
1692 | from functools import wraps |
1693 | |
1694 | === modified file 'plainbox/plainbox/impl/box.py' |
1695 | --- plainbox/plainbox/impl/box.py 2013-02-22 16:26:25 +0000 |
1696 | +++ plainbox/plainbox/impl/box.py 2013-03-07 16:10:38 +0000 |
1697 | @@ -18,12 +18,12 @@ |
1698 | # along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
1699 | |
1700 | """ |
1701 | -plainbox.impl.box |
1702 | -================= |
1703 | - |
1704 | -Internal implementation of plainbox |
1705 | - |
1706 | - * THIS MODULE DOES NOT HAVE STABLE PUBLIC API * |
1707 | +:mod:`plainbox.impl.box` -- command line interface |
1708 | +================================================== |
1709 | + |
1710 | +.. warning:: |
1711 | + |
1712 | + THIS MODULE DOES NOT HAVE STABLE PUBLIC API |
1713 | """ |
1714 | |
1715 | from argparse import ArgumentParser |
1716 | @@ -34,6 +34,7 @@ |
1717 | from logging import getLogger |
1718 | from os.path import join |
1719 | import argparse |
1720 | +import re |
1721 | import sys |
1722 | |
1723 | from plainbox import __version__ as version |
1724 | @@ -71,10 +72,16 @@ |
1725 | group.add_argument( |
1726 | '-i', '--include-pattern', action="append", |
1727 | metavar='PATTERN', default=[], dest='include_pattern_list', |
1728 | - help="Run jobs matching the given pattern") |
1729 | + help=("Run jobs matching the given regular expression. Matches " |
1730 | + "from the start to the end of the line.")) |
1731 | + group.add_argument( |
1732 | + '-x', '--exclude-pattern', action="append", |
1733 | + metavar="PATTERN", default=[], dest='exclude_pattern_list', |
1734 | + help=("Do not run jobs matching the given regular expression. " |
1735 | + "Matches from the start to the end of the line.")) |
1736 | # TODO: Find a way to handle the encoding of the file |
1737 | group.add_argument( |
1738 | - '-W', '--whitelist', |
1739 | + '-w', '--whitelist', |
1740 | metavar="WHITELIST", |
1741 | type=FileType("rt"), |
1742 | help="Load whitelist containing run patterns") |
1743 | @@ -88,18 +95,36 @@ |
1744 | def _get_matching_job_list(self, ns, job_list): |
1745 | # Find jobs that matched patterns |
1746 | matching_job_list = [] |
1747 | + # Pre-seed the include pattern list with data read from |
1748 | + # the whitelist file. |
1749 | if ns.whitelist: |
1750 | - ns.include_pattern_list.extend([pattern.strip() for pattern in |
1751 | - ns.whitelist.readlines()]) |
1752 | + ns.include_pattern_list.extend([ |
1753 | + pattern.strip() |
1754 | + for pattern in ns.whitelist.readlines()]) |
1755 | + # Decide which of the known jobs to include |
1756 | for job in job_list: |
1757 | - for pattern in ns.include_pattern_list: |
1758 | - if fnmatch(job.name, pattern): |
1759 | - matching_job_list.append(job) |
1760 | + # Reject all jobs that match any of the exclude |
1761 | + # patterns, matching strictly from the start to |
1762 | + # the end of the line. |
1763 | + for pattern in ns.exclude_pattern_list: |
1764 | + if re.match(r"^{pattern}$".format(pattern=pattern), job.name): |
1765 | break |
1766 | + else: |
1767 | + # Then accept (include) all job that matches |
1768 | + # any of include patterns, matching strictly |
1769 | + # from the start to the end of the line. |
1770 | + for pattern in ns.include_pattern_list: |
1771 | + if re.match(r"^{pattern}$".format(pattern=pattern), |
1772 | + job.name): |
1773 | + matching_job_list.append(job) |
1774 | + break |
1775 | return matching_job_list |
1776 | |
1777 | |
1778 | class SpecialCommand(PlainBoxCommand, CheckBoxCommandMixIn): |
1779 | + """ |
1780 | + Implementation of ``$ plainbox special`` |
1781 | + """ |
1782 | |
1783 | def invoked(self, ns): |
1784 | job_list = self.get_job_list(ns) |
1785 | @@ -261,6 +286,17 @@ |
1786 | raise SystemExit(str(exc)) |
1787 | return exporter |
1788 | |
1789 | + def ask_for_resume(self, prompt=None, allowed=None): |
1790 | + # FIXME: Add support/callbacks for a GUI |
1791 | + if prompt is None: |
1792 | + prompt = "Do you want to resume the previous session [Y/n]? " |
1793 | + if allowed is None: |
1794 | + allowed = ('', 'y', 'Y', 'n', 'N') |
1795 | + answer = None |
1796 | + while answer not in allowed: |
1797 | + answer = input(prompt) |
1798 | + return False if answer in ('n', 'N') else True |
1799 | + |
1800 | def _run_jobs(self, ns, job_list, exporter): |
1801 | # Compute the run list, this can give us notification about problems in |
1802 | # the selected jobs. Currently we just display each problem |
1803 | @@ -268,8 +304,13 @@ |
1804 | print("[ Analyzing Jobs ]".center(80, '=')) |
1805 | # Create a session that handles most of the stuff needed to run jobs |
1806 | session = SessionState(job_list) |
1807 | - self._update_desired_job_list(session, matching_job_list) |
1808 | with session.open(): |
1809 | + if session.previous_session_file(): |
1810 | + if self.ask_for_resume(): |
1811 | + session.resume() |
1812 | + else: |
1813 | + session.clean() |
1814 | + self._update_desired_job_list(session, matching_job_list) |
1815 | if (sys.stdin.isatty() and sys.stdout.isatty() and not |
1816 | ns.not_interactive): |
1817 | outcome_callback = self.ask_for_outcome |
1818 | |
1819 | === modified file 'plainbox/plainbox/impl/checkbox.py' |
1820 | --- plainbox/plainbox/impl/checkbox.py 2013-02-22 16:26:25 +0000 |
1821 | +++ plainbox/plainbox/impl/checkbox.py 2013-03-07 16:10:38 +0000 |
1822 | @@ -18,12 +18,12 @@ |
1823 | # along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
1824 | |
1825 | """ |
1826 | -plainbox.impl.checkbox |
1827 | -====================== |
1828 | - |
1829 | -Internal implementation of plainbox |
1830 | - |
1831 | - * THIS MODULE DOES NOT HAVE STABLE PUBLIC API * |
1832 | +:mod:`plainbox.impl.checkbox` -- CheckBox integration |
1833 | +===================================================== |
1834 | + |
1835 | +.. warning:: |
1836 | + |
1837 | + THIS MODULE DOES NOT HAVE STABLE PUBLIC API |
1838 | """ |
1839 | |
1840 | import io |
1841 | @@ -102,7 +102,7 @@ |
1842 | """ |
1843 | Return the required value of CHECKBOX_SHARE environment variable. |
1844 | |
1845 | - ..note:: |
1846 | + .. note:: |
1847 | This variable is only required by one script. |
1848 | It would be nice to remove this later on. |
1849 | """ |
1850 | @@ -119,7 +119,7 @@ |
1851 | This entry is required for CheckBox scripts to import the correct |
1852 | CheckBox python libraries. |
1853 | |
1854 | - ..note:: |
1855 | + .. note:: |
1856 | The result may be None |
1857 | """ |
1858 | # NOTE: When CheckBox is installed then all the scripts should not use |
1859 | @@ -159,7 +159,7 @@ |
1860 | """ |
1861 | Return an absolute path of the scripts directory |
1862 | |
1863 | - ..note:: |
1864 | + .. note:: |
1865 | The scripts may not work without setting PYTHONPATH and |
1866 | CHECKBOX_SHARE. |
1867 | """ |
1868 | |
1869 | === modified file 'plainbox/plainbox/impl/commands/__init__.py' |
1870 | --- plainbox/plainbox/impl/commands/__init__.py 2013-01-30 21:43:05 +0000 |
1871 | +++ plainbox/plainbox/impl/commands/__init__.py 2013-03-07 16:10:38 +0000 |
1872 | @@ -18,12 +18,12 @@ |
1873 | # along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
1874 | |
1875 | """ |
1876 | -plainbox.impl.commands |
1877 | -====================== |
1878 | - |
1879 | -Internal implementation of plainbox |
1880 | - |
1881 | - * THIS MODULE DOES NOT HAVE STABLE PUBLIC API * |
1882 | +:mod:`plainbox.impl.commands` -- shared code for plainbox sub-commands |
1883 | +====================================================================== |
1884 | + |
1885 | +.. warning:: |
1886 | + |
1887 | + THIS MODULE DOES NOT HAVE STABLE PUBLIC API |
1888 | """ |
1889 | |
1890 | from abc import abstractmethod, ABCMeta |
1891 | |
1892 | === modified file 'plainbox/plainbox/impl/commands/selftest.py' |
1893 | --- plainbox/plainbox/impl/commands/selftest.py 2013-02-08 17:02:12 +0000 |
1894 | +++ plainbox/plainbox/impl/commands/selftest.py 2013-03-07 16:10:38 +0000 |
1895 | @@ -19,12 +19,12 @@ |
1896 | # along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
1897 | |
1898 | """ |
1899 | -plainbox.impl.commands.selftest |
1900 | -=============================== |
1901 | - |
1902 | -Internal implementation of plainbox |
1903 | - |
1904 | - * THIS MODULE DOES NOT HAVE STABLE PUBLIC API * |
1905 | +:mod:`plainbox.impl.commands.selftest` -- selftest sub-command |
1906 | +============================================================== |
1907 | + |
1908 | +.. warning:: |
1909 | + |
1910 | + THIS MODULE DOES NOT HAVE STABLE PUBLIC API |
1911 | """ |
1912 | from unittest.runner import TextTestRunner |
1913 | |
1914 | |
1915 | === modified file 'plainbox/plainbox/impl/depmgr.py' |
1916 | --- plainbox/plainbox/impl/depmgr.py 2012-11-29 18:59:46 +0000 |
1917 | +++ plainbox/plainbox/impl/depmgr.py 2013-03-07 16:10:38 +0000 |
1918 | @@ -18,12 +18,12 @@ |
1919 | # along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
1920 | |
1921 | """ |
1922 | -plainbox.impl.depmgr |
1923 | -==================== |
1924 | - |
1925 | -Internal implementation of plainbox |
1926 | - |
1927 | - * THIS MODULE DOES NOT HAVE STABLE PUBLIC API * |
1928 | +:mod:`plainbox.impl.depmgr` -- dependency solver |
1929 | +================================================ |
1930 | + |
1931 | +.. warning:: |
1932 | + |
1933 | + THIS MODULE DOES NOT HAVE STABLE PUBLIC API |
1934 | """ |
1935 | |
1936 | from abc import ABCMeta |
1937 | @@ -148,15 +148,17 @@ |
1938 | @classmethod |
1939 | def resolve_dependencies(cls, job_list, visit_list=None): |
1940 | """ |
1941 | - Solve the dependency graph expressed as a list of job definitions. The |
1942 | - visit_list, if specified, allows to consider only a part of the graph |
1943 | - while still having access and knowledge of all jobs. |
1944 | - |
1945 | - Returns the solution (a list of jobs to execute in order) |
1946 | - |
1947 | - raises DependencyCycleError if a cyclic dependency is present. |
1948 | - |
1949 | - raises DependencyMissingErorr if a required job does not exist. |
1950 | + Solve the dependency graph expressed as a list of job definitions. |
1951 | + |
1952 | + :param list job_list: list of known jobs |
1953 | + :param list visit_list: (optional) list of jobs to solve |
1954 | + |
1955 | + The visit_list, if specified, allows to consider only a part of the |
1956 | + graph while still having access and knowledge of all jobs. |
1957 | + |
1958 | + :returns list: the solution (a list of jobs to execute in order) |
1959 | + :raises DependencyCycleError: if a cyclic dependency is present. |
1960 | + :raises DependencyMissingErorr: if a required job does not exist. |
1961 | """ |
1962 | return cls(job_list)._solve(visit_list) |
1963 | |
1964 | |
1965 | === modified file 'plainbox/plainbox/impl/exporter/__init__.py' |
1966 | --- plainbox/plainbox/impl/exporter/__init__.py 2013-02-22 16:26:25 +0000 |
1967 | +++ plainbox/plainbox/impl/exporter/__init__.py 2013-03-07 16:10:38 +0000 |
1968 | @@ -18,10 +18,12 @@ |
1969 | # along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
1970 | |
1971 | """ |
1972 | -plainbox.impl.exporter |
1973 | -====================== |
1974 | - |
1975 | - * THIS MODULE DOES NOT HAVE STABLE PUBLIC API * |
1976 | +:mod:`plainbox.impl.exporter` -- shared code for session state exporters |
1977 | +======================================================================== |
1978 | + |
1979 | +.. warning:: |
1980 | + |
1981 | + THIS MODULE DOES NOT HAVE STABLE PUBLIC API |
1982 | """ |
1983 | |
1984 | from abc import ABCMeta, abstractmethod |
1985 | @@ -38,11 +40,6 @@ |
1986 | class classproperty: |
1987 | """ |
1988 | Class property. |
1989 | - |
1990 | - @property |
1991 | - @classmethod |
1992 | - def foo(cls): |
1993 | - ... |
1994 | """ |
1995 | # I wish it was in the standard library or that the composition worked |
1996 | |
1997 | @@ -75,6 +72,7 @@ |
1998 | OPTION_WITH_DESIRED_JOB_LIST = 'with-job-list' |
1999 | OPTION_WITH_RESOURCE_MAP = 'with-resource-map' |
2000 | OPTION_WITH_JOB_DEFS = 'with-job-defs' |
2001 | + OPTION_WITH_ATTACHMENTS = 'with-attachments' |
2002 | |
2003 | SUPPORTED_OPTION_LIST = ( |
2004 | OPTION_WITH_IO_LOG, |
2005 | @@ -84,6 +82,7 @@ |
2006 | OPTION_WITH_JOB_LIST, |
2007 | OPTION_WITH_RESOURCE_MAP, |
2008 | OPTION_WITH_JOB_DEFS, |
2009 | + OPTION_WITH_ATTACHMENTS, |
2010 | ) |
2011 | |
2012 | def __init__(self, option_list=None): |
2013 | @@ -133,6 +132,8 @@ |
2014 | # TODO: turn session._resource_map to a public property |
2015 | for resource_name, resource_list in session._resource_map.items() |
2016 | } |
2017 | + if self.OPTION_WITH_ATTACHMENTS in self._option_list: |
2018 | + data['attachment_map'] = {} |
2019 | for job_name, job_state in session.job_state_map.items(): |
2020 | if job_state.result.outcome is None: |
2021 | continue |
2022 | @@ -151,6 +152,16 @@ |
2023 | continue |
2024 | data['result_map'][job_name][prop] = \ |
2025 | getattr(job_state.result.job, prop) |
2026 | + |
2027 | + # Add Attachements if requested |
2028 | + if job_state.result.job.plugin == 'attachment': |
2029 | + if self.OPTION_WITH_ATTACHMENTS in self._option_list: |
2030 | + raw_bytes = b''.join((record[2] for record in |
2031 | + job_state.result.io_log if record[1] == 'stdout')) |
2032 | + data['attachment_map'][job_name] = \ |
2033 | + base64.standard_b64encode(raw_bytes).decode('ASCII') |
2034 | + continue # Don't add attachments IO logs to the result_map |
2035 | + |
2036 | # Add IO log if requested |
2037 | if self.OPTION_WITH_IO_LOG in self._option_list: |
2038 | # If requested, squash the IO log so that only textual data is |
2039 | |
2040 | === modified file 'plainbox/plainbox/impl/exporter/json.py' |
2041 | --- plainbox/plainbox/impl/exporter/json.py 2012-12-10 12:38:50 +0000 |
2042 | +++ plainbox/plainbox/impl/exporter/json.py 2013-03-07 16:10:38 +0000 |
2043 | @@ -18,12 +18,11 @@ |
2044 | # along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
2045 | |
2046 | """ |
2047 | -plainbox.impl.exporter.json |
2048 | -=========================== |
2049 | - |
2050 | -Internal implementation of plainbox |
2051 | - |
2052 | - * THIS MODULE DOES NOT HAVE STABLE PUBLIC API * |
2053 | +:mod:`plainbox.impl.exporter.json` -- JSON exporter |
2054 | +=================================================== |
2055 | + |
2056 | +.. warning:: |
2057 | + THIS MODULE DOES NOT HAVE STABLE PUBLIC API |
2058 | """ |
2059 | |
2060 | import json |
2061 | |
2062 | === modified file 'plainbox/plainbox/impl/exporter/rfc822.py' |
2063 | --- plainbox/plainbox/impl/exporter/rfc822.py 2013-01-04 13:31:02 +0000 |
2064 | +++ plainbox/plainbox/impl/exporter/rfc822.py 2013-03-07 16:10:38 +0000 |
2065 | @@ -18,12 +18,12 @@ |
2066 | # along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
2067 | |
2068 | """ |
2069 | -plainbox.impl.exporter.rfc822 |
2070 | -=========================== |
2071 | - |
2072 | -Internal implementation of plainbox |
2073 | - |
2074 | - * THIS MODULE DOES NOT HAVE STABLE PUBLIC API * |
2075 | +:mod:`plainbox.impl.exporter.rfc822` -- RFC822 exporter |
2076 | +======================================================= |
2077 | + |
2078 | +.. warning:: |
2079 | + |
2080 | + THIS MODULE DOES NOT HAVE STABLE PUBLIC API |
2081 | """ |
2082 | |
2083 | |
2084 | |
2085 | === modified file 'plainbox/plainbox/impl/exporter/test_init.py' |
2086 | --- plainbox/plainbox/impl/exporter/test_init.py 2013-02-22 16:26:25 +0000 |
2087 | +++ plainbox/plainbox/impl/exporter/test_init.py 2013-03-07 16:10:38 +0000 |
2088 | @@ -24,6 +24,7 @@ |
2089 | Test definitions for plainbox.impl.exporter module |
2090 | """ |
2091 | |
2092 | +from tempfile import TemporaryDirectory |
2093 | from unittest import TestCase |
2094 | |
2095 | from plainbox.impl.exporter import SessionStateExporterBase |
2096 | @@ -31,7 +32,7 @@ |
2097 | from plainbox.impl.session import SessionState |
2098 | from plainbox.impl.job import JobDefinition |
2099 | from plainbox.impl.result import JobResult, IOLogRecord |
2100 | -from plainbox.impl.testing_utils import make_job, make_job_result |
2101 | +from plainbox.impl.testing_utils import make_io_log, make_job, make_job_result |
2102 | |
2103 | |
2104 | class ClassPropertyTests(TestCase): |
2105 | @@ -95,7 +96,7 @@ |
2106 | } |
2107 | self.assertEqual(data, expected_data) |
2108 | |
2109 | - def make_realistic_test_session(self): |
2110 | + def make_realistic_test_session(self, session_dir): |
2111 | # Create a more realistic session with two jobs but with richer set |
2112 | # of data in the actual jobs and results. |
2113 | job_a = JobDefinition({ |
2114 | @@ -115,17 +116,17 @@ |
2115 | 'job': job_a, |
2116 | 'outcome': 'pass', |
2117 | 'return_code': 0, |
2118 | - 'io_log': ( |
2119 | - IOLogRecord(0, 'stdout', b'testing\n'), |
2120 | - ) |
2121 | + 'io_log': make_io_log( |
2122 | + (IOLogRecord(0, 'stdout', b'testing\n'),), |
2123 | + session_dir) |
2124 | }) |
2125 | result_b = JobResult({ |
2126 | 'job': job_b, |
2127 | 'outcome': 'pass', |
2128 | 'return_code': 0, |
2129 | - 'io_log': ( |
2130 | - IOLogRecord(0, 'stdout', b'ready: yes\n'), |
2131 | - ) |
2132 | + 'io_log': make_io_log( |
2133 | + (IOLogRecord(0, 'stdout', b'ready: yes\n'),), |
2134 | + session_dir) |
2135 | }) |
2136 | session.update_job_result(job_a, result_a) |
2137 | session.update_job_result(job_b, result_b) |
2138 | @@ -139,10 +140,11 @@ |
2139 | # - OPTION_FLATTEN_IO_LOG |
2140 | # The implementation favours SQUASH_IO_LOG |
2141 | # and thus the code below tests that option |
2142 | - exporter = self.TestSessionStateExporter( |
2143 | - self.TestSessionStateExporter.supported_option_list) |
2144 | - session = self.make_realistic_test_session() |
2145 | - data = exporter.get_session_data_subset(session) |
2146 | + with TemporaryDirectory() as scratch_dir: |
2147 | + exporter = self.TestSessionStateExporter( |
2148 | + self.TestSessionStateExporter.supported_option_list) |
2149 | + session = self.make_realistic_test_session(scratch_dir) |
2150 | + data = exporter.get_session_data_subset(session) |
2151 | expected_data = { |
2152 | 'job_list': ['job_a', 'job_b'], |
2153 | 'run_list': ['job_b', 'job_a'], |
2154 | @@ -166,6 +168,8 @@ |
2155 | 'command': 'echo ready: yes', |
2156 | 'io_log': ['cmVhZHk6IHllcwo='], |
2157 | } |
2158 | + }, |
2159 | + 'attachment_map': { |
2160 | } |
2161 | } |
2162 | # This is just to make debugging easier |
2163 | |
2164 | === modified file 'plainbox/plainbox/impl/exporter/text.py' |
2165 | --- plainbox/plainbox/impl/exporter/text.py 2012-12-10 12:38:50 +0000 |
2166 | +++ plainbox/plainbox/impl/exporter/text.py 2013-03-07 16:10:38 +0000 |
2167 | @@ -18,12 +18,12 @@ |
2168 | # along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
2169 | |
2170 | """ |
2171 | -plainbox.impl.exporter.text |
2172 | -=========================== |
2173 | - |
2174 | -Internal implementation of plainbox |
2175 | - |
2176 | - * THIS MODULE DOES NOT HAVE STABLE PUBLIC API * |
2177 | +:mod:`plainbox.impl.exporter.text` -- plain text exporter |
2178 | +========================================================= |
2179 | + |
2180 | +.. warning:: |
2181 | + |
2182 | + THIS MODULE DOES NOT HAVE STABLE PUBLIC API |
2183 | """ |
2184 | |
2185 | |
2186 | |
2187 | === modified file 'plainbox/plainbox/impl/integration_tests.py' |
2188 | --- plainbox/plainbox/impl/integration_tests.py 2013-02-22 16:26:25 +0000 |
2189 | +++ plainbox/plainbox/impl/integration_tests.py 2013-03-07 16:10:38 +0000 |
2190 | @@ -18,16 +18,20 @@ |
2191 | # along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
2192 | |
2193 | """ |
2194 | -plainbox.impl.integration_tests |
2195 | -=============================== |
2196 | - |
2197 | -Integration tests for checkbox scripts |
2198 | +:mod:`plainbox.impl.integration_tests` -- integration tests |
2199 | +=========================================================== |
2200 | + |
2201 | +.. warning:: |
2202 | + |
2203 | + THIS MODULE DOES NOT HAVE STABLE PUBLIC API |
2204 | """ |
2205 | |
2206 | from tempfile import TemporaryDirectory |
2207 | from unittest import TestCase |
2208 | import json |
2209 | import os |
2210 | +import shutil |
2211 | +import tempfile |
2212 | |
2213 | from pkg_resources import resource_filename, resource_isdir, resource_listdir |
2214 | |
2215 | @@ -41,6 +45,14 @@ |
2216 | |
2217 | parameter_names = ('job_name',) |
2218 | |
2219 | + def setUp(self): |
2220 | + # session data are kept in XDG_CACHE_HOME/plainbox/.session |
2221 | + # To avoid resuming a real session, we have to select a temporary |
2222 | + # location instead |
2223 | + self._sandbox = tempfile.mkdtemp() |
2224 | + self._env = os.environ |
2225 | + os.environ['XDG_CACHE_HOME'] = self._sandbox |
2226 | + |
2227 | @classmethod |
2228 | def _gen_job_name_values(cls, package='plainbox', root='data/'): |
2229 | """ |
2230 | @@ -94,3 +106,7 @@ |
2231 | expected_result = json.load(stream) |
2232 | # Check that results match expected values |
2233 | self.assertEqual(actual_result, expected_result) |
2234 | + |
2235 | + def tearDown(self): |
2236 | + shutil.rmtree(self._sandbox) |
2237 | + os.environ = self._env |
2238 | |
2239 | === modified file 'plainbox/plainbox/impl/job.py' |
2240 | --- plainbox/plainbox/impl/job.py 2013-02-22 16:26:25 +0000 |
2241 | +++ plainbox/plainbox/impl/job.py 2013-03-07 16:10:38 +0000 |
2242 | @@ -18,12 +18,12 @@ |
2243 | # along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
2244 | |
2245 | """ |
2246 | -plainbox.impl.job |
2247 | -================= |
2248 | - |
2249 | -Internal implementation of plainbox |
2250 | - |
2251 | - * THIS MODULE DOES NOT HAVE STABLE PUBLIC API * |
2252 | +:mod:`plainbox.impl.job` -- job definition |
2253 | +========================================== |
2254 | + |
2255 | +.. warning:: |
2256 | + |
2257 | + THIS MODULE DOES NOT HAVE STABLE PUBLIC API |
2258 | """ |
2259 | |
2260 | import collections |
2261 | @@ -41,6 +41,11 @@ |
2262 | |
2263 | |
2264 | class JobDefinition(IJobDefinition): |
2265 | + """ |
2266 | + Job definition class. |
2267 | + |
2268 | + Thin wrapper around the RFC822 record that defines a checkbox job definition |
2269 | + """ |
2270 | |
2271 | @property |
2272 | def plugin(self): |
2273 | @@ -120,10 +125,15 @@ |
2274 | def _get_persistance_subset(self): |
2275 | state = {} |
2276 | state['data'] = {} |
2277 | - state['data']['plugin'] = self.plugin |
2278 | - state['data']['name'] = self.name |
2279 | + for key, value in self._data.items(): |
2280 | + state['data'][key] = value |
2281 | return state |
2282 | |
2283 | + def __eq__(self, other): |
2284 | + if not isinstance(other, JobDefinition): |
2285 | + return False |
2286 | + return self.get_checksum() == other.get_checksum() |
2287 | + |
2288 | def get_resource_program(self): |
2289 | """ |
2290 | Return a ResourceProgram based on the 'requires' expression. |
2291 | |
2292 | === added file 'plainbox/plainbox/impl/mock_job.py' |
2293 | --- plainbox/plainbox/impl/mock_job.py 1970-01-01 00:00:00 +0000 |
2294 | +++ plainbox/plainbox/impl/mock_job.py 2013-03-07 16:10:38 +0000 |
2295 | @@ -0,0 +1,36 @@ |
2296 | +# This file is part of Checkbox. |
2297 | +# |
2298 | +# Copyright 2013 Canonical Ltd. |
2299 | +# Written by: |
2300 | +# Zygmunt Krynicki <zygmunt.krynicki@canonical.com> |
2301 | +# |
2302 | +# Checkbox is free software: you can redistribute it and/or modify |
2303 | +# it under the terms of the GNU General Public License as published by |
2304 | +# the Free Software Foundation, either version 3 of the License, or |
2305 | +# (at your option) any later version. |
2306 | +# |
2307 | +# Checkbox is distributed in the hope that it will be useful, |
2308 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
2309 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2310 | +# GNU General Public License for more details. |
2311 | +# |
2312 | +# You should have received a copy of the GNU General Public License |
2313 | +# along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
2314 | + |
2315 | +""" |
2316 | +:mod:`plainbox.impl.mock_job` -- mock jobs |
2317 | +========================================== |
2318 | +""" |
2319 | + |
2320 | +from mock import Mock |
2321 | + |
2322 | +from plainbox.impl.job import JobDefinition |
2323 | + |
2324 | + |
2325 | +def MockJobDefinition(name,*args, **kwargs): |
2326 | + """ |
2327 | + Mock for JobDefinition class |
2328 | + """ |
2329 | + job = Mock(*args, spec_set=JobDefinition, **kwargs) |
2330 | + job.name = name |
2331 | + return job |
2332 | |
2333 | === modified file 'plainbox/plainbox/impl/resource.py' |
2334 | --- plainbox/plainbox/impl/resource.py 2013-02-22 16:26:25 +0000 |
2335 | +++ plainbox/plainbox/impl/resource.py 2013-03-07 16:10:38 +0000 |
2336 | @@ -18,12 +18,12 @@ |
2337 | # along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
2338 | |
2339 | """ |
2340 | -plainbox.impl.resource |
2341 | -====================== |
2342 | - |
2343 | -Internal implementation of plainbox |
2344 | - |
2345 | - * THIS MODULE DOES NOT HAVE STABLE PUBLIC API * |
2346 | +:mod:`plainbox.impl.resource` -- job resources |
2347 | +============================================== |
2348 | + |
2349 | +.. warning:: |
2350 | + |
2351 | + THIS MODULE DOES NOT HAVE STABLE PUBLIC API |
2352 | """ |
2353 | |
2354 | import ast |
2355 | @@ -221,7 +221,7 @@ |
2356 | """ |
2357 | A NodeVisitor subclass used to analyze requirement expressions. |
2358 | |
2359 | - ..warning:: |
2360 | + .. warning:: |
2361 | |
2362 | Implementation of this class requires understanding of |
2363 | some of the lower levels of python. The general idea is |
2364 | |
2365 | === modified file 'plainbox/plainbox/impl/result.py' |
2366 | --- plainbox/plainbox/impl/result.py 2013-02-22 16:26:25 +0000 |
2367 | +++ plainbox/plainbox/impl/result.py 2013-03-07 16:10:38 +0000 |
2368 | @@ -18,16 +18,19 @@ |
2369 | # along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
2370 | |
2371 | """ |
2372 | -plainbox.impl.result |
2373 | -==================== |
2374 | - |
2375 | -Internal implementation of plainbox |
2376 | - |
2377 | - * THIS MODULE DOES NOT HAVE STABLE PUBLIC API * |
2378 | +:mod:`plainbox.impl.result` -- job result |
2379 | +========================================= |
2380 | + |
2381 | +.. warning:: |
2382 | + |
2383 | + THIS MODULE DOES NOT HAVE STABLE PUBLIC API |
2384 | """ |
2385 | |
2386 | from collections import namedtuple |
2387 | +import base64 |
2388 | +import json |
2389 | import logging |
2390 | +import os |
2391 | |
2392 | from plainbox.abc import IJobResult |
2393 | |
2394 | @@ -48,6 +51,9 @@ |
2395 | |
2396 | |
2397 | class JobResult(IJobResult): |
2398 | + """ |
2399 | + Result of running a JobDefinition. |
2400 | + """ |
2401 | |
2402 | # The outcome of a job is a one-word classification how how it ran. There |
2403 | # are several values that were not used in the original implementation but |
2404 | @@ -112,7 +118,11 @@ |
2405 | |
2406 | @property |
2407 | def io_log(self): |
2408 | - return self._data.get('io_log', ()) |
2409 | + if os.path.exists(self._data.get('io_log', '')): |
2410 | + with open(self._data.get('io_log')) as f: |
2411 | + return json.load(f, cls=IoLogDecoder) |
2412 | + else: |
2413 | + return () |
2414 | |
2415 | @property |
2416 | def return_code(self): |
2417 | @@ -121,11 +131,8 @@ |
2418 | def _get_persistance_subset(self): |
2419 | state = {} |
2420 | state['data'] = {} |
2421 | - state['data']['job'] = self._data['job'] |
2422 | - state['data']['outcome'] = self._data.get('outcome', None) |
2423 | - state['data']['comments'] = self._data.get('comments') |
2424 | - state['data']['return_code'] = self._data.get('return_code') |
2425 | - # io_log are stored on disk, see session.jobs_io_log_dir |
2426 | + for key, value in self._data.items(): |
2427 | + state['data'][key] = value |
2428 | return state |
2429 | |
2430 | @classmethod |
2431 | @@ -134,3 +141,26 @@ |
2432 | Create a JobResult instance from JSON record |
2433 | """ |
2434 | return cls(record['data']) |
2435 | + |
2436 | + |
2437 | +class IoLogEncoder(json.JSONEncoder): |
2438 | + """ |
2439 | + JSON Serialize helper to encode binary io logs |
2440 | + """ |
2441 | + |
2442 | + def default(self, obj): |
2443 | + return base64.standard_b64encode(obj).decode('ASCII') |
2444 | + |
2445 | + |
2446 | +class IoLogDecoder(json.JSONDecoder): |
2447 | + """ |
2448 | + JSON Decoder helper for io logs objects |
2449 | + """ |
2450 | + |
2451 | + def decode(self, obj): |
2452 | + return tuple([IOLogRecord( |
2453 | + # io logs namedtuple are recorded as list in json, using _asdict() |
2454 | + # would require too much space for little benefit. |
2455 | + # IOLogRecord are re created using the list ordering |
2456 | + log[0], log[1], base64.standard_b64decode(log[2].encode('ASCII'))) |
2457 | + for log in super().decode(obj)]) |
2458 | |
2459 | === modified file 'plainbox/plainbox/impl/rfc822.py' |
2460 | --- plainbox/plainbox/impl/rfc822.py 2012-12-18 00:26:03 +0000 |
2461 | +++ plainbox/plainbox/impl/rfc822.py 2013-03-07 16:10:38 +0000 |
2462 | @@ -18,12 +18,14 @@ |
2463 | # along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
2464 | |
2465 | """ |
2466 | -plainbox.impl.rfc822 |
2467 | -==================== |
2468 | +:mod:`plainbox.impl.rfc822` -- RFC822 parser |
2469 | +============================================ |
2470 | |
2471 | Implementation of rfc822 serializer and deserializer. |
2472 | |
2473 | - * THIS MODULE DOES NOT HAVE STABLE PUBLIC API * |
2474 | +.. warning:: |
2475 | + |
2476 | + THIS MODULE DOES NOT HAVE STABLE PUBLIC API |
2477 | """ |
2478 | |
2479 | import logging |
2480 | @@ -37,10 +39,11 @@ |
2481 | """ |
2482 | Simple class for tracking where something came from |
2483 | |
2484 | - It has three attributes: |
2485 | - filename - the name of the file |
2486 | - line_start - the number of the line where the record begins |
2487 | - line_end - the number of the line where the record ends |
2488 | + :ivar filename: the name of the file |
2489 | + |
2490 | + :ivar line_start: the number of the line where the record begins |
2491 | + |
2492 | + :ivar line_end: the number of the line where the record ends |
2493 | """ |
2494 | |
2495 | __slots__ = ['filename', 'line_start', 'line_end'] |
2496 | |
2497 | === modified file 'plainbox/plainbox/impl/runner.py' |
2498 | --- plainbox/plainbox/impl/runner.py 2013-02-22 16:26:25 +0000 |
2499 | +++ plainbox/plainbox/impl/runner.py 2013-03-07 16:10:38 +0000 |
2500 | @@ -18,16 +18,17 @@ |
2501 | # along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
2502 | |
2503 | """ |
2504 | -plainbox.impl.runner |
2505 | -==================== |
2506 | - |
2507 | -Internal implementation of plainbox |
2508 | - |
2509 | - * THIS MODULE DOES NOT HAVE STABLE PUBLIC API * |
2510 | +:mod:`plainbox.impl.runner` -- job runner |
2511 | +========================================= |
2512 | + |
2513 | +.. warning:: |
2514 | + |
2515 | + THIS MODULE DOES NOT HAVE STABLE PUBLIC API |
2516 | """ |
2517 | |
2518 | import collections |
2519 | import datetime |
2520 | +import json |
2521 | import logging |
2522 | import os |
2523 | import string |
2524 | @@ -35,7 +36,7 @@ |
2525 | from plainbox.vendor import extcmd |
2526 | |
2527 | from plainbox.abc import IJobRunner |
2528 | -from plainbox.impl.result import JobResult, IOLogRecord |
2529 | +from plainbox.impl.result import JobResult, IOLogRecord, IoLogEncoder |
2530 | |
2531 | logger = logging.getLogger("plainbox.runner") |
2532 | |
2533 | @@ -50,6 +51,15 @@ |
2534 | return ''.join(c if c in valid_chars else '_' for c in _string) |
2535 | |
2536 | |
2537 | +def io_log_write(log, stream): |
2538 | + """ |
2539 | + JSON call to serialize io_log objects to disk |
2540 | + """ |
2541 | + json.dump( |
2542 | + log, stream, ensure_ascii=False, indent=None, cls=IoLogEncoder, |
2543 | + separators=(',', ':')) |
2544 | + |
2545 | + |
2546 | class CommandIOLogBuilder(extcmd.DelegateBase): |
2547 | """ |
2548 | Delegate for extcmd that builds io_log entries. |
2549 | @@ -146,15 +156,24 @@ |
2550 | def __init__(self, prompt): |
2551 | self._prompt = prompt |
2552 | self._lineno = collections.defaultdict(int) |
2553 | + self._abort = False |
2554 | |
2555 | def on_line(self, stream_name, line): |
2556 | + if self._abort: |
2557 | + return |
2558 | self._lineno[stream_name] += 1 |
2559 | - print("(job {}, <{}:{:05}>) {}".format( |
2560 | - self._prompt, stream_name, self._lineno[stream_name], |
2561 | - line.rstrip())) |
2562 | + try: |
2563 | + print("(job {}, <{}:{:05}>) {}".format( |
2564 | + self._prompt, stream_name, self._lineno[stream_name], |
2565 | + line.decode('UTF-8').rstrip())) |
2566 | + except UnicodeDecodeError: |
2567 | + self._abort = True |
2568 | |
2569 | |
2570 | class JobRunner(IJobRunner): |
2571 | + """ |
2572 | + Runner for jobs - executes jobs and produces results |
2573 | + """ |
2574 | |
2575 | def __init__(self, session_dir, jobs_io_log_dir, |
2576 | command_io_delegate=None, outcome_callback=None): |
2577 | @@ -173,6 +192,9 @@ |
2578 | self._outcome_callback = outcome_callback |
2579 | |
2580 | def run_job(self, job): |
2581 | + """ |
2582 | + Run the specified job an return the result |
2583 | + """ |
2584 | logger.info("Running %r", job) |
2585 | func_name = "_plugin_" + job.plugin.replace('-', '_') |
2586 | try: |
2587 | @@ -189,6 +211,8 @@ |
2588 | def _plugin_shell(self, job): |
2589 | return self._just_run_command(job) |
2590 | |
2591 | + _plugin_attachment = _plugin_shell |
2592 | + |
2593 | def _plugin_resource(self, job): |
2594 | return self._just_run_command(job) |
2595 | |
2596 | @@ -227,7 +251,7 @@ |
2597 | 'io_log': io_log |
2598 | }) |
2599 | |
2600 | - def _get_script_env(self, job): |
2601 | + def _get_script_env(self, job, only_changes=True): |
2602 | """ |
2603 | Compute the environment the script will be executed in |
2604 | """ |
2605 | @@ -237,7 +261,17 @@ |
2606 | env['LANG'] = 'C.UTF-8' |
2607 | # Allow the job to customize anything |
2608 | job.modify_execution_environment(env, self._session_dir) |
2609 | - return env |
2610 | + # If a differential environment is requested return only the subset |
2611 | + # that has been altered. |
2612 | + # |
2613 | + # XXX: This will effectively give the root user our PATH which _may_ be |
2614 | + # good bud _might_ be dangerous. This will need some peer review. |
2615 | + if only_changes: |
2616 | + return {key: value |
2617 | + for key, value in env.items() |
2618 | + if key not in os.environ or os.environ[key] != value} |
2619 | + else: |
2620 | + return env |
2621 | |
2622 | def _run_command(self, job): |
2623 | """ |
2624 | @@ -278,7 +312,7 @@ |
2625 | # Send the third copy to the output writer that writes everything to |
2626 | # disk. |
2627 | delegate = extcmd.Chain([ |
2628 | - extcmd.Decode(ui_io_delegate), |
2629 | + ui_io_delegate, |
2630 | io_log_builder, |
2631 | output_writer]) |
2632 | logger.debug("job[%s] extcmd delegate: %r", job.name, delegate) |
2633 | @@ -291,14 +325,37 @@ |
2634 | # threads although all callbacks will be fired from a single |
2635 | # thread (which is _not_ the main thread) |
2636 | logger.debug("job[%s] starting command: %s", job.name, job.command) |
2637 | - return_code = logging_popen.call( |
2638 | - # XXX: sadly using /bin/sh results in broken output |
2639 | - # XXX: maybe run it both ways and raise exceptions on differences? |
2640 | - ['bash', '-c', job.command], |
2641 | - env=self._get_script_env(job)) |
2642 | + # XXX: sadly using /bin/sh results in broken output |
2643 | + # XXX: maybe run it both ways and raise exceptions on differences? |
2644 | + cmd = ['bash', '-c', job.command] |
2645 | + if job.user is not None: |
2646 | + # When the job requires to run as root then elevate our permissions |
2647 | + # via pkexec(1). Since pkexec resets environment we need to somehow |
2648 | + # pass the extra things we require. To do that we use the env(1) |
2649 | + # command and pass it the list of changed environment variables. |
2650 | + # |
2651 | + # The whole pkexec and env part gets prepended to the command we |
2652 | + # were supposed to run. |
2653 | + cmd = ['pkexec', '--user', job.user, 'env'] + [ |
2654 | + "{key}={value}".format(key=key, value=value) |
2655 | + for key, value in self._get_script_env( |
2656 | + job, only_changes=True |
2657 | + ).items() |
2658 | + ] + cmd |
2659 | + logging.debug("job[%s] executing %r", job.name, cmd) |
2660 | + return_code = logging_popen.call(cmd) |
2661 | + else: |
2662 | + logging.debug("job[%s] executing %r", job.name, cmd) |
2663 | + return_code = logging_popen.call( |
2664 | + cmd, env=self._get_script_env(job)) |
2665 | logger.debug("job[%s] command return code: %r", |
2666 | job.name, return_code) |
2667 | # XXX: Perhaps handle process dying from signals here |
2668 | # When the process is killed proc.returncode is not set |
2669 | # and another (cannot remember now) attribute is set |
2670 | - return return_code, io_log_builder.io_log |
2671 | + fjson = os.path.join(self._jobs_io_log_dir, "{}.json".format(slug)) |
2672 | + with open(fjson, "wt") as stream: |
2673 | + io_log_write(io_log_builder.io_log, stream) |
2674 | + stream.flush() |
2675 | + os.fsync(stream.fileno()) |
2676 | + return return_code, fjson |
2677 | |
2678 | === modified file 'plainbox/plainbox/impl/session.py' |
2679 | --- plainbox/plainbox/impl/session.py 2013-02-22 16:26:25 +0000 |
2680 | +++ plainbox/plainbox/impl/session.py 2013-03-07 16:10:38 +0000 |
2681 | @@ -18,12 +18,12 @@ |
2682 | # along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
2683 | |
2684 | """ |
2685 | -plainbox.impl.session |
2686 | -===================== |
2687 | - |
2688 | -Internal implementation of plainbox |
2689 | - |
2690 | - * THIS MODULE DOES NOT HAVE STABLE PUBLIC API * |
2691 | +:mod:`plainbox.impl.session` -- session state handling |
2692 | +====================================================== |
2693 | + |
2694 | +.. warning:: |
2695 | + |
2696 | + THIS MODULE DOES NOT HAVE STABLE PUBLIC API |
2697 | """ |
2698 | import json |
2699 | import logging |
2700 | @@ -165,7 +165,7 @@ |
2701 | """ |
2702 | Class representing the state of a job in a session. |
2703 | |
2704 | - Contains two basic properties of each job (either of which can be None): |
2705 | + Contains two basic properties of each job: |
2706 | |
2707 | * the readiness_inhibitor_list that prevent the job form starting |
2708 | * the result (outcome) of the run (IJobResult) |
2709 | @@ -223,7 +223,7 @@ |
2710 | return self._result |
2711 | |
2712 | def fset(self, value): |
2713 | - if value.job is not self.job: |
2714 | + if value.job.get_checksum() != self.job.get_checksum(): |
2715 | raise ValueError("result job does not match") |
2716 | self._result = value |
2717 | |
2718 | @@ -278,53 +278,79 @@ |
2719 | """ |
2720 | Class representing all state needed during a single program session. |
2721 | |
2722 | + This is the central glue/entry-point for applications. It connects user |
2723 | + intents to the rest of the system / plumbing and keeps all of the state in |
2724 | + one place. |
2725 | + |
2726 | The set of utility methods and properties allow applications to easily |
2727 | handle the lower levels of dependencies, resources and ready states. |
2728 | |
2729 | - Once instantiated with a list of known jobs it is ready to react to |
2730 | - UI-driven changes. It is expected that the user will select / unselect |
2731 | - and run jobs. This class can react to both actions by recomputing the |
2732 | - dependency graph and updating the read states accordingly. |
2733 | - |
2734 | - Ready states (one for each job) allow the UI to take simple decisions |
2735 | - (either can or cannot run) |
2736 | + SessionState has the following instance variables, all of which are |
2737 | + currently exposed as properties. |
2738 | + |
2739 | + :ivar list job_list: A list of all known jobs |
2740 | + |
2741 | + Not all the jobs from this list are going to be executed (or selected |
2742 | + for execution) by the user. |
2743 | + |
2744 | + It may change at runtime because of local jobs. Note that in upcoming |
2745 | + changes this will start out empty and will be changeable dynamically. |
2746 | + It can still change due to local jobs but there is no API yes. |
2747 | + |
2748 | + :ivar dict job_state_map: mapping that tracks the state of each job |
2749 | + |
2750 | + Mapping from job name to :class:`JobState`. This basically has the test |
2751 | + result and the inhibitor of each job. It also serves as a |
2752 | + :attr:`plainbox.impl.job.JobDefinition.name`-> job lookup helper. |
2753 | + |
2754 | + Directly exposed with the intent to fuel part of the UI. This is a way |
2755 | + to get at the readiness state, result and readiness inhibitors, if any. |
2756 | + |
2757 | + XXX: this can loose data job_list has jobs with the same name. It would |
2758 | + be better to use job id as the keys here. A separate map could be used |
2759 | + for the name->job lookup. This will be fixed when session controller |
2760 | + branch lands in trunk as then jobs are dynamically added to the system |
2761 | + one at a time and proper error conditions can be detected and reported. |
2762 | + |
2763 | + :ivar list desired_job_list: subset of jobs selected for execution |
2764 | + |
2765 | + This is used to compute :attr:`run_list`. It can only be changed by |
2766 | + calling :meth:`update_desired_job_list()` which returns meaningful |
2767 | + values so this is not a settable property. |
2768 | + |
2769 | + :ivar list run_list: sorted list of jobs to execute |
2770 | + |
2771 | + This is basically a superset of desired_job_list and a subset of |
2772 | + job_list that is topologically sorted to allowing all desired jobs to |
2773 | + run. This property is updated whenever desired_job_list is changed. |
2774 | + |
2775 | + :ivar dict resource_map: all known resources |
2776 | + |
2777 | + A mapping from resource name to a list of |
2778 | + :class:`plainbox.impl.resource.Resource` objects. This encapsulates all |
2779 | + "knowledge" about the system plainbox is running on. |
2780 | + |
2781 | + It is needed to compute job readiness (as it stores resource data |
2782 | + needed by resource programs). It is also available to exporters. |
2783 | + |
2784 | + This is computed internally from the output of checkbox resource jobs, |
2785 | + it can only be changed by calling :meth:`update_job_result()` |
2786 | """ |
2787 | |
2788 | session_data_filename = 'session.json' |
2789 | |
2790 | def __init__(self, job_list): |
2791 | - # The original list of job that the system knows about. |
2792 | - # Not all jobs from this list are going to be executed |
2793 | - # (or selected for execution) by the user. |
2794 | self._job_list = job_list |
2795 | - # State of each job, see JobState for details but it basically |
2796 | - # has the test result and the inhibitor of each job. It also serves |
2797 | - # as a job.name -> job lookup helper. |
2798 | - # |
2799 | - # Directly exposed with the intent to fuel part of the UI. |
2800 | - # |
2801 | - # XXX: this can loose data job_list has jobs with the same name. It |
2802 | - # would be better to use job id as the keys here. A separate map could |
2803 | - # be used for the name->job lookup. |
2804 | self._job_state_map = {job.name: JobState(job) |
2805 | for job in self._job_list} |
2806 | - # A subset of job_list that was selected by the user for execution. |
2807 | - # Used to compute run_list. Can be changed at will during lifetime |
2808 | - # of this object |
2809 | self._desired_job_list = [] |
2810 | - # Copy of desired_job_list that was topologically sorted by the |
2811 | - # dependency solver. Jobs must run in this order (although not all jobs |
2812 | - # may actually run or will actually be successful) |
2813 | self._run_list = [] |
2814 | - # A collection of known resources. Mapping resource job name to a list |
2815 | - # of resource objects. Needed to compute task readiness (as it stores |
2816 | - # resource data needed by resource programs). Currently not exposed |
2817 | - # outside of this class. |
2818 | self._resource_map = {} |
2819 | # Temporary directory used as 'scratch space' for running jobs. Removed |
2820 | # entirely when session is terminated. Internally this is exposed as |
2821 | # $CHECKBOX_DATA to script environment. |
2822 | self._session_dir = None |
2823 | + |
2824 | # Directory used to store jobs IO logs. |
2825 | self._jobs_io_log_dir = None |
2826 | |
2827 | @@ -355,28 +381,34 @@ |
2828 | if self._session_dir is None: |
2829 | xdg_cache_home = os.environ.get('XDG_CACHE_HOME') or \ |
2830 | os.path.join(os.path.expanduser('~'), '.cache') |
2831 | - temp_dir = os.path.join(xdg_cache_home, 'plainbox') |
2832 | - if not os.path.isdir(temp_dir): |
2833 | - os.makedirs(temp_dir) |
2834 | - self._session_dir = tempfile.mkdtemp(dir=temp_dir) |
2835 | + self._session_dir = os.path.join(xdg_cache_home, 'plainbox') |
2836 | + if not os.path.isdir(self._session_dir): |
2837 | + os.makedirs(self._session_dir) |
2838 | if self._jobs_io_log_dir is None: |
2839 | self._jobs_io_log_dir = os.path.join(self._session_dir, 'io-logs') |
2840 | if not os.path.isdir(self._jobs_io_log_dir): |
2841 | os.makedirs(self._jobs_io_log_dir) |
2842 | return self |
2843 | |
2844 | - def close(self): |
2845 | + def clean(self): |
2846 | """ |
2847 | - Close the session and remove temporary disk state. |
2848 | - |
2849 | - This function removes the directory created by .open() and all the data |
2850 | - that was placed there. It is automatically called by __exit__, the |
2851 | - context manager exit function. Care should be taken to ensure that all |
2852 | - session data, particularly attachments, were saved before. |
2853 | + Clean the session directory. |
2854 | """ |
2855 | if self._session_dir is not None: |
2856 | shutil.rmtree(self._session_dir) |
2857 | self._session_dir = None |
2858 | + self._jobs_io_log_dir = None |
2859 | + self.open() |
2860 | + |
2861 | + def close(self): |
2862 | + """ |
2863 | + Close the session. |
2864 | + |
2865 | + It is automatically called by __exit__, the context manager exit |
2866 | + function. |
2867 | + """ |
2868 | + self._session_dir = None |
2869 | + self._jobs_io_log_dir = None |
2870 | |
2871 | def update_desired_job_list(self, desired_job_list): |
2872 | """ |
2873 | @@ -405,7 +437,7 @@ |
2874 | # resources or runtime complexity. |
2875 | try: |
2876 | self._run_list = DependencySolver.resolve_dependencies( |
2877 | - self._job_list, desired_job_list) |
2878 | + self._job_list, self._desired_job_list) |
2879 | except DependencyError as exc: |
2880 | # When a dependency error is detected remove the affected job |
2881 | # form _desired_job_list and try again. |
2882 | @@ -457,11 +489,22 @@ |
2883 | # Update all job readiness state |
2884 | self._recompute_job_readiness() |
2885 | |
2886 | + def previous_session_file(self): |
2887 | + """ |
2888 | + Check the filesystem for previous session data |
2889 | + Returns the full pathname to the session file if it exists |
2890 | + """ |
2891 | + session_filename = os.path.join(self._session_dir, |
2892 | + self.session_data_filename) |
2893 | + if os.path.exists(session_filename): |
2894 | + return session_filename |
2895 | + else: |
2896 | + return None |
2897 | + |
2898 | def persistent_save(self): |
2899 | """ |
2900 | Save to disk the minimum needed to resume plainbox where it stopped |
2901 | """ |
2902 | - |
2903 | # Ensure an atomic update of the session file: |
2904 | # - create a new temp file (on the same file system!) |
2905 | # - write data to the temp file |
2906 | @@ -472,7 +515,6 @@ |
2907 | # directory containing the file has also reached disk. |
2908 | # For that an explicit fsync() on a file descriptor for the directory |
2909 | # is also needed. |
2910 | - |
2911 | filename = os.path.join(self._session_dir, |
2912 | self.session_data_filename) |
2913 | |
2914 | @@ -493,6 +535,28 @@ |
2915 | os.fsync(session_dir_fd) |
2916 | os.close(session_dir_fd) |
2917 | |
2918 | + def resume(self): |
2919 | + """ |
2920 | + Erase the job_state_map and desired_job_list with the saved ones |
2921 | + """ |
2922 | + with open(self.previous_session_file(), 'r') as f: |
2923 | + previous_session = json.load( |
2924 | + f, object_hook=SessionStateEncoder().dict_to_object) |
2925 | + self._job_state_map = previous_session._job_state_map |
2926 | + desired_job_list = [] |
2927 | + for job in previous_session._desired_job_list: |
2928 | + if job in self._job_list: |
2929 | + desired_job_list.extend( |
2930 | + [j for j in self._job_list if j == job]) |
2931 | + elif (previous_session._job_state_map[job.name].result.outcome != |
2932 | + JobResult.OUTCOME_NONE): |
2933 | + # Keep jobs results from the previous session without a |
2934 | + # definition in the current job_list only if they have |
2935 | + # a valid result |
2936 | + desired_job_list.append(job) |
2937 | + self.update_desired_job_list(desired_job_list) |
2938 | + # FIXME: Restore io_logs from files |
2939 | + |
2940 | def _process_resource_result(self, result): |
2941 | new_resource_list = [] |
2942 | for record in self._gen_rfc822_records_from_io_log(result): |
2943 | @@ -686,7 +750,6 @@ |
2944 | job_state.readiness_inhibitor_list.append(inhibitor) |
2945 | |
2946 | def __enter__(self): |
2947 | - self.open() |
2948 | return self |
2949 | |
2950 | def __exit__(self, *args): |
2951 | |
2952 | === modified file 'plainbox/plainbox/impl/test_box.py' |
2953 | --- plainbox/plainbox/impl/test_box.py 2013-02-22 16:26:25 +0000 |
2954 | +++ plainbox/plainbox/impl/test_box.py 2013-03-07 16:10:38 +0000 |
2955 | @@ -24,15 +24,91 @@ |
2956 | Test definitions for plainbox.impl.box module |
2957 | """ |
2958 | |
2959 | +import os |
2960 | +import shutil |
2961 | +import tempfile |
2962 | + |
2963 | +from inspect import cleandoc |
2964 | +from mock import Mock |
2965 | from unittest import TestCase |
2966 | -from inspect import cleandoc |
2967 | - |
2968 | |
2969 | from plainbox import __version__ as version |
2970 | -from plainbox.impl.box import main |
2971 | +from plainbox.impl.box import main, CheckBoxCommandMixIn |
2972 | +from plainbox.impl.mock_job import MockJobDefinition |
2973 | from plainbox.testing_utils.io import TestIO |
2974 | |
2975 | |
2976 | +class MiscTests(TestCase): |
2977 | + |
2978 | + def setUp(self): |
2979 | + self.job_foo = MockJobDefinition(name='foo') |
2980 | + self.job_bar = MockJobDefinition(name='bar') |
2981 | + self.obj = CheckBoxCommandMixIn(Mock(name="checkbox")) |
2982 | + |
2983 | + def test_matching_job_list(self): |
2984 | + # Nothing gets selected automatically |
2985 | + ns = Mock() |
2986 | + ns.whitelist = None |
2987 | + ns.include_pattern_list = [] |
2988 | + ns.exclude_pattern_list = [] |
2989 | + observed = self.obj._get_matching_job_list(ns, [ |
2990 | + self.job_foo, self.job_bar]) |
2991 | + self.assertEqual(observed, []) |
2992 | + |
2993 | + def test_matching_job_list_including(self): |
2994 | + # Including jobs with glob pattern works |
2995 | + ns = Mock() |
2996 | + ns.whitelist = None |
2997 | + ns.include_pattern_list = ['f.+'] |
2998 | + ns.exclude_pattern_list = [] |
2999 | + observed = self.obj._get_matching_job_list(ns, [ |
3000 | + self.job_foo, self.job_bar]) |
3001 | + self.assertEqual(observed, [self.job_foo]) |
3002 | + |
3003 | + def test_matching_job_list_excluding(self): |
3004 | + # Excluding jobs with glob pattern works |
3005 | + ns = Mock() |
3006 | + ns.whitelist = None |
3007 | + ns.include_pattern_list = ['.+'] |
3008 | + ns.exclude_pattern_list = ['f.+'] |
3009 | + observed = self.obj._get_matching_job_list(ns, [ |
3010 | + self.job_foo, self.job_bar]) |
3011 | + self.assertEqual(observed, [self.job_bar]) |
3012 | + |
3013 | + def test_matching_job_list_whitelist(self): |
3014 | + # whitelists contain list of include patterns |
3015 | + # that are read and interpreted as usual |
3016 | + whitelist = Mock() |
3017 | + whitelist.readlines.return_value = ['foo'] |
3018 | + ns = Mock() |
3019 | + ns.whitelist = whitelist |
3020 | + ns.include_pattern_list = [] |
3021 | + ns.exclude_pattern_list = [] |
3022 | + observed = self.obj._get_matching_job_list(ns, [ |
3023 | + self.job_foo, self.job_bar]) |
3024 | + self.assertEqual(observed, [self.job_foo]) |
3025 | + |
3026 | + def test_no_prefix_matching_including(self): |
3027 | + # Include patterns should only match whole job name |
3028 | + ns = Mock() |
3029 | + ns.whitelist = None |
3030 | + ns.include_pattern_list = ['fo', 'ba.+'] |
3031 | + ns.exclude_pattern_list = [] |
3032 | + observed = self.obj._get_matching_job_list(ns, [self.job_foo, |
3033 | + self.job_bar]) |
3034 | + self.assertEqual(observed, [self.job_bar]) |
3035 | + |
3036 | + def test_no_prefix_matching_excluding(self): |
3037 | + # Exclude patterns should only match whole job name |
3038 | + ns = Mock() |
3039 | + ns.whitelist = None |
3040 | + ns.include_pattern_list = ['.+'] |
3041 | + ns.exclude_pattern_list = ['fo', 'ba.+'] |
3042 | + observed = self.obj._get_matching_job_list(ns, [self.job_foo, |
3043 | + self.job_bar]) |
3044 | + self.assertEqual(observed, [self.job_foo]) |
3045 | + |
3046 | + |
3047 | class TestMain(TestCase): |
3048 | |
3049 | def test_version(self): |
3050 | @@ -85,7 +161,7 @@ |
3051 | self.maxDiff = None |
3052 | expected = """ |
3053 | usage: plainbox special [-h] (-j | -e | -d) [--dot-resources] [-i PATTERN] |
3054 | - [-W WHITELIST] |
3055 | + [-x PATTERN] [-w WHITELIST] |
3056 | |
3057 | optional arguments: |
3058 | -h, --help show this help message and exit |
3059 | @@ -97,8 +173,12 @@ |
3060 | |
3061 | job definition options: |
3062 | -i PATTERN, --include-pattern PATTERN |
3063 | - Run jobs matching the given pattern |
3064 | - -W WHITELIST, --whitelist WHITELIST |
3065 | + Run jobs matching the given regular expression. |
3066 | + Matches from the start to the end of the line. |
3067 | + -x PATTERN, --exclude-pattern PATTERN |
3068 | + Do not run jobs matching the given regular expression. |
3069 | + Matches from the start to the end of the line. |
3070 | + -w WHITELIST, --whitelist WHITELIST |
3071 | Load whitelist containing run patterns |
3072 | """ |
3073 | self.assertEqual(io.combined, cleandoc(expected) + "\n") |
3074 | @@ -110,7 +190,7 @@ |
3075 | self.assertEqual(call.exception.args, (2,)) |
3076 | expected = """ |
3077 | usage: plainbox special [-h] (-j | -e | -d) [--dot-resources] [-i PATTERN] |
3078 | - [-W WHITELIST] |
3079 | + [-x PATTERN] [-w WHITELIST] |
3080 | plainbox special: error: one of the arguments -j/--list-jobs -e/--list-expressions -d/--dot is required |
3081 | """ |
3082 | self.assertEqual(io.combined, cleandoc(expected) + "\n") |
3083 | @@ -130,7 +210,7 @@ |
3084 | def test_run_list_jobs_with_filtering(self): |
3085 | with TestIO() as io: |
3086 | with self.assertRaises(SystemExit) as call: |
3087 | - main(['special', '--include-pattern=usb3*', '--list-jobs']) |
3088 | + main(['special', '--include-pattern=usb3.+', '--list-jobs']) |
3089 | self.assertEqual(call.exception.args, (0,)) |
3090 | # Test that usb3 insertion test was listed but the usb (2.0) test was not |
3091 | self.assertIn("usb3/insert", io.stdout.splitlines()) |
3092 | @@ -181,6 +261,14 @@ |
3093 | |
3094 | class TestRun(TestCase): |
3095 | |
3096 | + def setUp(self): |
3097 | + # session data are kept in XDG_CACHE_HOME/plainbox/.session |
3098 | + # To avoid resuming a real session, we have to select a temporary |
3099 | + # location instead |
3100 | + self._sandbox = tempfile.mkdtemp() |
3101 | + self._env = os.environ |
3102 | + os.environ['XDG_CACHE_HOME'] = self._sandbox |
3103 | + |
3104 | def test_help(self): |
3105 | with TestIO(combined=True) as io: |
3106 | with self.assertRaises(SystemExit) as call: |
3107 | @@ -189,7 +277,7 @@ |
3108 | self.maxDiff = None |
3109 | expected = """ |
3110 | usage: plainbox run [-h] [--not-interactive] [-n] [-f FORMAT] [-p OPTIONS] |
3111 | - [-o FILE] [-i PATTERN] [-W WHITELIST] |
3112 | + [-o FILE] [-i PATTERN] [-x PATTERN] [-w WHITELIST] |
3113 | |
3114 | optional arguments: |
3115 | -h, --help show this help message and exit |
3116 | @@ -211,8 +299,12 @@ |
3117 | |
3118 | job definition options: |
3119 | -i PATTERN, --include-pattern PATTERN |
3120 | - Run jobs matching the given pattern |
3121 | - -W WHITELIST, --whitelist WHITELIST |
3122 | + Run jobs matching the given regular expression. |
3123 | + Matches from the start to the end of the line. |
3124 | + -x PATTERN, --exclude-pattern PATTERN |
3125 | + Do not run jobs matching the given regular expression. |
3126 | + Matches from the start to the end of the line. |
3127 | + -w WHITELIST, --whitelist WHITELIST |
3128 | Load whitelist containing run patterns |
3129 | """ |
3130 | self.assertEqual(io.combined, cleandoc(expected) + "\n") |
3131 | @@ -246,8 +338,12 @@ |
3132 | self.assertEqual(call.exception.args, (0,)) |
3133 | expected = """ |
3134 | Each format may support a different set of options |
3135 | - json: with-io-log, squash-io-log, flatten-io-log, with-run-list, with-job-list, with-resource-map, with-job-defs, machine-json |
3136 | - rfc822: with-io-log, squash-io-log, flatten-io-log, with-run-list, with-job-list, with-resource-map, with-job-defs |
3137 | - text: with-io-log, squash-io-log, flatten-io-log, with-run-list, with-job-list, with-resource-map, with-job-defs |
3138 | + json: with-io-log, squash-io-log, flatten-io-log, with-run-list, with-job-list, with-resource-map, with-job-defs, with-attachments, machine-json |
3139 | + rfc822: with-io-log, squash-io-log, flatten-io-log, with-run-list, with-job-list, with-resource-map, with-job-defs, with-attachments |
3140 | + text: with-io-log, squash-io-log, flatten-io-log, with-run-list, with-job-list, with-resource-map, with-job-defs, with-attachments |
3141 | """ |
3142 | self.assertEqual(io.combined, cleandoc(expected) + "\n") |
3143 | + |
3144 | + def tearDown(self): |
3145 | + shutil.rmtree(self._sandbox) |
3146 | + os.environ = self._env |
3147 | |
3148 | === modified file 'plainbox/plainbox/impl/test_job.py' |
3149 | --- plainbox/plainbox/impl/test_job.py 2013-02-22 16:26:25 +0000 |
3150 | +++ plainbox/plainbox/impl/test_job.py 2013-03-07 16:10:38 +0000 |
3151 | @@ -239,8 +239,7 @@ |
3152 | job_enc = job._get_persistance_subset() |
3153 | self.assertEqual(job_enc['data']['plugin'], job.plugin) |
3154 | self.assertEqual(job_enc['data']['name'], job.name) |
3155 | - with self.assertRaises(KeyError): |
3156 | - job_enc['requires'] |
3157 | + self.assertEqual(job_enc['data']['requires'], job.requires) |
3158 | with self.assertRaises(KeyError): |
3159 | job_enc['depends'] |
3160 | with self.assertRaises(KeyError): |
3161 | @@ -280,7 +279,8 @@ |
3162 | "plugin": "user-verify" |
3163 | } |
3164 | }""" |
3165 | - job_dec = json.loads(raw_json, object_hook=SessionStateEncoder().dict_to_object) |
3166 | + job_dec = json.loads(raw_json, |
3167 | + object_hook=SessionStateEncoder().dict_to_object) |
3168 | self.assertIsInstance(job_dec, JobDefinition) |
3169 | self.assertEqual(job_dec.name, "camera/still") |
3170 | self.assertEqual(job_dec.plugin, "user-verify") |
3171 | |
3172 | === modified file 'plainbox/plainbox/impl/test_result.py' |
3173 | --- plainbox/plainbox/impl/test_result.py 2013-02-22 16:26:25 +0000 |
3174 | +++ plainbox/plainbox/impl/test_result.py 2013-03-07 16:10:38 +0000 |
3175 | @@ -25,10 +25,11 @@ |
3176 | """ |
3177 | import json |
3178 | |
3179 | +from tempfile import TemporaryDirectory |
3180 | from unittest import TestCase |
3181 | |
3182 | from plainbox.impl.result import JobResult |
3183 | -from plainbox.impl.testing_utils import make_job |
3184 | +from plainbox.impl.testing_utils import make_io_log, make_job |
3185 | from plainbox.impl.session import SessionStateEncoder |
3186 | |
3187 | |
3188 | @@ -50,22 +51,24 @@ |
3189 | self.assertIsNone(result.return_code) |
3190 | |
3191 | def test_everything(self): |
3192 | - result = JobResult({ |
3193 | - 'job': self.job, |
3194 | - 'outcome': JobResult.OUTCOME_PASS, |
3195 | - 'comments': "it said blah", |
3196 | - 'io_log': ((0, 'stdout', b'blah\n'),), |
3197 | - 'return_code': 0 |
3198 | - }) |
3199 | - self.assertEqual(str(result), "A: pass") |
3200 | - self.assertEqual(repr(result), ( |
3201 | - "<JobResult job:<JobDefinition name:'A' plugin:'dummy'>" |
3202 | - " outcome:'pass'>")) |
3203 | - self.assertIs(result.job, self.job) |
3204 | - self.assertEqual(result.outcome, JobResult.OUTCOME_PASS) |
3205 | - self.assertEqual(result.comments, "it said blah") |
3206 | - self.assertEqual(result.io_log, ((0, 'stdout', b'blah\n'),)) |
3207 | - self.assertEqual(result.return_code, 0) |
3208 | + with TemporaryDirectory() as scratch_dir: |
3209 | + result = JobResult({ |
3210 | + 'job': self.job, |
3211 | + 'outcome': JobResult.OUTCOME_PASS, |
3212 | + 'comments': "it said blah", |
3213 | + 'io_log': make_io_log(((0, 'stdout', b'blah\n'),), |
3214 | + scratch_dir), |
3215 | + 'return_code': 0 |
3216 | + }) |
3217 | + self.assertEqual(str(result), "A: pass") |
3218 | + self.assertEqual(repr(result), ( |
3219 | + "<JobResult job:<JobDefinition name:'A' plugin:'dummy'>" |
3220 | + " outcome:'pass'>")) |
3221 | + self.assertIs(result.job, self.job) |
3222 | + self.assertEqual(result.outcome, JobResult.OUTCOME_PASS) |
3223 | + self.assertEqual(result.comments, "it said blah") |
3224 | + self.assertEqual(result.io_log, ((0, 'stdout', b'blah\n'),)) |
3225 | + self.assertEqual(result.return_code, 0) |
3226 | |
3227 | def test_encode(self): |
3228 | result = JobResult({ |
3229 | @@ -99,7 +102,8 @@ |
3230 | "return_code": 0 |
3231 | } |
3232 | }""" |
3233 | - result_dec = json.loads(raw_json, object_hook=SessionStateEncoder().dict_to_object) |
3234 | + result_dec = json.loads(raw_json, |
3235 | + object_hook=SessionStateEncoder().dict_to_object) |
3236 | self.assertIsInstance(result_dec, JobResult) |
3237 | self.assertEqual(result_dec.job.name, "__audio__") |
3238 | self.assertEqual(result_dec.outcome, JobResult.OUTCOME_PASS) |
3239 | |
3240 | === modified file 'plainbox/plainbox/impl/test_runner.py' |
3241 | --- plainbox/plainbox/impl/test_runner.py 2013-02-22 16:26:25 +0000 |
3242 | +++ plainbox/plainbox/impl/test_runner.py 2013-03-07 16:10:38 +0000 |
3243 | @@ -73,11 +73,11 @@ |
3244 | with TestIO(combined=False) as io: |
3245 | obj = FallbackCommandOutputPrinter("example") |
3246 | # Whatever gets printed by the job... |
3247 | - obj.on_line('stdout', 'line 1\n') |
3248 | - obj.on_line('stderr', 'line 1\n') |
3249 | - obj.on_line('stdout', 'line 2\n') |
3250 | - obj.on_line('stdout', 'line 3\n') |
3251 | - obj.on_line('stderr', 'line 2\n') |
3252 | + obj.on_line('stdout', b'line 1\n') |
3253 | + obj.on_line('stderr', b'line 1\n') |
3254 | + obj.on_line('stdout', b'line 2\n') |
3255 | + obj.on_line('stdout', b'line 3\n') |
3256 | + obj.on_line('stderr', b'line 2\n') |
3257 | # Gets printed to stdout _only_, stderr is combined with stdout here |
3258 | self.assertEqual(io.stdout, ( |
3259 | "(job example, <stdout:00001>) line 1\n" |
3260 | |
3261 | === modified file 'plainbox/plainbox/impl/test_session.py' |
3262 | --- plainbox/plainbox/impl/test_session.py 2013-02-22 16:26:25 +0000 |
3263 | +++ plainbox/plainbox/impl/test_session.py 2013-03-07 16:10:38 +0000 |
3264 | @@ -25,18 +25,22 @@ |
3265 | """ |
3266 | |
3267 | import json |
3268 | +import os |
3269 | +import tempfile |
3270 | +import shutil |
3271 | |
3272 | +from tempfile import TemporaryDirectory |
3273 | from unittest import TestCase |
3274 | |
3275 | +from plainbox.impl.depmgr import DependencyMissingError |
3276 | from plainbox.impl.resource import Resource |
3277 | from plainbox.impl.result import JobResult |
3278 | from plainbox.impl.session import JobReadinessInhibitor |
3279 | from plainbox.impl.session import JobState |
3280 | from plainbox.impl.session import SessionState |
3281 | +from plainbox.impl.session import SessionStateEncoder |
3282 | from plainbox.impl.session import UndesiredJobReadinessInhibitor |
3283 | -from plainbox.impl.session import SessionStateEncoder |
3284 | -from plainbox.impl.testing_utils import make_job |
3285 | -from plainbox.impl.testing_utils import make_job_result |
3286 | +from plainbox.impl.testing_utils import make_io_log, make_job, make_job_result |
3287 | |
3288 | |
3289 | class JobReadinessInhibitorTests(TestCase): |
3290 | @@ -236,7 +240,8 @@ |
3291 | } |
3292 | } |
3293 | }""" |
3294 | - job_dec = json.loads(raw_json, object_hook=SessionStateEncoder().dict_to_object) |
3295 | + job_dec = json.loads(raw_json, |
3296 | + object_hook=SessionStateEncoder().dict_to_object) |
3297 | self.assertIsInstance(job_dec, JobState) |
3298 | self.assertEqual(repr(job_dec._result), |
3299 | ("<JobResult job:<JobDefinition name:'X'" |
3300 | @@ -271,6 +276,23 @@ |
3301 | self.assertIsNone(self.session_state.session_dir) |
3302 | |
3303 | |
3304 | +class RegressionTests(TestCase): |
3305 | + # Tests for bugfixes |
3306 | + |
3307 | + def test_crash_in_update_desired_job_list(self): |
3308 | + # This checks if a DependencyError can cause crash |
3309 | + # update_desired_job_list() with a ValueError, in certain conditions. |
3310 | + A = make_job('A', depends='X') |
3311 | + L = make_job('L', plugin='local') |
3312 | + session = SessionState([A, L]) |
3313 | + problems = session.update_desired_job_list([A, L]) |
3314 | + # We should get exactly one DependencyMissingError related to job A and |
3315 | + # the undefined job X (that is presumably defined by the local job L) |
3316 | + self.assertEqual(len(problems), 1) |
3317 | + self.assertIsInstance(problems[0], DependencyMissingError) |
3318 | + self.assertIs(problems[0].affected_job, A) |
3319 | + |
3320 | + |
3321 | class SessionStateSpecialTests(TestCase): |
3322 | |
3323 | # NOTE: those tests are essential. They allow testing the behavior of |
3324 | @@ -326,6 +348,7 @@ |
3325 | self.job_Y = make_job("Y") |
3326 | self.job_list = [self.job_A, self.job_R, self.job_X, self.job_Y] |
3327 | self.session = SessionState(self.job_list) |
3328 | + self.scratch_dir = TemporaryDirectory() |
3329 | |
3330 | def job_state(self, name): |
3331 | # A helper function to avoid overly long expressions |
3332 | @@ -391,7 +414,8 @@ |
3333 | # session. |
3334 | result_R = JobResult({ |
3335 | 'job': self.job_R, |
3336 | - 'io_log': ((0, 'stdout', b"attr: value\n"),) |
3337 | + 'io_log': make_io_log(((0, 'stdout', b"attr: value\n"),), |
3338 | + self.scratch_dir) |
3339 | }) |
3340 | self.session.update_job_result(self.job_R, result_R) |
3341 | # The most obvious thing that can happen, is that the result is simply |
3342 | @@ -439,12 +463,13 @@ |
3343 | # another proper record in that order. |
3344 | result_R = JobResult({ |
3345 | 'job': self.job_R, |
3346 | - 'io_log': ( |
3347 | - (0, 'stdout', b"attr: value-1\n"), |
3348 | - (1, 'stdout', b"\n"), |
3349 | - (1, 'stdout', b"I-sound-like-a-broken-record\n"), |
3350 | - (1, 'stdout', b"\n"), |
3351 | - (1, 'stdout', b"attr: value-2\n")) |
3352 | + 'io_log': make_io_log(( |
3353 | + (0, 'stdout', b"attr: value-1\n"), |
3354 | + (1, 'stdout', b"\n"), |
3355 | + (1, 'stdout', b"I-sound-like-a-broken-record\n"), |
3356 | + (1, 'stdout', b"\n"), |
3357 | + (1, 'stdout', b"attr: value-2\n")), |
3358 | + self.scratch_dir) |
3359 | }) |
3360 | # Since we cannot control the output of scripts and people indeed make |
3361 | # mistakes a warning is issued but no exception is raised to the |
3362 | @@ -521,7 +546,8 @@ |
3363 | self.session.update_desired_job_list([self.job_A]) |
3364 | result_R = JobResult({ |
3365 | 'job': self.job_R, |
3366 | - 'io_log': ((0, 'stdout', b'attr: wrong value\n'),) |
3367 | + 'io_log': make_io_log(((0, 'stdout', b'attr: wrong value\n'),), |
3368 | + self.scratch_dir) |
3369 | }) |
3370 | self.session.update_job_result(self.job_R, result_R) |
3371 | # Now A is inhibited by FAILED_RESOURCE |
3372 | @@ -538,7 +564,8 @@ |
3373 | # presented to a session that has some resources from that job already. |
3374 | result_R_old = JobResult({ |
3375 | 'job': self.job_R, |
3376 | - 'io_log': ((0, 'stdout', b"attr: old value\n"),) |
3377 | + 'io_log': make_io_log(((0, 'stdout', b"attr: old value\n"),), |
3378 | + self.scratch_dir) |
3379 | }) |
3380 | self.session.update_job_result(self.job_R, result_R_old) |
3381 | # So here the old result is stored into a new 'R' resource |
3382 | @@ -547,7 +574,8 @@ |
3383 | # Now we present the second result for the same job |
3384 | result_R_new = JobResult({ |
3385 | 'job': self.job_R, |
3386 | - 'io_log': ((0, 'stdout', b"attr: new value\n"),) |
3387 | + 'io_log': make_io_log(((0, 'stdout', b"attr: new value\n"),), |
3388 | + self.scratch_dir) |
3389 | }) |
3390 | self.session.update_job_result(self.job_R, result_R_new) |
3391 | # What should happen here is that the R resource is entirely replaced |
3392 | @@ -557,3 +585,149 @@ |
3393 | self.assertEqual(self.session._resource_map, expected_after) |
3394 | |
3395 | # TODO: add tests for local jobs |
3396 | + |
3397 | + def tearDown(self): |
3398 | + self.scratch_dir.cleanup() |
3399 | + |
3400 | + |
3401 | +class SessionStateLocalStorageTests(TestCase): |
3402 | + |
3403 | + def setUp(self): |
3404 | + # session data are kept in XDG_CACHE_HOME/plainbox/.session |
3405 | + # To avoid resuming a real session, we have to select a temporary |
3406 | + # location instead |
3407 | + self._sandbox = tempfile.mkdtemp() |
3408 | + self._env = os.environ |
3409 | + os.environ['XDG_CACHE_HOME'] = self._sandbox |
3410 | + |
3411 | + def job_state(self, name): |
3412 | + # A helper function to avoid overly long expressions |
3413 | + return self.session.job_state_map[name] |
3414 | + |
3415 | + def test_persistent_save(self): |
3416 | + self.job_A = make_job("A") |
3417 | + self.job_list = [self.job_A] |
3418 | + self.session = SessionState(self.job_list) |
3419 | + result_A = JobResult({ |
3420 | + 'job': self.job_A, |
3421 | + 'outcome': JobResult.OUTCOME_PASS, |
3422 | + 'comments': 'All good', |
3423 | + 'return_code': 0, |
3424 | + 'io_log': ((0, 'stdout', "Success !\n"),) |
3425 | + }) |
3426 | + session_json_text = """{ |
3427 | + "_job_state_map": { |
3428 | + "A": { |
3429 | + "_job": { |
3430 | + "data": { |
3431 | + "name": "A", |
3432 | + "plugin": "dummy", |
3433 | + "requires": null, |
3434 | + "depends": null |
3435 | + }, |
3436 | + "_class_id": "JOB_DEFINITION" |
3437 | + }, |
3438 | + "_result": { |
3439 | + "data": { |
3440 | + "job": { |
3441 | + "data": { |
3442 | + "name": "A", |
3443 | + "plugin": "dummy", |
3444 | + "requires": null, |
3445 | + "depends": null |
3446 | + }, |
3447 | + "_class_id": "JOB_DEFINITION" |
3448 | + }, |
3449 | + "outcome": "pass", |
3450 | + "return_code": 0, |
3451 | + "comments": "All good", |
3452 | + "io_log": [ |
3453 | + [ |
3454 | + 0, |
3455 | + "stdout", |
3456 | + "Success !\\n" |
3457 | + ] |
3458 | + ] |
3459 | + }, |
3460 | + "_class_id": "JOB_RESULT" |
3461 | + }, |
3462 | + "_class_id": "JOB_STATE" |
3463 | + } |
3464 | + }, |
3465 | + "_desired_job_list": [ |
3466 | + { |
3467 | + "data": { |
3468 | + "name": "A", |
3469 | + "plugin": "dummy", |
3470 | + "requires": null, |
3471 | + "depends": null |
3472 | + }, |
3473 | + "_class_id": "JOB_DEFINITION" |
3474 | + } |
3475 | + ], |
3476 | + "_class_id": "SESSION_STATE" |
3477 | + }""" |
3478 | + self.session.open() |
3479 | + self.session.update_desired_job_list([self.job_A]) |
3480 | + self.session.update_job_result(self.job_A, result_A) |
3481 | + self.session.persistent_save() |
3482 | + session_file = self.session.previous_session_file() |
3483 | + self.session.close() |
3484 | + self.assertIsNotNone(session_file) |
3485 | + with open(session_file) as f: |
3486 | + raw_json = json.load(f) |
3487 | + self.maxDiff = None |
3488 | + self.assertEqual(raw_json, json.loads(session_json_text)) |
3489 | + |
3490 | + def test_resume_session(self): |
3491 | + # All of the tests below are using one session. The session has four |
3492 | + # jobs, Job A depends on a resource provided by job R which has no |
3493 | + # dependencies at all. Both Job X and Y depend on job A. |
3494 | + # |
3495 | + # A -(resource dependency)-> R |
3496 | + # |
3497 | + # X -(direct dependency) -> A |
3498 | + # |
3499 | + # Y -(direct dependency) -> A |
3500 | + self.job_A = make_job("A", requires="R.attr == 'value'") |
3501 | + self.job_A_expr = self.job_A.get_resource_program().expression_list[0] |
3502 | + self.job_R = make_job("R", plugin="resource") |
3503 | + self.job_X = make_job("X", depends='A') |
3504 | + self.job_Y = make_job("Y", depends='A') |
3505 | + self.job_list = [self.job_A, self.job_R, self.job_X, self.job_Y] |
3506 | + # Create a new session (session_dir is empty) |
3507 | + self.session = SessionState(self.job_list) |
3508 | + result_R = JobResult({ |
3509 | + 'job': self.job_R, |
3510 | + 'io_log': make_io_log(((0, 'stdout', b"attr: value\n"),), |
3511 | + self._sandbox) |
3512 | + }) |
3513 | + result_A = JobResult({ |
3514 | + 'job': self.job_A, |
3515 | + 'outcome': JobResult.OUTCOME_PASS |
3516 | + }) |
3517 | + result_X = JobResult({ |
3518 | + 'job': self.job_X, |
3519 | + 'outcome': JobResult.OUTCOME_PASS |
3520 | + }) |
3521 | + # Job Y can't start as it requires job A |
3522 | + self.assertFalse(self.job_state('Y').can_start()) |
3523 | + self.session.update_desired_job_list([self.job_X, self.job_Y]) |
3524 | + self.session.open() |
3525 | + self.session.update_job_result(self.job_R, result_R) |
3526 | + self.session.update_job_result(self.job_A, result_A) |
3527 | + self.session.update_job_result(self.job_X, result_X) |
3528 | + self.session.persistent_save() |
3529 | + self.session.close() |
3530 | + # Create a new session (session_dir should contain session data) |
3531 | + self.session = SessionState(self.job_list) |
3532 | + self.session.open() |
3533 | + # Resume the previous session |
3534 | + self.session.resume() |
3535 | + # This time job Y can start |
3536 | + self.assertTrue(self.job_state('Y').can_start()) |
3537 | + self.session.close() |
3538 | + |
3539 | + def tearDown(self): |
3540 | + shutil.rmtree(self._sandbox) |
3541 | + os.environ = self._env |
3542 | |
3543 | === modified file 'plainbox/plainbox/impl/testing_utils.py' |
3544 | --- plainbox/plainbox/impl/testing_utils.py 2013-01-30 21:43:05 +0000 |
3545 | +++ plainbox/plainbox/impl/testing_utils.py 2013-03-07 16:10:38 +0000 |
3546 | @@ -18,19 +18,31 @@ |
3547 | # along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
3548 | |
3549 | """ |
3550 | -plainbox.impl.testing_utils |
3551 | -=========================== |
3552 | - |
3553 | -Internal implementation of plainbox |
3554 | - |
3555 | - * THIS MODULE DOES NOT HAVE STABLE PUBLIC API * |
3556 | +:mod:`plainbox.impl.testing_utils` -- plainbox specific test tools |
3557 | +================================================================== |
3558 | + |
3559 | +.. warning:: |
3560 | + |
3561 | + THIS MODULE DOES NOT HAVE STABLE PUBLIC API |
3562 | """ |
3563 | |
3564 | import inspect |
3565 | +from tempfile import NamedTemporaryFile |
3566 | |
3567 | from plainbox.impl.job import JobDefinition |
3568 | from plainbox.impl.result import JobResult |
3569 | from plainbox.impl.rfc822 import Origin |
3570 | +from plainbox.impl.runner import io_log_write |
3571 | + |
3572 | + |
3573 | +def make_io_log(io_log, io_log_dir): |
3574 | + """ |
3575 | + Make the io logs serialization to json and return the saved file pathname |
3576 | + WARNING: The caller has to remove the file once done with it! |
3577 | + """ |
3578 | + with NamedTemporaryFile(mode='w+t', delete=False) as stream: |
3579 | + io_log_write(io_log, stream) |
3580 | + return stream.name |
3581 | |
3582 | |
3583 | def make_job(name, plugin="dummy", requires=None, depends=None): |
3584 | |
3585 | === removed file 'plainbox/plainbox/impl/utils.py.moved' |
3586 | --- plainbox/plainbox/impl/utils.py.moved 2013-02-22 16:26:25 +0000 |
3587 | +++ plainbox/plainbox/impl/utils.py.moved 1970-01-01 00:00:00 +0000 |
3588 | @@ -1,58 +0,0 @@ |
3589 | -# This file is part of Checkbox. |
3590 | -# |
3591 | -# Copyright 2012 Canonical Ltd. |
3592 | -# Written by: |
3593 | -# Zygmunt Krynicki <zygmunt.krynicki@canonical.com> |
3594 | -# |
3595 | -# Checkbox is free software: you can redistribute it and/or modify |
3596 | -# it under the terms of the GNU General Public License as published by |
3597 | -# the Free Software Foundation, either version 3 of the License, or |
3598 | -# (at your option) any later version. |
3599 | -# |
3600 | -# Checkbox is distributed in the hope that it will be useful, |
3601 | -# but WITHOUT ANY WARRANTY; without even the implied warranty of |
3602 | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3603 | -# GNU General Public License for more details. |
3604 | -# |
3605 | -# You should have received a copy of the GNU General Public License |
3606 | -# along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
3607 | - |
3608 | -""" |
3609 | -plainbox.impl.utils |
3610 | -=================== |
3611 | - |
3612 | -Internal implementation of plainbox |
3613 | - |
3614 | - * THIS MODULE DOES NOT HAVE STABLE PUBLIC API * |
3615 | -""" |
3616 | - |
3617 | -from io import TextIOWrapper |
3618 | -from logging import getLogger |
3619 | - |
3620 | -from plainbox.impl.job import JobDefinition |
3621 | -from plainbox.impl.rfc822 import load_rfc822_records |
3622 | - |
3623 | - |
3624 | -logger = getLogger("plainbox.utils") |
3625 | - |
3626 | - |
3627 | -def load(somewhere): |
3628 | - if isinstance(somewhere, str): |
3629 | - # Load data from a file with the given name |
3630 | - filename = somewhere |
3631 | - with open(filename, 'rt', encoding='UTF-8') as stream: |
3632 | - return load(stream) |
3633 | - if isinstance(somewhere, TextIOWrapper): |
3634 | - stream = somewhere |
3635 | - logger.debug("Loading jobs definitions from %r...", stream.name) |
3636 | - record_list = load_rfc822_records(stream) |
3637 | - job_list = [] |
3638 | - for record in record_list: |
3639 | - job = JobDefinition.from_rfc822_record(record) |
3640 | - logger.debug("Loaded %r", job) |
3641 | - job_list.append(job) |
3642 | - return job_list |
3643 | - else: |
3644 | - raise TypeError( |
3645 | - "Unsupported type of 'somewhere': {!r}".format( |
3646 | - type(somewhere))) |
3647 | |
3648 | === modified file 'plainbox/plainbox/public.py' |
3649 | --- plainbox/plainbox/public.py 2013-02-22 16:26:25 +0000 |
3650 | +++ plainbox/plainbox/public.py 2013-03-07 16:10:38 +0000 |
3651 | @@ -18,8 +18,8 @@ |
3652 | # along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
3653 | |
3654 | """ |
3655 | -plainbox.public |
3656 | -=============== |
3657 | +:mod:`plainbox.public` -- public, stable API |
3658 | +============================================ |
3659 | |
3660 | Public, high-level API for third party developers. |
3661 | |
3662 | |
3663 | === modified file 'plainbox/plainbox/testing_utils/__init__.py' |
3664 | --- plainbox/plainbox/testing_utils/__init__.py 2013-01-30 21:43:05 +0000 |
3665 | +++ plainbox/plainbox/testing_utils/__init__.py 2013-03-07 16:10:38 +0000 |
3666 | @@ -18,8 +18,6 @@ |
3667 | # along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
3668 | |
3669 | """ |
3670 | -plainbox.testing_utils |
3671 | -====================== |
3672 | - |
3673 | -Testing utilities for internals of plainbox |
3674 | +:mod:`plainbox.testing_utils` - generic testing utilities |
3675 | +========================================================= |
3676 | """ |
3677 | |
3678 | === modified file 'plainbox/plainbox/testing_utils/cwd.py' |
3679 | --- plainbox/plainbox/testing_utils/cwd.py 2013-01-30 21:43:05 +0000 |
3680 | +++ plainbox/plainbox/testing_utils/cwd.py 2013-03-07 16:10:38 +0000 |
3681 | @@ -18,8 +18,8 @@ |
3682 | # along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
3683 | |
3684 | """ |
3685 | -plainbox.testing_utils.cwd |
3686 | -========================== |
3687 | +:mod:`plainbox.testing_utils.cwd` -- tools for testing in another directory |
3688 | +=========================================================================== |
3689 | |
3690 | Implementation of context managers for working in another directory |
3691 | """ |
3692 | |
3693 | === modified file 'plainbox/plainbox/testing_utils/io.py' |
3694 | --- plainbox/plainbox/testing_utils/io.py 2013-01-30 21:43:05 +0000 |
3695 | +++ plainbox/plainbox/testing_utils/io.py 2013-03-07 16:10:38 +0000 |
3696 | @@ -18,8 +18,8 @@ |
3697 | # along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
3698 | |
3699 | """ |
3700 | -plainbox.testing_utils.io |
3701 | -========================= |
3702 | +:mod:`plainbox.testing_utils.io` -- tools for testing IO |
3703 | +======================================================== |
3704 | |
3705 | Implementation of context managers for observing IO |
3706 | """ |
3707 | |
3708 | === modified file 'plainbox/plainbox/testing_utils/testcases.py' |
3709 | --- plainbox/plainbox/testing_utils/testcases.py 2013-01-30 21:43:05 +0000 |
3710 | +++ plainbox/plainbox/testing_utils/testcases.py 2013-03-07 16:10:38 +0000 |
3711 | @@ -18,8 +18,8 @@ |
3712 | # along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
3713 | |
3714 | """ |
3715 | -plainbox.testing_utils.testcases |
3716 | -================================ |
3717 | +:mod:`plainbox.testing_utils.testcases` -- additional TestCase classes |
3718 | +====================================================================== |
3719 | |
3720 | Implementation of additional TestCase classes that aid in testing. |
3721 | """ |
3722 | @@ -114,7 +114,7 @@ |
3723 | parameter values, otherwise this test will behave as if it never existed |
3724 | (analogous how multiplication by zero works). |
3725 | |
3726 | - ..note:: |
3727 | + .. note:: |
3728 | Technical note for tinkerers and subclass authors. Python unittest |
3729 | framework is pretty annoying to work with or extend. In practice you |
3730 | should always keep the source code (of a particular python version) |
3731 | |
3732 | === modified file 'plainbox/plainbox/tests.py' |
3733 | --- plainbox/plainbox/tests.py 2013-02-08 17:02:12 +0000 |
3734 | +++ plainbox/plainbox/tests.py 2013-03-07 16:10:38 +0000 |
3735 | @@ -18,10 +18,8 @@ |
3736 | # along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
3737 | |
3738 | """ |
3739 | -plainbox.tests |
3740 | -============== |
3741 | - |
3742 | -Auxiliary test loader for plainbox |
3743 | +:mod:`plainbox.tests` -- auxiliary test loaders for plainbox |
3744 | +============================================================ |
3745 | """ |
3746 | |
3747 | from unittest.loader import defaultTestLoader |
3748 | |
3749 | === modified file 'plainbox/plainbox/vendor/__init__.py' |
3750 | --- plainbox/plainbox/vendor/__init__.py 2012-11-29 18:59:46 +0000 |
3751 | +++ plainbox/plainbox/vendor/__init__.py 2013-03-07 16:10:38 +0000 |
3752 | @@ -0,0 +1,28 @@ |
3753 | +# This file is part of Checkbox. |
3754 | +# |
3755 | +# Copyright 2013 Canonical Ltd. |
3756 | +# Written by: |
3757 | +# Zygmunt Krynicki <zygmunt.krynicki@canonical.com> |
3758 | +# |
3759 | +# Checkbox is free software: you can redistribute it and/or modify |
3760 | +# it under the terms of the GNU General Public License as published by |
3761 | +# the Free Software Foundation, either version 3 of the License, or |
3762 | +# (at your option) any later version. |
3763 | +# |
3764 | +# Checkbox is distributed in the hope that it will be useful, |
3765 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
3766 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3767 | +# GNU General Public License for more details. |
3768 | +# |
3769 | +# You should have received a copy of the GNU General Public License |
3770 | +# along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
3771 | + |
3772 | +""" |
3773 | +:mod:`plainbox.vendor` -- vendorized packages |
3774 | +============================================= |
3775 | + |
3776 | +This module contains external packages that were vendorized (shipped with a |
3777 | +tree of another project) to simplify dependency management. There is no problem |
3778 | +with expressing those dependencies at pypi level but it would be annoying to |
3779 | +have to first package and introduce them to Ubuntu. |
3780 | +""" |
3781 | |
3782 | === modified file 'plainbox/plainbox/vendor/extcmd/__init__.py' |
3783 | --- plainbox/plainbox/vendor/extcmd/__init__.py 2013-02-22 16:26:25 +0000 |
3784 | +++ plainbox/plainbox/vendor/extcmd/__init__.py 2013-03-07 16:10:38 +0000 |
3785 | @@ -18,8 +18,8 @@ |
3786 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
3787 | |
3788 | """ |
3789 | -extcmd - subprocess with advanced output processing |
3790 | -=================================================== |
3791 | +:mod:`plainbox.vendor.extcmd` - subprocess with advanced output processing |
3792 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
3793 | |
3794 | Unlike subprocess, which just gives you a lump of output at the end, extcmd |
3795 | allows you to get callbacks (via a delegate class) on all IO. |
3796 | |
3797 | === modified file 'plainbox/setup.py' |
3798 | --- plainbox/setup.py 2013-02-22 16:26:25 +0000 |
3799 | +++ plainbox/setup.py 2013-03-07 16:10:38 +0000 |
3800 | @@ -31,6 +31,9 @@ |
3801 | author_email="zygmunt.krynicki@canonical.com", |
3802 | license="GPLv3+", |
3803 | description="Simple replacement for checkbox", |
3804 | + tests_require=[ |
3805 | + 'mock', |
3806 | + ], |
3807 | entry_points={ |
3808 | 'console_scripts': [ |
3809 | 'plainbox=plainbox.public:main', |
3810 | |
3811 | === modified file 'po/ace.po' |
3812 | --- po/ace.po 2013-02-22 16:26:25 +0000 |
3813 | +++ po/ace.po 2013-03-07 16:10:38 +0000 |
3814 | @@ -14,8 +14,8 @@ |
3815 | "MIME-Version: 1.0\n" |
3816 | "Content-Type: text/plain; charset=UTF-8\n" |
3817 | "Content-Transfer-Encoding: 8bit\n" |
3818 | -"X-Launchpad-Export-Date: 2013-02-15 04:31+0000\n" |
3819 | -"X-Generator: Launchpad (build 16491)\n" |
3820 | +"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n" |
3821 | +"X-Generator: Launchpad (build 16506)\n" |
3822 | |
3823 | #. Title of the user interface |
3824 | #: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1 |
3825 | @@ -964,7 +964,7 @@ |
3826 | msgstr "" |
3827 | |
3828 | #. description |
3829 | -#: ../jobs/input.txt.in:23 |
3830 | +#: ../jobs/input.txt.in:22 |
3831 | msgid "" |
3832 | "PURPOSE:\n" |
3833 | " This test will test your pointing device\n" |
3834 | @@ -976,7 +976,7 @@ |
3835 | msgstr "" |
3836 | |
3837 | #. description |
3838 | -#: ../jobs/input.txt.in:36 |
3839 | +#: ../jobs/input.txt.in:35 |
3840 | msgid "" |
3841 | "PURPOSE:\n" |
3842 | " This test will test your keyboard\n" |
3843 | |
3844 | === modified file 'po/af.po' |
3845 | --- po/af.po 2013-02-22 16:26:25 +0000 |
3846 | +++ po/af.po 2013-03-07 16:10:38 +0000 |
3847 | @@ -14,8 +14,8 @@ |
3848 | "MIME-Version: 1.0\n" |
3849 | "Content-Type: text/plain; charset=UTF-8\n" |
3850 | "Content-Transfer-Encoding: 8bit\n" |
3851 | -"X-Launchpad-Export-Date: 2013-02-15 04:31+0000\n" |
3852 | -"X-Generator: Launchpad (build 16491)\n" |
3853 | +"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n" |
3854 | +"X-Generator: Launchpad (build 16506)\n" |
3855 | |
3856 | #. Title of the user interface |
3857 | #: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1 |
3858 | @@ -964,7 +964,7 @@ |
3859 | msgstr "" |
3860 | |
3861 | #. description |
3862 | -#: ../jobs/input.txt.in:23 |
3863 | +#: ../jobs/input.txt.in:22 |
3864 | msgid "" |
3865 | "PURPOSE:\n" |
3866 | " This test will test your pointing device\n" |
3867 | @@ -976,7 +976,7 @@ |
3868 | msgstr "" |
3869 | |
3870 | #. description |
3871 | -#: ../jobs/input.txt.in:36 |
3872 | +#: ../jobs/input.txt.in:35 |
3873 | msgid "" |
3874 | "PURPOSE:\n" |
3875 | " This test will test your keyboard\n" |
3876 | |
3877 | === modified file 'po/am.po' |
3878 | --- po/am.po 2013-02-22 16:26:25 +0000 |
3879 | +++ po/am.po 2013-03-07 16:10:38 +0000 |
3880 | @@ -14,8 +14,8 @@ |
3881 | "MIME-Version: 1.0\n" |
3882 | "Content-Type: text/plain; charset=UTF-8\n" |
3883 | "Content-Transfer-Encoding: 8bit\n" |
3884 | -"X-Launchpad-Export-Date: 2013-02-15 04:31+0000\n" |
3885 | -"X-Generator: Launchpad (build 16491)\n" |
3886 | +"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n" |
3887 | +"X-Generator: Launchpad (build 16506)\n" |
3888 | |
3889 | #. Title of the user interface |
3890 | #: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1 |
3891 | @@ -964,7 +964,7 @@ |
3892 | msgstr "" |
3893 | |
3894 | #. description |
3895 | -#: ../jobs/input.txt.in:23 |
3896 | +#: ../jobs/input.txt.in:22 |
3897 | msgid "" |
3898 | "PURPOSE:\n" |
3899 | " This test will test your pointing device\n" |
3900 | @@ -976,7 +976,7 @@ |
3901 | msgstr "" |
3902 | |
3903 | #. description |
3904 | -#: ../jobs/input.txt.in:36 |
3905 | +#: ../jobs/input.txt.in:35 |
3906 | msgid "" |
3907 | "PURPOSE:\n" |
3908 | " This test will test your keyboard\n" |
3909 | |
3910 | === modified file 'po/ar.po' |
3911 | --- po/ar.po 2013-02-22 16:26:25 +0000 |
3912 | +++ po/ar.po 2013-03-07 16:10:38 +0000 |
3913 | @@ -14,8 +14,8 @@ |
3914 | "MIME-Version: 1.0\n" |
3915 | "Content-Type: text/plain; charset=UTF-8\n" |
3916 | "Content-Transfer-Encoding: 8bit\n" |
3917 | -"X-Launchpad-Export-Date: 2013-02-15 04:31+0000\n" |
3918 | -"X-Generator: Launchpad (build 16491)\n" |
3919 | +"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n" |
3920 | +"X-Generator: Launchpad (build 16506)\n" |
3921 | |
3922 | #. Title of the user interface |
3923 | #: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1 |
3924 | @@ -1139,7 +1139,7 @@ |
3925 | msgstr "" |
3926 | |
3927 | #. description |
3928 | -#: ../jobs/input.txt.in:23 |
3929 | +#: ../jobs/input.txt.in:22 |
3930 | msgid "" |
3931 | "PURPOSE:\n" |
3932 | " This test will test your pointing device\n" |
3933 | @@ -1151,7 +1151,7 @@ |
3934 | msgstr "" |
3935 | |
3936 | #. description |
3937 | -#: ../jobs/input.txt.in:36 |
3938 | +#: ../jobs/input.txt.in:35 |
3939 | msgid "" |
3940 | "PURPOSE:\n" |
3941 | " This test will test your keyboard\n" |
3942 | |
3943 | === modified file 'po/ast.po' |
3944 | --- po/ast.po 2013-02-22 16:26:25 +0000 |
3945 | +++ po/ast.po 2013-03-07 16:10:38 +0000 |
3946 | @@ -14,8 +14,8 @@ |
3947 | "MIME-Version: 1.0\n" |
3948 | "Content-Type: text/plain; charset=UTF-8\n" |
3949 | "Content-Transfer-Encoding: 8bit\n" |
3950 | -"X-Launchpad-Export-Date: 2013-02-15 04:31+0000\n" |
3951 | -"X-Generator: Launchpad (build 16491)\n" |
3952 | +"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n" |
3953 | +"X-Generator: Launchpad (build 16506)\n" |
3954 | "Language: ast\n" |
3955 | |
3956 | #. Title of the user interface |
3957 | @@ -1324,7 +1324,7 @@ |
3958 | msgstr "Axunta'l rexistru de depuración del instalador si existe." |
3959 | |
3960 | #. description |
3961 | -#: ../jobs/input.txt.in:23 |
3962 | +#: ../jobs/input.txt.in:22 |
3963 | msgid "" |
3964 | "PURPOSE:\n" |
3965 | " This test will test your pointing device\n" |
3966 | @@ -1343,7 +1343,7 @@ |
3967 | " ¿Comportóse'l preséu de punteru s'esperaba?" |
3968 | |
3969 | #. description |
3970 | -#: ../jobs/input.txt.in:36 |
3971 | +#: ../jobs/input.txt.in:35 |
3972 | msgid "" |
3973 | "PURPOSE:\n" |
3974 | " This test will test your keyboard\n" |
3975 | |
3976 | === modified file 'po/az.po' |
3977 | --- po/az.po 2013-02-22 16:26:25 +0000 |
3978 | +++ po/az.po 2013-03-07 16:10:38 +0000 |
3979 | @@ -14,8 +14,8 @@ |
3980 | "MIME-Version: 1.0\n" |
3981 | "Content-Type: text/plain; charset=UTF-8\n" |
3982 | "Content-Transfer-Encoding: 8bit\n" |
3983 | -"X-Launchpad-Export-Date: 2013-02-15 04:31+0000\n" |
3984 | -"X-Generator: Launchpad (build 16491)\n" |
3985 | +"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n" |
3986 | +"X-Generator: Launchpad (build 16506)\n" |
3987 | |
3988 | #. Title of the user interface |
3989 | #: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1 |
3990 | @@ -967,7 +967,7 @@ |
3991 | msgstr "" |
3992 | |
3993 | #. description |
3994 | -#: ../jobs/input.txt.in:23 |
3995 | +#: ../jobs/input.txt.in:22 |
3996 | msgid "" |
3997 | "PURPOSE:\n" |
3998 | " This test will test your pointing device\n" |
3999 | @@ -979,7 +979,7 @@ |
4000 | msgstr "" |
4001 | |
4002 | #. description |
4003 | -#: ../jobs/input.txt.in:36 |
4004 | +#: ../jobs/input.txt.in:35 |
4005 | msgid "" |
4006 | "PURPOSE:\n" |
4007 | " This test will test your keyboard\n" |
4008 | |
4009 | === modified file 'po/be.po' |
4010 | --- po/be.po 2013-02-22 16:26:25 +0000 |
4011 | +++ po/be.po 2013-03-07 16:10:38 +0000 |
4012 | @@ -14,8 +14,8 @@ |
4013 | "MIME-Version: 1.0\n" |
4014 | "Content-Type: text/plain; charset=UTF-8\n" |
4015 | "Content-Transfer-Encoding: 8bit\n" |
4016 | -"X-Launchpad-Export-Date: 2013-02-15 04:31+0000\n" |
4017 | -"X-Generator: Launchpad (build 16491)\n" |
4018 | +"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n" |
4019 | +"X-Generator: Launchpad (build 16506)\n" |
4020 | |
4021 | #. Title of the user interface |
4022 | #: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1 |
4023 | @@ -971,7 +971,7 @@ |
4024 | msgstr "" |
4025 | |
4026 | #. description |
4027 | -#: ../jobs/input.txt.in:23 |
4028 | +#: ../jobs/input.txt.in:22 |
4029 | msgid "" |
4030 | "PURPOSE:\n" |
4031 | " This test will test your pointing device\n" |
4032 | @@ -983,7 +983,7 @@ |
4033 | msgstr "" |
4034 | |
4035 | #. description |
4036 | -#: ../jobs/input.txt.in:36 |
4037 | +#: ../jobs/input.txt.in:35 |
4038 | msgid "" |
4039 | "PURPOSE:\n" |
4040 | " This test will test your keyboard\n" |
4041 | |
4042 | === modified file 'po/bg.po' |
4043 | --- po/bg.po 2013-02-22 16:26:25 +0000 |
4044 | +++ po/bg.po 2013-03-07 16:10:38 +0000 |
4045 | @@ -14,8 +14,8 @@ |
4046 | "MIME-Version: 1.0\n" |
4047 | "Content-Type: text/plain; charset=UTF-8\n" |
4048 | "Content-Transfer-Encoding: 8bit\n" |
4049 | -"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n" |
4050 | -"X-Generator: Launchpad (build 16491)\n" |
4051 | +"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n" |
4052 | +"X-Generator: Launchpad (build 16506)\n" |
4053 | |
4054 | #. Title of the user interface |
4055 | #: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1 |
4056 | @@ -968,7 +968,7 @@ |
4057 | msgstr "" |
4058 | |
4059 | #. description |
4060 | -#: ../jobs/input.txt.in:23 |
4061 | +#: ../jobs/input.txt.in:22 |
4062 | msgid "" |
4063 | "PURPOSE:\n" |
4064 | " This test will test your pointing device\n" |
4065 | @@ -980,7 +980,7 @@ |
4066 | msgstr "" |
4067 | |
4068 | #. description |
4069 | -#: ../jobs/input.txt.in:36 |
4070 | +#: ../jobs/input.txt.in:35 |
4071 | msgid "" |
4072 | "PURPOSE:\n" |
4073 | " This test will test your keyboard\n" |
4074 | |
4075 | === modified file 'po/bn.po' |
4076 | --- po/bn.po 2013-02-22 16:26:25 +0000 |
4077 | +++ po/bn.po 2013-03-07 16:10:38 +0000 |
4078 | @@ -14,8 +14,8 @@ |
4079 | "MIME-Version: 1.0\n" |
4080 | "Content-Type: text/plain; charset=UTF-8\n" |
4081 | "Content-Transfer-Encoding: 8bit\n" |
4082 | -"X-Launchpad-Export-Date: 2013-02-15 04:31+0000\n" |
4083 | -"X-Generator: Launchpad (build 16491)\n" |
4084 | +"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n" |
4085 | +"X-Generator: Launchpad (build 16506)\n" |
4086 | |
4087 | #. Title of the user interface |
4088 | #: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1 |
4089 | @@ -1215,7 +1215,7 @@ |
4090 | msgstr "ইনস্টলার ডিবাগ লগ বিদ্যমান থাকলে সংযুক্ত করা হয়।" |
4091 | |
4092 | #. description |
4093 | -#: ../jobs/input.txt.in:23 |
4094 | +#: ../jobs/input.txt.in:22 |
4095 | msgid "" |
4096 | "PURPOSE:\n" |
4097 | " This test will test your pointing device\n" |
4098 | @@ -1234,7 +1234,7 @@ |
4099 | " পয়েন্টকৃত ডিভাইসটি কি প্রত্যাশিত ভাবে কাজ করছে?" |
4100 | |
4101 | #. description |
4102 | -#: ../jobs/input.txt.in:36 |
4103 | +#: ../jobs/input.txt.in:35 |
4104 | msgid "" |
4105 | "PURPOSE:\n" |
4106 | " This test will test your keyboard\n" |
4107 | |
4108 | === modified file 'po/bo.po' |
4109 | --- po/bo.po 2013-02-22 16:26:25 +0000 |
4110 | +++ po/bo.po 2013-03-07 16:10:38 +0000 |
4111 | @@ -14,8 +14,8 @@ |
4112 | "MIME-Version: 1.0\n" |
4113 | "Content-Type: text/plain; charset=UTF-8\n" |
4114 | "Content-Transfer-Encoding: 8bit\n" |
4115 | -"X-Launchpad-Export-Date: 2013-02-15 04:34+0000\n" |
4116 | -"X-Generator: Launchpad (build 16491)\n" |
4117 | +"X-Launchpad-Export-Date: 2013-02-23 04:41+0000\n" |
4118 | +"X-Generator: Launchpad (build 16506)\n" |
4119 | |
4120 | #. Title of the user interface |
4121 | #: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1 |
4122 | @@ -964,7 +964,7 @@ |
4123 | msgstr "" |
4124 | |
4125 | #. description |
4126 | -#: ../jobs/input.txt.in:23 |
4127 | +#: ../jobs/input.txt.in:22 |
4128 | msgid "" |
4129 | "PURPOSE:\n" |
4130 | " This test will test your pointing device\n" |
4131 | @@ -976,7 +976,7 @@ |
4132 | msgstr "" |
4133 | |
4134 | #. description |
4135 | -#: ../jobs/input.txt.in:36 |
4136 | +#: ../jobs/input.txt.in:35 |
4137 | msgid "" |
4138 | "PURPOSE:\n" |
4139 | " This test will test your keyboard\n" |
4140 | |
4141 | === modified file 'po/br.po' |
4142 | --- po/br.po 2013-02-22 16:26:25 +0000 |
4143 | +++ po/br.po 2013-03-07 16:10:38 +0000 |
4144 | @@ -14,8 +14,8 @@ |
4145 | "MIME-Version: 1.0\n" |
4146 | "Content-Type: text/plain; charset=UTF-8\n" |
4147 | "Content-Transfer-Encoding: 8bit\n" |
4148 | -"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n" |
4149 | -"X-Generator: Launchpad (build 16491)\n" |
4150 | +"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n" |
4151 | +"X-Generator: Launchpad (build 16506)\n" |
4152 | |
4153 | #. Title of the user interface |
4154 | #: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1 |
4155 | @@ -964,7 +964,7 @@ |
4156 | msgstr "" |
4157 | |
4158 | #. description |
4159 | -#: ../jobs/input.txt.in:23 |
4160 | +#: ../jobs/input.txt.in:22 |
4161 | msgid "" |
4162 | "PURPOSE:\n" |
4163 | " This test will test your pointing device\n" |
4164 | @@ -976,7 +976,7 @@ |
4165 | msgstr "" |
4166 | |
4167 | #. description |
4168 | -#: ../jobs/input.txt.in:36 |
4169 | +#: ../jobs/input.txt.in:35 |
4170 | msgid "" |
4171 | "PURPOSE:\n" |
4172 | " This test will test your keyboard\n" |
4173 | |
4174 | === modified file 'po/bs.po' |
4175 | --- po/bs.po 2013-02-22 16:26:25 +0000 |
4176 | +++ po/bs.po 2013-03-07 16:10:38 +0000 |
4177 | @@ -14,8 +14,8 @@ |
4178 | "MIME-Version: 1.0\n" |
4179 | "Content-Type: text/plain; charset=UTF-8\n" |
4180 | "Content-Transfer-Encoding: 8bit\n" |
4181 | -"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n" |
4182 | -"X-Generator: Launchpad (build 16491)\n" |
4183 | +"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n" |
4184 | +"X-Generator: Launchpad (build 16506)\n" |
4185 | |
4186 | #. Title of the user interface |
4187 | #: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1 |
4188 | @@ -1271,7 +1271,7 @@ |
4189 | msgstr "Prilaže instalerski debug dnevnik ako postoji." |
4190 | |
4191 | #. description |
4192 | -#: ../jobs/input.txt.in:23 |
4193 | +#: ../jobs/input.txt.in:22 |
4194 | msgid "" |
4195 | "PURPOSE:\n" |
4196 | " This test will test your pointing device\n" |
4197 | @@ -1290,7 +1290,7 @@ |
4198 | " Da li radi pokazivački uređaj kao što je očekivano?" |
4199 | |
4200 | #. description |
4201 | -#: ../jobs/input.txt.in:36 |
4202 | +#: ../jobs/input.txt.in:35 |
4203 | msgid "" |
4204 | "PURPOSE:\n" |
4205 | " This test will test your keyboard\n" |
4206 | |
4207 | === modified file 'po/ca.po' |
4208 | --- po/ca.po 2013-02-22 16:26:25 +0000 |
4209 | +++ po/ca.po 2013-03-07 16:10:38 +0000 |
4210 | @@ -14,8 +14,8 @@ |
4211 | "MIME-Version: 1.0\n" |
4212 | "Content-Type: text/plain; charset=UTF-8\n" |
4213 | "Content-Transfer-Encoding: 8bit\n" |
4214 | -"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n" |
4215 | -"X-Generator: Launchpad (build 16491)\n" |
4216 | +"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n" |
4217 | +"X-Generator: Launchpad (build 16506)\n" |
4218 | |
4219 | #~ msgid "$output" |
4220 | #~ msgstr "$resultat" |
4221 | @@ -989,7 +989,7 @@ |
4222 | msgstr "" |
4223 | |
4224 | #. description |
4225 | -#: ../jobs/input.txt.in:23 |
4226 | +#: ../jobs/input.txt.in:22 |
4227 | msgid "" |
4228 | "PURPOSE:\n" |
4229 | " This test will test your pointing device\n" |
4230 | @@ -1001,7 +1001,7 @@ |
4231 | msgstr "" |
4232 | |
4233 | #. description |
4234 | -#: ../jobs/input.txt.in:36 |
4235 | +#: ../jobs/input.txt.in:35 |
4236 | msgid "" |
4237 | "PURPOSE:\n" |
4238 | " This test will test your keyboard\n" |
4239 | |
4240 | === modified file 'po/ca@valencia.po' |
4241 | --- po/ca@valencia.po 2013-02-22 16:26:25 +0000 |
4242 | +++ po/ca@valencia.po 2013-03-07 16:10:38 +0000 |
4243 | @@ -14,8 +14,8 @@ |
4244 | "MIME-Version: 1.0\n" |
4245 | "Content-Type: text/plain; charset=UTF-8\n" |
4246 | "Content-Transfer-Encoding: 8bit\n" |
4247 | -"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n" |
4248 | -"X-Generator: Launchpad (build 16491)\n" |
4249 | +"X-Launchpad-Export-Date: 2013-02-23 04:42+0000\n" |
4250 | +"X-Generator: Launchpad (build 16506)\n" |
4251 | |
4252 | #. Title of the user interface |
4253 | #: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1 |
4254 | @@ -986,7 +986,7 @@ |
4255 | msgstr "" |
4256 | |
4257 | #. description |
4258 | -#: ../jobs/input.txt.in:23 |
4259 | +#: ../jobs/input.txt.in:22 |
4260 | msgid "" |
4261 | "PURPOSE:\n" |
4262 | " This test will test your pointing device\n" |
4263 | @@ -998,7 +998,7 @@ |
4264 | msgstr "" |
4265 | |
4266 | #. description |
4267 | -#: ../jobs/input.txt.in:36 |
4268 | +#: ../jobs/input.txt.in:35 |
4269 | msgid "" |
4270 | "PURPOSE:\n" |
4271 | " This test will test your keyboard\n" |
4272 | |
4273 | === modified file 'po/ckb.po' |
4274 | --- po/ckb.po 2013-02-22 16:26:25 +0000 |
4275 | +++ po/ckb.po 2013-03-07 16:10:38 +0000 |
4276 | @@ -14,8 +14,8 @@ |
4277 | "MIME-Version: 1.0\n" |
4278 | "Content-Type: text/plain; charset=UTF-8\n" |
4279 | "Content-Transfer-Encoding: 8bit\n" |
4280 | -"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n" |
4281 | -"X-Generator: Launchpad (build 16491)\n" |
4282 | +"X-Launchpad-Export-Date: 2013-02-23 04:41+0000\n" |
4283 | +"X-Generator: Launchpad (build 16506)\n" |
4284 | |
4285 | #. Title of the user interface |
4286 | #: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1 |
4287 | @@ -964,7 +964,7 @@ |
4288 | msgstr "" |
4289 | |
4290 | #. description |
4291 | -#: ../jobs/input.txt.in:23 |
4292 | +#: ../jobs/input.txt.in:22 |
4293 | msgid "" |
4294 | "PURPOSE:\n" |
4295 | " This test will test your pointing device\n" |
4296 | @@ -976,7 +976,7 @@ |
4297 | msgstr "" |
4298 | |
4299 | #. description |
4300 | -#: ../jobs/input.txt.in:36 |
4301 | +#: ../jobs/input.txt.in:35 |
4302 | msgid "" |
4303 | "PURPOSE:\n" |
4304 | " This test will test your keyboard\n" |
4305 | |
4306 | === modified file 'po/cs.po' |
4307 | --- po/cs.po 2013-02-22 16:26:25 +0000 |
4308 | +++ po/cs.po 2013-03-07 16:10:38 +0000 |
4309 | @@ -14,8 +14,8 @@ |
4310 | "MIME-Version: 1.0\n" |
4311 | "Content-Type: text/plain; charset=UTF-8\n" |
4312 | "Content-Transfer-Encoding: 8bit\n" |
4313 | -"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n" |
4314 | -"X-Generator: Launchpad (build 16491)\n" |
4315 | +"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n" |
4316 | +"X-Generator: Launchpad (build 16506)\n" |
4317 | |
4318 | #: ../gtk/checkbox-gtk.ui.h:2 ../checkbox_gtk/gtk_interface.py:561 |
4319 | msgid "_Test" |
4320 | @@ -1215,7 +1215,7 @@ |
4321 | msgstr "Existuje-li, připojí ladicí záznam instalátoru" |
4322 | |
4323 | #. description |
4324 | -#: ../jobs/input.txt.in:23 |
4325 | +#: ../jobs/input.txt.in:22 |
4326 | msgid "" |
4327 | "PURPOSE:\n" |
4328 | " This test will test your pointing device\n" |
4329 | @@ -1234,7 +1234,7 @@ |
4330 | " Fungovalo dotykové zařízení dle očekávání?" |
4331 | |
4332 | #. description |
4333 | -#: ../jobs/input.txt.in:36 |
4334 | +#: ../jobs/input.txt.in:35 |
4335 | msgid "" |
4336 | "PURPOSE:\n" |
4337 | " This test will test your keyboard\n" |
4338 | |
4339 | === modified file 'po/cy.po' |
4340 | --- po/cy.po 2013-02-22 16:26:25 +0000 |
4341 | +++ po/cy.po 2013-03-07 16:10:38 +0000 |
4342 | @@ -14,8 +14,8 @@ |
4343 | "MIME-Version: 1.0\n" |
4344 | "Content-Type: text/plain; charset=UTF-8\n" |
4345 | "Content-Transfer-Encoding: 8bit\n" |
4346 | -"X-Launchpad-Export-Date: 2013-02-15 04:34+0000\n" |
4347 | -"X-Generator: Launchpad (build 16491)\n" |
4348 | +"X-Launchpad-Export-Date: 2013-02-23 04:41+0000\n" |
4349 | +"X-Generator: Launchpad (build 16506)\n" |
4350 | |
4351 | #. Title of the user interface |
4352 | #: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1 |
4353 | @@ -964,7 +964,7 @@ |
4354 | msgstr "" |
4355 | |
4356 | #. description |
4357 | -#: ../jobs/input.txt.in:23 |
4358 | +#: ../jobs/input.txt.in:22 |
4359 | msgid "" |
4360 | "PURPOSE:\n" |
4361 | " This test will test your pointing device\n" |
4362 | @@ -976,7 +976,7 @@ |
4363 | msgstr "" |
4364 | |
4365 | #. description |
4366 | -#: ../jobs/input.txt.in:36 |
4367 | +#: ../jobs/input.txt.in:35 |
4368 | msgid "" |
4369 | "PURPOSE:\n" |
4370 | " This test will test your keyboard\n" |
4371 | |
4372 | === modified file 'po/da.po' |
4373 | --- po/da.po 2013-02-22 16:26:25 +0000 |
4374 | +++ po/da.po 2013-03-07 16:10:38 +0000 |
4375 | @@ -14,8 +14,8 @@ |
4376 | "MIME-Version: 1.0\n" |
4377 | "Content-Type: text/plain; charset=UTF-8\n" |
4378 | "Content-Transfer-Encoding: 8bit\n" |
4379 | -"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n" |
4380 | -"X-Generator: Launchpad (build 16491)\n" |
4381 | +"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n" |
4382 | +"X-Generator: Launchpad (build 16506)\n" |
4383 | "X-Poedit-Language: Danish\n" |
4384 | |
4385 | #. Title of the user interface |
4386 | @@ -1131,7 +1131,7 @@ |
4387 | msgstr "" |
4388 | |
4389 | #. description |
4390 | -#: ../jobs/input.txt.in:23 |
4391 | +#: ../jobs/input.txt.in:22 |
4392 | msgid "" |
4393 | "PURPOSE:\n" |
4394 | " This test will test your pointing device\n" |
4395 | @@ -1143,7 +1143,7 @@ |
4396 | msgstr "" |
4397 | |
4398 | #. description |
4399 | -#: ../jobs/input.txt.in:36 |
4400 | +#: ../jobs/input.txt.in:35 |
4401 | msgid "" |
4402 | "PURPOSE:\n" |
4403 | " This test will test your keyboard\n" |
4404 | |
4405 | === modified file 'po/de.po' |
4406 | --- po/de.po 2013-02-22 16:26:25 +0000 |
4407 | +++ po/de.po 2013-03-07 16:10:38 +0000 |
4408 | @@ -14,8 +14,8 @@ |
4409 | "MIME-Version: 1.0\n" |
4410 | "Content-Type: text/plain; charset=UTF-8\n" |
4411 | "Content-Transfer-Encoding: 8bit\n" |
4412 | -"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n" |
4413 | -"X-Generator: Launchpad (build 16491)\n" |
4414 | +"X-Launchpad-Export-Date: 2013-02-23 04:39+0000\n" |
4415 | +"X-Generator: Launchpad (build 16506)\n" |
4416 | |
4417 | #: ../gtk/checkbox-gtk.ui.h:2 ../checkbox_gtk/gtk_interface.py:561 |
4418 | msgid "_Test" |
4419 | @@ -83,7 +83,7 @@ |
4420 | |
4421 | #: ../gtk/checkbox-gtk.ui.h:5 |
4422 | msgid "_Skip this test" |
4423 | -msgstr "Test _überspringen" |
4424 | +msgstr "_Diesen Test überspringen" |
4425 | |
4426 | #: ../gtk/checkbox-gtk.ui.h:6 ../checkbox_cli/cli_interface.py:460 |
4427 | #: ../checkbox_urwid/urwid_interface.py:289 |
4428 | @@ -1425,7 +1425,7 @@ |
4429 | "als Anlage bei, falls vorhanden." |
4430 | |
4431 | #. description |
4432 | -#: ../jobs/input.txt.in:23 |
4433 | +#: ../jobs/input.txt.in:22 |
4434 | msgid "" |
4435 | "PURPOSE:\n" |
4436 | " This test will test your pointing device\n" |
4437 | @@ -1445,7 +1445,7 @@ |
4438 | " Arbeitete das Zeigegerät so, wie es vorgesehen ist?" |
4439 | |
4440 | #. description |
4441 | -#: ../jobs/input.txt.in:36 |
4442 | +#: ../jobs/input.txt.in:35 |
4443 | msgid "" |
4444 | "PURPOSE:\n" |
4445 | " This test will test your keyboard\n" |
4446 | |
4447 | === modified file 'po/dv.po' |
4448 | --- po/dv.po 2013-02-22 16:26:25 +0000 |
4449 | +++ po/dv.po 2013-03-07 16:10:38 +0000 |
4450 | @@ -14,8 +14,8 @@ |
4451 | "MIME-Version: 1.0\n" |
4452 | "Content-Type: text/plain; charset=UTF-8\n" |
4453 | "Content-Transfer-Encoding: 8bit\n" |
4454 | -"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n" |
4455 | -"X-Generator: Launchpad (build 16491)\n" |
4456 | +"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n" |
4457 | +"X-Generator: Launchpad (build 16506)\n" |
4458 | |
4459 | #. Title of the user interface |
4460 | #: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1 |
4461 | @@ -964,7 +964,7 @@ |
4462 | msgstr "" |
4463 | |
4464 | #. description |
4465 | -#: ../jobs/input.txt.in:23 |
4466 | +#: ../jobs/input.txt.in:22 |
4467 | msgid "" |
4468 | "PURPOSE:\n" |
4469 | " This test will test your pointing device\n" |
4470 | @@ -976,7 +976,7 @@ |
4471 | msgstr "" |
4472 | |
4473 | #. description |
4474 | -#: ../jobs/input.txt.in:36 |
4475 | +#: ../jobs/input.txt.in:35 |
4476 | msgid "" |
4477 | "PURPOSE:\n" |
4478 | " This test will test your keyboard\n" |
4479 | |
4480 | === modified file 'po/el.po' |
4481 | --- po/el.po 2013-02-22 16:26:25 +0000 |
4482 | +++ po/el.po 2013-03-07 16:10:38 +0000 |
4483 | @@ -14,8 +14,8 @@ |
4484 | "MIME-Version: 1.0\n" |
4485 | "Content-Type: text/plain; charset=utf-8\n" |
4486 | "Content-Transfer-Encoding: 8bit\n" |
4487 | -"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n" |
4488 | -"X-Generator: Launchpad (build 16491)\n" |
4489 | +"X-Launchpad-Export-Date: 2013-02-23 04:39+0000\n" |
4490 | +"X-Generator: Launchpad (build 16506)\n" |
4491 | |
4492 | #: ../gtk/checkbox-gtk.ui.h:2 ../checkbox_gtk/gtk_interface.py:561 |
4493 | msgid "_Test" |
4494 | @@ -1389,7 +1389,7 @@ |
4495 | msgstr "Επισύναψη της καταγραφής αποσφαλμάτωσης του εγκαταστάτη αν υπάρχει." |
4496 | |
4497 | #. description |
4498 | -#: ../jobs/input.txt.in:23 |
4499 | +#: ../jobs/input.txt.in:22 |
4500 | msgid "" |
4501 | "PURPOSE:\n" |
4502 | " This test will test your pointing device\n" |
4503 | @@ -1409,7 +1409,7 @@ |
4504 | " Λειτούργησε η συσκευή κατάδειξης όπως θα περιμένατε;" |
4505 | |
4506 | #. description |
4507 | -#: ../jobs/input.txt.in:36 |
4508 | +#: ../jobs/input.txt.in:35 |
4509 | msgid "" |
4510 | "PURPOSE:\n" |
4511 | " This test will test your keyboard\n" |
4512 | |
4513 | === modified file 'po/en_AU.po' |
4514 | --- po/en_AU.po 2013-02-22 16:26:25 +0000 |
4515 | +++ po/en_AU.po 2013-03-07 16:10:38 +0000 |
4516 | @@ -14,8 +14,8 @@ |
4517 | "MIME-Version: 1.0\n" |
4518 | "Content-Type: text/plain; charset=UTF-8\n" |
4519 | "Content-Transfer-Encoding: 8bit\n" |
4520 | -"X-Launchpad-Export-Date: 2013-02-15 04:34+0000\n" |
4521 | -"X-Generator: Launchpad (build 16491)\n" |
4522 | +"X-Launchpad-Export-Date: 2013-02-23 04:41+0000\n" |
4523 | +"X-Generator: Launchpad (build 16506)\n" |
4524 | |
4525 | #. Title of the user interface |
4526 | #: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1 |
4527 | @@ -1254,7 +1254,7 @@ |
4528 | msgstr "Attaches the installer debug log if it exists." |
4529 | |
4530 | #. description |
4531 | -#: ../jobs/input.txt.in:23 |
4532 | +#: ../jobs/input.txt.in:22 |
4533 | msgid "" |
4534 | "PURPOSE:\n" |
4535 | " This test will test your pointing device\n" |
4536 | @@ -1273,7 +1273,7 @@ |
4537 | " Did the pointing device work as expected?" |
4538 | |
4539 | #. description |
4540 | -#: ../jobs/input.txt.in:36 |
4541 | +#: ../jobs/input.txt.in:35 |
4542 | msgid "" |
4543 | "PURPOSE:\n" |
4544 | " This test will test your keyboard\n" |
4545 | |
4546 | === modified file 'po/en_CA.po' |
4547 | --- po/en_CA.po 2013-02-22 16:26:25 +0000 |
4548 | +++ po/en_CA.po 2013-03-07 16:10:38 +0000 |
4549 | @@ -14,8 +14,8 @@ |
4550 | "MIME-Version: 1.0\n" |
4551 | "Content-Type: text/plain; charset=UTF-8\n" |
4552 | "Content-Transfer-Encoding: 8bit\n" |
4553 | -"X-Launchpad-Export-Date: 2013-02-15 04:35+0000\n" |
4554 | -"X-Generator: Launchpad (build 16491)\n" |
4555 | +"X-Launchpad-Export-Date: 2013-02-23 04:41+0000\n" |
4556 | +"X-Generator: Launchpad (build 16506)\n" |
4557 | |
4558 | #. Title of the user interface |
4559 | #: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1 |
4560 | @@ -964,7 +964,7 @@ |
4561 | msgstr "" |
4562 | |
4563 | #. description |
4564 | -#: ../jobs/input.txt.in:23 |
4565 | +#: ../jobs/input.txt.in:22 |
4566 | msgid "" |
4567 | "PURPOSE:\n" |
4568 | " This test will test your pointing device\n" |
4569 | @@ -976,7 +976,7 @@ |
4570 | msgstr "" |
4571 | |
4572 | #. description |
4573 | -#: ../jobs/input.txt.in:36 |
4574 | +#: ../jobs/input.txt.in:35 |
4575 | msgid "" |
4576 | "PURPOSE:\n" |
4577 | " This test will test your keyboard\n" |
4578 | |
4579 | === modified file 'po/en_GB.po' |
4580 | --- po/en_GB.po 2013-02-22 16:26:25 +0000 |
4581 | +++ po/en_GB.po 2013-03-07 16:10:38 +0000 |
4582 | @@ -14,8 +14,8 @@ |
4583 | "MIME-Version: 1.0\n" |
4584 | "Content-Type: text/plain; charset=UTF-8\n" |
4585 | "Content-Transfer-Encoding: 8bit\n" |
4586 | -"X-Launchpad-Export-Date: 2013-02-15 04:34+0000\n" |
4587 | -"X-Generator: Launchpad (build 16491)\n" |
4588 | +"X-Launchpad-Export-Date: 2013-02-23 04:41+0000\n" |
4589 | +"X-Generator: Launchpad (build 16506)\n" |
4590 | |
4591 | #~ msgid "Do you see color bars and static?" |
4592 | #~ msgstr "Do you see colour bars and static?" |
4593 | @@ -1257,7 +1257,7 @@ |
4594 | msgstr "Attaches the installer debug log if it exists." |
4595 | |
4596 | #. description |
4597 | -#: ../jobs/input.txt.in:23 |
4598 | +#: ../jobs/input.txt.in:22 |
4599 | msgid "" |
4600 | "PURPOSE:\n" |
4601 | " This test will test your pointing device\n" |
4602 | @@ -1276,7 +1276,7 @@ |
4603 | " Did the pointing device work as expected?" |
4604 | |
4605 | #. description |
4606 | -#: ../jobs/input.txt.in:36 |
4607 | +#: ../jobs/input.txt.in:35 |
4608 | msgid "" |
4609 | "PURPOSE:\n" |
4610 | " This test will test your keyboard\n" |
4611 | |
4612 | === modified file 'po/eo.po' |
4613 | --- po/eo.po 2013-02-22 16:26:25 +0000 |
4614 | +++ po/eo.po 2013-03-07 16:10:38 +0000 |
4615 | @@ -14,8 +14,8 @@ |
4616 | "MIME-Version: 1.0\n" |
4617 | "Content-Type: text/plain; charset=UTF-8\n" |
4618 | "Content-Transfer-Encoding: 8bit\n" |
4619 | -"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n" |
4620 | -"X-Generator: Launchpad (build 16491)\n" |
4621 | +"X-Launchpad-Export-Date: 2013-02-23 04:39+0000\n" |
4622 | +"X-Generator: Launchpad (build 16506)\n" |
4623 | |
4624 | #: ../checkbox/application.py:66 |
4625 | msgid "Usage: checkbox [OPTIONS]" |
4626 | @@ -1017,7 +1017,7 @@ |
4627 | msgstr "" |
4628 | |
4629 | #. description |
4630 | -#: ../jobs/input.txt.in:23 |
4631 | +#: ../jobs/input.txt.in:22 |
4632 | msgid "" |
4633 | "PURPOSE:\n" |
4634 | " This test will test your pointing device\n" |
4635 | @@ -1029,7 +1029,7 @@ |
4636 | msgstr "" |
4637 | |
4638 | #. description |
4639 | -#: ../jobs/input.txt.in:36 |
4640 | +#: ../jobs/input.txt.in:35 |
4641 | msgid "" |
4642 | "PURPOSE:\n" |
4643 | " This test will test your keyboard\n" |
4644 | |
4645 | === modified file 'po/es.po' |
4646 | --- po/es.po 2013-02-22 16:26:25 +0000 |
4647 | +++ po/es.po 2013-03-07 16:10:38 +0000 |
4648 | @@ -14,8 +14,8 @@ |
4649 | "MIME-Version: 1.0\n" |
4650 | "Content-Type: text/plain; charset=UTF-8\n" |
4651 | "Content-Transfer-Encoding: 8bit\n" |
4652 | -"X-Launchpad-Export-Date: 2013-02-15 04:34+0000\n" |
4653 | -"X-Generator: Launchpad (build 16491)\n" |
4654 | +"X-Launchpad-Export-Date: 2013-02-23 04:41+0000\n" |
4655 | +"X-Generator: Launchpad (build 16506)\n" |
4656 | |
4657 | #: ../checkbox/application.py:70 |
4658 | msgid "Print version information and exit." |
4659 | @@ -1418,7 +1418,7 @@ |
4660 | msgstr "Adjunta el registro de depuración del instalador si existe." |
4661 | |
4662 | #. description |
4663 | -#: ../jobs/input.txt.in:23 |
4664 | +#: ../jobs/input.txt.in:22 |
4665 | msgid "" |
4666 | "PURPOSE:\n" |
4667 | " This test will test your pointing device\n" |
4668 | @@ -1438,7 +1438,7 @@ |
4669 | " ¿Se comportó el dispositivo de puntero como se esperaba?" |
4670 | |
4671 | #. description |
4672 | -#: ../jobs/input.txt.in:36 |
4673 | +#: ../jobs/input.txt.in:35 |
4674 | msgid "" |
4675 | "PURPOSE:\n" |
4676 | " This test will test your keyboard\n" |
4677 | |
4678 | === modified file 'po/et.po' |
4679 | --- po/et.po 2013-02-22 16:26:25 +0000 |
4680 | +++ po/et.po 2013-03-07 16:10:38 +0000 |
4681 | @@ -14,8 +14,8 @@ |
4682 | "MIME-Version: 1.0\n" |
4683 | "Content-Type: text/plain; charset=UTF-8\n" |
4684 | "Content-Transfer-Encoding: 8bit\n" |
4685 | -"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n" |
4686 | -"X-Generator: Launchpad (build 16491)\n" |
4687 | +"X-Launchpad-Export-Date: 2013-02-23 04:39+0000\n" |
4688 | +"X-Generator: Launchpad (build 16506)\n" |
4689 | |
4690 | #. Title of the user interface |
4691 | #: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1 |
4692 | @@ -964,7 +964,7 @@ |
4693 | msgstr "" |
4694 | |
4695 | #. description |
4696 | -#: ../jobs/input.txt.in:23 |
4697 | +#: ../jobs/input.txt.in:22 |
4698 | msgid "" |
4699 | "PURPOSE:\n" |
4700 | " This test will test your pointing device\n" |
4701 | @@ -976,7 +976,7 @@ |
4702 | msgstr "" |
4703 | |
4704 | #. description |
4705 | -#: ../jobs/input.txt.in:36 |
4706 | +#: ../jobs/input.txt.in:35 |
4707 | msgid "" |
4708 | "PURPOSE:\n" |
4709 | " This test will test your keyboard\n" |
4710 | |
4711 | === modified file 'po/eu.po' |
4712 | --- po/eu.po 2013-02-22 16:26:25 +0000 |
4713 | +++ po/eu.po 2013-03-07 16:10:38 +0000 |
4714 | @@ -14,8 +14,8 @@ |
4715 | "MIME-Version: 1.0\n" |
4716 | "Content-Type: text/plain; charset=UTF-8\n" |
4717 | "Content-Transfer-Encoding: 8bit\n" |
4718 | -"X-Launchpad-Export-Date: 2013-02-15 04:31+0000\n" |
4719 | -"X-Generator: Launchpad (build 16491)\n" |
4720 | +"X-Launchpad-Export-Date: 2013-02-23 04:38+0000\n" |
4721 | +"X-Generator: Launchpad (build 16506)\n" |
4722 | |
4723 | #. Title of the user interface |
4724 | #: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1 |
4725 | @@ -964,7 +964,7 @@ |
4726 | msgstr "" |
4727 | |
4728 | #. description |
4729 | -#: ../jobs/input.txt.in:23 |
4730 | +#: ../jobs/input.txt.in:22 |
4731 | msgid "" |
4732 | "PURPOSE:\n" |
4733 | " This test will test your pointing device\n" |
4734 | @@ -976,7 +976,7 @@ |
4735 | msgstr "" |
4736 | |
4737 | #. description |
4738 | -#: ../jobs/input.txt.in:36 |
4739 | +#: ../jobs/input.txt.in:35 |
4740 | msgid "" |
4741 | "PURPOSE:\n" |
4742 | " This test will test your keyboard\n" |
4743 | |
4744 | === modified file 'po/fa.po' |
4745 | --- po/fa.po 2013-02-22 16:26:25 +0000 |
4746 | +++ po/fa.po 2013-03-07 16:10:38 +0000 |
4747 | @@ -14,8 +14,8 @@ |
4748 | "MIME-Version: 1.0\n" |
4749 | "Content-Type: text/plain; charset=UTF-8\n" |
4750 | "Content-Transfer-Encoding: 8bit\n" |
4751 | -"X-Launchpad-Export-Date: 2013-02-15 04:33+0000\n" |
4752 | -"X-Generator: Launchpad (build 16491)\n" |
4753 | +"X-Launchpad-Export-Date: 2013-02-23 04:40+0000\n" |
4754 | +"X-Generator: Launchpad (build 16506)\n" |
4755 | |
4756 | #. Title of the user interface |
4757 | #: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1 |
4758 | @@ -964,7 +964,7 @@ |
4759 | msgstr "" |
4760 | |
4761 | #. description |
4762 | -#: ../jobs/input.txt.in:23 |
4763 | +#: ../jobs/input.txt.in:22 |
4764 | msgid "" |
4765 | "PURPOSE:\n" |
4766 | " This test will test your pointing device\n" |
4767 | @@ -976,7 +976,7 @@ |
4768 | msgstr "" |
4769 | |
4770 | #. description |
4771 | -#: ../jobs/input.txt.in:36 |
4772 | +#: ../jobs/input.txt.in:35 |
4773 | msgid "" |
4774 | "PURPOSE:\n" |
4775 | " This test will test your keyboard\n" |
4776 | |
4777 | === modified file 'po/fi.po' |
4778 | --- po/fi.po 2013-02-22 16:26:25 +0000 |
4779 | +++ po/fi.po 2013-03-07 16:10:38 +0000 |
4780 | @@ -14,8 +14,8 @@ |
4781 | "MIME-Version: 1.0\n" |
4782 | "Content-Type: text/plain; charset=UTF-8\n" |
4783 | "Content-Transfer-Encoding: 8bit\n" |
4784 | -"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n" |
4785 | -"X-Generator: Launchpad (build 16491)\n" |
4786 | +"X-Launchpad-Export-Date: 2013-02-23 04:39+0000\n" |
4787 | +"X-Generator: Launchpad (build 16506)\n" |
4788 | |
4789 | #. Title of the user interface |
4790 | #: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1 |
4791 | @@ -1240,7 +1240,7 @@ |
4792 | msgstr "" |
4793 | |
4794 | #. description |
4795 | -#: ../jobs/input.txt.in:23 |
4796 | +#: ../jobs/input.txt.in:22 |
4797 | msgid "" |
4798 | "PURPOSE:\n" |
4799 | " This test will test your pointing device\n" |
4800 | @@ -1260,7 +1260,7 @@ |
4801 | " Toimiko osoitinlaite odotetulla tavalla?" |
4802 | |
4803 | #. description |
4804 | -#: ../jobs/input.txt.in:36 |
4805 | +#: ../jobs/input.txt.in:35 |
4806 | msgid "" |
4807 | "PURPOSE:\n" |
4808 | " This test will test your keyboard\n" |
4809 | |
4810 | === modified file 'po/fr.po' |
4811 | --- po/fr.po 2013-02-22 16:26:25 +0000 |
4812 | +++ po/fr.po 2013-03-07 16:10:38 +0000 |
4813 | @@ -13,8 +13,8 @@ |
4814 | "MIME-Version: 1.0\n" |
4815 | "Content-Type: text/plain; charset=UTF-8\n" |
4816 | "Content-Transfer-Encoding: 8bit\n" |
4817 | -"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n" |
4818 | -"X-Generator: Launchpad (build 16491)\n" |
4819 | +"X-Launchpad-Export-Date: 2013-02-23 04:39+0000\n" |
4820 | +"X-Generator: Launchpad (build 16506)\n" |
4821 | |
4822 | #. Title of the user interface |
4823 | #: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1 |
4824 | @@ -1363,7 +1363,7 @@ |
4825 | msgstr "Joint le journal de débogage de l'installateur s'il existe." |
4826 | |
4827 | #. description |
4828 | -#: ../jobs/input.txt.in:23 |
4829 | +#: ../jobs/input.txt.in:22 |
4830 | msgid "" |
4831 | "PURPOSE:\n" |
4832 | " This test will test your pointing device\n" |
4833 | @@ -1383,7 +1383,7 @@ |
4834 | " Est-ce que le périphérique de pointage a fonctionné correctement ?" |
4835 | |
4836 | #. description |
4837 | -#: ../jobs/input.txt.in:36 |
4838 | +#: ../jobs/input.txt.in:35 |
4839 | msgid "" |
4840 | "PURPOSE:\n" |
4841 | " This test will test your keyboard\n" |
4842 | |
4843 | === modified file 'po/ga.po' |
4844 | --- po/ga.po 2013-02-22 16:26:25 +0000 |
4845 | +++ po/ga.po 2013-03-07 16:10:38 +0000 |
4846 | @@ -14,8 +14,8 @@ |
4847 | "MIME-Version: 1.0\n" |
4848 | "Content-Type: text/plain; charset=UTF-8\n" |
4849 | "Content-Transfer-Encoding: 8bit\n" |
4850 | -"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n" |
4851 | -"X-Generator: Launchpad (build 16491)\n" |
4852 | +"X-Launchpad-Export-Date: 2013-02-23 04:39+0000\n" |
4853 | +"X-Generator: Launchpad (build 16506)\n" |
4854 | |
4855 | #. Title of the user interface |
4856 | #: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1 |
4857 | @@ -964,7 +964,7 @@ |
4858 | msgstr "" |
4859 | |
4860 | #. description |
4861 | -#: ../jobs/input.txt.in:23 |
4862 | +#: ../jobs/input.txt.in:22 |
4863 | msgid "" |
4864 | "PURPOSE:\n" |
4865 | " This test will test your pointing device\n" |
4866 | @@ -976,7 +976,7 @@ |
4867 | msgstr "" |
4868 | |
4869 | #. description |
4870 | -#: ../jobs/input.txt.in:36 |
4871 | +#: ../jobs/input.txt.in:35 |
4872 | msgid "" |
4873 | "PURPOSE:\n" |
4874 | " This test will test your keyboard\n" |
4875 | |
4876 | === modified file 'po/gd.po' |
4877 | --- po/gd.po 2013-02-22 16:26:25 +0000 |
4878 | +++ po/gd.po 2013-03-07 16:10:38 +0000 |
4879 | @@ -14,8 +14,8 @@ |
4880 | "MIME-Version: 1.0\n" |
4881 | "Content-Type: text/plain; charset=UTF-8\n" |
4882 | "Content-Transfer-Encoding: 8bit\n" |
4883 | -"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n" |
4884 | -"X-Generator: Launchpad (build 16491)\n" |
4885 | +"X-Launchpad-Export-Date: 2013-02-23 04:39+0000\n" |
4886 | +"X-Generator: Launchpad (build 16506)\n" |
4887 | |
4888 | #. Title of the user interface |
4889 | #: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1 |
4890 | @@ -1295,7 +1295,7 @@ |
4891 | msgstr "A' ceangal log dì-bhugaich an stàlaichear ma tha e ann." |
4892 | |
4893 | #. description |
4894 | -#: ../jobs/input.txt.in:23 |
4895 | +#: ../jobs/input.txt.in:22 |
4896 | msgid "" |
4897 | "PURPOSE:\n" |
4898 | " This test will test your pointing device\n" |
4899 | @@ -1315,7 +1315,7 @@ |
4900 | " An do dh'obraich an innleachd comharraich mar a bha dùil?" |
4901 | |
4902 | #. description |
4903 | -#: ../jobs/input.txt.in:36 |
4904 | +#: ../jobs/input.txt.in:35 |
4905 | msgid "" |
4906 | "PURPOSE:\n" |
4907 | " This test will test your keyboard\n" |
4908 | |
4909 | === modified file 'po/gl.po' |
4910 | --- po/gl.po 2013-02-22 16:26:25 +0000 |
4911 | +++ po/gl.po 2013-03-07 16:10:38 +0000 |
4912 | @@ -15,8 +15,8 @@ |
4913 | "MIME-Version: 1.0\n" |
4914 | "Content-Type: text/plain; charset=UTF-8\n" |
4915 | "Content-Transfer-Encoding: 8bit\n" |
4916 | -"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n" |
4917 | -"X-Generator: Launchpad (build 16491)\n" |
4918 | +"X-Launchpad-Export-Date: 2013-02-23 04:39+0000\n" |
4919 | +"X-Generator: Launchpad (build 16506)\n" |
4920 | |
4921 | #. Title of the user interface |
4922 | #: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1 |
4923 | @@ -1285,7 +1285,7 @@ |
4924 | msgstr "Anexa o rexistro de depuración do instalador se existe." |
4925 | |
4926 | #. description |
4927 | -#: ../jobs/input.txt.in:23 |
4928 | +#: ../jobs/input.txt.in:22 |
4929 | msgid "" |
4930 | "PURPOSE:\n" |
4931 | " This test will test your pointing device\n" |
4932 | @@ -1305,7 +1305,7 @@ |
4933 | " Comportouse o dispositivo de punteiro como se agardaba?" |
4934 | |
4935 | #. description |
4936 | -#: ../jobs/input.txt.in:36 |
4937 | +#: ../jobs/input.txt.in:35 |
4938 | msgid "" |
4939 | "PURPOSE:\n" |
4940 | " This test will test your keyboard\n" |
4941 | |
4942 | === modified file 'po/he.po' |
4943 | --- po/he.po 2013-02-22 16:26:25 +0000 |
4944 | +++ po/he.po 2013-03-07 16:10:38 +0000 |
4945 | @@ -14,8 +14,8 @@ |
4946 | "MIME-Version: 1.0\n" |
4947 | "Content-Type: text/plain; charset=UTF-8\n" |
4948 | "Content-Transfer-Encoding: 8bit\n" |
4949 | -"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n" |
4950 | -"X-Generator: Launchpad (build 16491)\n" |
4951 | +"X-Launchpad-Export-Date: 2013-02-23 04:39+0000\n" |
4952 | +"X-Generator: Launchpad (build 16506)\n" |
4953 | |
4954 | #: ../gtk/checkbox-gtk.ui.h:4 |
4955 | msgid "_No" |
4956 | @@ -1095,7 +1095,7 @@ |
4957 | msgstr "" |
4958 | |
4959 | #. description |
4960 | -#: ../jobs/input.txt.in:23 |
4961 | +#: ../jobs/input.txt.in:22 |
4962 | msgid "" |
4963 | "PURPOSE:\n" |
4964 | " This test will test your pointing device\n" |
4965 | @@ -1107,7 +1107,7 @@ |
4966 | msgstr "" |
4967 | |
4968 | #. description |
4969 | -#: ../jobs/input.txt.in:36 |
4970 | +#: ../jobs/input.txt.in:35 |
4971 | msgid "" |
4972 | "PURPOSE:\n" |
4973 | " This test will test your keyboard\n" |
4974 | |
4975 | === modified file 'po/hi.po' |
4976 | --- po/hi.po 2013-02-22 16:26:25 +0000 |
4977 | +++ po/hi.po 2013-03-07 16:10:38 +0000 |
4978 | @@ -14,8 +14,8 @@ |
4979 | "MIME-Version: 1.0\n" |
4980 | "Content-Type: text/plain; charset=UTF-8\n" |
4981 | "Content-Transfer-Encoding: 8bit\n" |
4982 | -"X-Launchpad-Export-Date: 2013-02-15 04:32+0000\n" |
4983 | -"X-Generator: Launchpad (build 16491)\n" |
4984 | +"X-Launchpad-Export-Date: 2013-02-23 04:39+0000\n" |
4985 | +"X-Generator: Launchpad (build 16506)\n" |
4986 | |
4987 | #. Title of the user interface |
4988 | #: ../gtk/checkbox-gtk.ui.h:1 ../qt/checkbox-qt.desktop.in.h:1 |
4989 | @@ -966,7 +966,7 @@ |
4990 | msgstr "" |
4991 | |
4992 | #. description |
4993 | -#: ../jobs/input.txt.in:23 |
4994 | +#: ../jobs/input.txt.in:22 |
4995 | msgid "" |
4996 | "PURPOSE:\n" |
4997 | " This test will test your pointing device\n" |
4998 | @@ -978,7 +978,7 @@ |
4999 | msgstr "" |
5000 |
The diff has been truncated for viewing.
Thanks, merged.