diff options
author | Guido Günther <agx@sigxcpu.org> | 2011-11-25 15:51:52 +0100 |
---|---|---|
committer | Guido Günther <agx@sigxcpu.org> | 2011-11-28 22:29:48 +0100 |
commit | c9a1595a666cc83f9e9e523f0b4f27502f61b998 (patch) | |
tree | 83334959f3559d8836d8caecc5db7205b795a3bf /gbp/deb | |
parent | f7a6b073a43e144d43550e92fc111d456c8bc973 (diff) |
Add ChangeLog class
making it easier to query versions. Add tests.
Diffstat (limited to 'gbp/deb')
-rw-r--r-- | gbp/deb/__init__.py | 85 | ||||
-rw-r--r-- | gbp/deb/changelog.py | 124 |
2 files changed, 127 insertions, 82 deletions
diff --git a/gbp/deb/__init__.py b/gbp/deb/__init__.py index 881d1ae9..dc3ba8b6 100644 --- a/gbp/deb/__init__.py +++ b/gbp/deb/__init__.py @@ -27,6 +27,7 @@ import glob import gbp.command_wrappers as gbpc from gbp.errors import GbpError from gbp.git import GitRepositoryError +from gbp.deb.changelog import ChangeLog, NoChangeLogError # When trying to parse a version-number from a dsc or changes file, these are # the valid characters. @@ -64,15 +65,6 @@ compressor_opts = { 'gzip' : [ '-n', 'gz' ], compressor_aliases = { 'bz2' : 'bzip2', 'gz' : 'gzip', } -class NoChangelogError(Exception): - """no changelog found""" - pass - -class ParseChangeLogError(Exception): - """problem parsing changelog""" - pass - - class DpkgCompareVersions(gbpc.Command): cmd='/usr/bin/dpkg' @@ -390,58 +382,10 @@ def parse_changelog_repo(repo, branch, filename): # repository errors. sha = repo.rev_parse("%s:%s" % (branch, filename)) except GitRepositoryError: - raise NoChangelogError, "Changelog %s not found in branch %s" % (filename, branch) + raise NoChangeLogError, "Changelog %s not found in branch %s" % (filename, branch) lines = repo.show(sha) - return parse_changelog('\n'.join(lines)) - -def parse_changelog(contents=None, filename=None): - """ - Parse the content of a changelog file. Either contents, containing - the contents of a changelog file, or filename, pointing to a - changelog file must be passed. - - Returns: - - cp['Version']: full version string including epoch - cp['Upstream-Version']: upstream version, if not debian native - cp['Debian-Version']: debian release - cp['Epoch']: epoch, if any - cp['NoEpoch-Version']: full version string excluding epoch - """ - # Check that either contents or filename is passed (but not both) - if (not filename and not contents) or (filename and contents): - raise Exception("Either filename or contents must be passed to parse_changelog") - - # If a filename was passed, check if it exists - if filename and not os.access(filename, os.F_OK): - raise NoChangelogError, "Changelog %s not found" % (filename, ) - - # If no filename was passed, let parse_changelog read from stdin - if not filename: - filename = '-' - - # Note that if contents is None, stdin will just be closed right - # away by communicate. - cmd = subprocess.Popen(['dpkg-parsechangelog', '-l%s' % filename], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (output, errors) = cmd.communicate(contents) - if cmd.returncode: - raise ParseChangeLogError, "Failed to parse changelog. dpkg-parsechangelog said:\n%s" % (errors, ) - # Parse the result of dpkg-parsechangelog (which looks like - # email headers) - cp = email.message_from_string(output) - try: - if ':' in cp['Version']: - cp['Epoch'], cp['NoEpoch-Version'] = cp['Version'].split(':', 1) - else: - cp['NoEpoch-Version'] = cp['Version'] - if '-' in cp['NoEpoch-Version']: - cp['Upstream-Version'], cp['Debian-Version'] = cp['NoEpoch-Version'].rsplit('-', 1) - else: - cp['Debian-Version'] = cp['NoEpoch-Version'] - except TypeError: - raise ParseChangeLogError, output.split('\n')[0] - return cp + return ChangeLog('\n'.join(lines)) def orig_file(cp, compression): @@ -456,18 +400,6 @@ def orig_file(cp, compression): ext = compressor_opts[compression][1] return "%s_%s.orig.tar.%s" % (cp['Source'], cp['Upstream-Version'], ext) - -def is_native(cp): - """ - Is this a debian native package - - >>> is_native(dict(Version="1")) - True - >>> is_native(dict(Version="1-1")) - False - """ - return not '-' in cp['Version'] - def is_valid_packagename(name): "Is this a valid Debian package name?" return packagename_re.match(name) @@ -497,17 +429,6 @@ def get_compression(orig_file): return None -def has_epoch(cp): - """ - Does the topmost version number in the changelog contain an epoch - >>> has_epoch(dict(Epoch="1")) - True - >>> has_epoch(dict()) - False - """ - return cp.has_key("Epoch") - - def has_orig(cp, compression, dir): "Check if orig.tar.gz exists in dir" try: diff --git a/gbp/deb/changelog.py b/gbp/deb/changelog.py new file mode 100644 index 00000000..bba8fa9a --- /dev/null +++ b/gbp/deb/changelog.py @@ -0,0 +1,124 @@ +# vim: set fileencoding=utf-8 : +# +# (C) 2011 Guido Günther <agx@sigxcpu.org> +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +"""A Debian Changelog""" + +import email +import os +import subprocess + +class NoChangeLogError(Exception): + """No changelog found""" + pass + +class ParseChangeLogError(Exception): + """Problem parsing changelog""" + pass + +class ChangeLog(object): + """A Debian changelog""" + + def __init__(self, contents=None, filename=None): + """ + Parse an existing changelog, Either contents, containing the contents + of a changelog file, or filename, pointing to a changelog file must be + passed. + """ + # Check that either contents or filename is passed (but not both) + if (not filename and not contents) or (filename and contents): + raise Exception("Either filename or contents must be passed") + + # If a filename was passed, check if it exists + if filename and not os.access(filename, os.F_OK): + raise NoChangeLogError, "Changelog %s not found" % (filename, ) + + # If no filename was passed, let's read from stdin + if not filename: + filename = '-' + + # Note that if contents is None, stdin will just be closed right + # away by communicate. + cmd = subprocess.Popen(['dpkg-parsechangelog', '-l%s' % filename], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + (output, errors) = cmd.communicate(contents) + if cmd.returncode: + raise ParseChangeLogError("Failed to parse changelog. " + "dpkg-parsechangelog said:\n%s" % (errors, )) + # Parse the result of dpkg-parsechangelog (which looks like + # email headers) + cp = email.message_from_string(output) + try: + if ':' in cp['Version']: + cp['Epoch'], cp['NoEpoch-Version'] = cp['Version'].split(':', 1) + else: + cp['NoEpoch-Version'] = cp['Version'] + if '-' in cp['NoEpoch-Version']: + cp['Upstream-Version'], cp['Debian-Version'] = cp['NoEpoch-Version'].rsplit('-', 1) + else: + cp['Debian-Version'] = cp['NoEpoch-Version'] + except TypeError: + raise ParseChangeLogError, output.split('\n')[0] + + self._cp = cp + + def __getitem__(self, item): + return self._cp[item] + + def __setitem__(self, item, value): + self._cp[item] = value + + + @property + def version(self): + """The full version string""" + return self._cp['Version'] + + @property + def upstream_version(self): + """The upstream version""" + return self._cp['Upstream-Version'] + + @property + def debian_version(self): + """The Debian part of the version number""" + return self._cp['Debian-Version'] + + @property + def epoch(self): + """The package's epoch""" + return self._cp['Epoch'] + + @property + def noepoch(self): + """The version string without the epoch""" + return self._cp['NoEpoch-Version'] + + def has_epoch(self): + """ + Whether the version has an epoch + + @return: C{True} if the version has an epoch, C{False} otherwise + @rtype: C{bool} + """ + return self._cp.has_key('Epoch') + + def is_native(self): + """ + Whether this is a native Debian package + """ + return not '-' in self.version |