Merge lp:~james-w/linaro-image-tools/hwpack-create-config into lp:linaro-image-tools/11.11
- hwpack-create-config
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 34 |
Proposed branch: | lp:~james-w/linaro-image-tools/hwpack-create-config |
Merge into: | lp:linaro-image-tools/11.11 |
Diff against target: |
402 lines (+375/-0) 5 files modified
.bzrignore (+1/-0) .testr.conf (+3/-0) hwpack/config.py (+167/-0) hwpack/tests/__init__.py (+8/-0) hwpack/tests/test_config.py (+196/-0) |
To merge this branch: | bzr merge lp:~james-w/linaro-image-tools/hwpack-create-config |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alexander Sack (community) | Approve | ||
Linaro Infrastructure | Pending | ||
Review via email: mp+33952@code.launchpad.net |
Commit message
Description of the change
Hi,
Here is a small branch to add the skeleton of the hwpack module with tests, and the start of
a hwpack.config for reading the configuration files specifying what to put in a hwpack.
You can read the description of the format at https:/
Thanks,
James
- 46. By James Westby
-
Add a testsuite function to run the tests.
- 47. By James Westby
-
Add a .testr.conf for the project.
- 48. By James Westby
-
Use a method to avoid hardcoding StringIO everywhere.
- 49. By James Westby
-
Use a helper assertion to reduce code duplication.
Michael Hudson-Doyle (mwhudson) wrote : | # |
I know this is late, but:
1) I would have appreciated some documentation on what the various properties on the Config option meant.
2) I'm sure there's a place for a _get_main_option helper -- origin, main and support at least are very similar.
Cheers,
mwh
Preview Diff
1 | === added file '.bzrignore' | |||
2 | --- .bzrignore 1970-01-01 00:00:00 +0000 | |||
3 | +++ .bzrignore 2010-08-27 20:28:42 +0000 | |||
4 | @@ -0,0 +1,1 @@ | |||
5 | 1 | .testrepository | ||
6 | 0 | 2 | ||
7 | === added file '.testr.conf' | |||
8 | --- .testr.conf 1970-01-01 00:00:00 +0000 | |||
9 | +++ .testr.conf 2010-08-27 20:28:42 +0000 | |||
10 | @@ -0,0 +1,3 @@ | |||
11 | 1 | [DEFAULT] | ||
12 | 2 | test_command=python -m subunit.run $IDLIST | ||
13 | 3 | test_id_list_default=hwpack.tests.test_suite | ||
14 | 0 | 4 | ||
15 | === added directory 'hwpack' | |||
16 | === added file 'hwpack/__init__.py' | |||
17 | === added file 'hwpack/config.py' | |||
18 | --- hwpack/config.py 1970-01-01 00:00:00 +0000 | |||
19 | +++ hwpack/config.py 2010-08-27 20:28:42 +0000 | |||
20 | @@ -0,0 +1,167 @@ | |||
21 | 1 | import ConfigParser | ||
22 | 2 | import re | ||
23 | 3 | |||
24 | 4 | class HwpackConfigError(Exception): | ||
25 | 5 | pass | ||
26 | 6 | |||
27 | 7 | |||
28 | 8 | class Config(object): | ||
29 | 9 | """Encapsulation of a hwpack-create configuration.""" | ||
30 | 10 | |||
31 | 11 | MAIN_SECTION = "hwpack" | ||
32 | 12 | NAME_KEY = "name" | ||
33 | 13 | NAME_REGEX = "[a-z0-9][a-z0-9+0.]+" | ||
34 | 14 | INCLUDE_DEBS_KEY = "include-debs" | ||
35 | 15 | SUPPORT_KEY = "support" | ||
36 | 16 | SOURCES_ENTRY_KEY = "sources-entry" | ||
37 | 17 | PACKAGES_KEY = "packages" | ||
38 | 18 | PACKAGE_REGEX = NAME_REGEX | ||
39 | 19 | ORIGIN_KEY = "origin" | ||
40 | 20 | MAINTAINER_KEY = "maintainer" | ||
41 | 21 | |||
42 | 22 | def __init__(self, fp): | ||
43 | 23 | """Create a Config. | ||
44 | 24 | |||
45 | 25 | :param fp: a file-like object containing the configuration. | ||
46 | 26 | """ | ||
47 | 27 | self.parser = ConfigParser.RawConfigParser() | ||
48 | 28 | self.parser.readfp(fp) | ||
49 | 29 | |||
50 | 30 | def validate(self): | ||
51 | 31 | """Check that this configuration follows the schema. | ||
52 | 32 | |||
53 | 33 | :raises HwpackConfigError: if it does not. | ||
54 | 34 | """ | ||
55 | 35 | if not self.parser.has_section(self.MAIN_SECTION): | ||
56 | 36 | raise HwpackConfigError("No [%s] section" % self.MAIN_SECTION) | ||
57 | 37 | self._validate_name() | ||
58 | 38 | self._validate_include_debs() | ||
59 | 39 | self._validate_support() | ||
60 | 40 | self._validate_sections() | ||
61 | 41 | |||
62 | 42 | @property | ||
63 | 43 | def name(self): | ||
64 | 44 | return self.parser.get(self.MAIN_SECTION, self.NAME_KEY) | ||
65 | 45 | |||
66 | 46 | @property | ||
67 | 47 | def include_debs(self): | ||
68 | 48 | try: | ||
69 | 49 | if not self.parser.get( | ||
70 | 50 | self.MAIN_SECTION, self.INCLUDE_DEBS_KEY): | ||
71 | 51 | return True | ||
72 | 52 | return self.parser.getboolean( | ||
73 | 53 | self.MAIN_SECTION, self.INCLUDE_DEBS_KEY) | ||
74 | 54 | except ConfigParser.NoOptionError: | ||
75 | 55 | return True | ||
76 | 56 | |||
77 | 57 | @property | ||
78 | 58 | def origin(self): | ||
79 | 59 | try: | ||
80 | 60 | origin = self.parser.get(self.MAIN_SECTION, self.ORIGIN_KEY) | ||
81 | 61 | if not origin: | ||
82 | 62 | return None | ||
83 | 63 | return origin | ||
84 | 64 | except ConfigParser.NoOptionError: | ||
85 | 65 | return None | ||
86 | 66 | |||
87 | 67 | @property | ||
88 | 68 | def maintainer(self): | ||
89 | 69 | try: | ||
90 | 70 | maintainer = self.parser.get( | ||
91 | 71 | self.MAIN_SECTION, self.MAINTAINER_KEY) | ||
92 | 72 | if not maintainer: | ||
93 | 73 | return None | ||
94 | 74 | return maintainer | ||
95 | 75 | except ConfigParser.NoOptionError: | ||
96 | 76 | return None | ||
97 | 77 | |||
98 | 78 | @property | ||
99 | 79 | def support(self): | ||
100 | 80 | try: | ||
101 | 81 | support = self.parser.get(self.MAIN_SECTION, self.SUPPORT_KEY) | ||
102 | 82 | if not support: | ||
103 | 83 | return None | ||
104 | 84 | return support | ||
105 | 85 | except ConfigParser.NoOptionError: | ||
106 | 86 | return None | ||
107 | 87 | |||
108 | 88 | def _validate_name(self): | ||
109 | 89 | try: | ||
110 | 90 | name = self.name | ||
111 | 91 | if not name: | ||
112 | 92 | raise HwpackConfigError("Empty value for name") | ||
113 | 93 | if re.match(self.NAME_REGEX, name) is None: | ||
114 | 94 | raise HwpackConfigError("Invalid name: %s" % name) | ||
115 | 95 | except ConfigParser.NoOptionError: | ||
116 | 96 | raise HwpackConfigError( | ||
117 | 97 | "No name in the [%s] section" % self.MAIN_SECTION) | ||
118 | 98 | |||
119 | 99 | def _validate_include_debs(self): | ||
120 | 100 | try: | ||
121 | 101 | self.include_debs | ||
122 | 102 | except ValueError: | ||
123 | 103 | raise HwpackConfigError( | ||
124 | 104 | "Invalid value for include-debs: %s" | ||
125 | 105 | % self.parser.get("hwpack", "include-debs")) | ||
126 | 106 | |||
127 | 107 | def _validate_support(self): | ||
128 | 108 | support = self.support | ||
129 | 109 | if support not in (None, "supported", "unsupported"): | ||
130 | 110 | raise HwpackConfigError( | ||
131 | 111 | "Invalid value for support: %s" % support) | ||
132 | 112 | |||
133 | 113 | def _validate_section_sources_entry(self, section_name): | ||
134 | 114 | try: | ||
135 | 115 | sources_entry = self.parser.get( | ||
136 | 116 | section_name, self.SOURCES_ENTRY_KEY) | ||
137 | 117 | if not sources_entry: | ||
138 | 118 | raise HwpackConfigError( | ||
139 | 119 | "The %s in the [%s] section is missing the URI" | ||
140 | 120 | % (self.SOURCES_ENTRY_KEY, section_name)) | ||
141 | 121 | if len(sources_entry.split(" ", 1)) < 2: | ||
142 | 122 | raise HwpackConfigError( | ||
143 | 123 | "The %s in the [%s] section is missing the distribution" | ||
144 | 124 | % (self.SOURCES_ENTRY_KEY, section_name)) | ||
145 | 125 | if sources_entry.startswith("deb"): | ||
146 | 126 | raise HwpackConfigError( | ||
147 | 127 | "The %s in the [%s] section shouldn't start with 'deb'" | ||
148 | 128 | % (self.SOURCES_ENTRY_KEY, section_name)) | ||
149 | 129 | except ConfigParser.NoOptionError: | ||
150 | 130 | raise HwpackConfigError( | ||
151 | 131 | "No %s in the [%s] section" | ||
152 | 132 | % (self.SOURCES_ENTRY_KEY, section_name)) | ||
153 | 133 | |||
154 | 134 | def _validate_section_packages(self, section_name): | ||
155 | 135 | try: | ||
156 | 136 | packages = self.parser.get(section_name, self.PACKAGES_KEY) | ||
157 | 137 | if not packages: | ||
158 | 138 | raise HwpackConfigError( | ||
159 | 139 | "The %s in the [%s] section is empty" | ||
160 | 140 | % (self.PACKAGES_KEY, section_name)) | ||
161 | 141 | for package in packages.split(" "): | ||
162 | 142 | if not package: | ||
163 | 143 | continue | ||
164 | 144 | if re.match(self.PACKAGE_REGEX, package) is None: | ||
165 | 145 | raise HwpackConfigError( | ||
166 | 146 | "Invalid value in %s in the [%s] section: %s" | ||
167 | 147 | % (self.PACKAGES_KEY, section_name, package)) | ||
168 | 148 | except ConfigParser.NoOptionError: | ||
169 | 149 | raise HwpackConfigError( | ||
170 | 150 | "No %s in the [%s] section" | ||
171 | 151 | % (self.PACKAGES_KEY, section_name)) | ||
172 | 152 | |||
173 | 153 | def _validate_section(self, section_name): | ||
174 | 154 | self._validate_section_sources_entry(section_name) | ||
175 | 155 | self._validate_section_packages(section_name) | ||
176 | 156 | |||
177 | 157 | def _validate_sections(self): | ||
178 | 158 | sections = self.parser.sections() | ||
179 | 159 | found = False | ||
180 | 160 | for section_name in sections: | ||
181 | 161 | if section_name == self.MAIN_SECTION: | ||
182 | 162 | continue | ||
183 | 163 | self._validate_section(section_name) | ||
184 | 164 | found = True | ||
185 | 165 | if not found: | ||
186 | 166 | raise HwpackConfigError( | ||
187 | 167 | "No sections other than [%s]" % self.MAIN_SECTION) | ||
188 | 0 | 168 | ||
189 | === added directory 'hwpack/tests' | |||
190 | === added file 'hwpack/tests/__init__.py' | |||
191 | --- hwpack/tests/__init__.py 1970-01-01 00:00:00 +0000 | |||
192 | +++ hwpack/tests/__init__.py 2010-08-27 20:28:42 +0000 | |||
193 | @@ -0,0 +1,8 @@ | |||
194 | 1 | import unittest | ||
195 | 2 | |||
196 | 3 | def test_suite(): | ||
197 | 4 | module_names = ['hwpack.tests.test_config', | ||
198 | 5 | ] | ||
199 | 6 | loader = unittest.TestLoader() | ||
200 | 7 | suite = loader.loadTestsFromNames(module_names) | ||
201 | 8 | return suite | ||
202 | 0 | 9 | ||
203 | === added file 'hwpack/tests/test_config.py' | |||
204 | --- hwpack/tests/test_config.py 1970-01-01 00:00:00 +0000 | |||
205 | +++ hwpack/tests/test_config.py 2010-08-27 20:28:42 +0000 | |||
206 | @@ -0,0 +1,196 @@ | |||
207 | 1 | from StringIO import StringIO | ||
208 | 2 | |||
209 | 3 | from testtools import TestCase | ||
210 | 4 | |||
211 | 5 | from hwpack.config import Config, HwpackConfigError | ||
212 | 6 | |||
213 | 7 | |||
214 | 8 | class ConfigTests(TestCase): | ||
215 | 9 | |||
216 | 10 | def test_create(self): | ||
217 | 11 | config = Config(StringIO()) | ||
218 | 12 | |||
219 | 13 | def get_config(self, contents): | ||
220 | 14 | return Config(StringIO(contents)) | ||
221 | 15 | |||
222 | 16 | def assertConfigError(self, contents, f, *args, **kwargs): | ||
223 | 17 | e = self.assertRaises(HwpackConfigError, f, *args, **kwargs) | ||
224 | 18 | self.assertEqual(contents, str(e)) | ||
225 | 19 | |||
226 | 20 | def assertValidationError(self, contents, config): | ||
227 | 21 | self.assertConfigError(contents, config.validate) | ||
228 | 22 | |||
229 | 23 | def test_validate_no_hwpack_section(self): | ||
230 | 24 | config = self.get_config("") | ||
231 | 25 | self.assertValidationError("No [hwpack] section", config) | ||
232 | 26 | |||
233 | 27 | def test_validate_no_name(self): | ||
234 | 28 | config = self.get_config("[hwpack]\n") | ||
235 | 29 | self.assertValidationError("No name in the [hwpack] section", config) | ||
236 | 30 | |||
237 | 31 | def test_validate_empty_name(self): | ||
238 | 32 | config = self.get_config("[hwpack]\nname = \n") | ||
239 | 33 | self.assertValidationError("Empty value for name", config) | ||
240 | 34 | |||
241 | 35 | def test_validate_invalid_name(self): | ||
242 | 36 | config = self.get_config("[hwpack]\nname = ~~\n") | ||
243 | 37 | self.assertValidationError("Invalid name: ~~", config) | ||
244 | 38 | |||
245 | 39 | def test_validate_invalid_include_debs(self): | ||
246 | 40 | config = self.get_config( | ||
247 | 41 | "[hwpack]\nname = ahwpack\n" | ||
248 | 42 | "include-debs = if you don't mind\n") | ||
249 | 43 | self.assertValidationError( | ||
250 | 44 | "Invalid value for include-debs: if you don't mind", config) | ||
251 | 45 | |||
252 | 46 | def test_validate_invalid_supported(self): | ||
253 | 47 | config = self.get_config( | ||
254 | 48 | "[hwpack]\nname = ahwpack\nsupport = if you pay us\n") | ||
255 | 49 | self.assertValidationError( | ||
256 | 50 | "Invalid value for support: if you pay us", config) | ||
257 | 51 | |||
258 | 52 | def test_validate_no_other_sections(self): | ||
259 | 53 | config = self.get_config("[hwpack]\nname = ahwpack\n") | ||
260 | 54 | self.assertValidationError( | ||
261 | 55 | "No sections other than [hwpack]", config) | ||
262 | 56 | |||
263 | 57 | def test_validate_other_section_no_sources_entry(self): | ||
264 | 58 | config = self.get_config( | ||
265 | 59 | "[hwpack]\nname = ahwpack\n\n[ubuntu]\n") | ||
266 | 60 | self.assertValidationError( | ||
267 | 61 | "No sources-entry in the [ubuntu] section", config) | ||
268 | 62 | |||
269 | 63 | def test_validate_other_section_empty_sources_entry(self): | ||
270 | 64 | config = self.get_config( | ||
271 | 65 | "[hwpack]\nname = ahwpack\n\n" | ||
272 | 66 | "[ubuntu]\nsources-entry = \n") | ||
273 | 67 | self.assertValidationError( | ||
274 | 68 | "The sources-entry in the [ubuntu] section is missing the URI", | ||
275 | 69 | config) | ||
276 | 70 | |||
277 | 71 | def test_validate_other_section_only_uri_in_sources_entry(self): | ||
278 | 72 | config = self.get_config( | ||
279 | 73 | "[hwpack]\nname = ahwpack\n\n" | ||
280 | 74 | "[ubuntu]\nsources-entry = foo\n") | ||
281 | 75 | self.assertValidationError( | ||
282 | 76 | "The sources-entry in the [ubuntu] section is missing the " | ||
283 | 77 | "distribution", config) | ||
284 | 78 | |||
285 | 79 | def test_validate_other_section_sources_entry_starting_with_deb(self): | ||
286 | 80 | config = self.get_config( | ||
287 | 81 | "[hwpack]\nname = ahwpack\n\n" | ||
288 | 82 | "[ubuntu]\nsources-entry = deb http://example.org/ " | ||
289 | 83 | "foo main\n") | ||
290 | 84 | self.assertValidationError( | ||
291 | 85 | "The sources-entry in the [ubuntu] section shouldn't start " | ||
292 | 86 | "with 'deb'", config) | ||
293 | 87 | |||
294 | 88 | def test_validate_other_section_sources_entry_starting_with_deb_src(self): | ||
295 | 89 | config = self.get_config( | ||
296 | 90 | "[hwpack]\nname = ahwpack\n\n" | ||
297 | 91 | "[ubuntu]\nsources-entry = deb-src http://example.org/ " | ||
298 | 92 | "foo main\n") | ||
299 | 93 | self.assertValidationError( | ||
300 | 94 | "The sources-entry in the [ubuntu] section shouldn't start " | ||
301 | 95 | "with 'deb'", config) | ||
302 | 96 | |||
303 | 97 | def test_validate_other_section_no_packages(self): | ||
304 | 98 | config = self.get_config( | ||
305 | 99 | "[hwpack]\nname = ahwpack\n\n" | ||
306 | 100 | "[ubuntu]\nsources-entry = foo bar\n") | ||
307 | 101 | self.assertValidationError( | ||
308 | 102 | "No packages in the [ubuntu] section", config) | ||
309 | 103 | |||
310 | 104 | def test_validate_other_section_empty_packages(self): | ||
311 | 105 | config = self.get_config( | ||
312 | 106 | "[hwpack]\nname = ahwpack\n\n" | ||
313 | 107 | "[ubuntu]\nsources-entry = foo bar\npackages = \n") | ||
314 | 108 | self.assertValidationError( | ||
315 | 109 | "The packages in the [ubuntu] section is empty", | ||
316 | 110 | config) | ||
317 | 111 | |||
318 | 112 | def test_validate_other_section_invalid_package_name(self): | ||
319 | 113 | config = self.get_config( | ||
320 | 114 | "[hwpack]\nname = ahwpack\n\n" | ||
321 | 115 | "[ubuntu]\nsources-entry = foo bar\n" | ||
322 | 116 | "packages = foo ~~ bar\n") | ||
323 | 117 | self.assertValidationError( | ||
324 | 118 | "Invalid value in packages in the [ubuntu] section: ~~", | ||
325 | 119 | config) | ||
326 | 120 | |||
327 | 121 | def test_validate_valid_config(self): | ||
328 | 122 | config = self.get_config( | ||
329 | 123 | "[hwpack]\nname = ahwpack\n\n" | ||
330 | 124 | "[ubuntu]\nsources-entry = foo bar\n" | ||
331 | 125 | "packages = foo bar\n") | ||
332 | 126 | self.assertEqual(None, config.validate()) | ||
333 | 127 | |||
334 | 128 | def test_name(self): | ||
335 | 129 | config = self.get_config("[hwpack]\nname = ahwpack\n") | ||
336 | 130 | self.assertEqual("ahwpack", config.name) | ||
337 | 131 | |||
338 | 132 | def test_include_debs(self): | ||
339 | 133 | config = self.get_config( | ||
340 | 134 | "[hwpack]\nname = ahwpack\ninclude-debs = false\n") | ||
341 | 135 | self.assertEqual(False, config.include_debs) | ||
342 | 136 | |||
343 | 137 | def test_include_debs_defaults_true(self): | ||
344 | 138 | config = self.get_config( | ||
345 | 139 | "[hwpack]\nname = ahwpack\n") | ||
346 | 140 | self.assertEqual(True, config.include_debs) | ||
347 | 141 | |||
348 | 142 | def test_include_debs_defaults_true_on_empty(self): | ||
349 | 143 | config = self.get_config( | ||
350 | 144 | "[hwpack]\nname = ahwpack\ninclude-debs = \n") | ||
351 | 145 | self.assertEqual(True, config.include_debs) | ||
352 | 146 | |||
353 | 147 | def test_origin(self): | ||
354 | 148 | config = self.get_config( | ||
355 | 149 | "[hwpack]\nname = ahwpack\norigin = linaro\n") | ||
356 | 150 | self.assertEqual("linaro", config.origin) | ||
357 | 151 | |||
358 | 152 | def test_origin_default_None(self): | ||
359 | 153 | config = self.get_config( | ||
360 | 154 | "[hwpack]\nname = ahwpack\n") | ||
361 | 155 | self.assertEqual(None, config.origin) | ||
362 | 156 | |||
363 | 157 | def test_origin_None_on_empty(self): | ||
364 | 158 | config = self.get_config( | ||
365 | 159 | "[hwpack]\nname = ahwpack\norigin = \n") | ||
366 | 160 | self.assertEqual(None, config.origin) | ||
367 | 161 | |||
368 | 162 | def test_maintainer(self): | ||
369 | 163 | maintainer = "Linaro Developers <linaro-dev@lists.linaro.org>" | ||
370 | 164 | config = self.get_config( | ||
371 | 165 | "[hwpack]\nname = ahwpack\nmaintainer = %s\n" % maintainer) | ||
372 | 166 | self.assertEqual(maintainer, config.maintainer) | ||
373 | 167 | |||
374 | 168 | def test_maintainer_default_None(self): | ||
375 | 169 | config = self.get_config( | ||
376 | 170 | "[hwpack]\nname = ahwpack\n") | ||
377 | 171 | self.assertEqual(None, config.maintainer) | ||
378 | 172 | |||
379 | 173 | def test_maintainer_None_on_empty(self): | ||
380 | 174 | config = self.get_config( | ||
381 | 175 | "[hwpack]\nname = ahwpack\nmaintainer = \n") | ||
382 | 176 | self.assertEqual(None, config.maintainer) | ||
383 | 177 | |||
384 | 178 | def test_support_supported(self): | ||
385 | 179 | config = self.get_config( | ||
386 | 180 | "[hwpack]\nname = ahwpack\nsupport = supported\n") | ||
387 | 181 | self.assertEqual("supported", config.support) | ||
388 | 182 | |||
389 | 183 | def test_support_unsupported(self): | ||
390 | 184 | config = self.get_config( | ||
391 | 185 | "[hwpack]\nname = ahwpack\nsupport = unsupported\n") | ||
392 | 186 | self.assertEqual("unsupported", config.support) | ||
393 | 187 | |||
394 | 188 | def test_support_default_None(self): | ||
395 | 189 | config = self.get_config( | ||
396 | 190 | "[hwpack]\nname = ahwpack\n") | ||
397 | 191 | self.assertEqual(None, config.support) | ||
398 | 192 | |||
399 | 193 | def test_support_None_on_empty(self): | ||
400 | 194 | config = self.get_config( | ||
401 | 195 | "[hwpack]\nname = ahwpack\nsupport = \n") | ||
402 | 196 | self.assertEqual(None, config.support) |
looks like a good start. merged.