bug 1257607 - Add Version type to moz.configure. r=glandium
authorTed Mielczarek <ted@mielczarek.org>
Thu, 17 Mar 2016 11:52:18 -0400
changeset 327235 e1e446ee68823667291e2d6136398f1c948b925d
parent 327234 a5bd947546623f30a25113b0bb996d781ff938f2
child 327236 93114df064a5b1b1ed524be0f7025f5037985d96
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersglandium
bugs1257607
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 1257607 - Add Version type to moz.configure. r=glandium This change adds a `Version` type to moz.configure which is a small wrapper around `distutils.version.Version`. It's suitable for wrapping version numbers in configure checks and doing equality or greater-than less-than comparisons in a sensible way. MozReview-Commit-ID: BOL6yvemulG
build/moz.configure/util.configure
moz.configure
python/moz.build
python/mozbuild/mozbuild/configure/util.py
python/mozbuild/mozbuild/test/configure/test_util.py
--- a/build/moz.configure/util.configure
+++ b/build/moz.configure/util.configure
@@ -84,16 +84,22 @@ del _defines
 @template
 def unique_list(l):
     result = []
     for i in l:
         if l not in result:
             result.append(i)
     return result
 
+@template
+@advanced
+def Version(v):
+    'A version number that can be compared usefully.'
+    from mozbuild.configure.util import Version as _Version
+    return _Version(v)
 
 # Denotes a deprecated option. Combines option() and @depends:
 # @deprecated_option('--option')
 # def option(value):
 #     ...
 # @deprecated_option() takes the same arguments as option(), except `help`.
 # The function may handle the option like a typical @depends function would,
 # but it is recommended it emits a deprecation error message suggesting an
--- a/moz.configure
+++ b/moz.configure
@@ -79,17 +79,17 @@ def perl_for_old_configure(value):
 @template
 def perl_version_check(min_version):
     @depends(perl)
     @checking('for minimum required perl version >= %s' % min_version)
     @advanced
     def get_perl_version(perl):
         import subprocess
         try:
-            return subprocess.check_output([perl, '-e', 'print $]'])
+            return Version(subprocess.check_output([perl, '-e', 'print $]']))
         except subprocess.CalledProcessError as e:
             error('Failed to get perl version: %s' % e.message)
 
     @depends(get_perl_version)
     def check_perl_version(version):
         if version < min_version:
             error('Perl %s or higher is required.' % min_version)
 
--- a/python/moz.build
+++ b/python/moz.build
@@ -31,16 +31,17 @@ PYTHON_UNIT_TESTS += [
     'mozbuild/mozbuild/test/backend/test_android_eclipse.py',
     'mozbuild/mozbuild/test/backend/test_build.py',
     'mozbuild/mozbuild/test/backend/test_configenvironment.py',
     'mozbuild/mozbuild/test/backend/test_recursivemake.py',
     'mozbuild/mozbuild/test/backend/test_visualstudio.py',
     'mozbuild/mozbuild/test/compilation/test_warnings.py',
     'mozbuild/mozbuild/test/configure/test_configure.py',
     'mozbuild/mozbuild/test/configure/test_options.py',
+    'mozbuild/mozbuild/test/configure/test_util.py',
     'mozbuild/mozbuild/test/controller/test_ccachestats.py',
     'mozbuild/mozbuild/test/controller/test_clobber.py',
     'mozbuild/mozbuild/test/frontend/test_context.py',
     'mozbuild/mozbuild/test/frontend/test_emitter.py',
     'mozbuild/mozbuild/test/frontend/test_namespaces.py',
     'mozbuild/mozbuild/test/frontend/test_reader.py',
     'mozbuild/mozbuild/test/frontend/test_sandbox.py',
     'mozbuild/mozbuild/test/test_base.py',
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/configure/util.py
@@ -0,0 +1,36 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+import itertools
+from distutils.version import LooseVersion
+
+
+class Version(LooseVersion):
+    '''A simple subclass of distutils.version.LooseVersion.
+    Adds attributes for `major`, `minor`, `patch` for the first three
+    version components so users can easily pull out major/minor
+    versions, like:
+
+    v = Version('1.2b')
+    v.major == 1
+    v.minor == 2
+    v.patch == 0
+    '''
+    def __init__(self, version):
+        # Can't use super, LooseVersion's base class is not a new-style class.
+        LooseVersion.__init__(self, version)
+        # Take the first three integer components, stopping at the first
+        # non-integer and padding the rest with zeroes.
+        (self.major, self.minor, self.patch) = list(itertools.chain(
+            itertools.takewhile(lambda x:isinstance(x, int), self.version),
+            (0, 0, 0)))[:3]
+
+
+    def __cmp__(self, other):
+        # LooseVersion checks isinstance(StringType), so work around it.
+        if isinstance(other, unicode):
+            other = other.encode('ascii')
+        return LooseVersion.__cmp__(self, other)
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/configure/test_util.py
@@ -0,0 +1,49 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+import unittest
+
+from mozunit import main
+
+from mozbuild.configure.util import Version
+
+
+class TestVersion(unittest.TestCase):
+    def test_version_simple(self):
+        v = Version('1')
+        self.assertEqual(v, '1')
+        self.assertLess(v, '2')
+        self.assertGreater(v, '0.5')
+        self.assertEqual(v.major, 1)
+        self.assertEqual(v.minor, 0)
+        self.assertEqual(v.patch, 0)
+
+    def test_version_more(self):
+        v = Version('1.2.3b')
+        self.assertLess(v, '2')
+        self.assertEqual(v.major, 1)
+        self.assertEqual(v.minor, 2)
+        self.assertEqual(v.patch, 3)
+
+    def test_version_bad(self):
+        # A version with a letter in the middle doesn't really make sense,
+        # so everything after it should be ignored.
+        v = Version('1.2b.3')
+        self.assertLess(v, '2')
+        self.assertEqual(v.major, 1)
+        self.assertEqual(v.minor, 2)
+        self.assertEqual(v.patch, 0)
+
+    def test_version_badder(self):
+        v = Version('1b.2.3')
+        self.assertLess(v, '2')
+        self.assertEqual(v.major, 1)
+        self.assertEqual(v.minor, 0)
+        self.assertEqual(v.patch, 0)
+
+
+if __name__ == '__main__':
+    main()