def test_global_options_validation(self): # Specify an invalid combination of options. ob = OptionsBootstrapper.create(args=['--loop', '--v1']) build_config = BuildConfigInitializer.get(ob) with self.assertRaises(OptionsError) as exc: OptionsInitializer.create(ob, build_config) self.assertIn('loop option only works with', str(exc.exception))
def _run(self): # Bootstrap options and logging. options_bootstrapper = self._options_bootstrapper or OptionsBootstrapper(env=self._env, args=self._args) options, build_config = OptionsInitializer(options_bootstrapper, exiter=self._exiter).setup() global_options = options.for_global_scope() # Apply exiter options. self._exiter.apply_options(options) # 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 the configs here. if global_options.verify_config: options_bootstrapper.verify_configs_against_options(options) # Launch RunTracker as early as possible (just after Subsystem options are initialized). run_tracker = RunTracker.global_instance() reporting = Reporting.global_instance() reporting.initialize(run_tracker, self._run_start_time) try: # Determine the build root dir. root_dir = get_buildroot() # Capture a repro of the 'before' state for this build, if needed. repro = Reproducer.global_instance().create_repro() if repro: repro.capture(run_tracker.run_info.get_as_dict()) # Record the preceding product graph size. run_tracker.pantsd_stats.set_preceding_graph_size(self._preceding_graph_size) # Setup and run GoalRunner. goal_runner = GoalRunner.Factory(root_dir, options, build_config, run_tracker, reporting, self._target_roots, self._daemon_build_graph, self._exiter).setup() goal_runner_result = goal_runner.run() if repro: # TODO: Have Repro capture the 'after' state (as a diff) as well? repro.log_location_of_repro_file() finally: run_tracker_result = run_tracker.end() # Take the exit code with higher abs value in case of negative values. final_exit_code = goal_runner_result if abs(goal_runner_result) > abs(run_tracker_result) else run_tracker_result self._exiter.exit(final_exit_code)
def clean_global_runtime_state(reset_subsystem=False): """Resets the global runtime state of a pants runtime for cleaner forking. :param bool reset_subsystem: Whether or not to clean Subsystem global state. """ if reset_subsystem: # Reset subsystem state. Subsystem.reset() # Reset Goals and Tasks. Goal.clear() # Reset backend/plugins state. OptionsInitializer.reset()
def parse_options(args, env, setup_logging=False, options_bootstrapper=None): options_bootstrapper = options_bootstrapper or OptionsBootstrapper(args=args, env=env) bootstrap_options = options_bootstrapper.get_bootstrap_options().for_global_scope() if setup_logging: # Bootstrap logging and then fully initialize options. setup_logging_from_options(bootstrap_options) build_config = BuildConfigInitializer.get(options_bootstrapper) options = OptionsInitializer.create(options_bootstrapper, build_config) return options, build_config, options_bootstrapper
def create(cls, options=None, args=None, build_root=None, change_calculator=None): """ :param Options options: An `Options` instance to use, if available. :param string args: Raw cli args to use for parsing if an `Options` instance isn't available. :param string build_root: The build root. :param ChangeCalculator change_calculator: A `ChangeCalculator` for calculating changes. """ if not options: assert args is not None, 'must pass `args` if not passing `options`' options, _ = OptionsInitializer(OptionsBootstrapper(args=args)).setup(init_logging=False) # Determine the literal target roots. spec_roots = cls.parse_specs(options.target_specs, build_root) # Determine `Changed` arguments directly from options to support pre-`Subsystem` # initialization paths. changed_options = options.for_scope('changed') changed_request = ChangedRequest.from_options(changed_options) logger.debug('args are: %s', args) logger.debug('spec_roots are: %s', spec_roots) logger.debug('changed_request is: %s', changed_request) if change_calculator and changed_request.is_actionable(): if spec_roots: # We've been provided spec roots (e.g. `./pants list ::`) AND a changed request. Error out. raise InvalidSpecConstraint('cannot provide changed parameters and target specs!') # We've been provided no spec roots (e.g. `./pants list`) AND a changed request. Compute # alternate target roots. changed_addresses = change_calculator.changed_target_addresses(changed_request) logger.debug('changed addresses: %s', changed_addresses) return ChangedTargetRoots(tuple(SingleAddress(a.spec_path, a.target_name) for a in changed_addresses)) return LiteralTargetRoots(spec_roots)
def runner_factory(sock, arguments, environment): exiter = self._exiter_class(sock) graph_helper = None deferred_exc = None self._logger.debug('execution commandline: %s', arguments) options_bootstrapper = OptionsBootstrapper(args=arguments) build_config = BuildConfigInitializer.get(options_bootstrapper) options = OptionsInitializer.create(options_bootstrapper, build_config) graph_helper, target_roots = None, None try: self._logger.debug('warming the product graph via %s', self._scheduler_service) # N.B. This call is made in the pre-fork daemon context for reach and reuse of the # resident scheduler. graph_helper, target_roots = self._scheduler_service.warm_product_graph( options, self._target_roots_calculator ) except Exception: deferred_exc = sys.exc_info() self._logger.warning( 'encountered exception during SchedulerService.warm_product_graph(), deferring:\n%s', ''.join(traceback.format_exception(*deferred_exc)) ) return self._runner_class( sock, exiter, arguments, environment, target_roots, graph_helper, self.fork_lock, deferred_exc )
def test_invalid_version(self): options_bootstrapper = OptionsBootstrapper(args=['--pants-version=99.99.9999']) initializer = OptionsInitializer(options_bootstrapper, WorkingSet()) with self.assertRaises(BuildConfigurationError): initializer.setup()
def test_invalid_version(self): options_bootstrapper = OptionsBootstrapper(args=['--pants-version=99.99.9999']) build_config = BuildConfigInitializer(options_bootstrapper) with self.assertRaises(BuildConfigurationError): OptionsInitializer.create(options_bootstrapper, build_config)
def parse_options(options_bootstrapper, build_config): options = OptionsInitializer.create(options_bootstrapper, build_config) options.freeze() return Options(options, build_config)
def parse_options(args, env, options_bootstrapper=None): options_bootstrapper = options_bootstrapper or OptionsBootstrapper.create(args=args, env=env) build_config = BuildConfigInitializer.get(options_bootstrapper) options = OptionsInitializer.create(options_bootstrapper, build_config) return options, build_config, options_bootstrapper
def parse_options( options_bootstrapper: OptionsBootstrapper, ) -> Tuple[Options, BuildConfiguration]: build_config = BuildConfigInitializer.get(options_bootstrapper) options = OptionsInitializer.create(options_bootstrapper, build_config) return options, build_config
def parse_options(options_bootstrapper): # TODO: Because _OptionsBootstapper is currently provided as a Param, this @rule relies on options # remaining relatively stable in order to be efficient. See #6845 for a discussion of how to make # minimize the size of that value. build_config = BuildConfigInitializer.get(options_bootstrapper) return _Options(OptionsInitializer.create(options_bootstrapper, build_config, init_subsystems=False))
def setup_legacy_graph( native: Native, options_bootstrapper: OptionsBootstrapper, build_configuration: BuildConfiguration, ) -> LegacyGraphScheduler: """Construct and return the components necessary for LegacyBuildGraph construction.""" build_root = get_buildroot() bootstrap_options = options_bootstrapper.bootstrap_options.for_global_scope( ) glob_expansion_failure_configured = not bootstrap_options.is_default( "glob_expansion_failure") files_not_found_behavior_configured = not bootstrap_options.is_default( "files_not_found_behavior") if glob_expansion_failure_configured and files_not_found_behavior_configured: raise ValueError( "Conflicting options used. You used the new, preferred `--files-not-found-behavior`, but " "also used the deprecated `--glob-expansion-failure`.\n\nPlease " "specify only one of these (preferably `--files-not-found-behavior`)." ) glob_match_error_behavior = (bootstrap_options.files_not_found_behavior .to_glob_match_error_behavior() if files_not_found_behavior_configured else bootstrap_options.glob_expansion_failure) deprecated_conditional( lambda: cast( bool, bootstrap_options.build_file_imports == BuildFileImportsBehavior.allow), removal_version="1.27.0.dev0", entity_description="Using `--build-file-imports=allow`", hint_message= ("Import statements should be avoided in BUILD files because they can easily break Pants " "caching and lead to stale results. It is not safe to ignore warnings of imports, so the " "`allow` option is being removed.\n\nTo prepare for this change, either set " "`--build-file-imports=warn` or `--build-file-imports=error` (we recommend using `error`)." "\n\nIf you still need to keep the functionality you have from the import statement, " "consider rewriting your code into a Pants plugin: " "https://www.pantsbuild.org/howto_plugin.html")) deprecated_conditional( lambda: bootstrap_options.is_default("build_file_imports"), removal_version="1.27.0.dev0", entity_description="Defaulting to `--build-file-imports=warn`", hint_message= ("Import statements should be avoided in BUILD files because they can easily break Pants " "caching and lead to stale results. The default behavior will change from warning to " "erroring in 1.27.0.dev0, and the option will be removed in 1.29.0.dev0.\n\nTo prepare for " "this change, please explicitly set the option `--build-file-imports=warn` or " "`--build-file-imports=error` (we recommend using `error`).\n\nIf you still need to keep " "the functionality you have from import statements, consider rewriting your code into a " "Pants plugin: https://www.pantsbuild.org/howto_plugin.html")) return EngineInitializer.setup_legacy_graph_extended( OptionsInitializer.compute_pants_ignore(build_root, bootstrap_options), bootstrap_options.local_store_dir, bootstrap_options.build_file_imports, options_bootstrapper, build_configuration, build_root=build_root, native=native, glob_match_error_behavior=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 aliases(cls): """TODO: This is a nasty escape hatch to pass aliases to LegacyPythonCallbacksParser.""" _, build_config = OptionsInitializer(OptionsBootstrapper()).setup(init_logging=False) return build_config.registered_aliases()
def _default_build_file_aliases(self): # TODO: Get default BuildFileAliases by extending BaseTest post # https://github.com/pantsbuild/pants/issues/4401 _, build_config = OptionsInitializer( OptionsBootstrapper()).setup(init_logging=False) return build_config.registered_aliases()
def create( cls, env: CompleteEnvironment, options_bootstrapper: OptionsBootstrapper, options_initializer: OptionsInitializer | None = None, scheduler: GraphScheduler | None = None, cancellation_latch: PySessionCancellationLatch | None = 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 for this run. :param options_bootstrapper: The OptionsBootstrapper instance to reuse. :param scheduler: If being called from the daemon, a warmed scheduler to use. """ options_initializer = options_initializer or OptionsInitializer(options_bootstrapper) build_config, options = options_initializer.build_config_and_options( options_bootstrapper, env, raise_=True ) stdio_destination_use_color(options.for_global_scope().colors) run_tracker = RunTracker(options_bootstrapper.args, options) union_membership = UnionMembership.from_rules(build_config.union_rules) # Option values are usually computed lazily on demand, but command line options are # eagerly computed for validation. with options_initializer.handle_unknown_flags(options_bootstrapper, env, raise_=True): for scope, values in options.scope_to_flags.items(): if values: # Only compute values if there were any command line options presented. options.for_scope(scope) # Verify configs. global_bootstrap_options = options_bootstrapper.bootstrap_options.for_global_scope() if global_bootstrap_options.verify_config: options.verify_configs(options_bootstrapper.config) # 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_initializer, options_bootstrapper, build_config, env, run_tracker.run_id, options, scheduler, cancellation_latch, ) specs = calculate_specs( options_bootstrapper=options_bootstrapper, options=options, session=graph_session.scheduler_session, ) profile_path = env.get("PANTS_PROFILE") return cls( options=options, options_bootstrapper=options_bootstrapper, build_config=build_config, run_tracker=run_tracker, specs=specs, graph_session=graph_session, union_membership=union_membership, profile_path=profile_path, )