Bug 1296530 - Move more things in the new DependsFunction and add a repr() for it. r?chmanchester draft
authorMike Hommey <mh+mozilla@glandium.org>
Thu, 13 Oct 2016 13:28:06 +0900
changeset 425031 b5cd447e7b0a129bc83f69d306ff4aa16e132991
parent 425030 eb1db14b38b0ace5694322434481850daf7743bd
child 425032 c6be6a83b7440ccffe020d57165b1c6b1483c037
push id32321
push userbmo:mh+mozilla@glandium.org
push dateFri, 14 Oct 2016 02:53:47 +0000
reviewerschmanchester
bugs1296530
milestone52.0a1
Bug 1296530 - Move more things in the new DependsFunction and add a repr() for it. r?chmanchester
build/moz.configure/util.configure
python/mozbuild/mozbuild/configure/__init__.py
--- a/build/moz.configure/util.configure
+++ b/build/moz.configure/util.configure
@@ -355,17 +355,17 @@ never = dependable(False)
 #   def option(value)
 #       return namespace(foo=value)
 #   set_config('FOO', delayed_getattr(option, 'foo')
 @template
 @imports('__sandbox__')
 def delayed_getattr(func, key):
     deps = __sandbox__._depends.get(func, ())
     if deps:
-        deps = deps.dependencies
+        deps = deps.sandboxed_dependencies
 
     def result(value, _=None):
         # The @depends function we're being passed may have returned
         # None, or an object that simply doesn't have the wanted key.
         # In that case, just return None.
         return getattr(value, key, None)
 
     # Automatically add a dependency on --help when the given @depends
--- a/python/mozbuild/mozbuild/configure/__init__.py
+++ b/python/mozbuild/mozbuild/configure/__init__.py
@@ -45,25 +45,43 @@ class ConfigureError(Exception):
 class SandboxDependsFunction(object):
     '''Sandbox-visible representation of @depends functions.'''
     def __call__(self, *arg, **kwargs):
         raise ConfigureError('The `%s` function may not be called'
                              % self.__name__)
 
 
 class DependsFunction(object):
-    __slots__ = ('func', 'dependencies')
-    def __init__(self, func, dependencies):
+    __slots__ = ('func', 'dependencies', 'sandboxed')
+    def __init__(self, sandbox, func, dependencies):
+        assert isinstance(sandbox, ConfigureSandbox)
         self.func = func
         self.dependencies = dependencies
+        self.sandboxed = wraps(func)(SandboxDependsFunction())
+        sandbox._depends[self.sandboxed] = self
 
     @property
     def name(self):
         return self.func.__name__
 
+    @property
+    def sandboxed_dependencies(self):
+        return [
+            d.sandboxed if isinstance(d, DependsFunction) else d
+            for d in self.dependencies
+        ]
+
+    def __repr__(self):
+        return '<%s.%s %s(%s)>' % (
+            self.__class__.__module__,
+            self.__class__.__name__,
+            self.name,
+            ', '.join(repr(d) for d in self.dependencies),
+        )
+
 
 class SandboxedGlobal(dict):
     '''Identifiable dict type for use as function global'''
 
 
 def forbidden_import(*args, **kwargs):
     raise ImportError('Importing modules is forbidden')
 
@@ -304,43 +322,45 @@ class ConfigureSandbox(dict):
             if need_help_dependency and self._help_option not in f.dependencies:
                 raise ConfigureError("Missing @depends for `%s`: '--help'" %
                                      f.name)
             return self._value_for(arg)
         return arg
 
     def _value_for(self, obj):
         if isinstance(obj, SandboxDependsFunction):
+            assert obj in self._depends
+            return self._value_for_depends(self._depends[obj])
+
+        elif isinstance(obj, DependsFunction):
             return self._value_for_depends(obj)
 
         elif isinstance(obj, Option):
             return self._value_for_option(obj)
 
         assert False
 
     @memoize
     def _value_for_depends(self, obj):
-        assert obj in self._depends
-        f = self._depends[obj]
-        assert not inspect.isgeneratorfunction(f.func)
-        with_help = self._help_option in f.dependencies
+        assert not inspect.isgeneratorfunction(obj.func)
+        with_help = self._help_option in obj.dependencies
         if with_help:
-            for arg in f.dependencies:
-                if isinstance(arg, SandboxDependsFunction):
-                    if self._help_option not in self._depends[arg].dependencies:
+            for arg in obj.dependencies:
+                if isinstance(arg, DependsFunction):
+                    if self._help_option not in arg.dependencies:
                         raise ConfigureError(
                             "`%s` depends on '--help' and `%s`. "
                             "`%s` must depend on '--help'"
-                            % (f.name, arg.__name__, arg.__name__))
+                            % (obj.name, arg.name, arg.name))
         elif self._help:
             raise ConfigureError("Missing @depends for `%s`: '--help'" %
-                                 f.name)
+                                 obj.name)
 
-        resolved_args = [self._value_for(d) for d in f.dependencies]
-        return f.func(*resolved_args)
+        resolved_args = [self._value_for(d) for d in obj.dependencies]
+        return obj.func(*resolved_args)
 
     @memoize
     def _value_for_option(self, option):
         implied = {}
         for implied_option in self._implied_options[:]:
             if implied_option.name not in (option.name, option.env):
                 continue
             self._implied_options.remove(implied_option)
@@ -440,40 +460,40 @@ class ConfigureSandbox(dict):
                     raise ConfigureError("'%s' is not a known option. "
                                          "Maybe it's declared too late?"
                                          % arg)
                 arg = self._options[name]
                 self._seen.add(arg)
                 dependencies.append(arg)
             elif isinstance(arg, SandboxDependsFunction):
                 assert arg in self._depends
+                arg = self._depends[arg]
                 dependencies.append(arg)
             else:
                 raise TypeError(
                     "Cannot use object of type '%s' as argument to @depends"
                     % type(arg).__name__)
         dependencies = tuple(dependencies)
 
         def decorator(func):
             if inspect.isgeneratorfunction(func):
                 raise ConfigureError(
                     'Cannot decorate generator functions with @depends')
             func, glob = self._prepare_function(func)
-            dummy = wraps(func)(SandboxDependsFunction())
-            self._depends[dummy] = DependsFunction(func, dependencies)
+            depends = DependsFunction(self, func, dependencies)
 
             # Only @depends functions with a dependency on '--help' are
             # executed immediately. Everything else is queued for later
             # execution.
             if self._help_option in dependencies:
-                self._value_for(dummy)
+                self._value_for(depends)
             elif not self._help:
-                self._execution_queue.append((self._value_for, (dummy,)))
+                self._execution_queue.append((self._value_for, (depends,)))
 
-            return dummy
+            return depends.sandboxed
 
         return decorator
 
     def include_impl(self, what):
         '''Implementation of include().
         Allows to include external files for execution in the sandbox.
         It is possible to use a @depends function as argument, in which case
         the result of the function is the file name to include. This latter