1
# -*- test-case-name: twisted.python.test.test_versions -*-
2
# Copyright (c) 2006-2008 Twisted Matrix Laboratories.
3
# See LICENSE for details.
6
Versions for Python packages.
16
An object that is bigger than all other objects.
18
def __cmp__(self, other):
20
@param other: Another object.
23
@return: 0 if other is inf, 1 otherwise.
33
class IncomparableVersions(TypeError):
35
Two versions could not be compared.
38
class Version(object):
40
An object that represents a three-part version number.
42
If running from an svn checkout, include the revision number in
45
def __init__(self, package, major, minor, micro, prerelease=None):
47
@param package: Name of the package that this is a version of.
49
@param major: The major version number.
51
@param minor: The minor version number.
53
@param micro: The micro version number.
55
@param prerelease: The prerelease number.
56
@type prerelease: C{int}
58
self.package = package
62
self.prerelease = prerelease
67
Return a string in canonical short version format,
68
<major>.<minor>.<micro>[+rSVNVer].
71
svnver = self._getSVNVersion()
73
s += '+r' + str(svnver)
79
Like L{short}, but without the +rSVNVer.
81
if self.prerelease is None:
84
pre = "pre%s" % (self.prerelease,)
85
return '%d.%d.%d%s' % (self.major,
92
svnver = self._formatSVNVersion()
94
svnver = ' #' + svnver
95
if self.prerelease is None:
98
prerelease = ", prerelease=%r" % (self.prerelease,)
99
return '%s(%r, %d, %d, %d%s)%s' % (
100
self.__class__.__name__,
110
return '[%s, version %s]' % (
115
def __cmp__(self, other):
117
Compare two versions, considering major versions, minor versions, micro
118
versions, then prereleases.
120
A version with a prerelease is always less than a version without a
121
prerelease. If both versions have prereleases, they will be included in
124
@param other: Another version.
125
@type other: L{Version}
127
@return: NotImplemented when the other object is not a Version, or one
130
@raise IncomparableVersions: when the package names of the versions
133
if not isinstance(other, self.__class__):
134
return NotImplemented
135
if self.package != other.package:
136
raise IncomparableVersions("%r != %r"
137
% (self.package, other.package))
139
if self.prerelease is None:
142
prerelease = self.prerelease
144
if other.prerelease is None:
147
otherpre = other.prerelease
160
def _parseSVNEntries_4(self, entriesFile):
162
Given a readable file object which represents a .svn/entries file in
163
format version 4, return the revision as a string. We do this by
164
reading first XML element in the document that has a 'revision'
167
from xml.dom.minidom import parse
168
doc = parse(entriesFile).documentElement
169
for node in doc.childNodes:
170
if hasattr(node, 'getAttribute'):
171
rev = node.getAttribute('revision')
173
return rev.encode('ascii')
176
def _parseSVNEntries_8(self, entriesFile):
178
Given a readable file object which represents a .svn/entries file in
179
format version 8, return the revision as a string.
181
entriesFile.readline()
182
entriesFile.readline()
183
entriesFile.readline()
184
return entriesFile.readline().strip()
187
# Add handlers for version 9 and 10 formats, which are the same as
188
# version 8 as far as revision information is concerned.
189
_parseSVNEntries_9 = _parseSVNEntries_8
190
_parseSVNEntriesTenPlus = _parseSVNEntries_8
193
def _getSVNVersion(self):
195
Figure out the SVN revision number based on the existance of
196
<package>/.svn/entries, and its contents. This requires discovering the
197
format version from the 'format' file and parsing the entries file
200
@return: None or string containing SVN Revision number.
202
mod = sys.modules.get(self.package)
204
svn = os.path.join(os.path.dirname(mod.__file__), '.svn')
205
if not os.path.exists(svn):
206
# It's not an svn working copy
209
formatFile = os.path.join(svn, 'format')
210
if os.path.exists(formatFile):
211
# It looks like a less-than-version-10 working copy.
212
format = file(formatFile).read().strip()
213
parser = getattr(self, '_parseSVNEntries_' + format, None)
215
# It looks like a version-10-or-greater working copy, which
216
# has version information in the entries file.
217
parser = self._parseSVNEntriesTenPlus
222
entriesFile = os.path.join(svn, 'entries')
223
entries = file(entriesFile)
226
return parser(entries)
233
def _formatSVNVersion(self):
234
ver = self._getSVNVersion()
237
return ' (SVN r%s)' % (ver,)
241
def getVersionString(version):
243
Get a friendly string for the given version object.
245
@param version: A L{Version} object.
246
@return: A string containing the package and short version number.
248
result = '%s %s' % (version.package, version.short())