Merge lp:~smoser/vmbuilder/mfdiff.moved-to-git into lp:~ubuntu-on-ec2/vmbuilder/mfdiff

Proposed by Scott Moser
Status: Merged
Merged at revision: 21
Proposed branch: lp:~smoser/vmbuilder/mfdiff.moved-to-git
Merge into: lp:~ubuntu-on-ec2/vmbuilder/mfdiff
Diff against target: 672 lines (+10/-643)
4 files modified
BUGS (+0/-4)
README (+10/-14)
TODO (+0/-9)
mfdiff (+0/-616)
To merge this branch: bzr merge lp:~smoser/vmbuilder/mfdiff.moved-to-git
Reviewer Review Type Date Requested Status
Dan Watkins (community) Approve
Ubuntu on EC2 Pending
Review via email: mp+347711@code.launchpad.net

Commit message

mfdiff has moved its revision control to git.

Its new upstream home is:
  https://code.launchpad.net/~cloud-images-release-managers/cloud-images/+git/mfdiff

To clone, either:
   git clone https://git.launchpad.net/~cloud-images-release-managers/cloud-images/+git/mfdiff
or
   git clone ssh://git.launchpad.net/~cloud-images-release-managers/cloud-images/+git/mfdiff

To post a comment you must log in.
Revision history for this message
Dan Watkins (oddbloke) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== removed file 'BUGS'
2--- BUGS 2011-07-19 20:33:52 +0000
3+++ BUGS 1970-01-01 00:00:00 +0000
4@@ -1,4 +0,0 @@
5-Known bugs:
6- - if the version of a binary package in 'to' or 'from' is *not* found in the
7- current archive, then it will not handle this. This situation occurs
8- when the binary version is not current in -updates.
9
10=== modified file 'README'
11--- README 2017-05-30 15:48:32 +0000
12+++ README 2018-06-08 17:34:35 +0000
13@@ -1,14 +1,10 @@
14-"Manifest Diff" (mfdiff) is a tool for determining what changed between
15-2 builds by looking at their manifests. A manifest is simply a
16-list of package and versions in a build, obtainable by:
17- dpkg-query', '-W', '--showformat=${Package} ${Version}\n'
18-
19-Example of running:
20- mf1=mfs/releases/trusty/release-20160314/ubuntu-14.04-server-cloudimg-amd64.manifest
21- mf2=mfs/releases/trusty/release-20170517/ubuntu-14.04-server-cloudimg-amd64.manifest
22- ./mfdiff amd64 trusty "${mf1}" "${mf2}"
23-
24-
25-sync manifests from cloud-images.ubuntu.com with:
26- rsync -av cloud-images.ubuntu.com::cloud-images/ --prune-empty-dirs mfs \
27- --filter "+ */" --filter "+ *.manifest" --filter "- *"
28+mfdiff has moved to git.
29+
30+mfdiff has moved its revision control to git.
31+Its new upstream home is:
32+ https://code.launchpad.net/~cloud-images-release-managers/cloud-images/+git/mfdiff
33+
34+To clone, either:
35+ git clone https://git.launchpad.net/~cloud-images-release-managers/cloud-images/+git/mfdiff
36+or
37+ git clone ssh://git.launchpad.net/~cloud-images-release-managers/cloud-images/+git/mfdiff
38
39=== removed file 'TODO'
40--- TODO 2010-10-21 19:57:03 +0000
41+++ TODO 1970-01-01 00:00:00 +0000
42@@ -1,9 +0,0 @@
43-- use apt.VersionCompare() to determine if changelog entry is newer
44- or older than desired. this would allow for changelogs missing exact
45- versions. should raise an error, but continue
46-- for linux packages (possibly more generically)
47- new: ['linux-image-2.6.32-25-virtual', 'linux-image-2.6.32-309-ec2']
48- removed: ['linux-image-2.6.32-24-virtual', 'linux-image-2.6.32-308-ec2']
49- both linux-image-2.6.32-309-ec2 and linux-image-2.6.32-308-ec2
50- came from source of 'linux-ec2'. need to detect that as a 'changed'
51- and collect relavant changelogs
52
53=== removed file 'mfdiff'
54--- mfdiff 2017-08-15 13:26:43 +0000
55+++ mfdiff 1970-01-01 00:00:00 +0000
56@@ -1,616 +0,0 @@
57-#!/usr/bin/env python
58-"""
59-Given two manifest files for a particular release/arch, find the
60-packages which have been added, removed, and changed. Print the
61-changelog entries for the changed packages limited to changes between
62-the two versions.
63-"""
64-
65-# vi:ts=4 expandtab
66-#
67-# Copyright (C) 2010, 2017 Canonical Ltd.
68-#
69-# Authors: Scott Moser <scott.moser@canonical.com>
70-# Robert C Jennings <robert.jennings@canonical.com>
71-#
72-# This program is free software: you can redistribute it and/or modify
73-# it under the terms of the GNU General Public License as published by
74-# the Free Software Foundation, version 3 of the License.
75-#
76-# This program is distributed in the hope that it will be useful,
77-# but WITHOUT ANY WARRANTY; without even the implied warranty of
78-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
79-# GNU General Public License for more details.
80-#
81-# You should have received a copy of the GNU General Public License
82-# along with this program. If not, see <http://www.gnu.org/licenses/>.
83-
84-import codecs
85-import locale
86-import logging
87-import os
88-import os.path
89-import re
90-import shutil
91-import sys
92-import tempfile
93-from optparse import OptionParser
94-
95-import apt
96-import requests
97-from debian.changelog import Changelog
98-from six import PY3, iteritems
99-
100-try:
101- from six import viewkeys
102-except ImportError:
103- # The version of six in trusty doesn't have viewkeys, so pull in the six
104- # code from a more recent version if we can't get it directly from six.
105- import operator
106- if PY3:
107- viewkeys = operator.methodcaller("keys")
108- else:
109- viewkeys = operator.methodcaller("viewkeys")
110-
111-try:
112- from apt import VersionCompare as version_compare
113-except ImportError:
114- from apt_pkg import version_compare as version_compare
115-
116-
117-class MissingChangelogError(Exception):
118- "The Changelog file could not be found on the server"
119- pass
120-
121-
122-class ChangelogMissingVersion(Exception):
123- "The Changelog is missing starting and/or ending versions for the search"
124- pass
125-
126-
127-class UnknownSourceVersionError(Exception):
128- "The binary package did not have a source version listed"
129- pass
130-
131-
132-def get_bin2src(packages, cache):
133- """
134- Find the source package names for a given binary package list
135-
136- :param list packages: List of binary packages
137- :param :class:`apt.Cache` cache: Open/updated apt cache
138- :return: List mapping binary package name to source package name
139- :rtype: dict
140- """
141-
142- ret = {}
143- logging.debug('Finding source package names for all binary packages')
144- for binpkg in packages:
145- pkg_name = binpkg.split(':')[0]
146- ret[binpkg] = cache[pkg_name].versions[0].source_name
147- return ret
148-
149-
150-def get_changelog(source, version, changelog_cache_d):
151- """
152- Download changelog for source / version and returns path to that
153-
154- :param str source: Source package name
155- :param str version: Source package version
156- :param str changelog_cache_d: path to store cached changelogs
157- :raises MissingChangelogError: If changelog file could not be downloaded
158- :return: changelog file for source package & version
159- :rtype: str
160- """
161-
162- cache_f = "%s/changelog.%s_%s" % (changelog_cache_d, source, version)
163-
164- if os.path.isfile(cache_f):
165- logging.debug("Using cached changelog for %s:%s", source, version)
166- return cache_f
167-
168- furls = []
169- num_colon_m = re.compile("[0-9]:")
170-
171- cache_tmp_fd, cache_tmp_path = tempfile.mkstemp(
172- ".changelog.%s_%s" % (source, version),
173- prefix="." + tempfile.gettempprefix(), dir=".")
174- cache_tmp = os.fdopen(cache_tmp_fd, "w")
175- for pile in ("main", "universe", "multiverse", "restricted"):
176- pre = source[0:1]
177- # packages starting with 'lib' are special
178- if source.startswith("lib"):
179- pre = source[0:4]
180-
181- # packages with '1:' versions have different paths
182- # update-manager at version 1:0.134.11.
183- # is main/u/update-manager/update-manager_0.134.11/
184- # rather than main/u/update-manager/update-manager_1:0.134.11
185- url_version = version
186- if num_colon_m.match(version):
187- url_version = version[2:]
188-
189- # Changelog URL example http://changelogs.ubuntu.com/changelogs/\
190- # pool/main/h/hal/hal_0.5.5.1-1ubuntu2/changelog
191- changelog_url = "http://changelogs.ubuntu.com/changelogs/pool/" \
192- "%s/%s/%s/%s_%s/changelog" % \
193- (pile, pre, source, source, url_version)
194-
195- changelog = requests.get(changelog_url)
196- if changelog.status_code == 200:
197- cache_tmp.write(changelog.content)
198- cache_tmp.close()
199- shutil.copy2(cache_tmp_path, cache_f)
200- os.unlink(cache_tmp_path)
201- return cache_f
202- else:
203- logging.error("missing %s: %s", source, changelog_url)
204- furls.append(changelog_url)
205- if os.path.exists(cache_tmp_path):
206- os.unlink(cache_tmp_path)
207- raise MissingChangelogError("Failed to find changelog for %s at version "
208- "%s.\n tried %s" % (source, version,
209- ' '.join(furls)))
210-
211-
212-def manifest_to_dict(filename):
213- """
214- Parse manifest file to create a package / version mapping
215-
216- :param str filename: Name of package manifest file
217- :return: List of package versions by name
218- :rtype: dict
219- """
220-
221- ret = {}
222- logging.debug('Reading package manifest from %s', filename)
223- with open(filename, "r") as manifest:
224- for line in manifest:
225- (pkg, ver) = line.split()
226- ret[pkg] = ver
227- return ret
228-
229-
230-def open_apt_cache(arch, release, cache_d=None):
231- """
232- Create, update, and open an apt cache.
233-
234- This creates an apt cache directory and write a sources.list file
235- before updating and opening the cache. The caller is responsible
236- for closing the cache.
237-
238- :param str arch: Package architecture
239- :param str release: Ubuntu release name (e.g. Xenial)
240- :param str cache_d: apt cache path
241- :returns: tuple of Open/updated apt cache and cache path name
242- :rtype: tuple(:class:`apt.Cache`, str)
243- """
244-
245- if not cache_d:
246- cache_d = "./cache.%s-%s" % (release, arch)
247- logging.info("Using %s as the apt cache directory", cache_d)
248-
249- if arch in ['amd64', 'i386']:
250- mirror = "http://archive.ubuntu.com/ubuntu/"
251- else:
252- mirror = "http://ports.ubuntu.com/ubuntu-ports/"
253- logging.debug('Configuring apt cache using mirror %s', mirror)
254-
255- pockets = (release, "%s-updates" % release, "%s-security" % release,
256- "%s-proposed" % release, )
257- components = ("main", "universe")
258- srclines = []
259- for pocket in pockets:
260- srcline = "deb %s %s %s" % (mirror, pocket, ' '.join(components))
261- logging.debug('Adding source: %s', srcline)
262- srclines.append(srcline)
263- try:
264- os.makedirs("%s/etc/apt" % cache_d)
265- except OSError as oserror:
266- if os.errno.EEXIST != oserror.errno:
267- raise
268- with open("%s/etc/apt/sources.list" % cache_d, "w") as asl:
269- asl.write('\n'.join(srclines))
270-
271- apt.apt_pkg.config.set("Apt::Architecture", arch)
272-
273- logging.debug('Using host apt keys for signature verification')
274- apt.apt_pkg.config.set("Dir::Etc::Trusted", "/etc/apt/trusted.gpg")
275- apt.apt_pkg.config.set("Dir::Etc::TrustedParts",
276- "/etc/apt/trusted.gpg.d/")
277-
278- cache = apt.Cache(rootdir=cache_d)
279- logging.info('Updating apt cache')
280- cache.update()
281- logging.info('Update of apt cache complete')
282- cache.open()
283- return cache, cache_d
284-
285-
286-def render_block(block):
287- """
288- Render a changelog block to something printable (dropping blank lines)
289-
290- :param :class:`debian.changelog.ChangeBlock` block: Changelog block
291- :return: String containing the changelog block text
292- :rtype: str
293- """
294- return '\n'.join([x for x in block.changes() if x])
295-
296-
297-def print_blocks(block_list):
298- """
299- Print a Changelog block list
300-
301- :param list block_list: List of :class:`debian.changelog.ChangeBlock`
302- """
303-
304- for block in block_list:
305- print(render_block(block).encode('utf-8').decode('utf-8'))
306-
307-
308-def kernel_fixups(manifest_from, manifest_to):
309- """
310- Fix up kernels so the pkg names match
311-
312- Kernel package names change from release to release so that they are
313- co-installable, but we need to find matching package names in the
314- two manifests to provide a list of changes between the versions of the
315- package in each manifest.
316- This function will return an altered version of manifest_from with kernel
317- package names changed to match kernel package names in manifest_to. This
318- will support later version comparisons.
319-
320- :param dict manifest_from: Dictionary mapping package to version for of
321- the starting manifest
322- :param dict manifest_to: Dictionary mapping package to version for the
323- ending manifest
324- :return: Starting manifest dictionary with altered kernel package names
325- to match names in ending manifest
326- :rtype dict:
327- """
328- kfixups = {}
329- kmatch = re.compile("linux-image-[0-9]")
330- for pkg in manifest_to:
331- # if this is a linux-image-* binary package do some hacks to make it
332- # look like manifest_from is the same (format like
333- # linux-image-2.6.32-32-virtual)
334- if kmatch.match(pkg):
335- logging.debug('Found kernel %s in manifest #2', pkg)
336- img_type = pkg.split("-")[-1]
337- if pkg in manifest_from:
338- logging.debug('Found same kernel in manifest #1')
339- continue
340- for fpkg in manifest_from:
341- if kmatch.match(fpkg) and fpkg.endswith("-%s" % img_type):
342- logging.debug('Found similar kernel %s in manifest #1',
343- fpkg)
344- kfixups[pkg] = fpkg
345-
346- for pkg_to, pkg_from in iteritems(kfixups):
347- logging.debug('Substituting kernel %s for %s in manifest #1 to '
348- 'enable version comparison', pkg_to, pkg_from)
349- manifest_from[pkg_to] = manifest_from[pkg_from]
350- del manifest_from[pkg_from]
351- return manifest_from
352-
353-
354-def find_added(manifest_from, manifest_to):
355- "Find new packages in manifest_to"
356- new = {}
357- for pkg in sorted(viewkeys(manifest_to) - viewkeys(manifest_from)):
358- logging.debug('New package: %s', pkg)
359- new[pkg] = manifest_to[pkg]
360- return new
361-
362-
363-def find_removed(manifest_from, manifest_to):
364- "Find packages removed from manifest_from"
365- removed = {}
366- for pkg in sorted(viewkeys(manifest_from) - viewkeys(manifest_to)):
367- logging.debug('Removed package: %s', pkg)
368- removed[pkg] = manifest_from[pkg]
369- return removed
370-
371-
372-def find_changed(manifest_from, manifest_to):
373- "Find modified packages"
374- changed = []
375- for pkg in sorted(viewkeys(manifest_from) & viewkeys(manifest_to)):
376- if manifest_from[pkg] != manifest_to[pkg]:
377- logging.debug('Changed package: %s', pkg)
378- changed.append(pkg)
379- return changed
380-
381-
382-def map_source_to_binary(cache, packages):
383- "Create a dictionary of source to list of binary packages"
384- src2bins = {}
385- for bin_pkg in packages:
386- bin_name = bin_pkg.split(':')[0]
387- if bin_name in cache:
388- src2bins.setdefault(
389- cache[bin_name].versions[0].source_name, []).append(bin_pkg)
390- return src2bins
391-
392-
393-def get_pkg_versions(cache, binary):
394- "Get all known versions from the apt cache"
395- pkg_name = binary.split(':')[0]
396- try:
397- return cache[pkg_name].versions
398- except KeyError:
399- raise Exception(
400- "%s not in cache or did not have version info in cache" %
401- pkg_name)
402-
403-
404-def source_version_for_binary(cache, binary, binary_ver):
405- "Find the source version data for a specific binary version"
406- versions = get_pkg_versions(cache, binary)
407- try:
408- return versions[binary_ver].source_version
409- except KeyError:
410- # Strip the architecture name from the binary
411- source_name = cache[binary.split(':')[0]].versions[0].source_name
412- msg = ("Unable to determine source version for %s. "
413- "Binary package %s/%s not in known source version "
414- "list (%s)" % (source_name, binary, binary_ver, versions))
415- raise UnknownSourceVersionError(msg)
416-
417-
418-def filter_changelog(changelog_path, version_low, version_high):
419- """
420- Extract changelog entries within a version range
421-
422- The range of changelog entries returned will include all entries
423- after version_low up to, and including, version_high.
424- If either the starting or ending version are not found in the
425- list of changelog entries the result will be incomplete and
426- a non-empty error message is returned to indicate the issue.
427-
428- :param str changelog_path: File name of the changelog to process
429- :return: list of changelog blocks and an error_msg if incomplete
430- :rtype tuple(list, str):
431- """
432-
433- with open(changelog_path, "r") as fileptr:
434- chlog = Changelog(fileptr.read())
435- change_blocks = []
436- start = False
437- end = False
438- error_msg = ''
439-
440- # The changelog blocks are in reverse order; we'll see high before low.
441- for block in chlog:
442- if block.version == version_high:
443- start = True
444- change_blocks = []
445- if block.version == version_low:
446- end = True
447- break
448- change_blocks.append(block)
449- if not start:
450- error_msg = "Missing starting version {} in {}. " \
451- "Changlelog will be incomplete".format(
452- version_high, changelog_path)
453- logging.error(error_msg)
454- if not end:
455- if error_msg:
456- # Start and end were not found, put a newline between their
457- # error messages
458- error_msg += '\n'
459- error_msg += "Missing ending version {} in {}. " \
460- "Changelog output truncated".format(
461- version_low, changelog_path)
462- logging.error(error_msg)
463- return change_blocks, error_msg
464-
465-
466-def print_changelogs(apt_cache, apt_cache_d, manifest_from, manifest_to,
467- changed):
468- """
469- Print changelog entries for each changed package limited to
470- changes in the package between the versions in the two manifests.
471-
472- :param :class:`apt.Cache` apt_cache: Open & up-to-date apt cache
473- :param str apt_cache_d: apt cache path
474- :param dict manifest_from: Packages and their versions in the
475- first manifest file
476- :param dict manifest_to: Packages and their versions in the
477- second manifest file
478- :param list changed: Packages which changed between the two manifests
479- """
480-
481- srcs = {}
482- errors = []
483- src2bins = map_source_to_binary(apt_cache, changed)
484-
485- # Generate changelog data per unique source package
486- for source_name in src2bins:
487- srcs[source_name] = {"changelog_file": "", "changeblocks": []}
488- src = srcs[source_name]
489-
490- # Use the first binary listed for a source package
491- binary_name = src2bins[source_name][0]
492-
493- # Find the source version data for the binary in manifest #2
494- try:
495- src['version_to'] = source_version_for_binary(
496- apt_cache, binary_name, manifest_to[binary_name])
497- except UnknownSourceVersionError as excp:
498- logging.error(str(excp))
499- errors.append(excp)
500- continue
501-
502- # Find the source version data for the binary in manifest #1
503- binver_from = manifest_from[binary_name]
504- try:
505- src['version_from'] = source_version_for_binary(
506- apt_cache, binary_name, binver_from)
507- except UnknownSourceVersionError as excp:
508- if manifest_to[binary_name] == src['version_to']:
509- logging.info('Could not find source version data in apt '
510- 'cache. Assuming source %s version %s from '
511- 'binary %s', source_name, binver_from,
512- binary_name)
513- src['version_from'] = binver_from
514- else:
515- logging.error(str(excp))
516- errors.append(excp)
517- continue
518-
519- # Check for version regression between manifests
520- try:
521- if version_compare(src['version_from'], src['version_to']) > 0:
522- msg = "Package version regression {} -> {}".format(
523- src['version_from'], src['version_to'])
524- raise UnknownSourceVersionError(msg)
525- except UnknownSourceVersionError as excp:
526- errors.append(excp)
527- continue
528-
529- # Get the changelog for this source package
530- try:
531- # Use the apt cache directory to store the changelog cache
532- srcs[source_name]["changelog_file"] = get_changelog(
533- source_name, src['version_to'], changelog_cache_d=apt_cache_d)
534- except MissingChangelogError as excp:
535- errors.append(excp)
536- continue
537-
538- # Filter the changelog to a list of blocks between the two versions
539- try:
540- srcs[source_name]["changeblocks"], incomplete = filter_changelog(
541- srcs[source_name]["changelog_file"], src['version_from'],
542- src['version_to'])
543- if incomplete:
544- raise ChangelogMissingVersion(incomplete)
545- except ChangelogMissingVersion as exp:
546- errors.append(exp)
547- continue
548-
549- # Print changelog ranges for changed packages
550- for source_name in sorted(src2bins):
551- binlist = sorted(src2bins[source_name])
552- binary = binlist[0]
553- print("==== %s: %s => %s ====" %
554- (source_name, manifest_from[binary], manifest_to[binary]))
555- print("==== %s" % ' '.join(binlist))
556- print_blocks(srcs[source_name]["changeblocks"])
557-
558- if errors:
559- print("**** Errors ****")
560- for error in errors:
561- print(error)
562-
563-
564-def parse_args():
565- """
566- Parse command line arguments
567-
568- :returns: options and remaining arguments from OptionParser.parse_args()
569- :rtype list:
570- """
571-
572- parser = OptionParser(usage="Usage: {} arch suite manifest1 manifest2\n"
573- "Compare two manifest files, and show "
574- "changelog differences."
575- .format(os.path.basename(sys.argv[0])))
576- parser.add_option("--cache-dir", dest="cache_d",
577- help="cache dir for info", metavar="DIR", type="string",
578- default=None)
579- parser.add_option("-v", "--verbose", action="count", dest="loglevel",
580- help="increase verbosity", default=0)
581-
582- (options, args) = parser.parse_args()
583-
584- if len(args) != 4:
585- parser.error('you must provide arch, release, and 2 manifest files')
586-
587- return options, args
588-
589-
590-def setup_logging(loglevel=0):
591- """
592- Configure logging
593-
594- By default, log WARNING and higher messages
595- :param int: loglevel 0: Warning, 1: Info, 2: Debug
596- """
597-
598- loglevel = [logging.WARNING,
599- logging.INFO,
600- logging.DEBUG][min(2, loglevel)]
601-
602- logging.basicConfig(
603- level=loglevel,
604- format="%(asctime)s %(name)s/%(levelname)s: %(message)s",
605- stream=sys.stderr)
606-
607-
608-def stdout_force_unicode():
609- """
610- Force output to UTF-8 at all times
611-
612- We want to output UTF-8 at all times to preserve Unicode characters
613- in the changelog blocks. For Python 2 we will wrap sys.stdout with
614- an instance of StreamWriter with our preferred coding. Python3 requires
615- no changes.
616-
617- When writing output to the terminal we get the encoding of the
618- terminal (utf-8 these days). When we redirect or pipe the output of
619- the program it is generally not possible to know what the input
620- encoding of the receiving program is, the encoding when redirecting
621- to a file will be None (Python 2.7) or UTF-8 (Python 3)
622-
623- $ python2.7 -c "import sys; print sys.stdout.encoding" | cat
624- None
625-
626- $ python3.4 -c "import sys; print(sys.stdout.encoding)" | cat
627- UTF-8
628-
629- Source:
630- https://wiki.python.org/moin/PrintFails#print.2C_write_and_Unicode_in_pre-3.0_Python
631- """
632-
633- if sys.version_info[0] < 3:
634- encoding = codecs.getwriter(locale.getpreferredencoding())
635- sys.stdout = encoding(sys.stdout)
636-
637-
638-def main():
639- """
640- Given two manifest files for a particular release/arch, find the
641- packages which have been added, removed, and changed. Print the
642- changelog entries for the changed packages limited to changes between
643- the two versions.
644- """
645-
646- stdout_force_unicode()
647- options, (arch, release, manifest_from_filename,
648- manifest_to_filename) = parse_args()
649-
650- setup_logging(options.loglevel)
651-
652- # index both manifests
653- manifest_to = manifest_to_dict(manifest_to_filename)
654- manifest_from = kernel_fixups(manifest_to_dict(manifest_from_filename),
655- manifest_to)
656-
657- new = find_added(manifest_from, manifest_to)
658- removed = find_removed(manifest_from, manifest_to)
659- changed = find_changed(manifest_from, manifest_to)
660-
661- print("new: %s" % new)
662- print("removed: %s" % removed)
663- print("changed: %s" % changed)
664-
665- # if modified packages, download all changelogs from changelogs.
666- if changed:
667- cache, cache_d = open_apt_cache(arch, release, options.cache_d)
668- print_changelogs(cache, cache_d, manifest_from, manifest_to, changed)
669-
670-
671-if __name__ == "__main__":
672- main()

Subscribers

People subscribed via source and target branches

to all changes: