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(), )
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
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))
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)
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, )