예제 #1
0
    def validate_instance(cls, opts):
        """Validates an instance of global options for cases that are not prohibited via registration.

    For example: mutually exclusive options may be registered by passing a `mutually_exclusive_group`,
    but when multiple flags must be specified together, it can be necessary to specify post-parse
    checks.

    Raises pants.option.errors.OptionsError on validation failure.
    """
        if opts.loop and (not opts.v2 or opts.v1):
            raise OptionsError(
                'The `--loop` option only works with @console_rules, and thus requires '
                '`--v2 --no-v1` to function as expected.')
        if opts.loop and not opts.enable_pantsd:
            raise OptionsError(
                'The `--loop` option requires `--enable-pantsd`, in order to watch files.'
            )

        if opts.v2_ui and not opts.v2:
            raise OptionsError(
                'The `--v2-ui` option requires `--v2` to be enabled together.')

        if opts.remote_execution and not opts.remote_execution_server:
            raise OptionsError(
                "The `--remote-execution` option requires also setting "
                "`--remote-execution-server` to work properly.")

        if opts.remote_execution_server and not opts.remote_store_server:
            raise OptionsError(
                "The `--remote-execution-server` option requires also setting "
                "`--remote-store-server`. Often these have the same value.")
예제 #2
0
    def validate_instance(cls, opts):
        """Validates an instance of global options for cases that are not prohibited via
        registration.

        For example: mutually exclusive options may be registered by passing a `mutually_exclusive_group`,
        but when multiple flags must be specified together, it can be necessary to specify post-parse
        checks.

        Raises pants.option.errors.OptionsError on validation failure.
        """
        if opts.remote_execution and not opts.remote_execution_server:
            raise OptionsError(
                "The `--remote-execution` option requires also setting "
                "`--remote-execution-server` to work properly.")

        if opts.remote_execution_server and not opts.remote_store_server:
            raise OptionsError(
                "The `--remote-execution-server` option requires also setting "
                "`--remote-store-server`. Often these have the same value.")
        if opts.remote_cache_read and not opts.remote_store_server:
            raise OptionsError(
                "The `--remote-cache-read` option requires also setting "
                "`--remote-store-server` to work properly.")
        if opts.remote_cache_write and not opts.remote_store_server:
            raise OptionsError(
                "The `--remote-cache-write` option requires also setting "
                "`--remote-store-server` to work properly.")
예제 #3
0
 def validate_scope(cls) -> None:
     options_scope = getattr(cls, "options_scope", None)
     if options_scope is None:
         raise OptionsError(f"{cls.__name__} must set options_scope.")
     if not cls.is_valid_scope_name(options_scope):
         raise OptionsError(
             f'Options scope "{options_scope}" is not valid:\nReplace in code with a new '
             "scope name consisting of only lower-case letters, digits, underscores, "
             "and non-consecutive dashes.")
예제 #4
0
 def validate_headers(opt_name: str) -> None:
     command_line_opt_name = f"--{opt_name.replace('_', '-')}"
     for k, v in getattr(opts, opt_name).items():
         if not k.isascii():
             raise OptionsError(
                 f"All values in `{command_line_opt_name}` must be ASCII, but the key "
                 f"in `{k}: {v}` has non-ASCII characters.")
         if not v.isascii():
             raise OptionsError(
                 f"All values in `{command_line_opt_name}` must be ASCII, but the value in "
                 f"`{k}: {v}` has non-ASCII characters.")
예제 #5
0
  def validate_instance(cls, opts):
    """Validates an instance of global options for cases that are not prohibited via registration.

    For example: mutually exclusive options may be registered by passing a `mutually_exclusive_group`,
    but when multiple flags must be specified together, it can be necessary to specify post-parse
    checks.

    Raises pants.option.errors.OptionsError on validation failure.
    """
    if opts.loop and (not opts.v2 or opts.v1):
      raise OptionsError('The --loop option only works with @console_rules, and thus requires '
                         '`--v2 --no-v1` to function as expected.')
    if opts.loop and not opts.enable_pantsd:
      raise OptionsError('The --loop option requires `--enable-pantsd`, in order to watch files.')
예제 #6
0
    def verify_configs_against_options(self, options):
        """Verify all loaded configs have correct scopes and options.

    :param options: Fully bootstrapped valid options.
    :return: None.
    """
        has_error = False
        for config in self._post_bootstrap_config.configs:
            for section in config.sections():
                if section == GLOBAL_SCOPE_CONFIG_SECTION:
                    scope = GLOBAL_SCOPE
                else:
                    scope = section
                try:
                    valid_options_under_scope = set(options.for_scope(scope))
                except OptionsError:
                    logger.error("Invalid scope [{}] in {}".format(
                        section, config.configpath))
                    has_error = True
                else:
                    # All the options specified under [`section`] in `config` excluding bootstrap defaults.
                    all_options_under_scope = set(
                        config.configparser.options(section)) - set(
                            config.configparser.defaults())
                    for option in all_options_under_scope:
                        if option not in valid_options_under_scope:
                            logger.error(
                                "Invalid option '{}' under [{}] in {}".format(
                                    option, section, config.configpath))
                            has_error = True

        if has_error:
            raise OptionsError(
                "Invalid config entries detected. See log for details.")
예제 #7
0
 def get_scope_info(cls):
     """Returns a ScopeInfo instance representing this Optionable's options scope."""
     if cls.options_scope is None or cls.options_scope_category is None:
         raise OptionsError(
             '{} must set options_scope and options_scope_category.'.format(
                 cls.__name__))
     return ScopeInfo(cls.options_scope, cls.options_scope_category, cls)
예제 #8
0
 def validate_scope_name_component(cls, s):
     if not cls.is_valid_scope_name_component(s):
         raise OptionsError(
             'Options scope "{}" is not valid:\n'
             'Replace in code with a new scope name consisting of dash-separated-words, '
             'with words consisting only of lower-case letters and digits.'.
             format(s))
예제 #9
0
 def main(self) -> MainSpecification:
     is_default_console_script = self.options.is_default("console_script")
     is_default_entry_point = self.options.is_default("entry_point")
     if not is_default_console_script and not is_default_entry_point:
         raise OptionsError(
             f"Both [{self.scope}].console-script={self.options.console_script} and "
             f"[{self.scope}].entry-point={self.options.entry_point} are configured but these "
             f"options are mutually exclusive. Please pick one.")
     if not is_default_console_script:
         return ConsoleScript(cast(str, self.options.console_script))
     if not is_default_entry_point:
         return EntryPoint.parse(cast(str, self.options.entry_point))
     return self.default_main
예제 #10
0
    def validate_instance(cls, opts):
        """Validates an instance of global options for cases that are not prohibited via
        registration.

        For example: mutually exclusive options may be registered by passing a `mutually_exclusive_group`,
        but when multiple flags must be specified together, it can be necessary to specify post-parse
        checks.

        Raises pants.option.errors.OptionsError on validation failure.
        """
        if opts.remote_execution and not opts.remote_execution_server:
            raise OptionsError(
                "The `--remote-execution` option requires also setting "
                "`--remote-execution-server` to work properly.")

        if opts.remote_execution_server and not opts.remote_store_server:
            raise OptionsError(
                "The `--remote-execution-server` option requires also setting "
                "`--remote-store-server`. Often these have the same value.")
        if opts.remote_cache_read and not opts.remote_store_server:
            raise OptionsError(
                "The `--remote-cache-read` option requires also setting "
                "`--remote-store-server` to work properly.")
        if opts.remote_cache_write and not opts.remote_store_server:
            raise OptionsError(
                "The `--remote-cache-write` option requires also setting "
                "`--remote-store-server` to work properly.")

        if opts.remote_execution and (opts.remote_cache_read
                                      or opts.remote_cache_write):
            raise OptionsError(
                "`--remote-execution` cannot be set at the same time as either "
                "`--remote-cache-read` or `--remote-cache-write`.\n\nIf remote execution is "
                "enabled, it will already use remote caching.")

        # Ensure that timeout values are non-zero.
        if opts.remote_store_initial_timeout <= 0:
            raise OptionsError(
                "The --remote-store-initial-timeout option requires a positive number of "
                "milliseconds.")
        if opts.remote_store_timeout_multiplier <= 0.0:
            raise OptionsError(
                "The --remote-store-timeout-multiplier option requires a positive number for the "
                "multiplier.")
        if opts.remote_store_maximum_timeout <= 0:
            raise OptionsError(
                "The --remote-store-initial-timeout option requires a positive number of "
                "milliseconds.")
예제 #11
0
 def main(self) -> MainSpecification:
     is_default_console_script = self.options.is_default("console_script")
     is_default_entry_point = self.options.is_default("entry_point")
     if not is_default_console_script and not is_default_entry_point:
         raise OptionsError(
             softwrap(f"""
                 Both [{self.options_scope}].console-script={self.console_script} and
                 [{self.options_scope}].entry-point={self.entry_point} are configured
                 but these options are mutually exclusive. Please pick one.
                 """))
     if not is_default_console_script:
         assert self.console_script is not None
         return ConsoleScript(self.console_script)
     if not is_default_entry_point:
         assert self.entry_point is not None
         return EntryPoint.parse(self.entry_point)
     return self.default_main
예제 #12
0
 def get_scope_info(cls):
     """Returns a ScopeInfo instance representing this Optionable's options scope."""
     if cls.options_scope is None:
         raise OptionsError(f"{cls.__name__} must set options_scope.")
     return ScopeInfo(cls.options_scope, cls)
예제 #13
0
 def validate_scope_name_component(cls, s: str) -> None:
     if not cls.is_valid_scope_name_component(s):
         raise OptionsError(
             f'Options scope "{s}" is not valid:\nReplace in code with a new scope name consisting of '
             f"dash-separated-words, with words consisting only of lower-case letters and digits."
         )
예제 #14
0
 def get_parser_by_scope(self, scope):
   try:
     return self._parser_by_scope[scope]
   except KeyError:
     raise OptionsError('No such options scope: {}'.format(scope))
예제 #15
0
    def from_options(cls, options: Options) -> ExecutionOptions:
        bootstrap_options = options.bootstrap_option_values()
        assert bootstrap_options is not None
        # Possibly insert some headers and disable remote execution/caching.
        remote_execution_headers = cast(
            Dict[str, str], bootstrap_options.remote_execution_headers)
        remote_store_headers = cast(Dict[str, str],
                                    bootstrap_options.remote_store_headers)
        remote_execution = cast(bool, bootstrap_options.remote_execution)
        remote_cache_read = cast(bool, bootstrap_options.remote_cache_read)
        remote_cache_write = cast(bool, bootstrap_options.remote_cache_write)
        if bootstrap_options.remote_oauth_bearer_token_path:
            oauth_token = (Path(
                bootstrap_options.remote_oauth_bearer_token_path).resolve().
                           read_text().strip())
            if set(oauth_token).intersection({"\n", "\r"}):
                raise OptionsError(
                    f"OAuth bearer token path {bootstrap_options.remote_oauth_bearer_token_path} "
                    "must not contain multiple lines.")
            token_header = {"authorization": f"Bearer {oauth_token}"}
            remote_execution_headers.update(token_header)
            remote_store_headers.update(token_header)
        if bootstrap_options.remote_auth_plugin and (remote_execution
                                                     or remote_cache_read
                                                     or remote_cache_write):
            if ":" not in bootstrap_options.remote_auth_plugin:
                raise OptionsError(
                    "Invalid value for `--remote-auth-plugin`: "
                    f"{bootstrap_options.remote_auth_plugin}. Please use the format "
                    f"`path.to.module:my_func`.")
            auth_plugin_path, auth_plugin_func = bootstrap_options.remote_auth_plugin.split(
                ":")
            auth_plugin_module = importlib.import_module(auth_plugin_path)
            auth_plugin_func = getattr(auth_plugin_module, auth_plugin_func)
            auth_plugin_result = cast(
                AuthPluginResult,
                auth_plugin_func(
                    initial_execution_headers=remote_execution_headers,
                    initial_store_headers=remote_store_headers,
                    options=options,
                ),
            )
            if not auth_plugin_result.is_available:
                # NB: This is debug because we expect plugins to log more informative messages.
                logger.debug(
                    "Disabling remote caching and remote execution because authentication was not "
                    "available via the plugin from `--remote-auth-plugin`.")
                remote_execution = False
                remote_cache_read = False
                remote_cache_write = False
            else:
                remote_execution_headers = auth_plugin_result.execution_headers
                remote_store_headers = auth_plugin_result.store_headers

        return cls(
            # Remote execution strategy.
            remote_execution=remote_execution,
            remote_cache_read=remote_cache_read,
            remote_cache_write=remote_cache_write,
            # General remote setup.
            remote_instance_name=bootstrap_options.remote_instance_name,
            remote_ca_certs_path=bootstrap_options.remote_ca_certs_path,
            # Process execution setup.
            process_execution_local_parallelism=bootstrap_options.
            process_execution_local_parallelism,
            process_execution_remote_parallelism=bootstrap_options.
            process_execution_remote_parallelism,
            process_execution_cleanup_local_dirs=bootstrap_options.
            process_execution_cleanup_local_dirs,
            process_execution_use_local_cache=bootstrap_options.
            process_execution_use_local_cache,
            process_execution_cache_namespace=bootstrap_options.
            process_execution_cache_namespace,
            process_execution_local_enable_nailgun=bootstrap_options.
            process_execution_local_enable_nailgun,
            # Remote store setup.
            remote_store_server=bootstrap_options.remote_store_server,
            remote_store_headers=remote_store_headers,
            remote_store_thread_count=bootstrap_options.
            remote_store_thread_count,
            remote_store_chunk_bytes=bootstrap_options.
            remote_store_chunk_bytes,
            remote_store_chunk_upload_timeout_seconds=bootstrap_options.
            remote_store_chunk_upload_timeout_seconds,
            remote_store_rpc_retries=bootstrap_options.
            remote_store_rpc_retries,
            remote_store_connection_limit=bootstrap_options.
            remote_store_connection_limit,
            remote_store_initial_timeout=bootstrap_options.
            remote_store_initial_timeout,
            remote_store_timeout_multiplier=bootstrap_options.
            remote_store_timeout_multiplier,
            remote_store_maximum_timeout=bootstrap_options.
            remote_store_maximum_timeout,
            # Remote cache setup.
            remote_cache_eager_fetch=bootstrap_options.
            remote_cache_eager_fetch,
            # Remote execution setup.
            remote_execution_server=bootstrap_options.remote_execution_server,
            remote_execution_extra_platform_properties=bootstrap_options.
            remote_execution_extra_platform_properties,
            remote_execution_headers=remote_execution_headers,
            remote_execution_overall_deadline_secs=bootstrap_options.
            remote_execution_overall_deadline_secs,
        )
예제 #16
0
    def validate_instance(cls, opts):
        """Validates an instance of global options for cases that are not prohibited via
        registration.

        For example: mutually exclusive options may be registered by passing a `mutually_exclusive_group`,
        but when multiple flags must be specified together, it can be necessary to specify post-parse
        checks.

        Raises pants.option.errors.OptionsError on validation failure.
        """
        if opts.remote_execution and (opts.remote_cache_read
                                      or opts.remote_cache_write):
            raise OptionsError(
                "`--remote-execution` cannot be set at the same time as either "
                "`--remote-cache-read` or `--remote-cache-write`.\n\nIf remote execution is "
                "enabled, it will already use remote caching.")

        if opts.remote_execution and not opts.remote_execution_server:
            raise OptionsError(
                "The `--remote-execution` option requires also setting "
                "`--remote-execution-server` to work properly.")
        if opts.remote_execution_server and not opts.remote_store_server:
            raise OptionsError(
                "The `--remote-execution-server` option requires also setting "
                "`--remote-store-server`. Often these have the same value.")

        if opts.remote_cache_read and not opts.remote_store_server:
            raise OptionsError(
                "The `--remote-cache-read` option requires also setting "
                "`--remote-store-server` to work properly.")
        if opts.remote_cache_write and not opts.remote_store_server:
            raise OptionsError(
                "The `--remote-cache-write` option requires also setting "
                "`--remote-store-server` to work properly.")

        # Ensure that timeout values are non-zero.
        if opts.remote_store_initial_timeout <= 0:
            raise OptionsError(
                "The --remote-store-initial-timeout option requires a positive number of "
                "milliseconds.")
        if opts.remote_store_timeout_multiplier <= 0.0:
            raise OptionsError(
                "The --remote-store-timeout-multiplier option requires a positive number for the "
                "multiplier.")
        if opts.remote_store_maximum_timeout <= 0:
            raise OptionsError(
                "The --remote-store-initial-timeout option requires a positive number of "
                "milliseconds.")

        # Ensure that remote headers are ASCII.
        def validate_headers(opt_name: str) -> None:
            command_line_opt_name = f"--{opt_name.replace('_', '-')}"
            for k, v in getattr(opts, opt_name).items():
                if not k.isascii():
                    raise OptionsError(
                        f"All values in `{command_line_opt_name}` must be ASCII, but the key "
                        f"in `{k}: {v}` has non-ASCII characters.")
                if not v.isascii():
                    raise OptionsError(
                        f"All values in `{command_line_opt_name}` must be ASCII, but the value in "
                        f"`{k}: {v}` has non-ASCII characters.")

        validate_headers("remote_execution_headers")
        validate_headers("remote_store_headers")