Merge lp:~ursinha/ubuntu-cdimage/add-manifest-changelog-libs into lp:ubuntu-cdimage
- add-manifest-changelog-libs
- Merge into mainline
Status: | Rejected |
---|---|
Rejected by: | Steve Langasek |
Proposed branch: | lp:~ursinha/ubuntu-cdimage/add-manifest-changelog-libs |
Merge into: | lp:ubuntu-cdimage |
Diff against target: |
1242 lines (+1123/-58) 7 files modified
bin/diff-manifest (+5/-58) bin/image-changelog (+49/-0) lib/cdimage/changelog.py (+160/-0) lib/cdimage/manifest.py (+318/-0) lib/cdimage/tests/helpers.py (+14/-0) lib/cdimage/tests/test_changelog.py (+193/-0) lib/cdimage/tests/test_manifest.py (+384/-0) |
To merge this branch: | bzr merge lp:~ursinha/ubuntu-cdimage/add-manifest-changelog-libs |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Steve Langasek | Needs Resubmitting | ||
Review via email:
|
Commit message
Description of the change
This branch adds two new libs to cdimage: manifest.py and changelog.py, required to generate between-images changelogs by parsing their manifests and fetching packages' changelog information. manifest.py also contains the methods previously declared in diff-manifest, that now only calls such methods. Tests were added.
- 1341. By Ursula Junque
-
lib/cdimage/
manifest. py: printing all the changed packages in the changed packages session, regardless they have a changelog or not - 1342. By Ursula Junque
-
lib/cdimage/
manifest. py: sometimes the changelogs are manually (?) changed and versions are removed from it, added a check to return only the newest changelog block in case that happens - 1343. By Ursula Junque
-
lib/cdimage/
tests/test_ manifest. py: testing whenever the old source version
doesn't exist in the current package changelog, which may happen due to a
debian sync for example - 1344. By Ursula Junque
-
lib/cdimage/
manifest. py: making it clear what are binary versions and source
versions; also adding some docs to the methods - 1345. By Ursula Junque
-
lib/cdimage/
manifest. py: fixing the changed packages output
Unmerged revisions
- 1345. By Ursula Junque
-
lib/cdimage/
manifest. py: fixing the changed packages output - 1344. By Ursula Junque
-
lib/cdimage/
manifest. py: making it clear what are binary versions and source
versions; also adding some docs to the methods - 1343. By Ursula Junque
-
lib/cdimage/
tests/test_ manifest. py: testing whenever the old source version
doesn't exist in the current package changelog, which may happen due to a
debian sync for example - 1342. By Ursula Junque
-
lib/cdimage/
manifest. py: sometimes the changelogs are manually (?) changed and versions are removed from it, added a check to return only the newest changelog block in case that happens - 1341. By Ursula Junque
-
lib/cdimage/
manifest. py: printing all the changed packages in the changed packages session, regardless they have a changelog or not - 1340. By Ursula Junque
-
bin/image-
changelog: calling manifest. parse_file; lib/cdimage/ manifest. py:
adding text to differentiate packages with changelogs (found in
changelogs.ubuntu. com) from the others - 1339. By Ursula Junque
-
tests/test_
manifest. py: testing manifest_ diff.get_ changes( ) - 1338. By Ursula Junque
-
lib/cdimage/
manifest. py: using correct function to return the changes in the
changelog - 1337. By Ursula Junque
-
Fixing pyflakes errors; closing the file when I extract the manifest content.
- 1336. By Ursula Junque
-
tests/*: fixing pep8 and flakes problems
Preview Diff
1 | === modified file 'bin/diff-manifest' |
2 | --- bin/diff-manifest 2013-03-21 08:41:44 +0000 |
3 | +++ bin/diff-manifest 2013-08-30 23:19:27 +0000 |
4 | @@ -1,6 +1,6 @@ |
5 | #! /usr/bin/python |
6 | # |
7 | -# Copyright (C) 2011, 2012 Canonical Ltd. |
8 | +# Copyright (C) 2011, 2013 Canonical Ltd. |
9 | # Author: Kate Stewart <kate.stewart@canonical.com> |
10 | # Author: Colin Watson <cjwatson@canonical.com> |
11 | |
12 | @@ -14,48 +14,11 @@ |
13 | from __future__ import print_function |
14 | |
15 | from optparse import OptionParser |
16 | +import os |
17 | import sys |
18 | |
19 | - |
20 | -def next_package(manifest): |
21 | - """Get the next package name and version information from a manifest.""" |
22 | - while manifest: |
23 | - line = manifest.pop(0) |
24 | - if not line: |
25 | - # silently skip empty lines |
26 | - continue |
27 | - bits = line.split() |
28 | - if len(bits) < 2: |
29 | - print("WARNING: '%s' not in format 'package version'" % line, |
30 | - file=sys.stderr) |
31 | - else: |
32 | - return bits |
33 | - return None |
34 | - |
35 | - |
36 | -def manifest_pairs(ma, mb): |
37 | - """Generate a current pair of packages, one from each manifest to compare. |
38 | - """ |
39 | - left = next_package(ma) |
40 | - right = next_package(mb) |
41 | - while left and right: |
42 | - if left[0] == right[0]: |
43 | - yield left, right |
44 | - left = next_package(ma) |
45 | - right = next_package(mb) |
46 | - elif left[0] < right[0]: |
47 | - yield left, None |
48 | - left = next_package(ma) |
49 | - else: # left[0] > right[0] |
50 | - yield None, right |
51 | - right = next_package(mb) |
52 | - # drain off whichever file still has packages in it |
53 | - while left: |
54 | - yield left, None |
55 | - left = next_package(ma) |
56 | - while right: |
57 | - yield None, right |
58 | - right = next_package(mb) |
59 | +sys.path.insert(0, os.path.join(sys.path[0], os.pardir, "lib")) |
60 | +from cdimage.manifest import compare_manifests |
61 | |
62 | |
63 | def main(): |
64 | @@ -64,23 +27,7 @@ |
65 | if len(args) < 2: |
66 | parser.error("must provide two manifest files to diff") |
67 | |
68 | - # create similarly ordered lists from each manifest file |
69 | - with open(args[0]) as mfa: |
70 | - ma = sorted(mfa.readlines()) |
71 | - with open(args[1]) as mfb: |
72 | - mb = sorted(mfb.readlines()) |
73 | - |
74 | - # analyze relation between pairs of packages from manifest lists |
75 | - for a, b in manifest_pairs(ma, mb): |
76 | - if a and b: |
77 | - if a[1] == b[1]: |
78 | - print("= %s\t%s\t%s" % (a[0], a[1], b[1])) |
79 | - else: |
80 | - print("? %s\t%s\t%s" % (a[0], a[1], b[1])) |
81 | - elif a: |
82 | - print("< %s\t%s\t--" % (a[0], a[1])) |
83 | - else: |
84 | - print("> %s\t--\t%s" % (b[0], b[1])) |
85 | + compare_manifests(args[0], args[1]) |
86 | |
87 | |
88 | if __name__ == '__main__': |
89 | |
90 | === added file 'bin/image-changelog' |
91 | --- bin/image-changelog 1970-01-01 00:00:00 +0000 |
92 | +++ bin/image-changelog 2013-08-30 23:19:27 +0000 |
93 | @@ -0,0 +1,49 @@ |
94 | +#! /usr/bin/python |
95 | + |
96 | +# Copyright (C) 2013 Canonical Ltd. |
97 | +# Author: Ursula Junque <ursula.junque@canonical.com> |
98 | + |
99 | +# This program is free software: you can redistribute it and/or modify |
100 | +# it under the terms of the GNU General Public License as published by |
101 | +# the Free Software Foundation; version 3 of the License. |
102 | +# |
103 | +# This program is distributed in the hope that it will be useful, |
104 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
105 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
106 | +# GNU General Public License for more details. |
107 | +# |
108 | +# You should have received a copy of the GNU General Public License |
109 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
110 | + |
111 | +"""Generates a changelog of an image comparing its manifest with the previous |
112 | +one.""" |
113 | + |
114 | +import os |
115 | +import sys |
116 | +from optparse import OptionParser |
117 | + |
118 | +sys.path.insert(0, os.path.join(sys.path[0], os.pardir, "lib")) |
119 | +from cdimage.manifest import Manifest, ManifestDiff |
120 | + |
121 | + |
122 | +def main(): |
123 | + parser = OptionParser(usage="Usage: %prog manifest1 manifest2") |
124 | + _, args = parser.parse_args() |
125 | + if len(args) < 2: |
126 | + parser.error("must provide two manifest files to diff") |
127 | + |
128 | + # TODO: look for the manifest paths and get them directly instead of |
129 | + # passing as an argument |
130 | + |
131 | + old_manifest = Manifest(args[0]) |
132 | + old_manifest.parse_file() |
133 | + new_manifest = Manifest(args[1]) |
134 | + new_manifest.parse_file() |
135 | + |
136 | + manifest_diff = ManifestDiff() |
137 | + manifest_diff.compare_manifests(old_manifest, new_manifest) |
138 | + manifest_diff.output_changes() |
139 | + |
140 | + |
141 | +if __name__ == '__main__': |
142 | + main() |
143 | |
144 | === added file 'lib/cdimage/changelog.py' |
145 | --- lib/cdimage/changelog.py 1970-01-01 00:00:00 +0000 |
146 | +++ lib/cdimage/changelog.py 2013-08-30 23:19:27 +0000 |
147 | @@ -0,0 +1,160 @@ |
148 | +# Copyright (C) 2013 Canonical Ltd. |
149 | +# Author: Ursula Junque <ursula.junque@canonical.com> |
150 | + |
151 | +# Utilities to parse and handle ubuntu changelogs. |
152 | +# |
153 | +# This program is free software: you can redistribute it and/or modify it |
154 | +# under the terms of the the GNU General Public License version 3, as |
155 | +# published by the Free Software Foundation. |
156 | +# |
157 | +# This program is distributed in the hope that it will be useful, but |
158 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
159 | +# MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR |
160 | +# PURPOSE. See the applicable version of the GNU Lesser General Public |
161 | +# License for more details. |
162 | +# |
163 | +# You should have received a copy of the GNU General Public License |
164 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
165 | + |
166 | + |
167 | +import urllib |
168 | +from debian import changelog |
169 | + |
170 | + |
171 | +CHANGELOG_WEBSITE = "http://changelogs.ubuntu.com/changelogs" |
172 | +# Currently only most recent series |
173 | + |
174 | + |
175 | +class BinaryToSourceLinkNotFound(Exception): |
176 | + """Raised in case the "binary to source" url returns a 404.""" |
177 | + |
178 | + |
179 | +class ChangelogNotFound(Exception): |
180 | + """Raised in case the changelog url returns a 404.""" |
181 | + def __init__(self, name, version, url): |
182 | + self.name = name |
183 | + self.version = version |
184 | + self.url = url |
185 | + |
186 | + def __str__(self): |
187 | + return "Changelog not found: %s_%s" % (self.name, self.version) |
188 | + |
189 | + |
190 | +class EmptyUrlError(Exception): |
191 | + """Raised in case the url is None.""" |
192 | + |
193 | + |
194 | +class VersionNotFound(Exception): |
195 | + """An exception to signal a version isn't found in the changelog.""" |
196 | + |
197 | + def __init__(self, version): |
198 | + self.version = str(version) |
199 | + |
200 | + def __str__(self): |
201 | + return "Version not found in changelog: %s" % self.version |
202 | + |
203 | + |
204 | +def get_source_changelog_url(binary_name, binary_version): |
205 | + """Returns source changelog url given a binary name and version.""" |
206 | + if binary_name is None or binary_version is None: |
207 | + return None |
208 | + if binary_name.startswith("lib"): |
209 | + prefix = binary_name[0:4] |
210 | + else: |
211 | + prefix = binary_name[0] |
212 | + url = "%s/binary/%s/%s/%s/changelog" % (CHANGELOG_WEBSITE, prefix, |
213 | + binary_name, binary_version) |
214 | + return url |
215 | + |
216 | + |
217 | +def get_changelog_url(source_name, source_version, component): |
218 | + """Returns source changelog url given source name and version.""" |
219 | + if source_name is None or source_version is None or component is None: |
220 | + return None |
221 | + if source_name.startswith("lib"): |
222 | + prefix = source_name[0:4] |
223 | + else: |
224 | + prefix = source_name[0] |
225 | + url = ("%s/pool/%s/%s/%s-%s/changelog" % (CHANGELOG_WEBSITE, component, |
226 | + prefix, source_name, source_version)) |
227 | + return url |
228 | + |
229 | + |
230 | +def get_changelog(binary_name, binary_version): |
231 | + """Returns a source Changelog object of a given binary and version. |
232 | + |
233 | + Looks up the source name and version that originated the binary of version |
234 | + provided. Retrieves the source url and parses it, returning a Changelog |
235 | + object. |
236 | + """ |
237 | + url = get_source_changelog_url(binary_name, binary_version) |
238 | + if url is None: |
239 | + raise EmptyUrlError() |
240 | + try: |
241 | + content = urllib.urlopen(url) |
242 | + if content.code == 404: |
243 | + raise ChangelogNotFound(binary_name, binary_version, url) |
244 | + if content.code == 200: |
245 | + return Changelog(content) |
246 | + return None |
247 | + except ChangelogNotFound: |
248 | + raise |
249 | + |
250 | + |
251 | +class Changelog(changelog.Changelog): |
252 | + """Extends deb822.changelog.Changelog. |
253 | + |
254 | + Add ability to get a slice of changelog given the versions in between, |
255 | + also get a block given a version. |
256 | + """ |
257 | + |
258 | + def __init__(self, file_): |
259 | + super(Changelog, self).__init__(file_) |
260 | + |
261 | + @property |
262 | + def source_name(self): |
263 | + return self._blocks[0].package |
264 | + |
265 | + @property |
266 | + def raw_version(self): |
267 | + """Return the last version string""" |
268 | + return self._blocks[0]._raw_version |
269 | + |
270 | + def has_version(self, version): |
271 | + """Returns True if version is found in parsed changelog.""" |
272 | + return str(version) in self._raw_versions() |
273 | + |
274 | + def get_changes_interval(self, start_version, end_version=None, |
275 | + include_start_version=True): |
276 | + """Get all changelog blocks on an interval of versions. |
277 | + |
278 | + Default is returning all changelog blocks in the given interval, |
279 | + including the start version. If you want to get changes excluding the |
280 | + start version, set include_start_version to False. |
281 | + """ |
282 | + if end_version is None: |
283 | + end_version = self.get_version() |
284 | + elif not self.has_version(end_version): |
285 | + raise VersionNotFound(end_version) |
286 | + if not self.has_version(start_version): |
287 | + raise VersionNotFound(start_version) |
288 | + |
289 | + start_index = self._raw_versions().index(str(start_version)) |
290 | + end_index = self._raw_versions().index(str(end_version)) |
291 | + |
292 | + if include_start_version: |
293 | + start_index += 1 |
294 | + |
295 | + return self._blocks[end_index:start_index] |
296 | + |
297 | + def get_changes_after_version(self, start_version, up_to=None): |
298 | + """Returns all changelog blocks after given version.""" |
299 | + return self.get_changes_interval(start_version, up_to, |
300 | + include_start_version=False) |
301 | + |
302 | + def get_change_for_version(self, version): |
303 | + """Returns changeblock of a version.""" |
304 | + if self.has_version(version): |
305 | + index = self._raw_versions().index(str(version)) |
306 | + return self._blocks[index] |
307 | + raise VersionNotFound(version) |
308 | |
309 | === added file 'lib/cdimage/manifest.py' |
310 | --- lib/cdimage/manifest.py 1970-01-01 00:00:00 +0000 |
311 | +++ lib/cdimage/manifest.py 2013-08-30 23:19:27 +0000 |
312 | @@ -0,0 +1,318 @@ |
313 | +# Copyright (C) 2011, 2013 Canonical Ltd. |
314 | +# Author: Kate Stewart <kate.stewart@canonical.com> |
315 | +# Author: Colin Watson <cjwatson@canonical.com> |
316 | +# Author: Ursula Junque <ursula.junque@canonical.com> |
317 | + |
318 | +# This program is free software: you can redistribute it and/or modify |
319 | +# it under the terms of the GNU General Public License as published by |
320 | +# the Free Software Foundation; version 3 of the License. |
321 | +# |
322 | +# This program is distributed in the hope that it will be useful, |
323 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
324 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
325 | +# GNU General Public License for more details. |
326 | +# |
327 | +# You should have received a copy of the GNU General Public License |
328 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
329 | + |
330 | +"""Manifest handler.""" |
331 | + |
332 | +from __future__ import print_function |
333 | + |
334 | +__metaclass__ = type |
335 | + |
336 | + |
337 | +from cdimage.log import logger |
338 | +from cdimage.changelog import ( |
339 | + ChangelogNotFound, |
340 | + get_changelog, |
341 | + VersionNotFound, |
342 | +) |
343 | + |
344 | + |
345 | +def compare_manifests(manifest1, manifest2): |
346 | + # create similarly ordered lists from each manifest file |
347 | + with open(manifest1) as mfa: |
348 | + ma = sorted(mfa.readlines()) |
349 | + with open(manifest2) as mfb: |
350 | + mb = sorted(mfb.readlines()) |
351 | + |
352 | + # analyze relation between pairs of packages from manifest lists |
353 | + for a, b in _manifest_pairs(ma, mb): |
354 | + if a and b: |
355 | + if a[1] == b[1]: |
356 | + print("= %s\t%s\t%s" % (a[0], a[1], b[1])) |
357 | + else: |
358 | + print("? %s\t%s\t%s" % (a[0], a[1], b[1])) |
359 | + elif a: |
360 | + print("< %s\t%s\t--" % (a[0], a[1])) |
361 | + else: |
362 | + print("> %s\t--\t%s" % (b[0], b[1])) |
363 | + |
364 | + |
365 | +def _next_package(manifest): |
366 | + """Get the next package name and version information from a manifest.""" |
367 | + while manifest: |
368 | + line = manifest.pop(0) |
369 | + if not line: |
370 | + # silently skip empty lines |
371 | + continue |
372 | + bits = line.split() |
373 | + if len(bits) < 2: |
374 | + logger.warning("'%s' not in format 'package version'" % line) |
375 | + else: |
376 | + return bits |
377 | + return None |
378 | + |
379 | + |
380 | +def _manifest_pairs(ma, mb): |
381 | + """Generate a current pair of packages, one from each manifest to compare. |
382 | + """ |
383 | + left = _next_package(ma) |
384 | + right = _next_package(mb) |
385 | + while left and right: |
386 | + if left[0] == right[0]: |
387 | + yield left, right |
388 | + left = _next_package(ma) |
389 | + right = _next_package(mb) |
390 | + elif left[0] < right[0]: |
391 | + yield left, None |
392 | + left = _next_package(ma) |
393 | + else: # left[0] > right[0] |
394 | + yield None, right |
395 | + right = _next_package(mb) |
396 | + # drain off whichever file still has packages in it |
397 | + while left: |
398 | + yield left, None |
399 | + left = _next_package(ma) |
400 | + while right: |
401 | + yield None, right |
402 | + right = _next_package(mb) |
403 | + |
404 | + |
405 | +class Manifest: |
406 | + |
407 | + def __init__(self, manifest_name=None): |
408 | + self.filename = manifest_name |
409 | + self.content = {} |
410 | + |
411 | + def parse_file(self, manifest_name=None): |
412 | + if manifest_name is None and self.filename is not None: |
413 | + filename = self.filename |
414 | + file_ = open(filename) |
415 | + content = file_.readlines() |
416 | + file_.close() |
417 | + return self.parse(content) |
418 | + return None |
419 | + |
420 | + def parse(self, content): |
421 | + if content is None: |
422 | + return None |
423 | + for line in content: |
424 | + parsed_line = line.strip().split() |
425 | + if not parsed_line: |
426 | + continue |
427 | + self.content[parsed_line[0]] = parsed_line[1] |
428 | + return self.content |
429 | + |
430 | + @property |
431 | + def packages(self): |
432 | + return set(self.content.keys()) |
433 | + |
434 | + def get_version(self, package_name): |
435 | + try: |
436 | + return self.content[package_name] |
437 | + except KeyError: |
438 | + return None |
439 | + |
440 | + |
441 | +class PackageDiff: |
442 | + |
443 | + def __init__(self, binary_name, old_binary_version, new_binary_version): |
444 | + self.binary_name = binary_name |
445 | + self.old_binary_version = old_binary_version |
446 | + self.new_binary_version = new_binary_version |
447 | + self.old_changelog = self.get_changelog_info(old_binary_version) |
448 | + self.new_changelog = self.get_changelog_info(new_binary_version) |
449 | + self.old_source_info = self._get_source_info(self.old_changelog) |
450 | + self.new_source_info = self._get_source_info(self.new_changelog) |
451 | + |
452 | + @property |
453 | + def old_source_name(self): |
454 | + return self.old_source_info[0] |
455 | + |
456 | + @property |
457 | + def new_source_name(self): |
458 | + return self.new_source_info[0] |
459 | + |
460 | + @property |
461 | + def old_source_version(self): |
462 | + return self.old_source_info[1] |
463 | + |
464 | + @property |
465 | + def new_source_version(self): |
466 | + return self.new_source_info[1] |
467 | + |
468 | + @property |
469 | + def source_has_changed(self): |
470 | + return (self.old_source_name != self.new_source_name) |
471 | + |
472 | + def get_changelog_info(self, binary_version): |
473 | + """Fetches the changelog information for the given binary version. |
474 | + |
475 | + This method fetches the changelog specific to this binary |
476 | + version, so the latest source name and version in the changelog are |
477 | + guaranteed to refer to this binary name and version. |
478 | + """ |
479 | + return get_changelog(self.binary_name, binary_version) |
480 | + |
481 | + @property |
482 | + def source_name(self): |
483 | + return self.new_source_name |
484 | + |
485 | + @property |
486 | + def source_info(self): |
487 | + return (self.source_name, self.old_source_version, |
488 | + self.new_source_version) |
489 | + |
490 | + def _get_source_info(self, changelog): |
491 | + """Return the latest source name version given a changelog.""" |
492 | + if changelog is not None: |
493 | + return changelog.source_name, changelog.raw_version |
494 | + else: |
495 | + return None, None |
496 | + |
497 | + @property |
498 | + def changes(self): |
499 | + """List of changelog blocks between two binary versions.""" |
500 | + try: |
501 | + if self.source_has_changed: |
502 | + # Return only the latest change of the recent changelog. |
503 | + return [self.new_changelog.get_change_for_version( |
504 | + self.new_source_version)] |
505 | + changes = self.new_changelog.get_changes_after_version( |
506 | + self.old_source_version, self.new_source_version) |
507 | + except VersionNotFound as e: |
508 | + # Sometimes the old versions disappear from the changelog due to |
509 | + # debian syncs. Whenever that happens, retrieve only the latest |
510 | + # change. |
511 | + if e.version == self.old_source_version: |
512 | + changes = [self.new_changelog.get_change_for_version( |
513 | + self.new_source_version)] |
514 | + else: |
515 | + # If the problem is the newest version, there's something |
516 | + # really wrong, this is not supposed to happen. |
517 | + raise |
518 | + return changes |
519 | + |
520 | + |
521 | +class ManifestDiff: |
522 | + |
523 | + def __init__(self): |
524 | + self.added_pkgs = {} |
525 | + self.removed_pkgs = {} |
526 | + self._changed_pkgs = {} |
527 | + self.changelogs = {} |
528 | + self.missing_pkgs = {} |
529 | + |
530 | + def compare_manifests(self, manifest1, manifest2): |
531 | + """Compares two Manifest objects generating the differences.""" |
532 | + self.added_pkgs = {pkg: manifest2.get_version(pkg) for pkg in ( |
533 | + manifest2.packages - manifest1.packages)} |
534 | + self.removed_pkgs = {pkg: manifest1.get_version(pkg) for pkg in ( |
535 | + manifest1.packages - manifest2.packages)} |
536 | + |
537 | + for pkg in manifest1.packages.intersection(manifest2.packages): |
538 | + version1 = manifest1.get_version(pkg) |
539 | + version2 = manifest2.get_version(pkg) |
540 | + if version1 != version2: |
541 | + self._changed_pkgs[pkg] = (version1, version2) |
542 | + |
543 | + def compare(self, dict1, dict2): |
544 | + """Compares two {pkg: version} dicts generating the differences.""" |
545 | + self.added_pkgs = {pkg: dict2[pkg] for pkg in ( |
546 | + set(dict2.keys()) - set(dict1.keys()))} |
547 | + self.removed_pkgs = {pkg: dict1[pkg] for pkg in ( |
548 | + set(dict1.keys()) - set(dict2.keys()))} |
549 | + |
550 | + for pkg in set(dict1.keys()).intersection(set(dict2.keys())): |
551 | + version1 = dict1[pkg] |
552 | + version2 = dict2[pkg] |
553 | + if version1 != version2: |
554 | + self._changed_pkgs[pkg] = (version1, version2) |
555 | + |
556 | + def print_new_pkgs(self): |
557 | + for pkg in sorted(list(self.added_pkgs.keys())): |
558 | + print("%s - %s" % (pkg, self.added_pkgs[pkg])) |
559 | + |
560 | + def print_removed_pkgs(self): |
561 | + for pkg in sorted(list(self.removed_pkgs.keys())): |
562 | + print("%s - %s" % (pkg, self.removed_pkgs[pkg])) |
563 | + |
564 | + def get_changes(self): |
565 | + for pkg, versions in list(self._changed_pkgs.items()): |
566 | + old_binary_version, new_binary_version = versions |
567 | + try: |
568 | + pkg_name = pkg.split(":")[0] |
569 | + pkg_changes = PackageDiff(pkg_name, old_binary_version, |
570 | + new_binary_version) |
571 | + except ChangelogNotFound as e: |
572 | + self.missing_pkgs[pkg] = (versions, e) |
573 | + continue |
574 | + if pkg_changes.source_name in self.changelogs: |
575 | + continue |
576 | + self.changelogs[pkg_changes.source_name] = pkg_changes |
577 | + return self.changelogs |
578 | + |
579 | + def print_changed_pkgs(self): |
580 | + changed_pkgs = "" |
581 | + changelogs = "" |
582 | + for pkg in sorted(list(self.changed_pkgs.keys())): |
583 | + packagediff = self.changed_pkgs[pkg] |
584 | + changed_pkgs += "%s - %s -> %s\n" % ( |
585 | + pkg, packagediff.old_source_version, |
586 | + packagediff.new_source_version) |
587 | + for change in packagediff.changes: |
588 | + changelogs += " %s" % str(change) |
589 | + for pkg in sorted(list(self.missing_pkgs.keys())): |
590 | + versions, error = self.missing_pkgs[pkg] |
591 | + changed_pkgs += "%s (binary) - %s -> %s\n" % (pkg, versions[0], |
592 | + versions[1]) |
593 | + print(changed_pkgs) |
594 | + print("== Changelogs ==\n") |
595 | + print(changelogs) |
596 | + |
597 | + def print_changed_pkgs_changelogs(self): |
598 | + for pkg in sorted(list(self.changed_pkgs.keys())): |
599 | + for change in self.changed_pkgs[pkg]: |
600 | + print(" %s" % str(change)) |
601 | + |
602 | + def print_missing_pkgs(self, hide_errors=True): |
603 | + for pkg in sorted(list(self.missing_pkgs.keys())): |
604 | + if hide_errors: |
605 | + print("%s" % pkg) |
606 | + else: |
607 | + print("%s - %s" % (pkg, self.missing_pkgs[pkg][1].version)) |
608 | + |
609 | + @property |
610 | + def changed_pkgs(self): |
611 | + if self.changelogs: |
612 | + return self.changelogs |
613 | + return self.get_changes() |
614 | + |
615 | + def output_changes(self): |
616 | + if self.added_pkgs: |
617 | + print("== Added packages ==") |
618 | + self.print_new_pkgs() |
619 | + if self.removed_pkgs: |
620 | + print("\n== Removed packages ==") |
621 | + self.print_removed_pkgs() |
622 | + if self.changed_pkgs: |
623 | + print("\n== Changed packages ==") |
624 | + self.print_changed_pkgs() |
625 | + |
626 | + if self.missing_pkgs: |
627 | + missing = len(self.missing_pkgs) |
628 | + print("== Changed packages not found in the archive (%s) ==" % |
629 | + missing) |
630 | + self.print_missing_pkgs(hide_errors=False) |
631 | |
632 | === modified file 'lib/cdimage/tests/helpers.py' |
633 | --- lib/cdimage/tests/helpers.py 2013-03-27 17:31:02 +0000 |
634 | +++ lib/cdimage/tests/helpers.py 2013-08-30 23:19:27 +0000 |
635 | @@ -130,6 +130,20 @@ |
636 | assertRaisesRegex = unittest.TestCase.assertRaisesRegexp |
637 | |
638 | |
639 | +class FakeUrlOpenReturn: |
640 | + """Object to mock the return of urllib.urlopen.""" |
641 | + |
642 | + def __init__(self, code, content): |
643 | + self.code = code |
644 | + self.content = content |
645 | + |
646 | + def __repr__(self): |
647 | + return self.content |
648 | + |
649 | + def __iter__(self): |
650 | + return (line for line in self.content.split("\n")) |
651 | + |
652 | + |
653 | @contextlib.contextmanager |
654 | def mkfile(path, mode="w"): |
655 | osextras.ensuredir(os.path.dirname(path)) |
656 | |
657 | === added file 'lib/cdimage/tests/test_changelog.py' |
658 | --- lib/cdimage/tests/test_changelog.py 1970-01-01 00:00:00 +0000 |
659 | +++ lib/cdimage/tests/test_changelog.py 2013-08-30 23:19:27 +0000 |
660 | @@ -0,0 +1,193 @@ |
661 | +#! /usr/bin/python |
662 | + |
663 | +# Copyright (C) 2013 Canonical Ltd. |
664 | +# Author: Ursula Junque <ursula.junque@canonical.com> |
665 | + |
666 | +# This program is free software: you can redistribute it and/or modify |
667 | +# it under the terms of the GNU General Public License as published by |
668 | +# the Free Software Foundation; version 3 of the License. |
669 | +# |
670 | +# This program is distributed in the hope that it will be useful, |
671 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
672 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
673 | +# GNU General Public License for more details. |
674 | +# |
675 | +# You should have received a copy of the GNU General Public License |
676 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
677 | + |
678 | +"""Unit tests for cdimage.changelog.""" |
679 | + |
680 | +from __future__ import print_function |
681 | + |
682 | +__metaclass__ = type |
683 | + |
684 | +import os |
685 | + |
686 | +from cdimage.changelog import (Changelog, ChangelogNotFound, EmptyUrlError, |
687 | + get_source_changelog_url, get_changelog_url, |
688 | + get_changelog, VersionNotFound) |
689 | +from cdimage.tests.helpers import FakeUrlOpenReturn, mkfile, TestCase |
690 | + |
691 | +try: |
692 | + from unittest import mock |
693 | +except ImportError: |
694 | + import mock |
695 | + |
696 | + |
697 | +CHANGELOG_CONTENT = ("""unzip (5.51-1) unstable; urgency=low |
698 | + * New upstream release, improves error message when a zipfile is not |
699 | + readable (Closes: #139331). |
700 | + * Added a newline character to the CannotOpenZipfile string for the |
701 | + previous fix to be really complete. |
702 | + |
703 | + -- Santiago Vila <sanvila@debian.org> Sun, 6 Jun 2004 17:57:46 +0200 |
704 | + |
705 | +unzip (5.51a.0-2) unstable; urgency=low |
706 | + |
707 | + * Added unshrinking support (Closes: #252563). |
708 | + |
709 | + -- Santiago Vila <sanvila@debian.org> Tue, 25 May 2004 14:38:26 +0200 |
710 | + |
711 | +unzip (5.50-4) unstable; urgency=low |
712 | + |
713 | + * Changed __GNU__ to __GLIBC__ in unix/unxcfg.h to support glibc-based |
714 | + systems not being GNU itself, like GNU/KFreeBSD and GNU/KNetBSD. |
715 | + |
716 | + -- Santiago Vila <sanvila@debian.org> Sun, 16 Nov 2003 14:45:28 +0100 |
717 | + |
718 | +unzip (5.50-3) unstable; urgency=high |
719 | + |
720 | + * Fixed "unzip directory traversal revisited" again (Bug #206439). |
721 | + There was still a missing case that the previous patch didn't catch. |
722 | + Patch borrowed from unzip-5.50-33.src.rpm. |
723 | + * For reference, this is (still) CAN-2003-0282. |
724 | + |
725 | + -- Santiago Vila <sanvila@debian.org> Wed, 20 Aug 2003 23:00:42 +0200 |
726 | + |
727 | +unzip (5.50-2) unstable; urgency=high |
728 | + |
729 | + * Fixed "unzip directory traversal revisited" problem (Bug #199648). |
730 | + A filename containing ".somenonprintablechar." will not unpack |
731 | + into .. anymore. Patch borrowed from unzip-5.50-11.src.rpm. |
732 | + * For reference, this is CAN-2003-0282. |
733 | + * No more doc symlinks. |
734 | + |
735 | + -- Santiago Vila <sanvila@debian.org> Mon, 7 Jul 2003 20:25:20 +0200 |
736 | +""") |
737 | + |
738 | + |
739 | +class ChangelogTests(TestCase): |
740 | + |
741 | + def setUp(self): |
742 | + super(ChangelogTests, self).setUp() |
743 | + temp_dir = self.use_temp_dir() |
744 | + changelog_path = os.path.join(temp_dir, "changelog") |
745 | + with mkfile(changelog_path) as f: |
746 | + print(CHANGELOG_CONTENT, file=f) |
747 | + file_ = open(changelog_path) |
748 | + self.changelog = Changelog(file_) |
749 | + file_.close() |
750 | + |
751 | + def test_changelog_has_version(self): |
752 | + version = "5.51-1" |
753 | + self.assertTrue(self.changelog.has_version(version)) |
754 | + version = "foobar" |
755 | + self.assertFalse(self.changelog.has_version(version)) |
756 | + |
757 | + def test_changelog_raw_version(self): |
758 | + version = self.changelog.get_version() |
759 | + self.assertEqual(str(version), self.changelog.raw_version) |
760 | + |
761 | + def test_changelog_get_changes_interval(self): |
762 | + start_version = "5.50-2" |
763 | + end_version = "5.51-1" |
764 | + # 5.50-2 5.50-3 5.50-4 5.51a.0-2 5.51-1 |
765 | + |
766 | + self.assertEqual(len(self.changelog.get_changes_interval(start_version, |
767 | + end_version, include_start_version=False)), 4) |
768 | + self.assertEqual(len(self.changelog.get_changes_interval(start_version, |
769 | + end_version)), 5) |
770 | + |
771 | + def test_changelog_get_changes_interval_no_endversion(self): |
772 | + start_version = "5.50-4" |
773 | + end_version = None |
774 | + |
775 | + changes = self.changelog.get_changes_interval( |
776 | + start_version, end_version, include_start_version=False) |
777 | + self.assertEqual(len(changes), 2) |
778 | + changes = self.changelog.get_changes_interval(start_version) |
779 | + self.assertEqual(len(changes), 3) |
780 | + |
781 | + changes_versions = [change._raw_version for change in changes] |
782 | + self.assertTrue("5.51-1" in changes_versions) |
783 | + self.assertTrue("5.51a.0-2" in changes_versions) |
784 | + self.assertTrue("5.50-4" in changes_versions) |
785 | + |
786 | + def test_changelog_get_changes_after_version(self): |
787 | + start_version = "5.50-3" |
788 | + |
789 | + changes = self.changelog.get_changes_after_version(start_version) |
790 | + self.assertEqual(len(changes), 3) |
791 | + changes_versions = [change._raw_version for change in changes] |
792 | + self.assertTrue("5.50-4" in changes_versions) |
793 | + self.assertTrue("5.51a.0-2" in changes_versions) |
794 | + self.assertTrue("5.51-1" in changes_versions) |
795 | + self.assertTrue("5.50-3" not in changes_versions) |
796 | + |
797 | + def test_changelog_get_changes_interval_version_doesnt_exist(self): |
798 | + start_version = "foobar" |
799 | + self.assertRaises(VersionNotFound, |
800 | + self.changelog.get_changes_interval, |
801 | + start_version) |
802 | + |
803 | + |
804 | +class TestGetUrls(TestCase): |
805 | + |
806 | + def setUp(self): |
807 | + super(TestGetUrls, self).setUp() |
808 | + |
809 | + def test_get_source_changelog_url(self): |
810 | + url = ("http://changelogs.ubuntu.com/changelogs/binary/f/" |
811 | + "foobar/1.0/changelog") |
812 | + self.assertEqual(get_source_changelog_url("foobar", "1.0"), url) |
813 | + |
814 | + def test_get_source_changelog_url_missing_argument(self): |
815 | + self.assertEqual(get_source_changelog_url(None, "1.0"), None) |
816 | + self.assertEqual(get_source_changelog_url("foobar", None), None) |
817 | + self.assertEqual(get_source_changelog_url(None, None), None) |
818 | + |
819 | + def test_get_changelog_url(self): |
820 | + url = ("http://changelogs.ubuntu.com/changelogs/pool/main/f/" |
821 | + "foobar-1.0/changelog") |
822 | + self.assertEqual(get_changelog_url("foobar", "1.0", "main"), url) |
823 | + |
824 | + def test_get_changelog_url_missing_argument(self): |
825 | + self.assertEqual(get_changelog_url("foobar", "1.0", None), None) |
826 | + self.assertEqual(get_changelog_url("foobar", None, "main"), None) |
827 | + self.assertEqual(get_changelog_url(None, "1.0", "main"), None) |
828 | + |
829 | + |
830 | +class TestGetChangelog(TestCase): |
831 | + |
832 | + def setUp(self): |
833 | + super(TestGetChangelog, self).setUp() |
834 | + |
835 | + @mock.patch("urllib.urlopen", |
836 | + return_value=FakeUrlOpenReturn(200, CHANGELOG_CONTENT)) |
837 | + def test_get_changelog(self, mock_urlopen): |
838 | + changelog = get_changelog("foobar", "1.0") |
839 | + self.assertIsNotNone(changelog) |
840 | + |
841 | + @mock.patch("urllib.urlopen", |
842 | + return_value=FakeUrlOpenReturn(404, "Not found")) |
843 | + def test_get_changelog_url_not_found(self, mock_urlopen): |
844 | + self.assertRaises(ChangelogNotFound, get_changelog, "foobar", "1.0") |
845 | + |
846 | + @mock.patch("urllib.urlopen", |
847 | + return_value=FakeUrlOpenReturn(500, "Forbidden")) |
848 | + def test_get_changelog_othererror(self, mock_urlopen): |
849 | + changelog = get_changelog("foobar", "1.0") |
850 | + self.assertIsNone(changelog) |
851 | + |
852 | + def test_get_changelog_urlisNone(self): |
853 | + self.assertRaises(EmptyUrlError, get_changelog, None, None) |
854 | |
855 | === added file 'lib/cdimage/tests/test_manifest.py' |
856 | --- lib/cdimage/tests/test_manifest.py 1970-01-01 00:00:00 +0000 |
857 | +++ lib/cdimage/tests/test_manifest.py 2013-08-30 23:19:27 +0000 |
858 | @@ -0,0 +1,384 @@ |
859 | +#! /usr/bin/python |
860 | + |
861 | +# Copyright (C) 2013 Canonical Ltd. |
862 | +# Author: Ursula Junque <ursinha@ubuntu.com> |
863 | + |
864 | +# This program is free software: you can redistribute it and/or modify |
865 | +# it under the terms of the GNU General Public License as published by |
866 | +# the Free Software Foundation; version 3 of the License. |
867 | +# |
868 | +# This program is distributed in the hope that it will be useful, |
869 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
870 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
871 | +# GNU General Public License for more details. |
872 | +# |
873 | +# You should have received a copy of the GNU General Public License |
874 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
875 | + |
876 | +"""Unit tests for cdimage.manifest.""" |
877 | + |
878 | +from __future__ import print_function |
879 | +import os |
880 | + |
881 | +__metaclass__ = type |
882 | + |
883 | +try: |
884 | + from unittest import mock |
885 | +except ImportError: |
886 | + import mock |
887 | + |
888 | +import urllib |
889 | +urllib.urlopen = mock.Mock() |
890 | + |
891 | +from cdimage.manifest import Manifest, ManifestDiff, PackageDiff |
892 | +from cdimage.tests.helpers import dedent, FakeUrlOpenReturn, mkfile, TestCase |
893 | + |
894 | + |
895 | +def generate_manifest_file(content, temp_dir, filename=None): |
896 | + if filename is None: |
897 | + filename = "manifest" |
898 | + manifest_path = os.path.join(temp_dir, filename) |
899 | + with mkfile(manifest_path) as f: |
900 | + print(content, file=f) |
901 | + return manifest_path |
902 | + |
903 | + |
904 | +class TestManifest(TestCase): |
905 | + |
906 | + CONTENT = dedent("""\ |
907 | + apparmor 2.8.0-0ubuntu19.1 |
908 | + at-spi2-core 2.9.4-1ubuntu1 |
909 | + libatk-bridge2.0-0:armhf 2.9.3-1""") |
910 | + |
911 | + def setUp(self): |
912 | + super(TestManifest, self).setUp() |
913 | + self.temp_dir = self.use_temp_dir() |
914 | + self.parsed_content = {"apparmor": "2.8.0-0ubuntu19.1", |
915 | + "at-spi2-core": "2.9.4-1ubuntu1", |
916 | + "libatk-bridge2.0-0:armhf": "2.9.3-1"} |
917 | + |
918 | + def _generate_manifest_from_file(self, content=None): |
919 | + if content is None: |
920 | + content = self.CONTENT |
921 | + return Manifest(generate_manifest_file(content, self.temp_dir)) |
922 | + |
923 | + def test_parse_regular_file(self): |
924 | + manifest = self._generate_manifest_from_file() |
925 | + self.assertEqual(self.parsed_content, manifest.parse_file()) |
926 | + |
927 | + def test_parse_empty_file(self): |
928 | + manifest = self._generate_manifest_from_file(content="") |
929 | + self.assertEqual({}, manifest.parse_file()) |
930 | + |
931 | + def test_parse(self): |
932 | + manifest = Manifest() |
933 | + content = self.CONTENT.split("\n") |
934 | + self.assertEqual(manifest.parse(content), self.parsed_content) |
935 | + |
936 | + def test_packages(self): |
937 | + manifest = Manifest() |
938 | + content = self.CONTENT.split("\n") |
939 | + parsed_content = manifest.parse(content) |
940 | + self.assertEqual(set(parsed_content.keys()), manifest.packages) |
941 | + |
942 | + def test_get_version(self): |
943 | + manifest = Manifest() |
944 | + content = self.CONTENT.split("\n") |
945 | + manifest.parse(content) |
946 | + package = "apparmor" |
947 | + self.assertEqual(manifest.get_version(package), "2.8.0-0ubuntu19.1") |
948 | + |
949 | + def test_get_version_package_not_found(self): |
950 | + manifest = Manifest() |
951 | + content = self.CONTENT.split("\n") |
952 | + manifest.parse(content) |
953 | + package = "foobar" |
954 | + self.assertEqual(manifest.get_version(package), None) |
955 | + |
956 | + |
957 | +OLD_CHANGELOG_CONTENT = ("""\ |
958 | +unzip (5.51a.0-2) unstable; urgency=low |
959 | + |
960 | + * Added unshrinking support (Closes: #252563). |
961 | + |
962 | + -- Santiago Vila <sanvila@debian.org> Tue, 25 May 2004 14:38:26 +0200""") |
963 | + |
964 | +NEW_CHANGELOG_CONTENT = ("""\ |
965 | +unzip (5.51-1) unstable; urgency=low |
966 | + * New upstream release, improves error message when a zipfile is not |
967 | + readable (Closes: #139331). |
968 | + * Added a newline character to the CannotOpenZipfile string for the |
969 | + previous fix to be really complete. |
970 | + |
971 | + -- Santiago Vila <sanvila@debian.org> Sun, 6 Jun 2004 17:57:46 +0200 |
972 | + |
973 | +unzip (5.51a.0-3) unstable; urgency=low |
974 | + * One release in the middle to get two changes between manifests. |
975 | + |
976 | + -- Santiago Vila <sanvila@debian.org> Wed, 26 Jun 2004 17:57:46 +0200 |
977 | + |
978 | +unzip (5.51a.0-2) unstable; urgency=low |
979 | + |
980 | + * Added unshrinking support (Closes: #252563). |
981 | + |
982 | + -- Santiago Vila <sanvila@debian.org> Tue, 25 May 2004 14:38:26 +0200""") |
983 | + |
984 | +OLD_CHANGELOG_NO_VERSION_CONTENT = ("""\ |
985 | +unzip (5.51a.0-1) unstable; urgency=low |
986 | + |
987 | + * Added unshrinking support (Closes: #252563). |
988 | + |
989 | + -- Santiago Vila <sanvila@debian.org> Tue, 25 May 2004 14:38:26 +0200""") |
990 | + |
991 | +NEW_CHANGELOG_CONTENT_NEWSOURCE = ("""\ |
992 | +unzippo (6.0) unstable; urgency=low |
993 | + |
994 | + * Added unshrinking support (Closes: #252563). |
995 | + |
996 | + -- Santiago Vila <sanvila@debian.org> Tue, 25 May 2004 14:38:26 +0200""") |
997 | + |
998 | + |
999 | +class TestPackageDiffSameSource(TestCase): |
1000 | + |
1001 | + def setUp(self): |
1002 | + super(TestPackageDiffSameSource, self).setUp() |
1003 | + urllib.urlopen.side_effect = [ |
1004 | + FakeUrlOpenReturn(200, OLD_CHANGELOG_CONTENT), |
1005 | + FakeUrlOpenReturn(200, NEW_CHANGELOG_CONTENT)] |
1006 | + self.old_version = "5.51a.0-2" |
1007 | + self.new_version = "5.51-1" |
1008 | + self.packagediff = PackageDiff("unzip", self.old_version, |
1009 | + self.new_version) |
1010 | + |
1011 | + def test_packagediff_old_source_name(self): |
1012 | + self.assertEqual(self.packagediff.old_source_name, "unzip") |
1013 | + |
1014 | + def test_packagediff_new_source_name(self): |
1015 | + self.assertEqual(self.packagediff.new_source_name, "unzip") |
1016 | + |
1017 | + def test_packagediff_old_source_version(self): |
1018 | + self.assertEqual(self.packagediff.old_source_version, "5.51a.0-2") |
1019 | + |
1020 | + def test_packagediff_new_source_version(self): |
1021 | + self.assertEqual(self.packagediff.new_source_version, "5.51-1") |
1022 | + |
1023 | + def test_packagediff_source_hasnt_changed(self): |
1024 | + self.assertFalse(self.packagediff.source_has_changed) |
1025 | + self.assertEqual(self.packagediff.source_name, "unzip") |
1026 | + |
1027 | + def test_packagediff_source_name_is_new_source_name(self): |
1028 | + self.assertEqual(self.packagediff.new_source_name, |
1029 | + self.packagediff.source_name) |
1030 | + |
1031 | + def test_changes(self): |
1032 | + self.assertEqual(len(self.packagediff.changes), 2) |
1033 | + |
1034 | + |
1035 | +class TestPackageDiffSameSourceMissingVersion(TestCase): |
1036 | + def setUp(self): |
1037 | + super(TestPackageDiffSameSourceMissingVersion, self).setUp() |
1038 | + |
1039 | + def test_changes_old_version_is_gone(self): |
1040 | + urllib.urlopen.side_effect = [ |
1041 | + FakeUrlOpenReturn(200, OLD_CHANGELOG_NO_VERSION_CONTENT), |
1042 | + FakeUrlOpenReturn(200, NEW_CHANGELOG_CONTENT)] |
1043 | + old_version = "5.51a.0-1" |
1044 | + new_version = "5.51-1" |
1045 | + packagediff = PackageDiff("unzip", old_version, new_version) |
1046 | + self.assertEqual(len(packagediff.changes), 1) |
1047 | + self.assertEqual(packagediff.changes[0].version, new_version) |
1048 | + |
1049 | + |
1050 | +class TestPackageDiffDifferentSource(TestCase): |
1051 | + |
1052 | + def setUp(self): |
1053 | + super(TestPackageDiffDifferentSource, self).setUp() |
1054 | + urllib.urlopen.side_effect = [ |
1055 | + FakeUrlOpenReturn(200, OLD_CHANGELOG_CONTENT), |
1056 | + FakeUrlOpenReturn(200, NEW_CHANGELOG_CONTENT_NEWSOURCE)] |
1057 | + self.packagediff = PackageDiff("unzip", "5.51a.0-2", "6.0") |
1058 | + |
1059 | + def test_packagediff_source_has_changed(self): |
1060 | + self.assertTrue(self.packagediff.source_has_changed) |
1061 | + self.assertEqual(self.packagediff.new_source_name, "unzippo") |
1062 | + |
1063 | + def test_packagediff_source_name_is_new_source_name(self): |
1064 | + self.assertEqual(self.packagediff.new_source_name, |
1065 | + self.packagediff.source_name) |
1066 | + self.assertNotEqual(self.packagediff.old_source_name, |
1067 | + self.packagediff.source_name) |
1068 | + |
1069 | + def test_changes(self): |
1070 | + # Check if it's returning only the latest change of the new changelog. |
1071 | + self.assertEqual(len(self.packagediff.changes), 1) |
1072 | + |
1073 | + |
1074 | +FOO_NEW_CHANGELOG = """\ |
1075 | +foo (0.1-0ubuntu3) unstable; urgency=low |
1076 | + * More foo stuff |
1077 | + |
1078 | + -- John Doe <johndoe@example.com> Sun, 6 Jun 2004 17:57:46 +0200 |
1079 | + |
1080 | +foo (0.1-0ubuntu2) unstable; urgency=low |
1081 | + * Initial release |
1082 | + |
1083 | + -- John Doe <johndoe@example.com> Tue, 25 May 2004 14:38:26 +0200""" |
1084 | + |
1085 | +FOO_OLD_CHANGELOG = """\ |
1086 | +foo (0.1-0ubuntu2) unstable; urgency=low |
1087 | + * Initial release |
1088 | + |
1089 | + -- John Doe <johndoe@example.com> Tue, 25 May 2004 14:38:26 +0200""" |
1090 | + |
1091 | +BAR_NEW_CHANGELOG = """\ |
1092 | +bar (0.2-1ubuntu4) unstable; urgency=low |
1093 | + * Baring the thing |
1094 | + |
1095 | + -- John Doe <johndoe@example.com> Mon, 7 Jun 2004 17:57:46 +0200 |
1096 | + |
1097 | +bar (0.2-1ubuntu3) unstable; urgency=low |
1098 | + * Release in the middle |
1099 | + |
1100 | + -- John Doe <johndoe@example.com> Wed, 26 Jun 2004 17:57:46 +0200 |
1101 | + |
1102 | +bar (0.2-1ubuntu2) unstable; urgency=low |
1103 | + * Initial release |
1104 | + |
1105 | + -- John Doe <johndoe@example.com> Mon, 24 May 2004 14:38:26 +0200""" |
1106 | + |
1107 | +BAR_OLD_CHANGELOG = """\ |
1108 | +bar (0.2-1ubuntu2) unstable; urgency=low |
1109 | + * Initial release |
1110 | + |
1111 | + -- John Doe <johndoe@example.com> Mon, 24 May 2004 14:38:26 +0200""" |
1112 | + |
1113 | + |
1114 | +class TestManifestDiff(TestCase): |
1115 | + |
1116 | + # Old manifest: foo, bar, baz, libbaz1, foo5, libbar6 |
1117 | + OLD_MANIFEST = dedent("""\ |
1118 | + foo 0.1-0ubuntu2 |
1119 | + bar 0.2-1ubuntu2 |
1120 | + libbaz1 0.3-0ubuntu1 |
1121 | + libbar6 1.3-2+13.10.20130520-0ubuntu1""") |
1122 | + |
1123 | + # New manifest: foo, bar, baz, libbaz2, foo5, libbar7 |
1124 | + # - Added packages: libbaz2, libbar7 |
1125 | + # - Removed packages: libbaz1, libbar6 |
1126 | + # - Updated packages: foo, bar, baz, foo5 |
1127 | + NEW_MANIFEST = dedent("""\ |
1128 | + foo 0.1-0ubuntu3 |
1129 | + bar 0.2-1ubuntu4 |
1130 | + libbaz2 0.4-0ubuntu1 |
1131 | + libbar7 1.5""") |
1132 | + |
1133 | + def setUp(self): |
1134 | + super(TestManifestDiff, self).setUp() |
1135 | + self.manifest_diff = ManifestDiff() |
1136 | + |
1137 | + def _generate_manifest_files(self): |
1138 | + temp_dir = self.use_temp_dir() |
1139 | + self.manifest1_file = generate_manifest_file(self.OLD_MANIFEST, |
1140 | + temp_dir, "manifest1") |
1141 | + self.manifest2_file = generate_manifest_file(self.NEW_MANIFEST, |
1142 | + temp_dir, "manifest2") |
1143 | + |
1144 | + def test_compare_manifests(self): |
1145 | + self._generate_manifest_files() |
1146 | + manifest1 = Manifest(self.manifest1_file) |
1147 | + manifest1.parse_file() |
1148 | + manifest2 = Manifest(self.manifest2_file) |
1149 | + manifest2.parse_file() |
1150 | + manifest_diff = self.manifest_diff |
1151 | + manifest_diff.compare_manifests(manifest1, manifest2) |
1152 | + |
1153 | + # - Added packages: libbaz2, libbar7 |
1154 | + self.assertEqual(len(manifest_diff.added_pkgs), 2) |
1155 | + self.assertTrue("libbaz2" in manifest_diff.added_pkgs) |
1156 | + self.assertTrue("libbar7" in manifest_diff.added_pkgs) |
1157 | + self.assertTrue("libbaz2" not in manifest_diff._changed_pkgs) |
1158 | + |
1159 | + # - Removed packages: libbaz1, libbar6 |
1160 | + self.assertEqual(len(manifest_diff.removed_pkgs), 2) |
1161 | + self.assertTrue("libbaz1" in manifest_diff.removed_pkgs) |
1162 | + self.assertTrue("libbar6" in manifest_diff.removed_pkgs) |
1163 | + self.assertTrue("libbaz1" not in manifest_diff._changed_pkgs) |
1164 | + |
1165 | + # - Updated packages: foo, bar |
1166 | + self.assertEqual(len(manifest_diff._changed_pkgs), 2) |
1167 | + self.assertTrue("foo" in manifest_diff._changed_pkgs) |
1168 | + self.assertTrue("bar" in manifest_diff._changed_pkgs) |
1169 | + |
1170 | + # All packages in both manifests (ignoring duplicates) |
1171 | + all_packages = manifest1.packages.union(manifest2.packages) |
1172 | + self.assertEqual((len(manifest_diff.added_pkgs) + |
1173 | + len(manifest_diff.removed_pkgs) + |
1174 | + len(manifest_diff._changed_pkgs)), |
1175 | + len(all_packages)) |
1176 | + |
1177 | + def test_compare_dicts(self): |
1178 | + manifest1 = Manifest() |
1179 | + content1 = self.OLD_MANIFEST.split("\n") |
1180 | + manifest1.parse(content1) |
1181 | + manifest2 = Manifest() |
1182 | + content2 = self.NEW_MANIFEST.split("\n") |
1183 | + manifest2.parse(content2) |
1184 | + |
1185 | + manifest_diff = self.manifest_diff |
1186 | + |
1187 | + dict1 = manifest1.content |
1188 | + dict2 = manifest2.content |
1189 | + |
1190 | + manifest_diff.compare(dict1, dict2) |
1191 | + # - Added packages: libbaz2, libbar7 |
1192 | + self.assertEqual(len(manifest_diff.added_pkgs), 2) |
1193 | + self.assertTrue("libbaz2" in manifest_diff.added_pkgs) |
1194 | + self.assertTrue("libbar7" in manifest_diff.added_pkgs) |
1195 | + self.assertTrue("libbaz2" not in manifest_diff._changed_pkgs) |
1196 | + |
1197 | + # - Removed packages: libbaz1, libbar6 |
1198 | + self.assertEqual(len(manifest_diff.removed_pkgs), 2) |
1199 | + self.assertTrue("libbaz1" in manifest_diff.removed_pkgs) |
1200 | + self.assertTrue("libbar6" in manifest_diff.removed_pkgs) |
1201 | + self.assertTrue("libbaz1" not in manifest_diff._changed_pkgs) |
1202 | + |
1203 | + # - Updated packages: foo, bar |
1204 | + self.assertEqual(len(manifest_diff._changed_pkgs), 2) |
1205 | + self.assertTrue("foo" in manifest_diff._changed_pkgs) |
1206 | + self.assertTrue("bar" in manifest_diff._changed_pkgs) |
1207 | + |
1208 | + # All packages in both manifests (ignoring duplicates) |
1209 | + all_packages = manifest1.packages.union(manifest2.packages) |
1210 | + self.assertEqual((len(manifest_diff.added_pkgs) + |
1211 | + len(manifest_diff.removed_pkgs) + |
1212 | + len(manifest_diff._changed_pkgs)), |
1213 | + len(all_packages)) |
1214 | + |
1215 | + def test_get_changes(self): |
1216 | + manifest1 = Manifest() |
1217 | + content1 = self.OLD_MANIFEST.split("\n") |
1218 | + manifest1.parse(content1) |
1219 | + manifest2 = Manifest() |
1220 | + content2 = self.NEW_MANIFEST.split("\n") |
1221 | + manifest2.parse(content2) |
1222 | + |
1223 | + manifest_diff = self.manifest_diff |
1224 | + |
1225 | + dict1 = manifest1.content |
1226 | + dict2 = manifest2.content |
1227 | + |
1228 | + manifest_diff.compare(dict1, dict2) |
1229 | + |
1230 | + # Two packages changed, foo and bar. bar had two new versions since old |
1231 | + # manifest, foo had one. |
1232 | + |
1233 | + urllib.urlopen.side_effect = [ |
1234 | + FakeUrlOpenReturn(200, FOO_OLD_CHANGELOG), |
1235 | + FakeUrlOpenReturn(200, FOO_NEW_CHANGELOG), |
1236 | + FakeUrlOpenReturn(200, BAR_OLD_CHANGELOG), |
1237 | + FakeUrlOpenReturn(200, BAR_NEW_CHANGELOG)] |
1238 | + changes = self.manifest_diff.get_changes() |
1239 | + # One entry for each changed package |
1240 | + self.assertIsNotNone(changes) |
1241 | + self.assertEqual(len(changes["foo"].changes), 1) |
1242 | + self.assertEqual(len(changes["bar"].changes), 2) |
Unfortunately this MP never got reviewed, and in the meantime we are moving the source to git which means this would need to be resubmitted. It is not clear to me what the application of this new code was supposed to be so it is not a priority for me to review and land this change prior to migration to git. Please resubmit against git if it's still relevant.