Merge lp:~zyga/checkbox/fix-1476678 into lp:checkbox
- fix-1476678
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Sylvain Pineau |
Approved revision: | 3912 |
Merged at revision: | 3912 |
Proposed branch: | lp:~zyga/checkbox/fix-1476678 |
Merge into: | lp:checkbox |
Diff against target: |
264 lines (+146/-20) 2 files modified
plainbox/plainbox/impl/unit/packaging.py (+92/-20) plainbox/plainbox/impl/unit/test_packging.py (+54/-0) |
To merge this branch: | bzr merge lp:~zyga/checkbox/fix-1476678 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Sylvain Pineau (community) | Approve | ||
Review via email: mp+265506@code.launchpad.net |
Commit message
Description of the change
Zygmunt Krynicki (zyga) wrote : | # |
Zygmunt Krynicki (zyga) wrote : | # |
Currently this crashes for me like this:
python3 manage.py packaging
CRITICAL plainbox.crashes: Executable 'manage.py' invoked with Namespace(
Traceback (most recent call last):
File "/usr/lib/
return self.dispatch_
File "/usr/lib/
return ns.command.
File "/usr/lib/
driver.
File "/usr/lib/
if self.is_
File "/usr/lib/
if (not _strategy_
File "/usr/lib/
and unit.os_version_id == os_release[
KeyError: 'VERSION_ID'
I think it's because 'sid' doesn't have VERSION_ID field. I'll patch the code to fix that.
Zygmunt Krynicki (zyga) wrote : | # |
Yes, this is from sid:
cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux stretch/sid"
NAME="Debian GNU/Linux"
ID=debian
HOME_URL="https:/
SUPPORT_URL="https:/
BUG_REPORT_URL="https:/
Sigh :-) I'll report this as a separate bug. Let's land this
Zygmunt Krynicki (zyga) wrote : | # |
Reported as https:/
Zygmunt Krynicki (zyga) wrote : | # |
I'll do some more testing and review this myself. Separate review is welcome but if you don't want to test this all the way I can do that.
- 3909. By Sylvain Pineau
-
"Release_
2015_Week30 [r=sylvain-pineau][bug=1331302,1341769, 1347120, 1382321, 1383447, 1387782, 1387843, 1388055, 1388747, 1389253, 1399481, 1400646, 1403933, 1406719, 1410501, 1428615, 1451343, 1451541] [author= checkbox- dev]" - 3910. By Zygmunt Krynicki
-
"automatic merge of lp:~zyga/checkbox/fix-1477131/ by tarmac [r=sylvain-pineau][bug=1477131][author=zyga]"
- 3911. By Zygmunt Krynicki
-
plainbox:
unit:packaging: improve documentation Signed-off-by: Zygmunt Krynicki <email address hidden>
- 3912. By Zygmunt Krynicki
-
plainbox:
unit:packaging: fix parsing of Debian meta-data This patch fixes how multiple-entry packaging meta-data units are parsed.
The fix makes the example in the documentation behave as intended.Fixes: https:/
/bugs.launchpad .net/plainbox/ +bug/1476678
Signed-off-by: Zygmunt Krynicki <email address hidden>
Sylvain Pineau (sylvain-pineau) wrote : | # |
+1, thanks for the fix
Preview Diff
1 | === modified file 'plainbox/plainbox/impl/unit/packaging.py' | |||
2 | --- plainbox/plainbox/impl/unit/packaging.py 2015-07-22 12:57:27 +0000 | |||
3 | +++ plainbox/plainbox/impl/unit/packaging.py 2015-07-22 13:45:52 +0000 | |||
4 | @@ -114,6 +114,7 @@ | |||
5 | 114 | import abc | 114 | import abc |
6 | 115 | import errno | 115 | import errno |
7 | 116 | import logging | 116 | import logging |
8 | 117 | import re | ||
9 | 117 | import sys | 118 | import sys |
10 | 118 | 119 | ||
11 | 119 | from plainbox.i18n import gettext as _ | 120 | from plainbox.i18n import gettext as _ |
12 | @@ -142,12 +143,12 @@ | |||
13 | 142 | 143 | ||
14 | 143 | @property | 144 | @property |
15 | 144 | def os_id(self): | 145 | def os_id(self): |
17 | 145 | """ Identifier of the operating system. """ | 146 | """Identifier of the operating system.""" |
18 | 146 | return self.get_record_value(self.Meta.fields.os_id) | 147 | return self.get_record_value(self.Meta.fields.os_id) |
19 | 147 | 148 | ||
20 | 148 | @property | 149 | @property |
21 | 149 | def os_version_id(self): | 150 | def os_version_id(self): |
23 | 150 | """ Version of the operating system. """ | 151 | """Version of the operating system.""" |
24 | 151 | return self.get_record_value(self.Meta.fields.os_version_id) | 152 | return self.get_record_value(self.Meta.fields.os_version_id) |
25 | 152 | 153 | ||
26 | 153 | class Meta: | 154 | class Meta: |
27 | @@ -156,7 +157,7 @@ | |||
28 | 156 | 157 | ||
29 | 157 | class fields(SymbolDef): | 158 | class fields(SymbolDef): |
30 | 158 | 159 | ||
32 | 159 | """ Symbols for each field of a packaging meta-data unit. """ | 160 | """Symbols for each field of a packaging meta-data unit.""" |
33 | 160 | 161 | ||
34 | 161 | os_id = 'os-id' | 162 | os_id = 'os-id' |
35 | 162 | os_version_id = 'os-version-id' | 163 | os_version_id = 'os-version-id' |
36 | @@ -174,46 +175,108 @@ | |||
37 | 174 | 175 | ||
38 | 175 | class PackagingDriverError(Exception): | 176 | class PackagingDriverError(Exception): |
39 | 176 | 177 | ||
41 | 177 | """ Base for all packaging driver exceptions. """ | 178 | """Base for all packaging driver exceptions.""" |
42 | 178 | 179 | ||
43 | 179 | 180 | ||
44 | 180 | class NoPackagingDetected(PackagingDriverError): | 181 | class NoPackagingDetected(PackagingDriverError): |
45 | 181 | 182 | ||
47 | 182 | """ Exception raised when packaging cannot be found. """ | 183 | """Exception raised when packaging cannot be found.""" |
48 | 183 | 184 | ||
49 | 184 | 185 | ||
50 | 185 | class NoApplicableBinaryPackages(PackagingDriverError): | 186 | class NoApplicableBinaryPackages(PackagingDriverError): |
51 | 186 | 187 | ||
53 | 187 | """ Exception raised when no applicable binary packages are found. """ | 188 | """Exception raised when no applicable binary packages are found.""" |
54 | 188 | 189 | ||
55 | 189 | 190 | ||
56 | 190 | class IPackagingDriver(metaclass=abc.ABCMeta): | 191 | class IPackagingDriver(metaclass=abc.ABCMeta): |
57 | 191 | 192 | ||
59 | 192 | """ Interface for all packaging drivers. """ | 193 | """Interface for all packaging drivers.""" |
60 | 193 | 194 | ||
61 | 194 | @abc.abstractmethod | 195 | @abc.abstractmethod |
62 | 195 | def __init__(self, os_release: 'Dict[str, str]'): | 196 | def __init__(self, os_release: 'Dict[str, str]'): |
64 | 196 | pass | 197 | """ |
65 | 198 | Initialize the packaging driver. | ||
66 | 199 | |||
67 | 200 | :param os_release: | ||
68 | 201 | The dictionary that represents the contents of the | ||
69 | 202 | ``/etc/os-release`` file. Using this file the packaging driver can | ||
70 | 203 | infer information about the target operating system that the | ||
71 | 204 | packaging will be built for. | ||
72 | 205 | |||
73 | 206 | This assumes that packages are built natively, not through a | ||
74 | 207 | cross-compiler of some sort where the target distribution is | ||
75 | 208 | different from the host distribution. | ||
76 | 209 | """ | ||
77 | 197 | 210 | ||
78 | 198 | @abc.abstractmethod | 211 | @abc.abstractmethod |
79 | 199 | def inspect_provider(self, provider: 'Provider1') -> None: | 212 | def inspect_provider(self, provider: 'Provider1') -> None: |
81 | 200 | pass | 213 | """ |
82 | 214 | Inspect a provider looking for packaging meta-data. | ||
83 | 215 | |||
84 | 216 | :param provider: | ||
85 | 217 | A provider object to look at. All of the packaging meta-data units | ||
86 | 218 | there are inspected, if they are applicable (see | ||
87 | 219 | :meth:`is_applicable()`. Information from applicable units is | ||
88 | 220 | collected using the :meth:`collect()` method. | ||
89 | 221 | """ | ||
90 | 201 | 222 | ||
91 | 202 | @abc.abstractmethod | 223 | @abc.abstractmethod |
92 | 203 | def is_applicable(self, unit: Unit) -> bool: | 224 | def is_applicable(self, unit: Unit) -> bool: |
94 | 204 | pass | 225 | """ |
95 | 226 | Check if the given unit is applicable for collecting. | ||
96 | 227 | |||
97 | 228 | :param unit: | ||
98 | 229 | The unit to inspect. This doesn't have to be a packaging meta-data | ||
99 | 230 | unit. In fact, all units are checked with this method. | ||
100 | 231 | :returns: | ||
101 | 232 | True if the unit is applicable for collection. | ||
102 | 233 | |||
103 | 234 | Packaging meta-data units that have certain properties are applicable. | ||
104 | 235 | Refer to the documentation of the module for details. | ||
105 | 236 | """ | ||
106 | 205 | 237 | ||
107 | 206 | @abc.abstractmethod | 238 | @abc.abstractmethod |
108 | 207 | def collect(self, unit: Unit) -> None: | 239 | def collect(self, unit: Unit) -> None: |
110 | 208 | pass | 240 | """ |
111 | 241 | Collect information from the given applicable unit. | ||
112 | 242 | |||
113 | 243 | :param unit: | ||
114 | 244 | The unit to collect information from. This is usually expressed as | ||
115 | 245 | additional fields that are specific to the type of native packaging | ||
116 | 246 | for the system. | ||
117 | 247 | |||
118 | 248 | Collected information is recorded and made available for the | ||
119 | 249 | :meth:`modify_packaging_tree()` method later. | ||
120 | 250 | """ | ||
121 | 209 | 251 | ||
122 | 210 | @abc.abstractmethod | 252 | @abc.abstractmethod |
123 | 211 | def inspect_packaging(self) -> None: | 253 | def inspect_packaging(self) -> None: |
125 | 212 | pass | 254 | """ |
126 | 255 | Inspect the packaging tree for additional information. | ||
127 | 256 | |||
128 | 257 | :raises NoPackagingDetected: | ||
129 | 258 | Exception raised when packaging cannot be found. | ||
130 | 259 | :raises NoApplicableBinaryPackages: | ||
131 | 260 | Exception raised when no applicable binary packages are found. | ||
132 | 261 | |||
133 | 262 | This method looks at the packaging system located in the current | ||
134 | 263 | directory. This can be the ``debian/`` directory, a particular | ||
135 | 264 | ``.spec`` file or anything else. Information obtained from the package | ||
136 | 265 | is used to infer additional properties that can aid in the packaging | ||
137 | 266 | process. | ||
138 | 267 | """ | ||
139 | 213 | 268 | ||
140 | 214 | @abc.abstractmethod | 269 | @abc.abstractmethod |
141 | 215 | def modify_packaging_tree(self) -> None: | 270 | def modify_packaging_tree(self) -> None: |
143 | 216 | pass | 271 | """ |
144 | 272 | Modify the packaging tree with information from the packaging units. | ||
145 | 273 | |||
146 | 274 | This method uses all of the available information collected from | ||
147 | 275 | particular packaging meta-data units and from the native packaging to | ||
148 | 276 | modify the packaging. Additional dependencies may be injected in | ||
149 | 277 | appropriate places. Please refer to the documentation specific to your | ||
150 | 278 | packaging system for details. | ||
151 | 279 | """ | ||
152 | 217 | 280 | ||
153 | 218 | 281 | ||
154 | 219 | def _strategy_id_version(unit, os_release): | 282 | def _strategy_id_version(unit, os_release): |
155 | @@ -237,7 +300,7 @@ | |||
156 | 237 | 300 | ||
157 | 238 | class PackagingDriverBase(IPackagingDriver): | 301 | class PackagingDriverBase(IPackagingDriver): |
158 | 239 | 302 | ||
160 | 240 | """ Base implementation of a packaging driver. """ | 303 | """Base implementation of a packaging driver.""" |
161 | 241 | 304 | ||
162 | 242 | def __init__(self, os_release: 'Dict[str, str]'): | 305 | def __init__(self, os_release: 'Dict[str, str]'): |
163 | 243 | self.os_release = os_release | 306 | self.os_release = os_release |
164 | @@ -262,7 +325,12 @@ | |||
165 | 262 | 325 | ||
166 | 263 | class NullPackagingDriver(PackagingDriverBase): | 326 | class NullPackagingDriver(PackagingDriverBase): |
167 | 264 | 327 | ||
169 | 265 | """ Null implementation of a packaging driver. """ | 328 | """ |
170 | 329 | Null implementation of a packaging driver. | ||
171 | 330 | |||
172 | 331 | This driver just does nothing at all. It is used as a fall-back when | ||
173 | 332 | nothing better is detected. | ||
174 | 333 | """ | ||
175 | 266 | 334 | ||
176 | 267 | def is_applicable(self, unit: Unit) -> bool: | 335 | def is_applicable(self, unit: Unit) -> bool: |
177 | 268 | return False | 336 | return False |
178 | @@ -316,10 +384,14 @@ | |||
179 | 316 | def collect(self, unit: Unit) -> None: | 384 | def collect(self, unit: Unit) -> None: |
180 | 317 | def rel_list(field): | 385 | def rel_list(field): |
181 | 318 | relations = unit.get_record_value(field, '').replace('\n', ' ') | 386 | relations = unit.get_record_value(field, '').replace('\n', ' ') |
186 | 319 | return ', '.join([rel.strip() for rel in relations.split(',')]) | 387 | return ( |
187 | 320 | self._depends.append(rel_list('Depends')) | 388 | rel.strip() |
188 | 321 | self._suggests.append(rel_list('Suggests')) | 389 | for rel in re.split(', *', relations) |
189 | 322 | self._recommends.append(rel_list('Recommends')) | 390 | if rel.strip() |
190 | 391 | ) | ||
191 | 392 | self._depends.extend(rel_list('Depends')) | ||
192 | 393 | self._suggests.extend(rel_list('Suggests')) | ||
193 | 394 | self._recommends.extend(rel_list('Recommends')) | ||
194 | 323 | 395 | ||
195 | 324 | def _write_pkg_substvars(self, pkg): | 396 | def _write_pkg_substvars(self, pkg): |
196 | 325 | fname = 'debian/{}.substvars'.format(pkg) | 397 | fname = 'debian/{}.substvars'.format(pkg) |
197 | @@ -357,7 +429,7 @@ | |||
198 | 357 | 429 | ||
199 | 358 | 430 | ||
200 | 359 | def get_packaging_driver() -> IPackagingDriver: | 431 | def get_packaging_driver() -> IPackagingDriver: |
202 | 360 | """ Get the packaging driver appropriate for the current platform. """ | 432 | """Get the packaging driver appropriate for the current platform.""" |
203 | 361 | if sys.platform.startswith("linux"): | 433 | if sys.platform.startswith("linux"): |
204 | 362 | os_release = get_os_release() | 434 | os_release = get_os_release() |
205 | 363 | if (os_release.get('ID') == 'debian' | 435 | if (os_release.get('ID') == 'debian' |
206 | 364 | 436 | ||
207 | === added file 'plainbox/plainbox/impl/unit/test_packging.py' | |||
208 | --- plainbox/plainbox/impl/unit/test_packging.py 1970-01-01 00:00:00 +0000 | |||
209 | +++ plainbox/plainbox/impl/unit/test_packging.py 2015-07-22 13:45:52 +0000 | |||
210 | @@ -0,0 +1,54 @@ | |||
211 | 1 | # This file is part of Checkbox. | ||
212 | 2 | # | ||
213 | 3 | # Copyright 2015 Canonical Ltd. | ||
214 | 4 | # Written by: | ||
215 | 5 | # Zygmunt Krynicki <zygmunt.krynicki@canonical.com> | ||
216 | 6 | # | ||
217 | 7 | # Checkbox is free software: you can redistribute it and/or modify | ||
218 | 8 | # it under the terms of the GNU General Public License version 3, | ||
219 | 9 | # as published by the Free Software Foundation. | ||
220 | 10 | # | ||
221 | 11 | # Checkbox is distributed in the hope that it will be useful, | ||
222 | 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
223 | 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
224 | 14 | # GNU General Public License for more details. | ||
225 | 15 | # | ||
226 | 16 | # You should have received a copy of the GNU General Public License | ||
227 | 17 | # along with Checkbox. If not, see <http://www.gnu.org/licenses/>. | ||
228 | 18 | |||
229 | 19 | """Tests for the PackagingMetaDataUnit and friends.""" | ||
230 | 20 | |||
231 | 21 | from unittest import TestCase | ||
232 | 22 | |||
233 | 23 | from plainbox.impl.unit.packaging import DebianPackagingDriver | ||
234 | 24 | from plainbox.impl.unit.packaging import PackagingMetaDataUnit | ||
235 | 25 | |||
236 | 26 | |||
237 | 27 | class DebianPackagingDriverTests(TestCase): | ||
238 | 28 | |||
239 | 29 | """Tests for the DebianPackagingDriver class.""" | ||
240 | 30 | |||
241 | 31 | def test_fix_1476678(self): | ||
242 | 32 | """Check https://bugs.launchpad.net/plainbox/+bug/1476678.""" | ||
243 | 33 | driver = DebianPackagingDriver({}) | ||
244 | 34 | driver.collect(PackagingMetaDataUnit({ | ||
245 | 35 | 'Depends': ( | ||
246 | 36 | 'python3-checkbox-support (>= 0.2),\n' | ||
247 | 37 | 'python3 (>= 3.2),\n'), | ||
248 | 38 | 'Recommends': ( | ||
249 | 39 | 'dmidecode,\n' | ||
250 | 40 | 'dpkg (>= 1.13),\n' | ||
251 | 41 | 'lsb-release,\n' | ||
252 | 42 | 'wodim') | ||
253 | 43 | })) | ||
254 | 44 | self.assertEqual(driver._depends, [ | ||
255 | 45 | 'python3-checkbox-support (>= 0.2)', | ||
256 | 46 | 'python3 (>= 3.2)', | ||
257 | 47 | ]) | ||
258 | 48 | self.assertEqual(driver._recommends, [ | ||
259 | 49 | 'dmidecode', | ||
260 | 50 | 'dpkg (>= 1.13)', | ||
261 | 51 | 'lsb-release', | ||
262 | 52 | 'wodim' | ||
263 | 53 | ]) | ||
264 | 54 | self.assertEqual(driver._suggests, []) |
This is almost, but not quite. I need to see what's missing :-|