예제 #1
0
    def create(
        cls,
        env: Mapping[str, str],
        options_bootstrapper: OptionsBootstrapper,
        scheduler: Optional[LegacyGraphScheduler] = None,
    ) -> "LocalPantsRunner":
        """Creates a new LocalPantsRunner instance by parsing options.

        By the time this method runs, logging will already have been initialized in either
        PantsRunner or DaemonPantsRunner.

        :param env: The environment (e.g. os.environ) for this run.
        :param options_bootstrapper: The OptionsBootstrapper instance to reuse.
        :param scheduler: If being called from the daemon, a warmed scheduler to use.
        """
        build_root = get_buildroot()
        global_bootstrap_options = options_bootstrapper.bootstrap_options.for_global_scope(
        )
        options, build_config = LocalPantsRunner.parse_options(
            options_bootstrapper)

        # Option values are usually computed lazily on demand,
        # but command line options are eagerly computed for validation.
        for scope in options.scope_to_flags.keys():
            options.for_scope(scope)

        # Verify configs.
        if global_bootstrap_options.verify_config:
            options.verify_configs(options_bootstrapper.config)

        union_membership = UnionMembership(build_config.union_rules())

        # If we're running with the daemon, we'll be handed a warmed Scheduler, which we use
        # to initialize a session here.
        graph_session = cls._init_graph_session(options_bootstrapper,
                                                build_config, options,
                                                scheduler)

        global_options = options.for_global_scope()
        specs = SpecsCalculator.create(
            options=options,
            build_root=build_root,
            session=graph_session.scheduler_session,
            exclude_patterns=tuple(global_options.exclude_target_regexp),
            tags=tuple(global_options.tag),
        )

        profile_path = env.get("PANTS_PROFILE")

        return cls(
            build_root=build_root,
            options=options,
            options_bootstrapper=options_bootstrapper,
            build_config=build_config,
            specs=specs,
            graph_session=graph_session,
            union_membership=union_membership,
            profile_path=profile_path,
            _run_tracker=RunTracker.global_instance(),
        )
예제 #2
0
    def _body(
        self,
        session: LegacyGraphSession,
        options: Options,
        options_bootstrapper: OptionsBootstrapper,
    ) -> Tuple[Specs, int]:
        global_options = options.for_global_scope()
        specs = SpecsCalculator.create(
            options=options,
            session=session.scheduler_session,
            exclude_patterns=tuple(global_options.exclude_target_regexp)
            if global_options.exclude_target_regexp else tuple(),
            tags=tuple(global_options.tag) if global_options.tag else tuple(),
        )
        exit_code = PANTS_SUCCEEDED_EXIT_CODE

        v1_goals, ambiguous_goals, v2_goals = options.goals_by_version

        if v2_goals or (ambiguous_goals and global_options.v2):
            goals = v2_goals + (ambiguous_goals
                                if global_options.v2 else tuple())

            # N.B. @goal_rules run pre-fork in order to cache the products they request during execution.
            exit_code = session.run_goal_rules(
                options_bootstrapper=options_bootstrapper,
                union_membership=self._union_membership,
                options=options,
                goals=goals,
                specs=specs,
            )

        return specs, exit_code
예제 #3
0
    def _maybe_init_specs(
        specs: Optional[Specs],
        graph_session: LegacyGraphSession,
        options: Options,
        build_root: str,
    ) -> Specs:
        if specs:
            return specs

        global_options = options.for_global_scope()
        return SpecsCalculator.create(
            options=options,
            build_root=build_root,
            session=graph_session.scheduler_session,
            exclude_patterns=tuple(global_options.exclude_target_regexp),
            tags=tuple(global_options.tag))
예제 #4
0
    def run(self):
        # Ensure anything referencing sys.argv inherits the Pailgun'd args.
        sys.argv = self.args

        # Invoke a Pants run with stdio redirected and a proxied environment.
        with self.nailgunned_stdio(
                self.maybe_shutdown_socket,
                self.env) as finalizer, DaemonExiter.override_global_exiter(
                    self.maybe_shutdown_socket,
                    finalizer), hermetic_environment_as(**self.env):

            exit_code = PANTS_SUCCEEDED_EXIT_CODE
            try:
                # Clean global state.
                clean_global_runtime_state(reset_subsystem=True)

                options_bootstrapper = OptionsBootstrapper.create(
                    args=self.args, env=self.env)
                options, build_config = LocalPantsRunner.parse_options(
                    options_bootstrapper)

                global_options = options.for_global_scope()
                session = self.scheduler_service.prepare_graph(options)

                specs = SpecsCalculator.create(
                    options=options,
                    session=session.scheduler_session,
                    exclude_patterns=tuple(
                        global_options.exclude_target_regexp),
                    tags=tuple(global_options.tag) if global_options.tag else
                    (),
                )

                if options.help_request:
                    help_printer = HelpPrinter(
                        options=options,
                        union_membership=UnionMembership(
                            build_config.union_rules()),
                    )
                    exit_code = help_printer.print_help()
                else:
                    exit_code = self.scheduler_service.graph_run_v2(
                        session, specs, options, options_bootstrapper)

                # self.scheduler_service.graph_run_v2 will already run v2 or ambiguous goals. We should
                # only enter this code path if v1 is set.
                if global_options.v1:
                    with ExceptionSink.exiter_as_until_exception(
                            lambda _: PantsRunFailCheckerExiter()):
                        runner = LocalPantsRunner.create(
                            self.env, options_bootstrapper, specs, session)

                        env_start_time = self.env.pop(
                            "PANTSD_RUNTRACKER_CLIENT_START_TIME", None)
                        start_time = float(
                            env_start_time) if env_start_time else None
                        runner.set_start_time(start_time)
                        runner.run()

            except KeyboardInterrupt:
                self._exiter.exit_and_fail("Interrupted by user.\n")
            except _PantsRunFinishedWithFailureException as e:
                ExceptionSink.log_exception(
                    "Pants run failed with exception: {}; exiting".format(e))
                self._exiter.exit(e.exit_code)
            except Exception as e:
                # TODO: We override sys.excepthook above when we call ExceptionSink.set_exiter(). That
                # excepthook catches `SignalHandledNonLocalExit`s from signal handlers, which isn't
                # happening here, so something is probably overriding the excepthook. By catching Exception
                # and calling this method, we emulate the normal, expected sys.excepthook override.
                ExceptionSink._log_unhandled_exception_and_exit(exc=e)
            else:
                self._exiter.exit(exit_code)
예제 #5
0
    def create(
        cls,
        env: Mapping[str, str],
        options_bootstrapper: OptionsBootstrapper,
        specs: Optional[Specs] = None,
        daemon_graph_session: Optional[LegacyGraphSession] = None,
    ) -> "LocalPantsRunner":
        """Creates a new LocalPantsRunner instance by parsing options.

        :param env: The environment (e.g. os.environ) for this run.
        :param options_bootstrapper: The OptionsBootstrapper instance to reuse.
        :param specs: The specs for this run, i.e. either the address or filesystem specs.
        :param daemon_graph_session: The graph helper for this session.
        """
        build_root = get_buildroot()
        global_options = options_bootstrapper.bootstrap_options.for_global_scope(
        )
        # This works as expected due to the encapsulated_logger in DaemonPantsRunner and
        # we don't have to gate logging setup anymore.

        level = LogLevel.ERROR if getattr(global_options, "quiet",
                                          False) else global_options.level
        ignores = global_options.ignore_pants_warnings
        clear_previous_loggers()
        setup_logging_to_stderr(level, warnings_filter_regexes=ignores)
        log_dir = global_options.logdir
        if log_dir:
            setup_logging_to_file(level,
                                  log_dir=log_dir,
                                  warnings_filter_regexes=ignores)

        options, build_config = LocalPantsRunner.parse_options(
            options_bootstrapper)

        # Option values are usually computed lazily on demand,
        # but command line options are eagerly computed for validation.
        for scope in options.scope_to_flags.keys():
            options.for_scope(scope)

        # Verify configs.
        if global_options.verify_config:
            options.verify_configs(options_bootstrapper.config)

        union_membership = UnionMembership(build_config.union_rules())

        # If we're running with the daemon, we'll be handed a session from the
        # resident graph helper - otherwise initialize a new one here.
        graph_session = (daemon_graph_session
                         if daemon_graph_session else cls._init_graph_session(
                             options_bootstrapper, build_config, options))

        if specs is None:
            global_options = options.for_global_scope()
            specs = SpecsCalculator.create(
                options=options,
                build_root=build_root,
                session=graph_session.scheduler_session,
                exclude_patterns=tuple(global_options.exclude_target_regexp),
                tags=tuple(global_options.tag),
            )

        profile_path = env.get("PANTS_PROFILE")

        return cls(
            build_root=build_root,
            options=options,
            options_bootstrapper=options_bootstrapper,
            build_config=build_config,
            specs=specs,
            graph_session=graph_session,
            union_membership=union_membership,
            is_daemon=daemon_graph_session is not None,
            profile_path=profile_path,
        )