Bug 1296530 - Store DependsFunction information for the sandbox as class instances instead of tuples. r?chmanchester
--- a/build/moz.configure/util.configure
+++ b/build/moz.configure/util.configure
@@ -353,17 +353,19 @@ never = dependable(False)
# of a @depends function in a non-immediate manner.
# @depends('--option')
# 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, (None, ()))
+ deps = __sandbox__._depends.get(func, ())
+ if deps:
+ deps = deps.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
@@ -44,16 +44,27 @@ 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):
+ self.func = func
+ self.dependencies = dependencies
+
+ @property
+ def name(self):
+ return self.func.__name__
+
+
class SandboxedGlobal(dict):
'''Identifiable dict type for use as function global'''
def forbidden_import(*args, **kwargs):
raise ImportError('Importing modules is forbidden')
@@ -110,18 +121,17 @@ class ConfigureSandbox(dict):
def __init__(self, config, environ=os.environ, argv=sys.argv,
stdout=sys.stdout, stderr=sys.stderr, logger=None):
dict.__setitem__(self, '__builtins__', self.BUILTINS)
self._paths = []
self._all_paths = set()
self._templates = set()
- # Store the real function and its dependencies, behind each
- # DependsFunction generated from @depends.
+ # Associate SandboxDependsFunctions to DependsFunctions.
self._depends = {}
self._seen = set()
# Store the @imports added to a given function.
self._imports = {}
self._options = OrderedDict()
# Store raw option (as per command line or environment) for each Option
self._raw_options = OrderedDict()
@@ -285,53 +295,52 @@ class ConfigureSandbox(dict):
raise KeyError('Cannot assign `%s` because it is neither a '
'@depends nor a @template' % key)
return super(ConfigureSandbox, self).__setitem__(key, value)
def _resolve(self, arg, need_help_dependency=True):
if isinstance(arg, SandboxDependsFunction):
assert arg in self._depends
- func, deps = self._depends[arg]
- if need_help_dependency and self._help_option not in deps:
+ f = self._depends[arg]
+ if need_help_dependency and self._help_option not in f.dependencies:
raise ConfigureError("Missing @depends for `%s`: '--help'" %
- func.__name__)
+ f.name)
return self._value_for(arg)
return arg
def _value_for(self, obj):
if isinstance(obj, SandboxDependsFunction):
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
- func, dependencies = self._depends[obj]
- assert not inspect.isgeneratorfunction(func)
- with_help = self._help_option in dependencies
+ f = self._depends[obj]
+ assert not inspect.isgeneratorfunction(f.func)
+ with_help = self._help_option in f.dependencies
if with_help:
- for arg in dependencies:
+ for arg in f.dependencies:
if isinstance(arg, SandboxDependsFunction):
- _, deps = self._depends[arg]
- if self._help_option not in deps:
+ if self._help_option not in self._depends[arg].dependencies:
raise ConfigureError(
"`%s` depends on '--help' and `%s`. "
"`%s` must depend on '--help'"
- % (func.__name__, arg.__name__, arg.__name__))
+ % (f.name, arg.__name__, arg.__name__))
elif self._help:
raise ConfigureError("Missing @depends for `%s`: '--help'" %
- func.__name__)
+ f.name)
- resolved_args = [self._value_for(d) for d in dependencies]
- return func(*resolved_args)
+ resolved_args = [self._value_for(d) for d in f.dependencies]
+ return f.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)
@@ -444,17 +453,17 @@ class ConfigureSandbox(dict):
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] = func, dependencies
+ self._depends[dummy] = DependsFunction(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)
elif not self._help:
self._execution_queue.append((self._value_for, (dummy,)))
@@ -682,17 +691,17 @@ class ConfigureSandbox(dict):
The `reason` argument indicates what caused the option to be implied.
It is necessary when it cannot be inferred from the `value`.
'''
# Don't do anything when --help was on the command line
if self._help:
return
if not reason and isinstance(value, SandboxDependsFunction):
- deps = self._depends[value][1]
+ deps = self._depends[value].dependencies
possible_reasons = [d for d in deps if d != self._help_option]
if len(possible_reasons) == 1:
if isinstance(possible_reasons[0], Option):
reason = possible_reasons[0]
if not reason and (isinstance(value, (bool, tuple)) or
isinstance(value, types.StringTypes)):
# A reason can be provided automatically when imply_option
# is called with an immediate value.