From 335012b188e0feeafff42ec3cccb507d1676e023 Mon Sep 17 00:00:00 2001 From: Justin Wood Date: Mon, 23 Apr 2018 14:14:04 -0400 Subject: [PATCH] Bug 1453274 - Support esr version strings. r=rail MozReview-Commit-ID: K7khNCzOwQK --HG-- extra : rebase_source : 33225a5ecb879705327af505920d4db040a91d7b --- python/mozrelease/mozrelease/versions.py | 56 ++++++++++++++++++++++-- python/mozrelease/test/test_versions.py | 18 +++++--- 2 files changed, 64 insertions(+), 10 deletions(-) diff --git a/python/mozrelease/mozrelease/versions.py b/python/mozrelease/mozrelease/versions.py index 51e5001b04b7..0f828b04d776 100644 --- a/python/mozrelease/mozrelease/versions.py +++ b/python/mozrelease/mozrelease/versions.py @@ -1,10 +1,46 @@ from __future__ import absolute_import -from distutils.version import StrictVersion +from distutils.version import StrictVersion, LooseVersion import re -class ModernMozillaVersion(StrictVersion): +class MozillaVersionCompareMixin(): + def __cmp__(self, other): + has_esr = set() + if isinstance(other, LooseModernMozillaVersion) and str(other).endswith('esr'): + # If other version ends with esr, coerce through MozillaVersion ending up with + # a StrictVersion if possible + has_esr.add('other') + other = MozillaVersion(str(other)[:-3]) # strip ESR from end of string + if isinstance(self, LooseModernMozillaVersion) and str(self).endswith('esr'): + # If our version ends with esr, coerce through MozillaVersion ending up with + # a StrictVersion if possible + has_esr.add('self') + self = MozillaVersion(str(self)[:-3]) # strip ESR from end of string + if isinstance(other, LooseModernMozillaVersion) or \ + isinstance(self, LooseModernMozillaVersion): + # If we're still LooseVersion for self or other, run LooseVersion compare + # Being sure to pass through Loose Version type first + val = LooseVersion.__cmp__( + LooseModernMozillaVersion(str(self)), + LooseModernMozillaVersion(str(other))) + else: + # No versions are loose, therefore we can use StrictVersion + val = StrictVersion.__cmp__(self, other) + if has_esr.isdisjoint(set(['other', 'self'])) or \ + has_esr.issuperset(set(['other', 'self'])): + # If both had esr string or neither, then cmp() was accurate + return val + elif val is not 0: + # cmp is accurate here even if esr is present in only 1 compare, since + # versions are not equal + return val + elif 'other' in has_esr: + return -1 # esr is not greater than non esr + return 1 # non esr is greater than esr + + +class ModernMozillaVersion(MozillaVersionCompareMixin, StrictVersion): """A version class that is slightly less restrictive than StrictVersion. Instead of just allowing "a" or "b" as prerelease tags, it allows any alpha. This allows us to support the once-shipped "3.6.3plugin1" and @@ -13,7 +49,7 @@ class ModernMozillaVersion(StrictVersion): ([a-zA-Z]+(\d+))?$""", re.VERBOSE) -class AncientMozillaVersion(StrictVersion): +class AncientMozillaVersion(MozillaVersionCompareMixin, StrictVersion): """A version class that is slightly less restrictive than StrictVersion. Instead of just allowing "a" or "b" as prerelease tags, it allows any alpha. This allows us to support the once-shipped "3.6.3plugin1" and @@ -24,6 +60,16 @@ class AncientMozillaVersion(StrictVersion): ([a-zA-Z]+(\d+))?$""", re.VERBOSE) +class LooseModernMozillaVersion(MozillaVersionCompareMixin, LooseVersion): + """A version class that is more restrictive than LooseVersion. + This class reduces the valid strings to "esr", "a", "b" and "rc" in order + to support esr. StrictVersion requires a trailing number after all strings.""" + component_re = re.compile(r'(\d+ | a | b | rc | esr | \.)', re.VERBOSE) + + def __repr__(self): + return "LooseModernMozillaVersion ('%s')" % str(self) + + def MozillaVersion(version): try: return ModernMozillaVersion(version) @@ -34,6 +80,10 @@ def MozillaVersion(version): return AncientMozillaVersion(version) except ValueError: pass + try: + return LooseModernMozillaVersion(version) + except ValueError: + pass raise ValueError("Version number %s is invalid." % version) diff --git a/python/mozrelease/test/test_versions.py b/python/mozrelease/test/test_versions.py index 7f6209803e91..92512ee83387 100644 --- a/python/mozrelease/test/test_versions.py +++ b/python/mozrelease/test/test_versions.py @@ -48,17 +48,17 @@ ALL_VERSIONS = [ # Keep this sorted '3.5.10', # ... Start skipping around... '4.0b9', - # '10.0.2esr', - # '10.0.3esr', + '10.0.2esr', + '10.0.3esr', '32.0', '49.0a1', '49.0a2', '59.0', '60.0', - # '60.0esr', - # '60.0.1esr', + '60.0esr', + '60.0.1esr', '60.1', - # '60.1.0esr', + '60.1esr', '61.0', ] @@ -80,12 +80,16 @@ def test_versions_parseable(version): assert MozillaVersion(version) is not None -def test_versions_compare(comparable_versions): +def test_versions_compare_less(comparable_versions): """Test that versions properly compare in order.""" smaller_version, larger_version = comparable_versions assert MozillaVersion(smaller_version) < MozillaVersion(larger_version) + + +def test_versions_compare_greater(comparable_versions): + """Test that versions properly compare in order.""" + smaller_version, larger_version = comparable_versions assert MozillaVersion(larger_version) > MozillaVersion(smaller_version) - assert MozillaVersion(larger_version) != MozillaVersion(smaller_version) @pytest.mark.parametrize('version', ALL_VERSIONS)