Based on the DpkgVersion class by Raphael Hertzog in svn://svn.debian.org/qa/trunk/pts/www/bin/common.py r2361
Closes: #562257, #573009 --- debian_bundle/debian_support.py | 176 ++++++++++++++++++++++++++++++++------- 1 files changed, 146 insertions(+), 30 deletions(-) diff --git a/debian_bundle/debian_support.py b/debian_bundle/debian_support.py index 6543206..e13a251 100644 --- a/debian_bundle/debian_support.py +++ b/debian_bundle/debian_support.py @@ -23,8 +23,13 @@ import hashlib import types from deprecation import function_deprecated_by -import apt_pkg -apt_pkg.init() + +try: + import apt_pkg + apt_pkg.init() + __have_apt_pkg = True +except ImportError: + __have_apt_pkg = False class ParseError(Exception): """An exception which is used to signal a parse failure. @@ -58,24 +63,24 @@ class ParseError(Exception): printOut = function_deprecated_by(print_out) -class Version: - """Version class which uses the original APT comparison algorithm.""" +class AptPkgVersion(object): + """Represents a Debian package version, using apt_pkg.VersionCompare""" def __init__(self, version): """Creates a new Version object.""" - t = type(version) - if t == types.UnicodeType: - version = version.encode('UTF-8') + if not isinstance(version, (str, unicode)): + raise ValueError, "version must be a string or unicode object" + + if isinstance(version, unicode): + self.__as_string = version.encode("utf-8") else: - assert t == types.StringType, `version` - assert version <> "" - self.__asString = version + self.__as_string = version def __str__(self): - return self.__asString + return self.__as_string def __repr__(self): - return 'Version(%s)' % `self.__asString` + return "%s('%s')" % (self.__class__.__name__, self) def __cmp__(self, other): return apt_pkg.VersionCompare(str(self), str(other)) @@ -83,8 +88,118 @@ class Version: def __hash__(self): return hash(str(self)) +# NativeVersion based on the DpkgVersion class by Raphael Hertzog in +# svn://svn.debian.org/qa/trunk/pts/www/bin/common.py r2361 +class NativeVersion(object): + """Represents a Debian package version, with native Python comparison""" + + re_all_digits_or_not = re.compile("\d+|\D+") + re_digits = re.compile("\d+") + re_digit = re.compile("\d") + re_alpha = re.compile("[A-Za-z]") + re_epoch_and_version = re.compile("(\d*):(.+)") + re_version_and_revision = re.compile("(.+)-(.*)") + + def __init__(self, version): + result = self.re_epoch_and_version.match(version) + if result is not None: + self.epoch = int(result.group(1)) + version = result.group(2) + self.no_epoch = False + else: + self.epoch = 0 + self.no_epoch = True + result = self.re_version_and_revision.match(version) + if result is not None: + self.version = result.group(1) + self.revision = result.group(2) + self.no_revision = False + else: + self.version = version + self.revision = "0" + self.no_revision = True -version_compare = apt_pkg.VersionCompare + def __str__(self): + version = "" + if not self.no_epoch: + version += self.epoch + ":" + version += self.version + if not self.no_revision: + version += "-" + self.revision + return version + + def __repr__(self): + return "%s('%s')" % (self.__class__.__name__, self) + + def __cmp__(self, other): + res = cmp(self.epoch, other.epoch) + if res != 0: + return res + res = self._version_cmp_part(self.version, other.version) + if res != 0: + return res + return self._version_cmp_part(self.revision, other.revision) + + @classmethod + def _order(cls, x): + """Return an integer value for character x""" + if x == '~': + return -1 + elif cls.re_digit.match(x): + return int(x) + 1 + elif cls.re_alpha.match(x): + return ord(x) + else: + return ord(x) + 256 + + @classmethod + def _version_cmp_string(cls, va, vb): + la = [cls._order(x) for x in va] + lb = [cls._order(x) for x in vb] + while la or lb: + a = 0 + b = 0 + if la: + a = la.pop(0) + if lb: + b = lb.pop(0) + res = cmp(a, b) + if res != 0: + return res + return 0 + + @classmethod + def _version_cmp_part(cls, va, vb): + la = cls.re_all_digits_or_not.findall(va) + lb = cls.re_all_digits_or_not.findall(vb) + while la or lb: + a = "0" + b = "0" + if la: + a = la.pop(0) + if lb: + b = lb.pop(0) + if cls.re_digits.match(a) and cls.re_digits.match(b): + a = int(a) + b = int(b) + res = cmp(a, b) + if res != 0: + return res + else: + res = cls._version_cmp_string(a, b) + if res != 0: + return res + return 0 + +if __have_apt_pkg: + class Version(AptPkgVersion): + pass +else: + class Version(NativeVersion): + pass + +def version_compare(a, b): + return cmp(Version(a), Version(b)) class PackageFile: """A Debian package file. @@ -423,23 +538,24 @@ mergeAsSets = function_deprecated_by(merge_as_sets) def test(): # Version - assert Version('0') < Version('a') - assert Version('1.0') < Version('1.1') - assert Version('1.2') < Version('1.11') - assert Version('1.0-0.1') < Version('1.1') - assert Version('1.0-0.1') < Version('1.0-1') - assert Version('1.0-0.1') == Version('1.0-0.1') - assert Version('1.0-0.1') < Version('1.0-1') - assert Version('1.0final-5sarge1') > Version('1.0final-5') \ - > Version('1.0a7-2') - assert Version('0.9.2-5') < Version('0.9.2+cvs.1.0.dev.2004.07.28-1.5') - assert Version('1:500') < Version('1:5000') - assert Version('100:500') > Version('11:5000') - assert Version('1.0.4-2') > Version('1.0pre7-2') - assert Version('1.5~rc1') < Version('1.5') - assert Version('1.5~rc1') < Version('1.5+b1') - assert Version('1.5~rc1') < Version('1.5~rc2') - assert Version('1.5~rc1') > Version('1.5~dev0') + for cls in (AptPkgVersion, NativeVersion): + assert cls('0') < cls('a') + assert cls('1.0') < cls('1.1') + assert cls('1.2') < cls('1.11') + assert cls('1.0-0.1') < cls('1.1') + assert cls('1.0-0.1') < cls('1.0-1') + assert cls('1.0-0.1') == cls('1.0-0.1') + assert cls('1.0-0.1') < cls('1.0-1') + assert cls('1.0final-5sarge1') > cls('1.0final-5') \ + > cls('1.0a7-2') + assert cls('0.9.2-5') < cls('0.9.2+cvs.1.0.dev.2004.07.28-1.5') + assert cls('1:500') < cls('1:5000') + assert cls('100:500') > cls('11:5000') + assert cls('1.0.4-2') > cls('1.0pre7-2') + assert cls('1.5~rc1') < cls('1.5') + assert cls('1.5~rc1') < cls('1.5+b1') + assert cls('1.5~rc1') < cls('1.5~rc2') + assert cls('1.5~rc1') > cls('1.5~dev0') # Release assert intern_release('sarge') < intern_release('etch') -- 1.6.6 -- To UNSUBSCRIBE, email to debian-bugs-dist-requ...@lists.debian.org with a subject of "unsubscribe". Trouble? Contact listmas...@lists.debian.org