def _dependency(self, arg, callee_name, arg_name=None): if isinstance(arg, six.string_types): prefix, name, values = Option.split_option(arg) if values != (): raise ConfigureError("Option must not contain an '='") if name not in self._options: raise ConfigureError("'%s' is not a known option. " "Maybe it's declared too late?" % arg) arg = self._options[name] self._seen.add(arg) elif isinstance(arg, SandboxDependsFunction): assert arg in self._depends arg = self._depends[arg] else: raise TypeError( "Cannot use object of type '%s' as %sargument to %s" % (type(arg).__name__, '`%s` ' % arg_name if arg_name else '', callee_name)) return arg
def _dependency(self, arg, callee_name, arg_name=None): if isinstance(arg, types.StringTypes): prefix, name, values = Option.split_option(arg) if values != (): raise ConfigureError("Option must not contain an '='") if name not in self._options: raise ConfigureError("'%s' is not a known option. " "Maybe it's declared too late?" % arg) arg = self._options[name] self._seen.add(arg) elif isinstance(arg, SandboxDependsFunction): assert arg in self._depends arg = self._depends[arg] else: raise TypeError( "Cannot use object of type '%s' as %sargument to %s" % (type(arg).__name__, '`%s` ' % arg_name if arg_name else '', callee_name)) return arg
def imply_option_impl(self, option, value, reason=None, when=None): '''Implementation of imply_option(). Injects additional options as if they had been passed on the command line. The `option` argument is a string as in option()'s `name` or `env`. The option must be declared after `imply_option` references it. The `value` argument indicates the value to pass to the option. It can be: - True. In this case `imply_option` injects the positive option (--enable-foo/--with-foo). imply_option('--enable-foo', True) imply_option('--disable-foo', True) are both equivalent to `--enable-foo` on the command line. - False. In this case `imply_option` injects the negative option (--disable-foo/--without-foo). imply_option('--enable-foo', False) imply_option('--disable-foo', False) are both equivalent to `--disable-foo` on the command line. - None. In this case `imply_option` does nothing. imply_option('--enable-foo', None) imply_option('--disable-foo', None) are both equivalent to not passing any flag on the command line. - a string or a tuple. In this case `imply_option` injects the positive option with the given value(s). imply_option('--enable-foo', 'a') imply_option('--disable-foo', 'a') are both equivalent to `--enable-foo=a` on the command line. imply_option('--enable-foo', ('a', 'b')) imply_option('--disable-foo', ('a', 'b')) are both equivalent to `--enable-foo=a,b` on the command line. Because imply_option('--disable-foo', ...) can be misleading, it is recommended to use the positive form ('--enable' or '--with') for `option`. The `value` argument can also be (and usually is) a reference to a @depends function, in which case the result of that function will be used as per the descripted mapping above. The `reason` argument indicates what caused the option to be implied. It is necessary when it cannot be inferred from the `value`. ''' when = self._normalize_when(when, 'imply_option') # 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].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, six.string_types)): # A reason can be provided automatically when imply_option # is called with an immediate value. _, filename, line, _, _, _ = inspect.stack()[1] reason = "imply_option at %s:%s" % (filename, line) if not reason: raise ConfigureError( "Cannot infer what implies '%s'. Please add a `reason` to " "the `imply_option` call." % option) prefix, name, values = Option.split_option(option) if values != (): raise ConfigureError("Implied option must not contain an '='") self._implied_options.append(ReadOnlyNamespace( option=option, prefix=prefix, name=name, value=value, caller=inspect.stack()[1], reason=reason, when=when, ))
def depends_impl(self, *args): '''Implementation of @depends() This function is a decorator. It returns a function that subsequently takes a function and returns a dummy function. The dummy function identifies the actual function for the sandbox, while preventing further function calls from within the sandbox. @depends() takes a variable number of option strings or dummy function references. The decorated function is called as soon as the decorator is called, and the arguments it receives are the OptionValue or function results corresponding to each of the arguments to @depends. As an exception, when a HelpFormatter is attached, only functions that have '--help' in their @depends argument list are called. The decorated function is altered to use a different global namespace for its execution. This different global namespace exposes a limited set of functions from os.path, and two additional functions: `imply_option` and `set_config`. The former allows to inject additional options as if they had been passed on the command line. The latter declares new configuration items for consumption by moz.build. ''' if not args: raise ConfigureError('@depends needs at least one argument') with_help = False resolved_args = [] for arg in args: if isinstance(arg, types.StringTypes): prefix, name, values = Option.split_option(arg) if values != (): raise ConfigureError("Option must not contain an '='") if name not in self._options: raise ConfigureError("'%s' is not a known option. " "Maybe it's declared too late?" % arg) arg = self._options[name] if arg == self._help_option: with_help = True elif isinstance(arg, DummyFunction): assert arg in self._depends arg = self._depends[arg] else: raise TypeError( "Cannot use object of type '%s' as argument to @depends" % type(arg)) self._seen.add(arg) resolved_arg = self._results.get(arg) if resolved_arg is None: assert arg in self._db or self._help resolved_arg = self._db.get(arg) resolved_args.append(resolved_arg) def decorator(func): if inspect.isgeneratorfunction(func): raise ConfigureError( 'Cannot decorate generator functions with @depends') func, glob = self._prepare_function(func) result = DependsOutput() glob.update( imply_option=result.imply_option, set_config=result.__setitem__, ) dummy = wraps(func)(DummyFunction()) self._depends[dummy] = func func.with_help = with_help if with_help: for arg in args: if (isinstance(arg, DummyFunction) and not self._depends[arg].with_help): raise ConfigureError( "`%s` depends on '--help' and `%s`. " "`%s` must depend on '--help'" % (func.__name__, arg.__name__, arg.__name__)) if self._help and not with_help: return dummy self._results[func] = func(*resolved_args) self._db[func] = ReadOnlyDict(result) for option, reason in result.implied_options: self._helper.add(option, 'implied') if not reason: deps = [] for name, value in zip(args, resolved_args): if not isinstance(value, OptionValue): raise ConfigureError( "Cannot infer what implied '%s'" % option) if name == '--help': continue deps.append(value.format(self._db.get(value) or name)) if len(deps) != 1: raise ConfigureError( "Cannot infer what implied '%s'" % option) reason = deps[0] self._implied_options[option] = func, reason if not self._help: for k, v in result.iteritems(): if k in self._config: raise ConfigureError( "Cannot add '%s' to configuration: Key already " "exists" % k) self._config[k] = v return dummy return decorator
def imply_option_impl(self, option, value, reason=None, when=None): '''Implementation of imply_option(). Injects additional options as if they had been passed on the command line. The `option` argument is a string as in option()'s `name` or `env`. The option must be declared after `imply_option` references it. The `value` argument indicates the value to pass to the option. It can be: - True. In this case `imply_option` injects the positive option (--enable-foo/--with-foo). imply_option('--enable-foo', True) imply_option('--disable-foo', True) are both equivalent to `--enable-foo` on the command line. - False. In this case `imply_option` injects the negative option (--disable-foo/--without-foo). imply_option('--enable-foo', False) imply_option('--disable-foo', False) are both equivalent to `--disable-foo` on the command line. - None. In this case `imply_option` does nothing. imply_option('--enable-foo', None) imply_option('--disable-foo', None) are both equivalent to not passing any flag on the command line. - a string or a tuple. In this case `imply_option` injects the positive option with the given value(s). imply_option('--enable-foo', 'a') imply_option('--disable-foo', 'a') are both equivalent to `--enable-foo=a` on the command line. imply_option('--enable-foo', ('a', 'b')) imply_option('--disable-foo', ('a', 'b')) are both equivalent to `--enable-foo=a,b` on the command line. Because imply_option('--disable-foo', ...) can be misleading, it is recommended to use the positive form ('--enable' or '--with') for `option`. The `value` argument can also be (and usually is) a reference to a @depends function, in which case the result of that function will be used as per the descripted mapping above. 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].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. _, filename, line, _, _, _ = inspect.stack()[1] reason = "imply_option at %s:%s" % (filename, line) if not reason: raise ConfigureError( "Cannot infer what implies '%s'. Please add a `reason` to " "the `imply_option` call." % option) when = self._normalize_when(when, 'imply_option') prefix, name, values = Option.split_option(option) if values != (): raise ConfigureError("Implied option must not contain an '='") self._implied_options.append(ReadOnlyNamespace( option=option, prefix=prefix, name=name, value=value, caller=inspect.stack()[1], reason=reason, when=when, ))
def depends_impl(self, *args): '''Implementation of @depends() This function is a decorator. It returns a function that subsequently takes a function and returns a dummy function. The dummy function identifies the actual function for the sandbox, while preventing further function calls from within the sandbox. @depends() takes a variable number of option strings or dummy function references. The decorated function is called as soon as the decorator is called, and the arguments it receives are the OptionValue or function results corresponding to each of the arguments to @depends. As an exception, when a HelpFormatter is attached, only functions that have '--help' in their @depends argument list are called. The decorated function is altered to use a different global namespace for its execution. This different global namespace exposes a limited set of functions from os.path. ''' if not args: raise ConfigureError('@depends needs at least one argument') dependencies = [] for arg in args: if isinstance(arg, types.StringTypes): prefix, name, values = Option.split_option(arg) if values != (): raise ConfigureError("Option must not contain an '='") if name not in self._options: 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, DependsFunction): assert arg in self._depends 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)(DependsFunction()) self._depends[dummy] = 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,))) return dummy return decorator
def depends_impl(self, *args): '''Implementation of @depends() This function is a decorator. It returns a function that subsequently takes a function and returns a dummy function. The dummy function identifies the actual function for the sandbox, while preventing further function calls from within the sandbox. @depends() takes a variable number of option strings or dummy function references. The decorated function is called as soon as the decorator is called, and the arguments it receives are the OptionValue or function results corresponding to each of the arguments to @depends. As an exception, when a HelpFormatter is attached, only functions that have '--help' in their @depends argument list are called. The decorated function is altered to use a different global namespace for its execution. This different global namespace exposes a limited set of functions from os.path. ''' if not args: raise ConfigureError('@depends needs at least one argument') resolved_args = [] dependencies = [] for arg in args: if isinstance(arg, types.StringTypes): prefix, name, values = Option.split_option(arg) if values != (): raise ConfigureError("Option must not contain an '='") if name not in self._options: 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) assert arg in self._option_values or self._help resolved_arg = self._option_values.get(arg) elif isinstance(arg, DummyFunction): assert arg in self._depends dependencies.append(arg) arg, _ = self._depends[arg] resolved_arg = self._results.get(arg) else: raise TypeError( "Cannot use object of type '%s' as argument to @depends" % type(arg)) resolved_args.append(resolved_arg) 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)(DummyFunction()) self._depends[dummy] = func, dependencies with_help = self._help_option in dependencies if with_help: for arg in args: if isinstance(arg, DummyFunction): _, deps = self._depends[arg] if self._help_option not in deps: raise ConfigureError( "`%s` depends on '--help' and `%s`. " "`%s` must depend on '--help'" % (func.__name__, arg.__name__, arg.__name__)) if not self._help or with_help: self._results[func] = func(*resolved_args) return dummy return decorator
def depends_impl(self, *args): '''Implementation of @depends() This function is a decorator. It returns a function that subsequently takes a function and returns a dummy function. The dummy function identifies the actual function for the sandbox, while preventing further function calls from within the sandbox. @depends() takes a variable number of option strings or dummy function references. The decorated function is called as soon as the decorator is called, and the arguments it receives are the OptionValue or function results corresponding to each of the arguments to @depends. As an exception, when a HelpFormatter is attached, only functions that have '--help' in their @depends argument list are called. The decorated function is altered to use a different global namespace for its execution. This different global namespace exposes a limited set of functions from os.path, and two additional functions: `imply_option` and `set_config`. The former allows to inject additional options as if they had been passed on the command line. The latter declares new configuration items for consumption by moz.build. ''' if not args: raise ConfigureError('@depends needs at least one argument') with_help = False resolved_args = [] for arg in args: if isinstance(arg, types.StringTypes): prefix, name, values = Option.split_option(arg) if values != (): raise ConfigureError("Option must not contain an '='") if name not in self._options: raise ConfigureError("'%s' is not a known option. " "Maybe it's declared too late?" % arg) arg = self._options[name] if arg == self._help_option: with_help = True self._seen.add(arg) assert arg in self._db or self._help resolved_arg = self._db.get(arg) elif isinstance(arg, DummyFunction): assert arg in self._depends arg = self._depends[arg] resolved_arg = self._results.get(arg) else: raise TypeError( "Cannot use object of type '%s' as argument to @depends" % type(arg)) resolved_args.append(resolved_arg) def decorator(func): if inspect.isgeneratorfunction(func): raise ConfigureError( 'Cannot decorate generator functions with @depends') func, glob = self._prepare_function(func) result = DependsOutput() glob.update( imply_option=result.imply_option, set_config=result.__setitem__, ) dummy = wraps(func)(DummyFunction()) self._depends[dummy] = func func.with_help = with_help if with_help: for arg in args: if (isinstance(arg, DummyFunction) and not self._depends[arg].with_help): raise ConfigureError( "`%s` depends on '--help' and `%s`. " "`%s` must depend on '--help'" % (func.__name__, arg.__name__, arg.__name__)) if self._help and not with_help: return dummy self._results[func] = func(*resolved_args) for option, reason in result.implied_options: self._helper.add(option, 'implied') if not reason: deps = [] for name, value in zip(args, resolved_args): if not isinstance(value, OptionValue): raise ConfigureError( "Cannot infer what implied '%s'" % option) if name == '--help': continue deps.append(value.format(self._db.get(value) or name)) if len(deps) != 1: raise ConfigureError("Cannot infer what implied '%s'" % option) reason = deps[0] self._implied_options[option] = func, reason if not self._help: for k, v in result.iteritems(): if k in self._config: raise ConfigureError( "Cannot add '%s' to configuration: Key already " "exists" % k) self._config[k] = v return dummy return decorator