def mock_console( options_bootstrapper: OptionsBootstrapper, *, stdin_content: bytes | str | None = None, ) -> Iterator[Tuple[Console, StdioReader]]: global_bootstrap_options = options_bootstrapper.bootstrap_options.for_global_scope( ) @contextmanager def stdin_context(): if stdin_content is None: yield open("/dev/null", "r") else: with temporary_file(binary_mode=isinstance(stdin_content, bytes)) as stdin_file: stdin_file.write(stdin_content) stdin_file.close() yield open(stdin_file.name, "r") with initialize_stdio(global_bootstrap_options), stdin_context( ) as stdin, temporary_file(binary_mode=False) as stdout, temporary_file( binary_mode=False) as stderr, stdio_destination( stdin_fileno=stdin.fileno(), stdout_fileno=stdout.fileno(), stderr_fileno=stderr.fileno(), ): # NB: We yield a Console without overriding the destination argument, because we have # already done a sys.std* level replacement. The replacement is necessary in order for # InteractiveProcess to have native file handles to interact with. yield Console(use_colors=global_bootstrap_options.colors), StdioReader( _stdout=Path(stdout.name), _stderr=Path(stderr.name))
def __call__( self, command: str, args: Tuple[str, ...], env: Dict[str, str], cancellation_latch: PySessionCancellationLatch, stdin_fileno: int, stdout_fileno: int, stderr_fileno: int, ) -> ExitCode: request_timeout = float(env.get("PANTSD_REQUEST_TIMEOUT_LIMIT", -1)) # NB: Order matters: we acquire a lock before mutating either `sys.std*`, `os.environ`, etc. with self._one_run_at_a_time( stderr_fileno, cancellation_latch=cancellation_latch, timeout=request_timeout, ): # NB: `single_daemonized_run` implements exception handling, so only the most primitive # errors will escape this function, where they will be logged by the server. logger.info(f"handling request: `{' '.join(args)}`") try: with stdio_destination( stdin_fileno=stdin_fileno, stdout_fileno=stdout_fileno, stderr_fileno=stderr_fileno, ): return self.single_daemonized_run(((command,) + args), env, cancellation_latch) finally: logger.info(f"request completed: `{' '.join(args)}`")
def wrapper(*args, **kwargs): stdout_fileno, stderr_fileno = sys.stdout.fileno( ), sys.stderr.fileno() with temporary_dir() as tempdir, initialize_stdio_raw( level, False, False, {}, True, [], tempdir), stdin_context() as stdin, stdio_destination( stdin.fileno(), stdout_fileno, stderr_fileno): return func(*args, **kwargs)
def run(self, start_time: float) -> ExitCode: self.scrub_pythonpath() options_bootstrapper = OptionsBootstrapper.create(env=self.env, args=self.args, allow_pantsrc=True) with warnings.catch_warnings(record=True): bootstrap_options = options_bootstrapper.bootstrap_options global_bootstrap_options = bootstrap_options.for_global_scope() # We enable logging here, and everything before it will be routed through regular # Python logging. stdin_fileno = sys.stdin.fileno() stdout_fileno = sys.stdout.fileno() stderr_fileno = sys.stderr.fileno() with initialize_stdio(global_bootstrap_options), stdio_destination( stdin_fileno=stdin_fileno, stdout_fileno=stdout_fileno, stderr_fileno=stderr_fileno, ): # N.B. We inline imports to speed up the python thin client run, and avoids importing # engine types until after the runner has had a chance to set PANTS_BIN_NAME. if self._should_run_with_pantsd(global_bootstrap_options): from pants.bin.remote_pants_runner import RemotePantsRunner try: remote_runner = RemotePantsRunner(self.args, self.env, options_bootstrapper) return remote_runner.run(start_time) except RemotePantsRunner.Fallback as e: logger.warning( f"Client exception: {e!r}, falling back to non-daemon mode" ) from pants.bin.local_pants_runner import LocalPantsRunner # We only install signal handling via ExceptionSink if the run will execute in this process. ExceptionSink.install( log_location=init_workdir(global_bootstrap_options), pantsd_instance=False) runner = LocalPantsRunner.create( env=CompleteEnvironment(self.env), options_bootstrapper=options_bootstrapper) return runner.run(start_time)
def mock_console( options_bootstrapper: OptionsBootstrapper, ) -> Iterator[Tuple[Console, StdioReader]]: global_bootstrap_options = options_bootstrapper.bootstrap_options.for_global_scope( ) with initialize_stdio(global_bootstrap_options), open( "/dev/null", "r") as stdin, temporary_file( binary_mode=False) as stdout, temporary_file( binary_mode=False) as stderr, stdio_destination( stdin_fileno=stdin.fileno(), stdout_fileno=stdout.fileno(), stderr_fileno=stderr.fileno(), ): # NB: We yield a Console without overriding the destination argument, because we have # already done a sys.std* level replacement. The replacement is necessary in order for # InteractiveProcess to have native file handles to interact with. yield Console(use_colors=global_bootstrap_options.colors), StdioReader( _stdout=Path(stdout.name), _stderr=Path(stderr.name))
def mock_console( options_bootstrapper: OptionsBootstrapper, *, stdin_content: bytes | str | None = None, ) -> Iterator[tuple[Console, StdioReader]]: global_bootstrap_options = options_bootstrapper.bootstrap_options.for_global_scope( ) colors = (options_bootstrapper.full_options_for_scopes( [GlobalOptions.get_scope_info()], allow_unknown_options=True).for_global_scope().colors) with initialize_stdio(global_bootstrap_options), stdin_context( stdin_content) as stdin, temporary_file( binary_mode=False) as stdout, temporary_file( binary_mode=False) as stderr, stdio_destination( stdin_fileno=stdin.fileno(), stdout_fileno=stdout.fileno(), stderr_fileno=stderr.fileno(), ): # NB: We yield a Console without overriding the destination argument, because we have # already done a sys.std* level replacement. The replacement is necessary in order for # InteractiveProcess to have native file handles to interact with. yield Console(use_colors=colors), StdioReader( _stdout=Path(stdout.name), _stderr=Path(stderr.name))