Update and rename MantenerFIFO to MantenerFIFO.md
[vsorcdistro/.git] / ryu / .eggs / pbr-5.3.1-py2.7.egg / pbr / version.py
1
2 #    Copyright 2012 OpenStack Foundation
3 #    Copyright 2012-2013 Hewlett-Packard Development Company, L.P.
4 #
5 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
6 #    not use this file except in compliance with the License. You may obtain
7 #    a copy of the License at
8 #
9 #         http://www.apache.org/licenses/LICENSE-2.0
10 #
11 #    Unless required by applicable law or agreed to in writing, software
12 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 #    License for the specific language governing permissions and limitations
15 #    under the License.
16
17 """
18 Utilities for consuming the version from pkg_resources.
19 """
20
21 import itertools
22 import operator
23 import sys
24
25
26 def _is_int(string):
27     try:
28         int(string)
29         return True
30     except ValueError:
31         return False
32
33
34 class SemanticVersion(object):
35     """A pure semantic version independent of serialisation.
36
37     See the pbr doc 'semver' for details on the semantics.
38     """
39
40     def __init__(
41             self, major, minor=0, patch=0, prerelease_type=None,
42             prerelease=None, dev_count=None):
43         """Create a SemanticVersion.
44
45         :param major: Major component of the version.
46         :param minor: Minor component of the version. Defaults to 0.
47         :param patch: Patch level component. Defaults to 0.
48         :param prerelease_type: What sort of prerelease version this is -
49             one of a(alpha), b(beta) or rc(release candidate).
50         :param prerelease: For prerelease versions, what number prerelease.
51             Defaults to 0.
52         :param dev_count: How many commits since the last release.
53         """
54         self._major = major
55         self._minor = minor
56         self._patch = patch
57         self._prerelease_type = prerelease_type
58         self._prerelease = prerelease
59         if self._prerelease_type and not self._prerelease:
60             self._prerelease = 0
61         self._dev_count = dev_count or 0  # Normalise 0 to None.
62
63     def __eq__(self, other):
64         if not isinstance(other, SemanticVersion):
65             return False
66         return self.__dict__ == other.__dict__
67
68     def __hash__(self):
69         return sum(map(hash, self.__dict__.values()))
70
71     def _sort_key(self):
72         """Return a key for sorting SemanticVersion's on."""
73         # key things:
74         # - final is after rc's, so we make that a/b/rc/z
75         # - dev==None is after all other devs, so we use sys.maxsize there.
76         # - unqualified dev releases come before any pre-releases.
77         # So we do:
78         # (major, minor, patch) - gets the major grouping.
79         # (0|1) unqualified dev flag
80         # (a/b/rc/z) - release segment grouping
81         # pre-release level
82         # dev count, maxsize for releases.
83         rc_lookup = {'a': 'a', 'b': 'b', 'rc': 'rc', None: 'z'}
84         if self._dev_count and not self._prerelease_type:
85             uq_dev = 0
86         else:
87             uq_dev = 1
88         return (
89             self._major, self._minor, self._patch,
90             uq_dev,
91             rc_lookup[self._prerelease_type], self._prerelease,
92             self._dev_count or sys.maxsize)
93
94     def __lt__(self, other):
95         """Compare self and other, another Semantic Version."""
96         # NB(lifeless) this could perhaps be rewritten as
97         # lt (tuple_of_one, tuple_of_other) with a single check for
98         # the typeerror corner cases - that would likely be faster
99         # if this ever becomes performance sensitive.
100         if not isinstance(other, SemanticVersion):
101             raise TypeError("ordering to non-SemanticVersion is undefined")
102         return self._sort_key() < other._sort_key()
103
104     def __le__(self, other):
105         return self == other or self < other
106
107     def __ge__(self, other):
108         return not self < other
109
110     def __gt__(self, other):
111         return not self <= other
112
113     def __ne__(self, other):
114         return not self == other
115
116     def __repr__(self):
117         return "pbr.version.SemanticVersion(%s)" % self.release_string()
118
119     @classmethod
120     def from_pip_string(klass, version_string):
121         """Create a SemanticVersion from a pip version string.
122
123         This method will parse a version like 1.3.0 into a SemanticVersion.
124
125         This method is responsible for accepting any version string that any
126         older version of pbr ever created.
127
128         Therefore: versions like 1.3.0a1 versions are handled, parsed into a
129         canonical form and then output - resulting in 1.3.0.0a1.
130         Pre pbr-semver dev versions like 0.10.1.3.g83bef74 will be parsed but
131         output as 0.10.1.dev3.g83bef74.
132
133         :raises ValueError: Never tagged versions sdisted by old pbr result in
134             just the git hash, e.g. '1234567' which poses a substantial problem
135             since they collide with the semver versions when all the digits are
136             numerals. Such versions will result in a ValueError being thrown if
137             any non-numeric digits are present. They are an exception to the
138             general case of accepting anything we ever output, since they were
139             never intended and would permanently mess up versions on PyPI if
140             ever released - we're treating that as a critical bug that we ever
141             made them and have stopped doing that.
142         """
143
144         try:
145             return klass._from_pip_string_unsafe(version_string)
146         except IndexError:
147             raise ValueError("Invalid version %r" % version_string)
148
149     @classmethod
150     def _from_pip_string_unsafe(klass, version_string):
151         # Versions need to start numerically, ignore if not
152         version_string = version_string.lstrip('vV')
153         if not version_string[:1].isdigit():
154             raise ValueError("Invalid version %r" % version_string)
155         input_components = version_string.split('.')
156         # decimals first (keep pre-release and dev/hashes to the right)
157         components = [c for c in input_components if c.isdigit()]
158         digit_len = len(components)
159         if digit_len == 0:
160             raise ValueError("Invalid version %r" % version_string)
161         elif digit_len < 3:
162             if (digit_len < len(input_components) and
163                     input_components[digit_len][0].isdigit()):
164                 # Handle X.YaZ - Y is a digit not a leadin to pre-release.
165                 mixed_component = input_components[digit_len]
166                 last_component = ''.join(itertools.takewhile(
167                     lambda x: x.isdigit(), mixed_component))
168                 components.append(last_component)
169                 input_components[digit_len:digit_len + 1] = [
170                     last_component, mixed_component[len(last_component):]]
171                 digit_len += 1
172             components.extend([0] * (3 - digit_len))
173         components.extend(input_components[digit_len:])
174         major = int(components[0])
175         minor = int(components[1])
176         dev_count = None
177         post_count = None
178         prerelease_type = None
179         prerelease = None
180
181         def _parse_type(segment):
182             # Discard leading digits (the 0 in 0a1)
183             isdigit = operator.methodcaller('isdigit')
184             segment = ''.join(itertools.dropwhile(isdigit, segment))
185             isalpha = operator.methodcaller('isalpha')
186             prerelease_type = ''.join(itertools.takewhile(isalpha, segment))
187             prerelease = segment[len(prerelease_type)::]
188             return prerelease_type, int(prerelease)
189         if _is_int(components[2]):
190             patch = int(components[2])
191         else:
192             # legacy version e.g. 1.2.0a1 (canonical is 1.2.0.0a1)
193             # or 1.2.dev4.g1234 or 1.2.b4
194             patch = 0
195             components[2:2] = [0]
196         remainder = components[3:]
197         remainder_starts_with_int = False
198         try:
199             if remainder and int(remainder[0]):
200                 remainder_starts_with_int = True
201         except ValueError:
202             pass
203         if remainder_starts_with_int:
204             # old dev format - 0.1.2.3.g1234
205             dev_count = int(remainder[0])
206         else:
207             if remainder and (remainder[0][0] == '0' or
208                               remainder[0][0] in ('a', 'b', 'r')):
209                 # Current RC/beta layout
210                 prerelease_type, prerelease = _parse_type(remainder[0])
211                 remainder = remainder[1:]
212             while remainder:
213                 component = remainder[0]
214                 if component.startswith('dev'):
215                     dev_count = int(component[3:])
216                 elif component.startswith('post'):
217                     dev_count = None
218                     post_count = int(component[4:])
219                 else:
220                     raise ValueError(
221                         'Unknown remainder %r in %r'
222                         % (remainder, version_string))
223                 remainder = remainder[1:]
224         result = SemanticVersion(
225             major, minor, patch, prerelease_type=prerelease_type,
226             prerelease=prerelease, dev_count=dev_count)
227         if post_count:
228             if dev_count:
229                 raise ValueError(
230                     'Cannot combine postN and devN - no mapping in %r'
231                     % (version_string,))
232             result = result.increment().to_dev(post_count)
233         return result
234
235     def brief_string(self):
236         """Return the short version minus any alpha/beta tags."""
237         return "%s.%s.%s" % (self._major, self._minor, self._patch)
238
239     def debian_string(self):
240         """Return the version number to use when building a debian package.
241
242         This translates the PEP440/semver precedence rules into Debian version
243         sorting operators.
244         """
245         return self._long_version("~")
246
247     def decrement(self):
248         """Return a decremented SemanticVersion.
249
250         Decrementing versions doesn't make a lot of sense - this method only
251         exists to support rendering of pre-release versions strings into
252         serialisations (such as rpm) with no sort-before operator.
253
254         The 9999 magic version component is from the spec on this - pbr-semver.
255
256         :return: A new SemanticVersion object.
257         """
258         if self._patch:
259             new_patch = self._patch - 1
260             new_minor = self._minor
261             new_major = self._major
262         else:
263             new_patch = 9999
264             if self._minor:
265                 new_minor = self._minor - 1
266                 new_major = self._major
267             else:
268                 new_minor = 9999
269                 if self._major:
270                     new_major = self._major - 1
271                 else:
272                     new_major = 0
273         return SemanticVersion(
274             new_major, new_minor, new_patch)
275
276     def increment(self, minor=False, major=False):
277         """Return an incremented SemanticVersion.
278
279         The default behaviour is to perform a patch level increment. When
280         incrementing a prerelease version, the patch level is not changed
281         - the prerelease serial is changed (e.g. beta 0 -> beta 1).
282
283         Incrementing non-pre-release versions will not introduce pre-release
284         versions - except when doing a patch incremental to a pre-release
285         version the new version will only consist of major/minor/patch.
286
287         :param minor: Increment the minor version.
288         :param major: Increment the major version.
289         :return: A new SemanticVersion object.
290         """
291         if self._prerelease_type:
292             new_prerelease_type = self._prerelease_type
293             new_prerelease = self._prerelease + 1
294             new_patch = self._patch
295         else:
296             new_prerelease_type = None
297             new_prerelease = None
298             new_patch = self._patch + 1
299         if minor:
300             new_minor = self._minor + 1
301             new_patch = 0
302             new_prerelease_type = None
303             new_prerelease = None
304         else:
305             new_minor = self._minor
306         if major:
307             new_major = self._major + 1
308             new_minor = 0
309             new_patch = 0
310             new_prerelease_type = None
311             new_prerelease = None
312         else:
313             new_major = self._major
314         return SemanticVersion(
315             new_major, new_minor, new_patch,
316             new_prerelease_type, new_prerelease)
317
318     def _long_version(self, pre_separator, rc_marker=""):
319         """Construct a long string version of this semver.
320
321         :param pre_separator: What separator to use between components
322             that sort before rather than after. If None, use . and lower the
323             version number of the component to preserve sorting. (Used for
324             rpm support)
325         """
326         if ((self._prerelease_type or self._dev_count)
327                 and pre_separator is None):
328             segments = [self.decrement().brief_string()]
329             pre_separator = "."
330         else:
331             segments = [self.brief_string()]
332         if self._prerelease_type:
333             segments.append(
334                 "%s%s%s%s" % (pre_separator, rc_marker, self._prerelease_type,
335                               self._prerelease))
336         if self._dev_count:
337             if not self._prerelease_type:
338                 segments.append(pre_separator)
339             else:
340                 segments.append('.')
341             segments.append('dev')
342             segments.append(self._dev_count)
343         return "".join(str(s) for s in segments)
344
345     def release_string(self):
346         """Return the full version of the package.
347
348         This including suffixes indicating VCS status.
349         """
350         return self._long_version(".", "0")
351
352     def rpm_string(self):
353         """Return the version number to use when building an RPM package.
354
355         This translates the PEP440/semver precedence rules into RPM version
356         sorting operators. Because RPM has no sort-before operator (such as the
357         ~ operator in dpkg),  we show all prerelease versions as being versions
358         of the release before.
359         """
360         return self._long_version(None)
361
362     def to_dev(self, dev_count):
363         """Return a development version of this semver.
364
365         :param dev_count: The number of commits since the last release.
366         """
367         return SemanticVersion(
368             self._major, self._minor, self._patch, self._prerelease_type,
369             self._prerelease, dev_count=dev_count)
370
371     def version_tuple(self):
372         """Present the version as a version_info tuple.
373
374         For documentation on version_info tuples see the Python
375         documentation for sys.version_info.
376
377         Since semver and PEP-440 represent overlapping but not subsets of
378         versions, we have to have some heuristic / mapping rules, and have
379         extended the releaselevel field to have alphadev, betadev and
380         candidatedev values. When they are present the dev count is used
381         to provide the serial.
382         - a/b/rc take precedence.
383         - if there is no pre-release version the dev version is used.
384         - serial is taken from the dev/a/b/c component.
385         - final non-dev versions never get serials.
386         """
387         segments = [self._major, self._minor, self._patch]
388         if self._prerelease_type:
389             type_map = {('a', False): 'alpha',
390                         ('b', False): 'beta',
391                         ('rc', False): 'candidate',
392                         ('a', True): 'alphadev',
393                         ('b', True): 'betadev',
394                         ('rc', True): 'candidatedev',
395                         }
396             segments.append(
397                 type_map[(self._prerelease_type, bool(self._dev_count))])
398             segments.append(self._dev_count or self._prerelease)
399         elif self._dev_count:
400             segments.append('dev')
401             segments.append(self._dev_count - 1)
402         else:
403             segments.append('final')
404             segments.append(0)
405         return tuple(segments)
406
407
408 class VersionInfo(object):
409
410     def __init__(self, package):
411         """Object that understands versioning for a package
412
413         :param package: name of the python package, such as glance, or
414                         python-glanceclient
415         """
416         self.package = package
417         self.version = None
418         self._cached_version = None
419         self._semantic = None
420
421     def __str__(self):
422         """Make the VersionInfo object behave like a string."""
423         return self.version_string()
424
425     def __repr__(self):
426         """Include the name."""
427         return "pbr.version.VersionInfo(%s:%s)" % (
428             self.package, self.version_string())
429
430     def _get_version_from_pkg_resources(self):
431         """Obtain a version from pkg_resources or setup-time logic if missing.
432
433         This will try to get the version of the package from the pkg_resources
434         record associated with the package, and if there is no such record
435         falls back to the logic sdist would use.
436         """
437         # Lazy import because pkg_resources is costly to import so defer until
438         # we absolutely need it.
439         import pkg_resources
440         try:
441             requirement = pkg_resources.Requirement.parse(self.package)
442             provider = pkg_resources.get_provider(requirement)
443             result_string = provider.version
444         except pkg_resources.DistributionNotFound:
445             # The most likely cause for this is running tests in a tree
446             # produced from a tarball where the package itself has not been
447             # installed into anything. Revert to setup-time logic.
448             from pbr import packaging
449             result_string = packaging.get_version(self.package)
450         return SemanticVersion.from_pip_string(result_string)
451
452     def release_string(self):
453         """Return the full version of the package.
454
455         This including suffixes indicating VCS status.
456         """
457         return self.semantic_version().release_string()
458
459     def semantic_version(self):
460         """Return the SemanticVersion object for this version."""
461         if self._semantic is None:
462             self._semantic = self._get_version_from_pkg_resources()
463         return self._semantic
464
465     def version_string(self):
466         """Return the short version minus any alpha/beta tags."""
467         return self.semantic_version().brief_string()
468
469     # Compatibility functions
470     canonical_version_string = version_string
471     version_string_with_vcs = release_string
472
473     def cached_version_string(self, prefix=""):
474         """Return a cached version string.
475
476         This will return a cached version string if one is already cached,
477         irrespective of prefix. If none is cached, one will be created with
478         prefix and then cached and returned.
479         """
480         if not self._cached_version:
481             self._cached_version = "%s%s" % (prefix,
482                                              self.version_string())
483         return self._cached_version