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
--- a/build/moz.configure/util.configure
+++ b/build/moz.configure/util.configure
@@ -79,16 +79,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,40 @@
+# 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) = [v if v else 0
+ for v, _ in itertools.izip_longest(
+ itertools.takewhile(
+ lambda x: isinstance(x, int), self.version),
+ xrange(3))][: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()