Exemple #1
0
 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
Exemple #2
0
 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
Exemple #3
0
    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,
        ))
Exemple #4
0
    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
Exemple #5
0
    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,
        ))
Exemple #6
0
    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
Exemple #7
0
    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
Exemple #8
0
    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