Beispiel #1
0
    def _init_graph_session(
        cls,
        options_bootstrapper: OptionsBootstrapper,
        build_config: BuildConfiguration,
        options: Options,
        scheduler: Optional[GraphScheduler] = None,
    ) -> GraphSession:
        native = Native()
        native.set_panic_handler()
        graph_scheduler_helper = scheduler or EngineInitializer.setup_graph(
            options_bootstrapper, build_config)

        try:
            global_scope = options.for_global_scope()
        except UnknownFlagsError as err:
            cls._handle_unknown_flags(err, options_bootstrapper)
            raise

        stream_workunits = len(
            options.for_global_scope().streaming_workunits_handlers) != 0
        return graph_scheduler_helper.new_session(
            RunTracker.global_instance().run_id,
            dynamic_ui=global_scope.dynamic_ui,
            use_colors=global_scope.get("colors", True),
            should_report_workunits=stream_workunits,
            session_values=SessionValues({
                OptionsBootstrapper:
                options_bootstrapper,
                PantsEnvironment:
                PantsEnvironment(os.environ),
            }),
        )
Beispiel #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 = Native()
     native.set_panic_handler()
     graph_scheduler_helper = scheduler or EngineInitializer.setup_graph(
         options_bootstrapper, build_config, env
     )
     with options_initializer.handle_unknown_flags(options_bootstrapper, env, raise_=True):
         global_options = options.for_global_scope()
     return graph_scheduler_helper.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,
     )
Beispiel #3
0
    def _init_graph_session(
        cls,
        options_bootstrapper: OptionsBootstrapper,
        build_config: BuildConfiguration,
        run_id: str,
        options: Options,
        scheduler: Optional[GraphScheduler] = None,
        cancellation_latch: Optional[PySessionCancellationLatch] = None,
    ) -> GraphSession:
        native = Native()
        native.set_panic_handler()
        graph_scheduler_helper = scheduler or EngineInitializer.setup_graph(
            options_bootstrapper, build_config
        )

        try:
            global_scope = options.for_global_scope()
        except UnknownFlagsError as err:
            cls._handle_unknown_flags(err, options_bootstrapper)
            raise

        return graph_scheduler_helper.new_session(
            run_id,
            dynamic_ui=global_scope.dynamic_ui,
            use_colors=global_scope.get("colors", True),
            session_values=SessionValues(
                {
                    OptionsBootstrapper: options_bootstrapper,
                    PantsEnvironment: PantsEnvironment(os.environ),
                }
            ),
            cancellation_latch=cancellation_latch,
        )
Beispiel #4
0
    def _init_graph_session(
        options_bootstrapper: OptionsBootstrapper,
        build_config: BuildConfiguration,
        options: Options,
    ) -> LegacyGraphSession:
        native = Native()
        native.set_panic_handler()
        graph_scheduler_helper = EngineInitializer.setup_legacy_graph(
            native, options_bootstrapper, build_config)

        v2_ui = options.for_global_scope().get("v2_ui", False)
        zipkin_trace_v2 = options.for_scope("reporting").zipkin_trace_v2
        # TODO(#8658) This should_report_workunits flag must be set to True for
        # StreamingWorkunitHandler to receive WorkUnits. It should eventually
        # be merged with the zipkin_trace_v2 flag, since they both involve most
        # of the same engine functionality, but for now is separate to avoid
        # breaking functionality associated with zipkin tracing while iterating on streaming workunit reporting.
        stream_workunits = len(
            options.for_global_scope().streaming_workunits_handlers) != 0
        return graph_scheduler_helper.new_session(
            zipkin_trace_v2,
            RunTracker.global_instance().run_id,
            v2_ui,
            should_report_workunits=stream_workunits,
        )
    def _connect_and_execute(
            self, pantsd_handle: PantsDaemonClient.Handle) -> ExitCode:
        native = Native()

        global_options = self._bootstrap_options.for_global_scope()
        executor = PyExecutor(
            *OptionsInitializer.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.buffer,
                                                 sys.stderr.buffer)
        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
Beispiel #6
0
 def _run_pants(self, sock, arguments, environment):
     """Execute a given run with a pants runner."""
     # For the pants run, we want to log to stderr.
     # TODO Might be worth to make contextmanagers for this?
     Native().override_thread_logging_destination_to_just_stderr()
     self.server.runner_factory(sock, arguments, environment).run()
     Native().override_thread_logging_destination_to_just_pantsd()
Beispiel #7
0
    def create(cls, options_bootstrapper) -> "PantsDaemon":
        """
        :param OptionsBootstrapper options_bootstrapper: The bootstrap options.
        :param bool full_init: Whether or not to fully initialize an engine et al for the purposes
                                of spawning a new daemon. `full_init=False` is intended primarily
                                for lightweight lifecycle checks (since there is a ~1s overhead to
                                initialize the engine). See the impl of `maybe_launch` for an example
                                of the intended usage.
        """
        native = Native()
        native.override_thread_logging_destination_to_just_pantsd()

        bootstrap_options = options_bootstrapper.bootstrap_options
        bootstrap_options_values = bootstrap_options.for_global_scope()

        core = PantsDaemonCore(cls._setup_services)

        server = native.new_nailgun_server(
            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,
        )
Beispiel #8
0
    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,
        )
Beispiel #9
0
def test_log_filtering_by_rule() -> None:
    native = Native()
    native.init_rust_logging(
        level=LogLevel.INFO.level,
        log_show_rust_3rdparty=False,
        use_color=False,
        show_target=True,
        log_levels_by_target={
            "debug_target": LogLevel.DEBUG,
        },
    )
    with temporary_dir() as tmpdir:
        setup_logging_to_file(LogLevel.INFO, log_dir=tmpdir)
        log_file = Path(tmpdir, "pants.log")

        native.write_log(msg="log msg one",
                         level=LogLevel.INFO.level,
                         target="some.target")
        native.write_log(msg="log msg two",
                         level=LogLevel.DEBUG.level,
                         target="some.other.target")
        native.write_log(msg="log msg three",
                         level=LogLevel.DEBUG.level,
                         target="debug_target")

        loglines = log_file.read_text().splitlines()

        assert "[INFO] (some.target) log msg one" in loglines[0]
        assert "[DEBUG] (debug_target) log msg three" in loglines[1]
        assert len(loglines) == 2
Beispiel #10
0
def test_file_logging() -> None:
    native = Native()
    native.init_rust_logging(
        level=LogLevel.INFO.level,  # Tests assume a log level of INFO
        log_show_rust_3rdparty=False,
        use_color=False,
        show_target=False,
        log_levels_by_target={},
    )
    logger = logging.getLogger("my_file_logger")
    with temporary_dir() as tmpdir:
        setup_logging_to_file(LogLevel.INFO, log_dir=tmpdir)
        log_file = Path(tmpdir, "pants.log")

        cat = "🐈"
        logger.warning("this is a warning")
        logger.info("this is some info")
        logger.debug("this is some debug info")
        logger.info(f"unicode: {cat}")

        loglines = log_file.read_text().splitlines()
        print(loglines)
        assert len(loglines) == 3
        assert "[WARN] this is a warning" in loglines[0]
        assert "[INFO] this is some info" in loglines[1]
        assert f"[INFO] unicode: {cat}" in loglines[2]
Beispiel #11
0
    def __init__(self, options: Options):
        """
        :API: public
        """
        self.native = Native()

        self._has_started: bool = False
        self._has_ended: bool = False

        # Select a globally unique ID for the run, that sorts by time.
        run_timestamp = time.time()
        run_uuid = uuid.uuid4().hex
        str_time = time.strftime("%Y_%m_%d_%H_%M_%S",
                                 time.localtime(run_timestamp))
        millis = int((run_timestamp * 1000) % 1000)
        self.run_id = f"pants_run_{str_time}_{millis}_{run_uuid}"

        self._all_options = options
        info_dir = os.path.join(
            self._all_options.for_global_scope().pants_workdir, "run-tracker")
        self._run_info: Dict[str, Any] = {}

        # pantsd stats.
        self._pantsd_metrics: Dict[str, int] = dict()

        self.run_logs_file = Path(info_dir, self.run_id, "logs")
        safe_mkdir_for(str(self.run_logs_file))
        self.native.set_per_run_log_path(str(self.run_logs_file))

        # Initialized in `start()`.
        self._run_start_time: Optional[float] = None
        self._run_total_duration: Optional[float] = None
Beispiel #12
0
    def create(cls,
               options_bootstrapper: OptionsBootstrapper) -> "PantsDaemon":

        with warnings.catch_warnings(record=True):
            bootstrap_options = options_bootstrapper.bootstrap_options
            bootstrap_options_values = bootstrap_options.for_global_scope()

        setup_warning_filtering(bootstrap_options_values.ignore_pants_warnings
                                or [])

        native = Native()
        native.override_thread_logging_destination_to_just_pantsd()

        core = PantsDaemonCore(cls._setup_services)

        server = native.new_nailgun_server(
            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,
        )
Beispiel #13
0
    def __init__(self, *args, **kwargs):
        """
        :API: public
        """
        super().__init__(*args, **kwargs)
        self._run_timestamp = time.time()
        self._cmd_line = " ".join(["pants"] + sys.argv[1:])
        self._v2_goal_rule_names: Tuple[str, ...] = tuple()

        self.run_uuid = uuid.uuid4().hex
        # Select a globally unique ID for the run, that sorts by time.
        millis = int((self._run_timestamp * 1000) % 1000)
        # run_uuid is used as a part of run_id and also as a trace_id for Zipkin tracing
        str_time = time.strftime("%Y_%m_%d_%H_%M_%S",
                                 time.localtime(self._run_timestamp))
        self.run_id = f"pants_run_{str_time}_{millis}_{self.run_uuid}"

        # Initialized in `initialize()`.
        self.run_info_dir = None
        self.run_info = None
        self.cumulative_timings = None
        self.self_timings = None

        # Initialized in `start()`.
        self.report = None
        self._main_root_workunit = None
        self._all_options = None

        # A lock to ensure that adding to stats at the end of a workunit
        # operates thread-safely.
        self._stats_lock = threading.Lock()

        # Log of success/failure/aborted for each workunit.
        self.outcomes = {}

        # Number of threads for foreground work.
        self._num_foreground_workers = self.options.num_foreground_workers

        # Number of threads for background work.
        self._num_background_workers = self.options.num_background_workers

        # self._threadlocal.current_workunit contains the current workunit for the calling thread.
        # Note that multiple threads may share a name (e.g., all the threads in a pool).
        self._threadlocal = threading.local()

        # For background work.  Created lazily if needed.
        self._background_root_workunit = None

        # Trigger subproc pool init while our memory image is still clean (see SubprocPool docstring).
        SubprocPool.set_num_processes(self._num_foreground_workers)
        SubprocPool.foreground()

        self._aborted = False

        self._end_memoized_result: Optional[ExitCode] = None

        self.native = Native()

        self.run_logs_file: Optional[Path] = None
Beispiel #14
0
 def __init__(self,
              log_level: LogLevel,
              native_filename: Optional[str] = None) -> None:
     super().__init__(None)
     self.native = Native()
     self.native_filename = native_filename
     self.setLevel(log_level.level)
     if not self.native_filename:
         self.native.setup_stderr_logger()
Beispiel #15
0
    def _setup_services(
        build_root: str,
        bootstrap_options: OptionValueContainer,
        legacy_graph_scheduler: LegacyGraphScheduler,
        native: Native,
        watchman: Watchman,
        union_membership: UnionMembership,
    ):
        """Initialize pantsd services.

        :returns: A PantsServices instance.
        """
        native.override_thread_logging_destination_to_just_pantsd()
        fs_event_service = (FSEventService(
            watchman,
            scheduler=legacy_graph_scheduler.scheduler,
            build_root=build_root)
                            if bootstrap_options.watchman_enable else None)

        invalidation_globs = OptionsInitializer.compute_pantsd_invalidation_globs(
            build_root, bootstrap_options)

        scheduler_service = SchedulerService(
            fs_event_service=fs_event_service,
            legacy_graph_scheduler=legacy_graph_scheduler,
            build_root=build_root,
            invalidation_globs=invalidation_globs,
            union_membership=union_membership,
            max_memory_usage_in_bytes=bootstrap_options.
            pantsd_max_memory_usage,
        )

        pailgun_service = PailgunService(
            bootstrap_options.pantsd_pailgun_port,
            DaemonPantsRunner(scheduler_service),
            scheduler_service,
        )

        store_gc_service = StoreGCService(legacy_graph_scheduler.scheduler)

        return PantsServices(
            services=tuple(service for service in (
                fs_event_service,
                scheduler_service,
                pailgun_service,
                store_gc_service,
            ) if service is not None),
            port_map=dict(pailgun=pailgun_service.pailgun_port()),
        )
Beispiel #16
0
def test_close_stdio(mock_close):
    mock_options = unittest.mock.Mock()
    mock_options_values = unittest.mock.Mock()
    mock_options.for_global_scope.return_value = mock_options_values
    mock_options_values.pants_subprocessdir = "non_existent_dir"
    mock_server = unittest.mock.Mock()

    def create_services(bootstrap_options, legacy_graph_scheduler):
        return PantsServices()

    pantsd = PantsDaemon(
        native=Native(),
        work_dir="test_work_dir",
        log_level=logging.INFO,
        server=mock_server,
        core=PantsDaemonCore(create_services),
        metadata_base_dir="/tmp/pants_test_metadata_dir",
        bootstrap_options=mock_options,
    )

    with stdio_as(-1, -1, -1):
        handles = (sys.stdin, sys.stdout, sys.stderr)
        fds = [h.fileno() for h in handles]
        pantsd._close_stdio()
        mock_close.assert_has_calls(unittest.mock.call(x) for x in fds)
        for handle in handles:
            assert handle.closed is True
Beispiel #17
0
    def setup_legacy_graph(
        options_bootstrapper: OptionsBootstrapper,
        build_configuration: BuildConfiguration,
    ) -> LegacyGraphScheduler:
        """Construct and return the components necessary for LegacyBuildGraph construction."""
        native = Native()
        build_root = get_buildroot()
        bootstrap_options = options_bootstrapper.bootstrap_options.for_global_scope(
        )
        use_gitignore = bootstrap_options.pants_ignore_use_gitignore

        return EngineInitializer.setup_legacy_graph_extended(
            OptionsInitializer.compute_pants_ignore(build_root,
                                                    bootstrap_options),
            use_gitignore,
            bootstrap_options.local_store_dir,
            bootstrap_options.local_execution_root_dir,
            bootstrap_options.named_caches_dir,
            bootstrap_options.build_file_prelude_globs,
            options_bootstrapper,
            build_configuration,
            build_root=build_root,
            native=native,
            glob_match_error_behavior=(
                bootstrap_options.files_not_found_behavior.
                to_glob_match_error_behavior()),
            build_ignore_patterns=bootstrap_options.build_ignore,
            exclude_target_regexps=bootstrap_options.exclude_target_regexp,
            subproject_roots=bootstrap_options.subproject_roots,
            include_trace_on_error=bootstrap_options.
            print_exception_stacktrace,
            execution_options=ExecutionOptions.from_bootstrap_options(
                bootstrap_options),
        )
 def setup_graph(
     options: Options,
     build_configuration: BuildConfiguration,
     executor: Optional[PyExecutor] = None,
 ) -> GraphScheduler:
     native = Native()
     build_root = get_buildroot()
     bootstrap_options = options.bootstrap_option_values()
     assert bootstrap_options is not None
     executor = executor or PyExecutor(
         *OptionsInitializer.compute_executor_arguments(bootstrap_options))
     return EngineInitializer.setup_graph_extended(
         build_configuration,
         ExecutionOptions.from_options(options),
         native=native,
         executor=executor,
         pants_ignore_patterns=OptionsInitializer.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 setup_graph(
     options_bootstrapper: OptionsBootstrapper,
     build_configuration: BuildConfiguration,
 ) -> GraphScheduler:
     native = Native()
     build_root = get_buildroot()
     bootstrap_options = options_bootstrapper.bootstrap_options.for_global_scope(
     )
     return EngineInitializer.setup_graph_extended(
         options_bootstrapper,
         build_configuration,
         ExecutionOptions.from_bootstrap_options(bootstrap_options),
         pants_ignore_patterns=OptionsInitializer.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,
         native=native,
         include_trace_on_error=bootstrap_options.
         print_exception_stacktrace,
     )
Beispiel #20
0
    def _init_engine(self, local_store_dir: Optional[str] = None) -> None:
        if self._scheduler is not None:
            return

        options_bootstrapper = OptionsBootstrapper.create(
            env={},
            args=["--pants-config-files=[]", *self.additional_options],
            allow_pantsrc=False)
        global_options = options_bootstrapper.bootstrap_options.for_global_scope(
        )
        local_store_dir = local_store_dir or global_options.local_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=[],
            use_gitignore=False,
            local_store_dir=local_store_dir,
            local_execution_root_dir=local_execution_root_dir,
            named_caches_dir=named_caches_dir,
            native=Native(),
            options_bootstrapper=options_bootstrapper,
            build_root=self.build_root,
            build_configuration=self.build_config(),
            execution_options=ExecutionOptions.from_bootstrap_options(
                global_options),
        ).new_session(build_id="buildid_for_test",
                      should_report_workunits=True)
        self._scheduler = graph_session.scheduler_session
Beispiel #21
0
    def process_request_thread(self, request, client_address):
        """Override of ThreadingMixIn.process_request_thread() that delegates to the request
        handler."""
        # Instantiate the request handler.
        Native().override_thread_logging_destination_to_just_pantsd()
        handler = self.RequestHandlerClass(request, client_address, self)

        _, _, _, environment = handler.parsed_request()

        try:
            with self.ensure_request_is_exclusive(environment, request):
                # Attempt to handle a request with the handler.
                handler.handle_request()
                self.request_complete_callback()
        except BrokenPipeError as e:
            # The client has closed the connection, most likely from a SIGINT
            self.logger.error(
                f"Request {request} abruptly closed with {type(e)}, probably because the client crashed or was sent a SIGINT."
            )
        except Exception as e:
            # If that fails, (synchronously) handle the error with the error handler sans-fork.
            try:
                self.logger.error(f"Request {request} errored with {type(e)}({e!r})")
                handler.handle_error(e)
            finally:
                # Shutdown the socket since we don't expect a fork() in the exception context.
                self.shutdown_request(request)
        else:
            # At this point, we expect a fork() has taken place - the parent side will return, and so we
            # close the request here from the parent without explicitly shutting down the socket. The
            # child half of this will perform an os._exit() before it gets to this point and is also
            # responsible for shutdown and closing of the socket when its execution is complete.
            self.close_request(request)
Beispiel #22
0
 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 init_rust_logger(
    log_level: LogLevel,
    log_show_rust_3rdparty: bool,
    use_color: bool,
    show_target: bool,
    log_levels_by_target: Dict[str, LogLevel] = {},
) -> None:
    Native().init_rust_logging(log_level.level, log_show_rust_3rdparty,
                               use_color, show_target, log_levels_by_target)
Beispiel #24
0
    def __init__(
        self,
        *,
        rules: Optional[Iterable] = None,
        target_types: Optional[Iterable[Type[Target]]] = None,
        objects: Optional[Dict[str, Any]] = None,
        context_aware_object_factories: Optional[Dict[str, Any]] = None,
    ) -> None:
        self.build_root = os.path.realpath(mkdtemp(suffix="_BUILD_ROOT"))
        safe_mkdir(self.build_root, clean=True)
        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(),
            *pants_environment.rules(),
            QueryRule(WrappedTarget, (Address,)),
        )
        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(all_rules)
        build_config_builder.register_target_types(target_types or ())
        self.build_config = build_config_builder.create()

        options_bootstrapper = create_options_bootstrapper()
        global_options = options_bootstrapper.bootstrap_options.for_global_scope()
        local_store_dir = global_options.local_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=[],
            use_gitignore=False,
            local_store_dir=local_store_dir,
            local_execution_root_dir=local_execution_root_dir,
            named_caches_dir=named_caches_dir,
            native=Native(),
            options_bootstrapper=options_bootstrapper,
            build_root=self.build_root,
            build_configuration=self.build_config,
            execution_options=ExecutionOptions.from_bootstrap_options(global_options),
        ).new_session(
            build_id="buildid_for_test",
            session_values=SessionValues(
                {OptionsBootstrapper: options_bootstrapper, PantsEnvironment: PantsEnvironment()}
            ),
            should_report_workunits=True,
        )
        self.scheduler = graph_session.scheduler_session
Beispiel #25
0
    def _stderr_logging(self, global_bootstrap_options):
        """Temporarily replaces existing handlers (ie, the pantsd handler) with a stderr handler.

        In the context of pantsd, there will be an existing handler for the pantsd log, which we
        temporarily replace. Making them additive would cause per-run logs to go to pantsd, which
        we don't want.

        TODO: It would be good to handle logging destinations entirely via the threadlocal state
        rather than via handler mutations.
        """
        handlers = get_logging_handlers()
        try:
            clear_logging_handlers()
            Native().override_thread_logging_destination_to_just_stderr()
            setup_logging(global_bootstrap_options, stderr_logging=True)
            yield
        finally:
            Native().override_thread_logging_destination_to_just_pantsd()
            set_logging_handlers(handlers)
Beispiel #26
0
 def setUpClass(cls) -> None:
     super().setUpClass()
     # NB: We must set this up at the class level, rather than per-test level, because
     # `init_rust_logging` must never be called more than once. The Rust logger is global and static,
     # and initializing it twice in the same test class results in a SIGABRT.
     Native().init_rust_logging(
         level=LogLevel.INFO.level,  # Tests assume a log level of INFO
         log_show_rust_3rdparty=False,
         use_color=False,
     )
Beispiel #27
0
class NativeWriter:
    scheduler_session: SchedulerSession
    native: Native = Native()

    def write(self, payload: str) -> None:
        raise NotImplementedError

    def flush(self):
        """flush() doesn't need to do anything for NativeWriter."""
        pass
Beispiel #28
0
def setup_logging_to_file(
    level: LogLevel,
    *,
    log_dir: str,
    log_filename: str = "pants.log",
) -> NativeHandler:
    native = Native()
    logger = logging.getLogger(None)

    _common_logging_setup(level)

    safe_mkdir(log_dir)
    log_path = os.path.join(log_dir, log_filename)

    native.setup_pantsd_logger(log_path)
    handler = NativeHandler(level, native_filename=log_path)

    logger.addHandler(handler)
    return handler
Beispiel #29
0
    def _init_graph_session(
        options_bootstrapper: OptionsBootstrapper,
        build_config: BuildConfiguration,
        options: Options,
        scheduler: Optional[LegacyGraphScheduler] = None,
    ) -> LegacyGraphSession:
        native = Native()
        native.set_panic_handler()
        graph_scheduler_helper = scheduler or EngineInitializer.setup_legacy_graph(
            options_bootstrapper, build_config)

        global_scope = options.for_global_scope()

        if global_scope.v2:
            dynamic_ui = resolve_conflicting_options(
                old_option="v2_ui",
                new_option="dynamic_ui",
                old_scope=GLOBAL_SCOPE,
                new_scope=GLOBAL_SCOPE,
                old_container=global_scope,
                new_container=global_scope,
            )
        else:
            dynamic_ui = False
        use_colors = global_scope.get("colors", True)

        zipkin_trace_v2 = options.for_scope("reporting").zipkin_trace_v2
        # TODO(#8658) This should_report_workunits flag must be set to True for
        # StreamingWorkunitHandler to receive WorkUnits. It should eventually
        # be merged with the zipkin_trace_v2 flag, since they both involve most
        # of the same engine functionality, but for now is separate to avoid
        # breaking functionality associated with zipkin tracing while iterating on streaming workunit reporting.
        stream_workunits = len(
            options.for_global_scope().streaming_workunits_handlers) != 0
        return graph_scheduler_helper.new_session(
            zipkin_trace_v2,
            RunTracker.global_instance().run_id,
            dynamic_ui=dynamic_ui,
            use_colors=use_colors,
            should_report_workunits=stream_workunits,
        )
Beispiel #30
0
    def __init__(
        self,
        log_level: LogLevel,
        stream: Optional[TextIO] = None,
        native_filename: Optional[str] = None,
    ):

        if stream is not None and native_filename is not None:
            raise RuntimeError("NativeHandler must output to either a stream or a file, not both")

        super().__init__(stream)
        self.native = Native()
        self.native_filename = native_filename
        self.setLevel(log_level.level)

        if stream:
            try:
                self.native.setup_stderr_logger(log_level.level)
            except Exception as e:
                print(f"Error setting up pantsd logger: {e!r}", file=sys.stderr)
                raise e