11
11
__metaclass__ = type
13
# This code came from sourcerer but has been heavily modified since.
15
from debian import changelog
13
# This code came from sourcerer.
19
18
# Regular expressions make validating things easy
20
19
valid_epoch = re.compile(r'^[0-9]+$')
21
20
valid_upstream = re.compile(r'^[0-9][A-Za-z0-9+:.~-]*$')
22
21
valid_revision = re.compile(r'^[A-Za-z0-9+.~]+$')
24
VersionError = changelog.VersionError
27
class BadInputError(VersionError):
31
class BadEpochError(BadInputError):
35
class BadUpstreamError(BadInputError):
39
class BadRevisionError(BadInputError):
43
class Version(changelog.Version):
23
# Character comparison table for upstream and revision components
24
cmp_table = "~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+-.:"
27
class VersionError(Exception): pass
28
class BadInputError(VersionError): pass
29
class BadEpochError(BadInputError): pass
30
class BadUpstreamError(BadInputError): pass
31
class BadRevisionError(BadInputError): pass
33
class Version(object):
44
34
"""Debian version number.
46
36
This class is designed to be reasonably transparent and allow you
56
46
upstream Upstream version
57
debian_version Debian/local revision
47
revision Debian/local revision
60
50
def __init__(self, ver):
51
"""Parse a string or number into the three components."""
64
raise BadInputError("Input cannot be empty")
67
changelog.Version.__init__(self, ver)
71
if self.epoch is not None:
58
raise BadInputError, "Input cannot be empty"
60
# Epoch is component before first colon
63
self.epoch = ver[:idx]
72
64
if not len(self.epoch):
73
raise BadEpochError("Epoch cannot be empty")
74
if not valid_epoch.match(self.epoch):
75
raise BadEpochError("Bad epoch format")
77
if self.debian_version is not None:
78
if self.debian_version == "":
79
raise BadRevisionError("Revision cannot be empty")
80
if not valid_revision.search(self.debian_version):
81
raise BadRevisionError("Bad revision format")
83
if not len(self.upstream_version):
84
raise BadUpstreamError("Upstream version cannot be empty")
85
if not valid_upstream.search(self.upstream_version):
65
raise BadEpochError, "Epoch cannot be empty"
66
if not valid_epoch.search(self.epoch):
67
raise BadEpochError, "Bad epoch format"
70
# Revision is component after last hyphen
73
self.revision = ver[idx+1:]
74
if not len(self.revision):
75
raise BadRevisionError, "Revision cannot be empty"
76
if not valid_revision.search(self.revision):
77
raise BadRevisionError, "Bad revision format"
80
# Remaining component is upstream
82
if not len(self.upstream):
83
raise BadUpstreamError, "Upstream version cannot be empty"
84
if not valid_upstream.search(self.upstream):
86
85
raise BadUpstreamError(
87
"Bad upstream version format %s" % self.upstream_version)
86
"Bad upstream version format", self.upstream)
88
self.epoch = int(self.epoch)
90
def getWithoutEpoch(self):
91
"""Return the version without the epoch."""
93
if self.revision is not None:
94
str += "-%s" % (self.revision,)
97
without_epoch = property(getWithoutEpoch)
100
"""Return the class as a string for printing."""
103
str += "%d:" % (self.epoch,)
105
if self.revision is not None:
106
str += "-%s" % (self.revision,)
110
"""Return a debugging representation of the object."""
111
return "<%s epoch: %d, upstream: %r, revision: %r>" \
112
% (self.__class__.__name__, self.epoch,
113
self.upstream, self.revision)
115
def __cmp__(self, other):
116
"""Compare two Version classes."""
117
other = Version(other)
119
result = cmp(self.epoch, other.epoch)
120
if result != 0: return result
122
result = deb_cmp(self.upstream, other.upstream)
123
if result != 0: return result
125
result = deb_cmp(self.revision or "", other.revision or "")
126
if result != 0: return result
131
def strcut(str, idx, accept):
132
"""Cut characters from str that are entirely in accept."""
134
while idx < len(str) and str[idx] in accept:
140
def deb_order(str, idx):
141
"""Return the comparison order of two characters."""
144
elif str[idx] == "~":
147
return cmp_table.index(str[idx])
149
def deb_cmp_str(x, y):
150
"""Compare two strings in a deb version."""
152
while (idx < len(x)) or (idx < len(y)):
153
result = deb_order(x, idx) - deb_order(y, idx)
164
"""Implement the string comparison outlined by Debian policy."""
166
while x_idx < len(x) or y_idx < len(y):
168
(x_str, x_idx) = strcut(x, x_idx, cmp_table)
169
(y_str, y_idx) = strcut(y, y_idx, cmp_table)
170
result = deb_cmp_str(x_str, y_str)
171
if result != 0: return result
174
(x_str, x_idx) = strcut(x, x_idx, "0123456789")
175
(y_str, y_idx) = strcut(y, y_idx, "0123456789")
176
result = cmp(int(x_str or "0"), int(y_str or "0"))
177
if result != 0: return result