def create(cls, options_bootstrapper: OptionsBootstrapper) -> PantsDaemon: # Any warnings that would be triggered here are re-triggered later per-run of Pants, so we # silence them. with warnings.catch_warnings(record=True): bootstrap_options = options_bootstrapper.bootstrap_options bootstrap_options_values = bootstrap_options.for_global_scope() native = Native() executor = PyExecutor(*GlobalOptions.compute_executor_arguments(bootstrap_options_values)) core = PantsDaemonCore(options_bootstrapper, executor, cls._setup_services) server = native.new_nailgun_server( executor, bootstrap_options_values.pantsd_pailgun_port, DaemonPantsRunner(core), ) return PantsDaemon( native=native, work_dir=bootstrap_options_values.pants_workdir, log_level=bootstrap_options_values.level, server=server, core=core, metadata_base_dir=bootstrap_options_values.pants_subprocessdir, bootstrap_options=bootstrap_options, )
def setup_graph( options_bootstrapper: OptionsBootstrapper, build_configuration: BuildConfiguration, env: CompleteEnvironment, executor: Optional[PyExecutor] = None, local_only: bool = False, ) -> GraphScheduler: native = Native() build_root = get_buildroot() bootstrap_options = options_bootstrapper.bootstrap_options.for_global_scope( ) options = options_bootstrapper.full_options(build_configuration) assert bootstrap_options is not None executor = executor or PyExecutor( *GlobalOptions.compute_executor_arguments(bootstrap_options)) execution_options = ExecutionOptions.from_options( options, env, local_only=local_only) return EngineInitializer.setup_graph_extended( build_configuration, execution_options, native=native, executor=executor, pants_ignore_patterns=GlobalOptions.compute_pants_ignore( build_root, bootstrap_options), use_gitignore=bootstrap_options.pants_ignore_use_gitignore, local_store_dir=bootstrap_options.local_store_dir, local_execution_root_dir=bootstrap_options. local_execution_root_dir, named_caches_dir=bootstrap_options.named_caches_dir, ca_certs_path=bootstrap_options.ca_certs_path, build_root=build_root, include_trace_on_error=bootstrap_options.print_stacktrace, native_engine_visualize_to=bootstrap_options. native_engine_visualize_to, )
def _connect_and_execute(self, pantsd_handle: PantsDaemonClient.Handle) -> ExitCode: native = Native() global_options = self._bootstrap_options.for_global_scope() executor = PyExecutor(*GlobalOptions.compute_executor_arguments(global_options)) # Merge the nailgun TTY capability environment variables with the passed environment dict. ng_env = NailgunProtocol.ttynames_to_env(sys.stdin, sys.stdout, sys.stderr) modified_env = { **self._env, **ng_env, "PANTSD_RUNTRACKER_CLIENT_START_TIME": str(self._start_time), "PANTSD_REQUEST_TIMEOUT_LIMIT": str( global_options.pantsd_timeout_when_multiple_invocations ), } command = self._args[0] args = self._args[1:] retries = 3 attempt = 1 while True: port = pantsd_handle.port logger.debug(f"Connecting to pantsd on port {port} attempt {attempt}/{retries}") # We preserve TTY settings since the server might write directly to the TTY, and we'd like # to clean up any side effects before exiting. # # We ignore keyboard interrupts because the nailgun client will handle them. with STTYSettings.preserved(), interrupts_ignored(): try: return native.new_nailgun_client(executor=executor, port=port).execute( command, args, modified_env ) # NailgunConnectionException represents a failure connecting to pantsd, so we retry # up to the retry limit. except native.lib.NailgunConnectionException as e: if attempt > retries: raise self.Fallback(e) # Wait one second before retrying logger.warning(f"Pantsd was unresponsive on port {port}, retrying.") time.sleep(1) # One possible cause of the daemon being non-responsive during an attempt might be if a # another lifecycle operation is happening concurrently (incl teardown). To account for # this, we won't begin attempting restarts until at least 1 attempt has passed. if attempt > 1: pantsd_handle = self._client.restart() attempt += 1