Esempio n. 1
0
def create_dynamic_remote_options(
    *,
    initial_headers: dict[str, str] | None = None,
    address: str | None = "grpc://fake.url:10",
    token_path: str | None = None,
    plugin: str | None = None,
) -> DynamicRemoteOptions:
    if initial_headers is None:
        initial_headers = {}
    args = [
        "--remote-cache-read",
        f"--remote-execution-address={address}",
        f"--remote-store-address={address}",
        f"--remote-store-headers={initial_headers}",
        f"--remote-execution-headers={initial_headers}",
        "--remote-instance-name=main",
    ]
    if token_path:
        args.append(f"--remote-oauth-bearer-token-path={token_path}")
    if plugin:
        args.append(f"--remote-auth-plugin={plugin}")
    ob = create_options_bootstrapper(args)
    env = CompleteEnvironment({})
    _build_config, options = OptionsInitializer(ob).build_config_and_options(ob, env, raise_=False)
    return DynamicRemoteOptions.from_options(options, env)[0]
Esempio n. 2
0
 def _init_graph_session(
     cls,
     options_initializer: OptionsInitializer,
     options_bootstrapper: OptionsBootstrapper,
     build_config: BuildConfiguration,
     env: CompleteEnvironment,
     run_id: str,
     options: Options,
     scheduler: Optional[GraphScheduler] = None,
     cancellation_latch: Optional[PySessionCancellationLatch] = None,
 ) -> GraphSession:
     native_engine.maybe_set_panic_handler()
     if scheduler is None:
         dynamic_remote_options, _ = DynamicRemoteOptions.from_options(options, env)
         bootstrap_options = options.bootstrap_option_values()
         assert bootstrap_options is not None
         scheduler = EngineInitializer.setup_graph(
             bootstrap_options, build_config, dynamic_remote_options
         )
     with options_initializer.handle_unknown_flags(options_bootstrapper, env, raise_=True):
         global_options = options.for_global_scope()
     return scheduler.new_session(
         run_id,
         dynamic_ui=global_options.dynamic_ui,
         use_colors=global_options.get("colors", True),
         session_values=SessionValues(
             {
                 OptionsBootstrapper: options_bootstrapper,
                 CompleteEnvironment: env,
             }
         ),
         cancellation_latch=cancellation_latch,
     )
Esempio n. 3
0
    def prepare(
            self, options_bootstrapper: OptionsBootstrapper,
            env: CompleteEnvironment
    ) -> tuple[GraphScheduler, OptionsInitializer]:
        """Get a scheduler for the given options_bootstrapper.

        Runs in a client context (generally in DaemonPantsRunner) so logging is sent to the client.
        """

        with self._handle_exceptions():
            build_config, options = self._options_initializer.build_config_and_options(
                options_bootstrapper, env, raise_=True)

        scheduler_restart_explanation: str | None = None

        # Because these options are computed dynamically via side-effects like reading from a file,
        # they need to be re-evaluated every run. We only reinitialize the scheduler if changes
        # were made, though.
        dynamic_remote_options, auth_plugin_result = DynamicRemoteOptions.from_options(
            options, env, self._prior_auth_plugin_result)
        remote_options_changed = (
            self._prior_dynamic_remote_options is not None
            and dynamic_remote_options != self._prior_dynamic_remote_options)
        if remote_options_changed:
            scheduler_restart_explanation = "Remote cache/execution options updated"

        # Compute the fingerprint of the bootstrap options. Note that unlike
        # PantsDaemonProcessManager (which fingerprints only `daemon=True` options), this
        # fingerprints all fingerprintable options in the bootstrap options, which are
        # all used to construct a Scheduler.
        options_fingerprint = OptionsFingerprinter.combined_options_fingerprint_for_scope(
            GLOBAL_SCOPE,
            options_bootstrapper.bootstrap_options,
        )
        bootstrap_options_changed = (self._fingerprint is not None and
                                     options_fingerprint != self._fingerprint)
        if bootstrap_options_changed:
            scheduler_restart_explanation = "Initialization options changed"

        with self._lifecycle_lock:
            if self._scheduler is None or scheduler_restart_explanation:
                # The fingerprint mismatches, either because this is the first run (and there is no
                # fingerprint) or because relevant options have changed. Create a new scheduler
                # and services.
                bootstrap_options = options.bootstrap_option_values()
                assert bootstrap_options is not None
                with self._handle_exceptions():
                    self._initialize(
                        options_fingerprint,
                        bootstrap_options,
                        build_config,
                        dynamic_remote_options,
                        scheduler_restart_explanation,
                    )

            self._prior_dynamic_remote_options = dynamic_remote_options
            self._prior_auth_plugin_result = auth_plugin_result

            assert self._scheduler is not None
            return self._scheduler, self._options_initializer
Esempio n. 4
0
def create_bootstrap_scheduler(
        options_bootstrapper: OptionsBootstrapper,
        executor: PyExecutor | None = None) -> BootstrapScheduler:
    bc_builder = BuildConfiguration.Builder()
    # To load plugins, we only need access to the Python/PEX rules.
    load_build_configuration_from_source(bc_builder, ["pants.backend.python"])
    # And to plugin-loading-specific rules.
    bc_builder.register_rules("_dummy_for_bootstrapping_",
                              plugin_resolver_rules())
    # We allow unrecognized options to defer any option error handling until post-bootstrap.
    bc_builder.allow_unknown_options()
    return BootstrapScheduler(
        EngineInitializer.setup_graph(
            options_bootstrapper.bootstrap_options.for_global_scope(),
            bc_builder.create(),
            DynamicRemoteOptions.disabled(),
            executor,
        ).scheduler)
Esempio n. 5
0
 def _init_graph_session(
     cls,
     options_initializer: OptionsInitializer,
     options_bootstrapper: OptionsBootstrapper,
     build_config: BuildConfiguration,
     env: CompleteEnvironment,
     run_id: str,
     options: Options,
     scheduler: GraphScheduler | None = None,
     cancellation_latch: PySessionCancellationLatch | None = None,
 ) -> GraphSession:
     native_engine.maybe_set_panic_handler()
     if scheduler is None:
         dynamic_remote_options, _ = DynamicRemoteOptions.from_options(options, env)
         bootstrap_options = options.bootstrap_option_values()
         assert bootstrap_options is not None
         scheduler = EngineInitializer.setup_graph(
             bootstrap_options, build_config, dynamic_remote_options
         )
     with options_initializer.handle_unknown_flags(options_bootstrapper, env, raise_=True):
         global_options = options.for_global_scope()
     return scheduler.new_session(
         run_id,
         dynamic_ui=global_options.dynamic_ui,
         ui_use_prodash=global_options.dynamic_ui_renderer
         == DynamicUIRenderer.experimental_prodash,
         use_colors=global_options.get("colors", True),
         max_workunit_level=max(
             global_options.streaming_workunits_level,
             global_options.level,
             *(
                 LogLevel[level.upper()]
                 for level in global_options.log_levels_by_target.values()
             ),
         ),
         session_values=SessionValues(
             {
                 OptionsBootstrapper: options_bootstrapper,
                 CompleteEnvironment: env,
             }
         ),
         cancellation_latch=cancellation_latch,
     )
Esempio n. 6
0
    def __init__(
            self,
            *,
            rules: Iterable | None = None,
            target_types: Iterable[type[Target]] | None = None,
            objects: dict[str, Any] | None = None,
            context_aware_object_factories: dict[str, Any] | None = None,
            isolated_local_store: bool = False,
            preserve_tmpdirs: bool = False,
            ca_certs_path: str | None = None,
            bootstrap_args: Iterable[str] = (),
    ) -> None:

        bootstrap_args = [*bootstrap_args]

        root_dir: Path | None = None
        if preserve_tmpdirs:
            root_dir = Path(mkdtemp(prefix="RuleRunner."))
            print(
                f"Preserving rule runner temporary directories at {root_dir}.",
                file=sys.stderr)
            bootstrap_args.extend([
                "--no-process-execution-local-cleanup",
                f"--local-execution-root-dir={root_dir}",
            ])
            build_root = (root_dir / "BUILD_ROOT").resolve()
            build_root.mkdir()
            self.build_root = str(build_root)
        else:
            self.build_root = os.path.realpath(
                safe_mkdtemp(prefix="_BUILD_ROOT"))

        safe_mkdir(self.pants_workdir)
        BuildRoot().path = self.build_root

        # TODO: Redesign rule registration for tests to be more ergonomic and to make this less
        #  special-cased.
        all_rules = (
            *(rules or ()),
            *source_root.rules(),
            QueryRule(WrappedTarget, [Address]),
            QueryRule(UnionMembership, []),
        )
        build_config_builder = BuildConfiguration.Builder()
        build_config_builder.register_aliases(
            BuildFileAliases(
                objects=objects,
                context_aware_object_factories=context_aware_object_factories))
        build_config_builder.register_rules("_dummy_for_test_", all_rules)
        build_config_builder.register_target_types("_dummy_for_test_",
                                                   target_types or ())
        self.build_config = build_config_builder.create()

        self.environment = CompleteEnvironment({})
        self.options_bootstrapper = create_options_bootstrapper(
            args=bootstrap_args)
        options = self.options_bootstrapper.full_options(self.build_config)
        global_options = self.options_bootstrapper.bootstrap_options.for_global_scope(
        )

        dynamic_remote_options, _ = DynamicRemoteOptions.from_options(
            options, self.environment)
        local_store_options = LocalStoreOptions.from_options(global_options)
        if isolated_local_store:
            if root_dir:
                lmdb_store_dir = root_dir / "lmdb_store"
                lmdb_store_dir.mkdir()
                store_dir = str(lmdb_store_dir)
            else:
                store_dir = safe_mkdtemp(prefix="lmdb_store.")
            local_store_options = dataclasses.replace(local_store_options,
                                                      store_dir=store_dir)

        local_execution_root_dir = global_options.local_execution_root_dir
        named_caches_dir = global_options.named_caches_dir

        graph_session = EngineInitializer.setup_graph_extended(
            pants_ignore_patterns=GlobalOptions.compute_pants_ignore(
                self.build_root, global_options),
            use_gitignore=False,
            local_store_options=local_store_options,
            local_execution_root_dir=local_execution_root_dir,
            named_caches_dir=named_caches_dir,
            build_root=self.build_root,
            build_configuration=self.build_config,
            executor=_EXECUTOR,
            execution_options=ExecutionOptions.from_options(
                global_options, dynamic_remote_options),
            ca_certs_path=ca_certs_path,
            engine_visualize_to=None,
        ).new_session(
            build_id="buildid_for_test",
            session_values=SessionValues({
                OptionsBootstrapper: self.options_bootstrapper,
                CompleteEnvironment: self.environment,
            }),
        )
        self.scheduler = graph_session.scheduler_session