Bug 1363811 - Allow to combine two DependsFunctions with "&". r?chmanchester draft
authorMike Hommey <mh+mozilla@glandium.org>
Wed, 17 May 2017 15:27:26 +0900
changeset 580724 364bf647bf8aaff1f64f4f85c0d7aad8d0405e6a
parent 580723 5f568887e58875358a655d380066fb974288012f
child 580725 cde7a0e4ac03926ee8d7941da1f0ad92a0daef39
push id59648
push userbmo:mh+mozilla@glandium.org
push dateThu, 18 May 2017 22:06:14 +0000
reviewerschmanchester
bugs1363811
milestone55.0a1
Bug 1363811 - Allow to combine two DependsFunctions with "&". r?chmanchester Similar to how they can be combined with "|", we now allow using "&". As for "|", it would have been better if it were "and", but it's not possible to override "and" in python ; __and__ is for "&".
python/mozbuild/mozbuild/configure/__init__.py
python/mozbuild/mozbuild/test/configure/test_configure.py
--- a/python/mozbuild/mozbuild/configure/__init__.py
+++ b/python/mozbuild/mozbuild/configure/__init__.py
@@ -41,27 +41,34 @@ import mozpack.path as mozpath
 class ConfigureError(Exception):
     pass
 
 
 class SandboxDependsFunction(object):
     '''Sandbox-visible representation of @depends functions.'''
     def __init__(self, unsandboxed):
         self._or = unsandboxed.__or__
+        self._and = unsandboxed.__and__
 
     def __call__(self, *arg, **kwargs):
         raise ConfigureError('The `%s` function may not be called'
                              % self.__name__)
 
     def __or__(self, other):
         if not isinstance(other, SandboxDependsFunction):
             raise ConfigureError('Can only do binary arithmetic operations '
                                  'with another @depends function.')
         return self._or(other).sandboxed
 
+    def __and__(self, other):
+        if not isinstance(other, SandboxDependsFunction):
+            raise ConfigureError('Can only do binary arithmetic operations '
+                                 'with another @depends function.')
+        return self._and(other).sandboxed
+
     def __nonzero__(self):
         raise ConfigureError(
             'Cannot do boolean operations on @depends functions.')
 
 
 class DependsFunction(object):
     __slots__ = (
         '_func', '_name', 'dependencies', 'when', 'sandboxed', 'sandbox',
@@ -130,16 +137,33 @@ class DependsFunction(object):
     def or_impl(iterable):
         # Applies "or" to all the items of iterable.
         # e.g. if iterable contains a, b and c, returns `a or b or c`.
         for i in iterable:
             if i:
                 return i
         return i
 
+    def __and__(self, other):
+        if isinstance(other, SandboxDependsFunction):
+            other = self.sandbox._depends.get(other)
+        assert isinstance(other, DependsFunction)
+        assert self.sandbox is other.sandbox
+        return CombinedDependsFunction(self.sandbox, self.and_impl,
+                                       (self, other))
+
+    @staticmethod
+    def and_impl(iterable):
+        # Applies "and" to all the items of iterable.
+        # e.g. if iterable contains a, b and c, returns `a and b and c`.
+        for i in iterable:
+            if not i:
+                return i
+        return i
+
 
 class CombinedDependsFunction(DependsFunction):
     def __init__(self, sandbox, func, dependencies):
         flatten_deps = []
         for d in dependencies:
             if isinstance(d, CombinedDependsFunction) and d._func is func:
                 for d2 in d.dependencies:
                     if d2 not in flatten_deps:
--- a/python/mozbuild/mozbuild/test/configure/test_configure.py
+++ b/python/mozbuild/mozbuild/test/configure/test_configure.py
@@ -1282,50 +1282,54 @@ class TestConfigure(unittest.TestCase):
                               '--foo is not available in this configuration')
 
         # And similarly doesn't fail when the condition is true.
         with self.moz_configure('''
             imply_option('--foo', True)
         ''' + moz_configure):
             self.get_config(['--enable-when'])
 
-    def test_depends_or(self):
+    def test_depends_binary_ops(self):
         with self.moz_configure('''
             option('--foo', nargs=1, help='foo')
             @depends('--foo')
             def foo(value):
                 return value or 0
 
             option('--bar', nargs=1, help='bar')
             @depends('--bar')
             def bar(value):
                 return value or ''
 
             option('--baz', nargs=1, help='baz')
             @depends('--baz')
             def baz(value):
                 return value
 
-            set_config('FOOBAR', foo | bar)
-            set_config('FOOBARBAZ', foo | bar | baz)
+            set_config('FOOorBAR', foo | bar)
+            set_config('FOOorBARorBAZ', foo | bar | baz)
+            set_config('FOOandBAR', foo & bar)
+            set_config('FOOandBARandBAZ', foo & bar & baz)
         '''):
             for foo_opt, foo_value in (
                 ('',  0),
                 ('--foo=foo', PositiveOptionValue(('foo',)))
             ):
                 for bar_opt, bar_value in (
                     ('', ''),
                     ('--bar=bar', PositiveOptionValue(('bar',)))
                 ):
                     for baz_opt, baz_value in (
                         ('', NegativeOptionValue()),
                         ('--baz=baz', PositiveOptionValue(('baz',)))
                     ):
                         config = self.get_config(
                             [x for x in (foo_opt, bar_opt, baz_opt) if x])
                         self.assertEqual(config, {
-                            'FOOBAR': foo_value or bar_value,
-                            'FOOBARBAZ': foo_value or bar_value or baz_value,
+                            'FOOorBAR': foo_value or bar_value,
+                            'FOOorBARorBAZ': foo_value or bar_value or baz_value,
+                            'FOOandBAR': foo_value and bar_value,
+                            'FOOandBARandBAZ': foo_value and bar_value and baz_value,
                         })
 
 
 if __name__ == '__main__':
     main()