Beispiel #1
0
def run_goal(
    targets: Sequence[Target],
    *,
    target_type: Optional[List[str]] = None,
    address_regex: Optional[List[str]] = None,
    tag_regex: Optional[List[str]] = None,
    granularity: Optional[TargetGranularity] = None,
) -> str:
    console = MockConsole(use_colors=False)
    run_rule_with_mocks(
        filter_targets,
        rule_args=[
            Targets(targets),
            create_goal_subsystem(
                FilterSubsystem,
                sep="\\n",
                output_file=None,
                target_type=target_type or [],
                address_regex=address_regex or [],
                tag_regex=tag_regex or [],
                granularity=granularity or TargetGranularity.all_targets,
                # Deprecated.
                type=[],
                target=[],
                regex=[],
                ancestor=[],
            ),
            console,
            RegisteredTargetTypes.create({type(tgt) for tgt in targets}),
        ],
    )
    assert not console.stderr.getvalue()
    return cast(str, console.stdout.getvalue())
Beispiel #2
0
def run_goal(
    targets: Sequence[Target],
    *,
    target_type: Optional[List[str]] = None,
    address_regex: Optional[List[str]] = None,
    tag_regex: Optional[List[str]] = None,
) -> str:
    console = MockConsole(use_colors=False)
    run_rule(
        filter_targets,
        rule_args=[
            Targets(targets),
            create_goal_subsystem(
                FilterOptions,
                sep="\\n",
                output_file=None,
                target_type=target_type or [],
                address_regex=address_regex or [],
                tag_regex=tag_regex or [],
            ),
            console,
            RegisteredTargetTypes.create({type(tgt)
                                          for tgt in targets}),
        ],
    )
    assert not console.stderr.getvalue()
    return cast(str, console.stdout.getvalue())
Beispiel #3
0
def test_determine_renamed_fields() -> None:
    class DeprecatedField(StringField):
        alias = "new_name"
        deprecated_alias = "old_name"
        deprecated_alias_removal_version = "99.9.0.dev0"

    class OkayField(StringField):
        alias = "okay"

    class Tgt(Target):
        alias = "tgt"
        core_fields = (DeprecatedField, OkayField)
        deprecated_alias = "deprecated_tgt"
        deprecated_alias_removal_version = "99.9.0.dev0"

    class TgtGenerator(TargetGenerator):
        alias = "generator"
        core_fields = ()
        moved_fields = (DeprecatedField, OkayField)

    registered_targets = RegisteredTargetTypes.create([Tgt, TgtGenerator])
    result = determine_renamed_field_types(registered_targets,
                                           UnionMembership({}))
    deprecated_fields = FrozenDict(
        {DeprecatedField.deprecated_alias: DeprecatedField.alias})
    assert result.target_field_renames == FrozenDict({
        k: deprecated_fields
        for k in (TgtGenerator.alias, Tgt.alias, Tgt.deprecated_alias)
    })
Beispiel #4
0
def run_goal(
    targets: Sequence[Target],
    *,
    target_type: list[str] | None = None,
    address_regex: list[str] | None = None,
    tag_regex: list[str] | None = None,
    granularity: TargetGranularity | None = None,
) -> str:
    with mock_console(create_options_bootstrapper()) as (console,
                                                         stdio_reader):
        run_rule_with_mocks(
            filter_targets,
            rule_args=[
                Targets(targets),
                create_goal_subsystem(
                    FilterSubsystem,
                    sep="\\n",
                    output_file=None,
                    target_type=target_type or [],
                    address_regex=address_regex or [],
                    tag_regex=tag_regex or [],
                    granularity=granularity or TargetGranularity.all_targets,
                    # Deprecated.
                    type=[],
                    target=[],
                    regex=[],
                    ancestor=[],
                ),
                console,
                RegisteredTargetTypes.create({type(tgt)
                                              for tgt in targets}),
            ],
        )
        assert not stdio_reader.get_stderr()
        return stdio_reader.get_stdout()
 def __init__(self, options: Options):
     super().__init__(options.for_global_scope().colors)
     self._all_help_info = HelpInfoExtracter.get_all_help_info(
         options,
         # We only care about the options-related help info, so we pass in
         # dummy values for the other arguments.
         UnionMembership({}),
         lambda x: tuple(),
         RegisteredTargetTypes({}),
     )
Beispiel #6
0
    def single_target_run(
        self,
        *,
        console: MockConsole,
        program_text: bytes,
        address_spec: str,
    ) -> Run:
        workspace = Workspace(self.scheduler)
        interactive_runner = InteractiveRunner(self.scheduler)

        class TestBinaryConfiguration(BinaryConfiguration):
            required_fields = ()

        class TestBinaryTarget(Target):
            alias = "binary"
            core_fields = ()

        address = Address.parse(address_spec)
        origin = SingleAddress(address.spec_path, address.target_name)
        res = run_rule(
            run,
            rule_args=[
                console,
                workspace,
                interactive_runner,
                BuildRoot(),
                TargetsWithOrigins([
                    TargetWithOrigin(
                        target=TestBinaryTarget(unhydrated_values={},
                                                address=address),
                        origin=origin,
                    )
                ]),
                create_goal_subsystem(RunOptions, args=[]),
                create_subsystem(GlobalOptions,
                                 pants_workdir=self.pants_workdir),
                UnionMembership(union_rules={
                    BinaryConfiguration:
                    OrderedSet([TestBinaryConfiguration])
                }),
                RegisteredTargetTypes.create([TestBinaryTarget]),
            ],
            mock_gets=[
                MockGet(
                    product_type=CreatedBinary,
                    subject_type=TestBinaryConfiguration,
                    mock=lambda _: self.create_mock_binary(program_text),
                ),
            ],
        )
        return cast(Run, res)
def run_goal(*,
             union_membership: Optional[UnionMembership] = None,
             details_target: Optional[str] = None) -> str:
    console = MockConsole(use_colors=False)
    run_rule(
        list_target_types,
        rule_args=[
            RegisteredTargetTypes.create(
                [FortranBinary, FortranLibrary, FortranTests]),
            union_membership or UnionMembership({}),
            MockOptions(details=details_target),
            console,
        ],
    )
    return cast(str, console.stdout.getvalue())
Beispiel #8
0
    def run(
        self,
        build_config: BuildConfiguration,
        graph_session: GraphSession,
        options: Options,
        specs: Specs,
        union_membership: UnionMembership,
    ) -> ExitCode:
        for server_request_type in union_membership.get(ExplorerServerRequest):
            logger.info(f"Using {server_request_type.__name__} to create the explorer server.")
            break
        else:
            logger.error(
                softwrap(
                    """
                    There is no Explorer backend server implementation registered.

                    Activate a backend/plugin that registers an implementation for the
                    `ExplorerServerRequest` union to fix this issue.
                    """
                )
            )
            return 127

        all_help_info = HelpInfoExtracter.get_all_help_info(
            options,
            union_membership,
            graph_session.goal_consumed_subsystem_scopes,
            RegisteredTargetTypes.create(build_config.target_types),
            build_config,
        )
        request_state = RequestState(
            all_help_info=all_help_info,
            build_configuration=build_config,
            scheduler_session=graph_session.scheduler_session,
        )
        server_request = server_request_type(
            address=self.address,
            port=self.port,
            request_state=request_state,
        )
        server = request_state.product_request(
            ExplorerServer,
            (server_request,),
            poll=True,
            timeout=90,
        )
        return server.run()
Beispiel #9
0
    def _print_help(self, request: HelpRequest) -> ExitCode:
        global_options = self.options.for_global_scope()

        all_help_info = HelpInfoExtracter.get_all_help_info(
            self.options,
            self.union_membership,
            self.graph_session.goal_consumed_subsystem_scopes,
            RegisteredTargetTypes.create(self.build_config.target_types),
        )
        help_printer = HelpPrinter(
            bin_name=global_options.pants_bin_name,
            help_request=request,
            all_help_info=all_help_info,
            color=global_options.colors,
        )
        return help_printer.print_help()
def run_goal(
    *, union_membership: Optional[UnionMembership] = None, details_target: Optional[str] = None
) -> str:
    console = MockConsole(use_colors=False)
    run_rule_with_mocks(
        list_target_types,
        rule_args=[
            RegisteredTargetTypes.create([FortranBinary, FortranLibrary, FortranTests]),
            union_membership or UnionMembership({}),
            create_goal_subsystem(
                TargetTypesSubsystem, sep="\\n", output_file=None, details=details_target
            ),
            console,
            PantsBin(name="./BNF"),
        ],
    )
    return cast(str, console.stdout.getvalue())
Beispiel #11
0
def test_specs_filter() -> None:
    class MockTgt1(Target):
        alias = "tgt1"
        core_fields = (Tags, )

    class MockTgt2(Target):
        alias = "tgt2"
        core_fields = (Tags, )

    specs_filter = SpecsFilter.create(
        create_goal_subsystem(
            FilterSubsystem,
            target_type=["tgt1"],
            tag_regex=[],
            address_regex=[],
            granularity=TargetGranularity.all_targets,
        ),
        RegisteredTargetTypes({
            "tgt1": MockTgt1,
            "tgt2": MockTgt2
        }),
        tags=["-a", "+b"],
        exclude_target_regexps=["skip-me"],
    )

    def make_tgt1(name: str, tags: list[str] | None = None) -> MockTgt1:
        return MockTgt1({Tags.alias: tags}, Address("", target_name=name))

    def make_tgt2(name: str, tags: list[str] | None = None) -> MockTgt2:
        return MockTgt2({Tags.alias: tags}, Address("", target_name=name))

    untagged_tgt = make_tgt1(name="untagged")
    b_tagged_tgt = make_tgt1(name="b-tagged", tags=["b"])
    b_tagged_exclude_regex_tgt = make_tgt1(name="skip-me", tags=["b"])
    a_and_b_tagged_tgt = make_tgt1(name="a-and-b-tagged", tags=["a", "b"])

    # Even though this has the tag `b`, it should be excluded because the target type.
    tgt2 = make_tgt2("tgt2", tags=["b"])

    def matches(tgt: Target) -> bool:
        return specs_filter.matches(tgt)

    assert matches(b_tagged_tgt) is True
    for t in (untagged_tgt, b_tagged_exclude_regex_tgt, a_and_b_tagged_tgt,
              tgt2):
        assert matches(t) is False
Beispiel #12
0
 def run(
     self,
     build_config: BuildConfiguration,
     graph_session: GraphSession,
     options: Options,
     specs: Specs,
     union_membership: UnionMembership,
 ) -> ExitCode:
     all_help_info = HelpInfoExtracter.get_all_help_info(
         options,
         union_membership,
         graph_session.goal_consumed_subsystem_scopes,
         RegisteredTargetTypes.create(build_config.target_types),
         build_config,
     )
     global_options = options.for_global_scope()
     help_printer = HelpPrinter(
         help_request=self.create_help_request(options),
         all_help_info=all_help_info,
         color=global_options.colors,
     )
     return help_printer.print_help()
Beispiel #13
0
    def setup_legacy_graph_extended(
        options_bootstrapper: OptionsBootstrapper,
        build_configuration: BuildConfiguration,
        execution_options: ExecutionOptions,
        *,
        pants_ignore_patterns: List[str],
        use_gitignore: bool,
        local_store_dir: str,
        local_execution_root_dir: str,
        named_caches_dir: str,
        build_root: Optional[str] = None,
        native: Optional[Native] = None,
        glob_match_error_behavior:
        GlobMatchErrorBehavior = GlobMatchErrorBehavior.warn,
        build_patterns: Optional[Iterable[str]] = None,
        build_file_prelude_globs: Optional[Iterable[str]] = None,
        build_ignore_patterns: Optional[Iterable[str]] = None,
        tags: Optional[Iterable[str]] = None,
        exclude_target_regexps: Optional[Iterable[str]] = None,
        subproject_roots: Optional[Iterable[str]] = None,
        include_trace_on_error: bool = True,
    ) -> LegacyGraphScheduler:
        """Construct and return the components necessary for LegacyBuildGraph construction."""

        build_root = build_root or get_buildroot()
        build_configuration = build_configuration or BuildConfigInitializer.get(
            options_bootstrapper)

        bootstrap_options = options_bootstrapper.bootstrap_options.for_global_scope(
        )
        execution_options = execution_options or DEFAULT_EXECUTION_OPTIONS

        build_file_aliases = build_configuration.registered_aliases
        rules = build_configuration.rules
        union_membership = UnionMembership.from_rules(
            build_configuration.union_rules)

        registered_target_types = RegisteredTargetTypes.create(
            build_configuration.target_types)
        parser = Parser(target_type_aliases=registered_target_types.aliases,
                        object_aliases=build_file_aliases)
        address_mapper = AddressMapper(
            parser=parser,
            prelude_glob_patterns=build_file_prelude_globs,
            build_patterns=build_patterns,
            build_ignore_patterns=build_ignore_patterns,
            tags=tags,
            exclude_target_regexps=exclude_target_regexps,
            subproject_roots=subproject_roots,
        )

        @rule
        def address_mapper_singleton() -> AddressMapper:
            return address_mapper

        @rule
        def glob_match_error_behavior_singleton() -> GlobMatchErrorBehavior:
            return glob_match_error_behavior

        @rule
        def build_configuration_singleton() -> BuildConfiguration:
            return build_configuration

        @rule
        def registered_target_types_singleton() -> RegisteredTargetTypes:
            return registered_target_types

        @rule
        def union_membership_singleton() -> UnionMembership:
            return union_membership

        @rule
        def build_root_singleton() -> BuildRoot:
            return cast(BuildRoot, BuildRoot.instance)

        # Create a Scheduler containing graph and filesystem rules, with no installed goals.
        rules = FrozenOrderedSet((
            *collect_rules(locals()),
            RootRule(Console),
            *build_files.rules(),
            *fs.rules(),
            *graph.rules(),
            *uuid.rules(),
            *options_parsing.rules(),
            *process.rules(),
            *create_platform_rules(),
            *changed_rules(),
            *rules,
        ))

        goal_map = EngineInitializer._make_goal_map_from_rules(rules)

        def ensure_absolute_path(v: str) -> str:
            return Path(v).resolve().as_posix()

        scheduler = Scheduler(
            native=native,
            ignore_patterns=pants_ignore_patterns,
            use_gitignore=use_gitignore,
            build_root=build_root,
            local_store_dir=ensure_absolute_path(local_store_dir),
            local_execution_root_dir=ensure_absolute_path(
                local_execution_root_dir),
            named_caches_dir=ensure_absolute_path(named_caches_dir),
            rules=rules,
            union_membership=union_membership,
            execution_options=execution_options,
            include_trace_on_error=include_trace_on_error,
            visualize_to_dir=bootstrap_options.native_engine_visualize_to,
        )

        return LegacyGraphScheduler(scheduler, build_file_aliases, goal_map)
Beispiel #14
0
    def run_test_rule(
        self,
        *,
        config: Type[TestConfiguration],
        targets: List[TargetWithOrigin],
        debug: bool = False,
        include_sources: bool = True,
    ) -> Tuple[int, str]:
        console = MockConsole(use_colors=False)
        options = MockOptions(debug=debug, run_coverage=False)
        interactive_runner = InteractiveRunner(self.scheduler)
        workspace = Workspace(self.scheduler)
        union_membership = UnionMembership(
            {TestConfiguration: OrderedSet([config])})

        def mock_coordinator_of_tests(
            wrapped_config: WrappedTestConfiguration,
        ) -> AddressAndTestResult:
            config = wrapped_config.config
            return AddressAndTestResult(
                address=config.address,
                test_result=config.test_result,  # type: ignore[attr-defined]
            )

        result: Test = run_rule(
            run_tests,
            rule_args=[
                console,
                options,
                interactive_runner,
                TargetsWithOrigins(targets),
                workspace,
                union_membership,
                RegisteredTargetTypes.create([MockTarget]),
            ],
            mock_gets=[
                MockGet(
                    product_type=AddressAndTestResult,
                    subject_type=WrappedTestConfiguration,
                    mock=lambda wrapped_config: mock_coordinator_of_tests(
                        wrapped_config),
                ),
                MockGet(
                    product_type=TestDebugRequest,
                    subject_type=TestConfiguration,
                    mock=lambda _: TestDebugRequest(self.make_ipr()),
                ),
                MockGet(
                    product_type=HydratedSources,
                    subject_type=HydrateSourcesRequest,
                    mock=lambda _: HydratedSources(
                        Snapshot(
                            directory_digest=EMPTY_DIRECTORY_DIGEST,
                            files=cast(Tuple[str, ...], ("test.hs", )
                                       if include_sources else ()),
                            dirs=(),
                        ),
                        filespec={"globs": []},
                    ),
                ),
                MockGet(
                    product_type=CoverageReport,
                    subject_type=CoverageDataBatch,
                    mock=lambda _: FilesystemCoverageReport(
                        result_digest=EMPTY_DIRECTORY_DIGEST,
                        directory_to_materialize_to=PurePath("mockety/mock"),
                        report_file=None,
                    ),
                ),
            ],
            union_membership=union_membership,
        )
        return result.exit_code, console.stdout.getvalue()
Beispiel #15
0
    def setup_legacy_graph_extended(
        pants_ignore_patterns: List[str],
        use_gitignore: bool,
        local_store_dir: str,
        local_execution_root_dir: str,
        named_caches_dir: str,
        build_file_prelude_globs: Tuple[str, ...],
        options_bootstrapper: OptionsBootstrapper,
        build_configuration: BuildConfiguration,
        execution_options: ExecutionOptions,
        build_root: Optional[str] = None,
        native: Optional[Native] = None,
        glob_match_error_behavior:
        GlobMatchErrorBehavior = GlobMatchErrorBehavior.warn,
        build_ignore_patterns=None,
        exclude_target_regexps=None,
        subproject_roots=None,
        include_trace_on_error: bool = True,
    ) -> LegacyGraphScheduler:
        """Construct and return the components necessary for LegacyBuildGraph construction.

        :param local_store_dir: The directory to use for storing the engine's LMDB store in.
        :param local_execution_root_dir: The directory to use for local execution sandboxes.
        :param named_caches_dir: The base directory for named cache storage.
        :param build_file_prelude_globs: Globs to match files to be prepended to all BUILD files.
        :param build_root: A path to be used as the build root. If None, then default is used.
        :param native: An instance of the native-engine subsystem.
        :param options_bootstrapper: A `OptionsBootstrapper` object containing bootstrap options.
        :param build_configuration: The `BuildConfiguration` object to get build file aliases from.
        :param glob_match_error_behavior: How to behave if a glob specified for a target's sources or
                                          bundles does not expand to anything.
        :param list build_ignore_patterns: A list of paths ignore patterns used when searching for BUILD
                                           files, usually taken from the '--build-ignore' global option.
        :param list exclude_target_regexps: A list of regular expressions for excluding targets.
        :param list subproject_roots: Paths that correspond with embedded build roots
                                      under the current build root.
        :param include_trace_on_error: If True, when an error occurs, the error message will include
                                       the graph trace.
        :param execution_options: Option values for (remote) process execution.
        """

        build_root = build_root or get_buildroot()
        build_configuration = build_configuration or BuildConfigInitializer.get(
            options_bootstrapper)
        bootstrap_options = options_bootstrapper.bootstrap_options.for_global_scope(
        )

        build_file_aliases = build_configuration.registered_aliases()
        rules = build_configuration.rules()

        registered_target_types = RegisteredTargetTypes.create(
            build_configuration.target_types())

        symbol_table = _legacy_symbol_table(build_file_aliases,
                                            registered_target_types)

        execution_options = execution_options or DEFAULT_EXECUTION_OPTIONS

        # Register "literal" subjects required for these rules.
        parser = LegacyPythonCallbacksParser(symbol_table, build_file_aliases)
        address_mapper = AddressMapper(
            parser=parser,
            prelude_glob_patterns=build_file_prelude_globs,
            build_ignore_patterns=build_ignore_patterns,
            exclude_target_regexps=exclude_target_regexps,
            subproject_roots=subproject_roots,
        )

        @rule
        def glob_match_error_behavior_singleton() -> GlobMatchErrorBehavior:
            return glob_match_error_behavior

        @rule
        def build_configuration_singleton() -> BuildConfiguration:
            return build_configuration

        @rule
        def symbol_table_singleton() -> SymbolTable:
            return symbol_table

        @rule
        def registered_target_types_singleton() -> RegisteredTargetTypes:
            return registered_target_types

        @rule
        def union_membership_singleton() -> UnionMembership:
            return UnionMembership(build_configuration.union_rules())

        @rule
        def build_root_singleton() -> BuildRoot:
            return cast(BuildRoot, BuildRoot.instance)

        # Create a Scheduler containing graph and filesystem rules, with no installed goals. The
        # LegacyBuildGraph will explicitly request the products it needs.
        rules = (
            RootRule(Console),
            glob_match_error_behavior_singleton,
            build_configuration_singleton,
            symbol_table_singleton,
            registered_target_types_singleton,
            union_membership_singleton,
            build_root_singleton,
            *interactive_runner.rules(),
            *graph.rules(),
            *options_parsing.rules(),
            *process.rules(),
            *target.rules(),
            *create_legacy_graph_tasks(),
            *create_fs_rules(),
            *create_platform_rules(),
            *create_graph_rules(address_mapper),
            *structs_rules(),
            *changed_rules(),
            *binary_tool_rules(),
            *binary_util_rules(),
            *rules,
        )

        goal_map = EngineInitializer._make_goal_map_from_rules(rules)

        union_rules = build_configuration.union_rules()

        scheduler = Scheduler(
            native=native,
            ignore_patterns=pants_ignore_patterns,
            use_gitignore=use_gitignore,
            build_root=build_root,
            local_store_dir=local_store_dir,
            local_execution_root_dir=local_execution_root_dir,
            named_caches_dir=named_caches_dir,
            rules=rules,
            union_rules=union_rules,
            execution_options=execution_options,
            include_trace_on_error=include_trace_on_error,
            visualize_to_dir=bootstrap_options.native_engine_visualize_to,
        )

        return LegacyGraphScheduler(scheduler, build_file_aliases, goal_map)
Beispiel #16
0
    def setup_graph_extended(
        build_configuration: BuildConfiguration,
        execution_options: ExecutionOptions,
        *,
        executor: PyExecutor,
        pants_ignore_patterns: list[str],
        use_gitignore: bool,
        local_store_options: LocalStoreOptions,
        local_execution_root_dir: str,
        named_caches_dir: str,
        use_deprecated_python_macros: bool,
        ca_certs_path: str | None = None,
        build_root: str | None = None,
        include_trace_on_error: bool = True,
        engine_visualize_to: str | None = None,
        watch_filesystem: bool = True,
    ) -> GraphScheduler:
        build_root_path = build_root or get_buildroot()

        rules = build_configuration.rules
        union_membership: UnionMembership
        registered_target_types = RegisteredTargetTypes.create(
            build_configuration.target_types)

        execution_options = execution_options or DEFAULT_EXECUTION_OPTIONS

        @rule
        def parser_singleton() -> Parser:
            return Parser(
                build_root=build_root_path,
                target_type_aliases=registered_target_types.aliases,
                object_aliases=build_configuration.registered_aliases,
                use_deprecated_python_macros=use_deprecated_python_macros,
            )

        @rule
        def build_configuration_singleton() -> BuildConfiguration:
            return build_configuration

        @rule
        def registered_target_types_singleton() -> RegisteredTargetTypes:
            return registered_target_types

        @rule
        def union_membership_singleton() -> UnionMembership:
            return union_membership

        @rule
        def build_root_singleton() -> BuildRoot:
            return cast(BuildRoot, BuildRoot.instance)

        # Create a Scheduler containing graph and filesystem rules, with no installed goals.
        rules = FrozenOrderedSet((
            *collect_rules(locals()),
            *build_files.rules(),
            *fs.rules(),
            *environment.rules(),
            *desktop.rules(),
            *graph.rules(),
            *options_parsing.rules(),
            *process.rules(),
            *system_binaries.rules(),
            *platform.rules(),
            *changed_rules(),
            *streaming_workunit_handler_rules(),
            *specs_calculator.rules(),
            *rules,
        ))

        goal_map = EngineInitializer._make_goal_map_from_rules(rules)

        union_membership = UnionMembership.from_rules((
            *build_configuration.union_rules,
            *(r for r in rules if isinstance(r, UnionRule)),
        ))

        rules = FrozenOrderedSet((
            *rules,
            # Install queries for each Goal.
            *(QueryRule(goal_type, GraphSession.goal_param_types)
              for goal_type in goal_map.values()),
            # Install queries for each request/response pair used by the BSP support.
            # Note: These are necessary because the BSP support is a built-in goal that makes
            # synchronous requests into the engine.
            *(QueryRule(impl.response_type, (impl.request_type, Workspace))
              for impl in union_membership.get(BSPHandlerMapping)),
            QueryRule(Snapshot, [PathGlobs]),  # Used by the SchedulerService.
        ))

        def ensure_absolute_path(v: str) -> str:
            return Path(v).resolve().as_posix()

        def ensure_optional_absolute_path(v: str | None) -> str | None:
            if v is None:
                return None
            return ensure_absolute_path(v)

        scheduler = Scheduler(
            ignore_patterns=pants_ignore_patterns,
            use_gitignore=use_gitignore,
            build_root=build_root_path,
            local_execution_root_dir=ensure_absolute_path(
                local_execution_root_dir),
            named_caches_dir=ensure_absolute_path(named_caches_dir),
            ca_certs_path=ensure_optional_absolute_path(ca_certs_path),
            rules=rules,
            union_membership=union_membership,
            executor=executor,
            execution_options=execution_options,
            local_store_options=local_store_options,
            include_trace_on_error=include_trace_on_error,
            visualize_to_dir=engine_visualize_to,
            watch_filesystem=watch_filesystem,
        )

        return GraphScheduler(scheduler, goal_map)
Beispiel #17
0
def test_get_all_help_info():
    class Global(Subsystem):
        options_scope = GLOBAL_SCOPE
        help = "Global options."

        opt1 = IntOption("--opt1", default=42, help="Option 1")
        # This is special in having a short option `-l`. Make sure it works.
        level = LogLevelOption()

    class Foo(Subsystem):
        options_scope = "foo"
        help = "A foo."

        opt2 = BoolOption("--opt2",
                          default=True,
                          advanced=True,
                          help="Option 2")

    class Bar(GoalSubsystem):
        name = "bar"
        help = "The bar goal."
        deprecated_options_scope = "bar-old"
        deprecated_options_scope_removal_version = "9.9.999"

    class QuxField(StringField):
        alias = "qux"
        default = "blahblah"
        help = "A qux string."

    class QuuxField(IntField):
        alias = "quux"
        required = True
        help = "A quux int.\n\nMust be non-zero. Or zero. Whatever you like really."

    class BazLibrary(Target):
        alias = "baz_library"
        help = "A library of baz-es.\n\nUse it however you like."

        core_fields = [QuxField, QuuxField]

    options = Options.create(
        env={},
        config=Config.load([]),
        known_scope_infos=[
            Global.get_scope_info(),
            Foo.get_scope_info(),
            Bar.get_scope_info()
        ],
        args=["./pants"],
        bootstrap_option_values=None,
    )
    Global.register_options_on_scope(options)
    Foo.register_options_on_scope(options)
    Bar.register_options_on_scope(options)

    @rule
    def rule_info_test(foo: Foo) -> Target:
        """This rule is for testing info extraction only."""

    def fake_consumed_scopes_mapper(scope: str) -> Tuple[str, ...]:
        return ("somescope", f"used_by_{scope or 'GLOBAL_SCOPE'}")

    bc_builder = BuildConfiguration.Builder()
    bc_builder.register_subsystems("help_info_extracter_test", (Foo, Bar))
    bc_builder.register_target_types("help_info_extracter_test",
                                     (BazLibrary, ))
    bc_builder.register_rules("help_info_extracter_test",
                              collect_rules(locals()))

    all_help_info = HelpInfoExtracter.get_all_help_info(
        options,
        UnionMembership({}),
        fake_consumed_scopes_mapper,
        RegisteredTargetTypes({BazLibrary.alias: BazLibrary}),
        bc_builder.create(),
    )

    all_help_info_dict = all_help_info.asdict()
    expected_all_help_info_dict = {
        "scope_to_help_info": {
            GLOBAL_SCOPE: {
                "scope":
                GLOBAL_SCOPE,
                "description":
                "Global options.",
                "provider":
                "",
                "is_goal":
                False,
                "deprecated_scope":
                None,
                "basic": (
                    {
                        "display_args": ("--opt1=<int>", ),
                        "comma_separated_display_args": "--opt1=<int>",
                        "scoped_cmd_line_args": ("--opt1", ),
                        "unscoped_cmd_line_args": ("--opt1", ),
                        "config_key": "opt1",
                        "env_var": "PANTS_OPT1",
                        "value_history": {
                            "ranked_values": (
                                {
                                    "rank": Rank.NONE,
                                    "value": None,
                                    "details": None
                                },
                                {
                                    "rank": Rank.HARDCODED,
                                    "value": 42,
                                    "details": None
                                },
                            ),
                        },
                        "typ": int,
                        "default": 42,
                        "help": "Option 1",
                        "deprecation_active": False,
                        "deprecated_message": None,
                        "removal_version": None,
                        "removal_hint": None,
                        "choices": None,
                        "comma_separated_choices": None,
                    },
                    {
                        "display_args":
                        ("-l=<LogLevel>", "--level=<LogLevel>"),
                        "comma_separated_display_args":
                        "-l=<LogLevel>, --level=<LogLevel>",
                        "scoped_cmd_line_args": ("-l", "--level"),
                        "unscoped_cmd_line_args": ("-l", "--level"),
                        "config_key":
                        "level",
                        "env_var":
                        "PANTS_LEVEL",
                        "value_history": {
                            "ranked_values": (
                                {
                                    "rank": Rank.NONE,
                                    "value": None,
                                    "details": None
                                },
                                {
                                    "rank": Rank.HARDCODED,
                                    "value": LogLevel.INFO,
                                    "details": None
                                },
                            ),
                        },
                        "typ":
                        LogLevel,
                        "default":
                        LogLevel.INFO,
                        "help":
                        "Set the logging level.",
                        "deprecation_active":
                        False,
                        "deprecated_message":
                        None,
                        "removal_version":
                        None,
                        "removal_hint":
                        None,
                        "choices": ("trace", "debug", "info", "warn", "error"),
                        "comma_separated_choices":
                        "trace, debug, info, warn, error",
                    },
                ),
                "advanced":
                tuple(),
                "deprecated":
                tuple(),
            },
            "foo": {
                "scope":
                "foo",
                "provider":
                "help_info_extracter_test",
                "description":
                "A foo.",
                "is_goal":
                False,
                "deprecated_scope":
                None,
                "basic": (),
                "advanced": ({
                    "display_args": ("--[no-]foo-opt2", ),
                    "comma_separated_display_args":
                    "--[no-]foo-opt2",
                    "scoped_cmd_line_args": ("--foo-opt2", "--no-foo-opt2"),
                    "unscoped_cmd_line_args": ("--opt2", "--no-opt2"),
                    "config_key":
                    "opt2",
                    "env_var":
                    "PANTS_FOO_OPT2",
                    "value_history": {
                        "ranked_values": (
                            {
                                "rank": Rank.NONE,
                                "value": None,
                                "details": None
                            },
                            {
                                "rank": Rank.HARDCODED,
                                "value": True,
                                "details": None
                            },
                        ),
                    },
                    "typ":
                    bool,
                    "default":
                    True,
                    "help":
                    "Option 2",
                    "deprecation_active":
                    False,
                    "deprecated_message":
                    None,
                    "removal_version":
                    None,
                    "removal_hint":
                    None,
                    "choices":
                    None,
                    "comma_separated_choices":
                    None,
                }, ),
                "deprecated":
                tuple(),
            },
            "bar": {
                "scope": "bar",
                "provider": "help_info_extracter_test",
                "description": "The bar goal.",
                "is_goal": True,
                "deprecated_scope": "bar-old",
                "basic": tuple(),
                "advanced": tuple(),
                "deprecated": tuple(),
            },
            "bar-old": {
                "scope": "bar-old",
                "provider": "help_info_extracter_test",
                "description": "The bar goal.",
                "is_goal": True,
                "deprecated_scope": "bar-old",
                "basic": tuple(),
                "advanced": tuple(),
                "deprecated": tuple(),
            },
        },
        "name_to_goal_info": {
            "bar": {
                "name": "bar",
                "provider": "help_info_extracter_test",
                "description": "The bar goal.",
                "consumed_scopes": ("somescope", "used_by_bar"),
                "is_implemented": True,
            },
            "bar-old": {
                "name": "bar",
                "provider": "help_info_extracter_test",
                "description": "The bar goal.",
                "consumed_scopes": ("somescope", "used_by_bar-old"),
                "is_implemented": True,
            },
        },
        "name_to_target_type_info": {
            "baz_library": {
                "alias":
                "baz_library",
                "provider":
                "help_info_extracter_test",
                "summary":
                "A library of baz-es.",
                "description":
                "A library of baz-es.\n\nUse it however you like.",
                "fields": (
                    {
                        "alias": "qux",
                        "provider": "",
                        "default": "'blahblah'",
                        "description": "A qux string.",
                        "required": False,
                        "type_hint": "str | None",
                    },
                    {
                        "alias":
                        "quux",
                        "provider":
                        "",
                        "default":
                        None,
                        "description":
                        "A quux int.\n\nMust be non-zero. Or zero. "
                        "Whatever you like really.",
                        "required":
                        True,
                        "type_hint":
                        "int",
                    },
                ),
            }
        },
        "name_to_rule_info": {
            "construct_scope_foo": {
                "description": None,
                "documentation": "A foo.",
                "input_gets": ("Get(ScopedOptions, Scope, ..)", ),
                "input_types": (),
                "name": "construct_scope_foo",
                "output_type": "Foo",
                "provider": "help_info_extracter_test",
            },
            "pants.help.help_info_extracter_test.test_get_all_help_info.rule_info_test":
            {
                "description": None,
                "documentation":
                "This rule is for testing info extraction only.",
                "input_gets": (),
                "input_types": ("Foo", ),
                "name":
                "pants.help.help_info_extracter_test.test_get_all_help_info.rule_info_test",
                "output_type": "Target",
                "provider": "help_info_extracter_test",
            },
        },
        "name_to_api_type_info": {
            "pants.help.help_info_extracter_test.Foo": {
                "consumed_by_rules":
                ("pants.help.help_info_extracter_test.test_get_all_help_info.rule_info_test",
                 ),
                "dependees": ("help_info_extracter_test", ),
                "dependencies": ("pants.option.scope", ),
                "documentation":
                None,
                "is_union":
                False,
                "module":
                "pants.help.help_info_extracter_test",
                "name":
                "Foo",
                "provider":
                "help_info_extracter_test",
                "returned_by_rules": ("construct_scope_foo", ),
                "union_members": (),
                "union_type":
                None,
                "used_in_rules": (),
            },
            "pants.engine.target.Target": {
                "consumed_by_rules": (),
                "dependees": (),
                "dependencies": (),
                "documentation":
                ("A Target represents an addressable set of metadata.\n\n    Set the `help` "
                 "class property with a description, which will be used in `./pants help`. For "
                 "the\n    best rendering, use soft wrapping (e.g. implicit string concatenation"
                 ") within paragraphs, but\n    hard wrapping (`\n`) to separate distinct "
                 "paragraphs and/or lists.\n    "),
                "is_union":
                False,
                "module":
                "pants.engine.target",
                "name":
                "Target",
                "provider":
                "help_info_extracter_test",
                "returned_by_rules":
                ("pants.help.help_info_extracter_test.test_get_all_help_info.rule_info_test",
                 ),
                "union_members": (),
                "union_type":
                None,
                "used_in_rules": (),
            },
            "pants.option.scope.Scope": {
                "consumed_by_rules": (),
                "dependees": (),
                "dependencies": (),
                "documentation": "An options scope.",
                "is_union": False,
                "module": "pants.option.scope",
                "name": "Scope",
                "provider": "pants.option.scope",
                "returned_by_rules": (),
                "union_members": (),
                "union_type": None,
                "used_in_rules": ("construct_scope_foo", ),
            },
        },
    }

    # Break down this colossal structure into pieces so it is easier to spot where the issue is.
    # Check keys equality first, then contents
    assert set(expected_all_help_info_dict) == set(all_help_info_dict)
    for key in all_help_info_dict:
        actual = all_help_info_dict[key]
        expected = expected_all_help_info_dict[key]
        assert expected == actual
Beispiel #18
0
    def setup_graph_extended(
        build_configuration: BuildConfiguration,
        execution_options: ExecutionOptions,
        native: Native,
        *,
        executor: PyExecutor,
        pants_ignore_patterns: List[str],
        use_gitignore: bool,
        local_store_dir: str,
        local_execution_root_dir: str,
        named_caches_dir: str,
        ca_certs_path: Optional[str] = None,
        build_root: Optional[str] = None,
        include_trace_on_error: bool = True,
        native_engine_visualize_to: Optional[str] = None,
    ) -> GraphScheduler:
        build_root = build_root or get_buildroot()

        rules = build_configuration.rules
        union_membership = UnionMembership.from_rules(
            build_configuration.union_rules)
        registered_target_types = RegisteredTargetTypes.create(
            build_configuration.target_types)

        execution_options = execution_options or DEFAULT_EXECUTION_OPTIONS

        @rule
        def parser_singleton() -> Parser:
            return Parser(
                target_type_aliases=registered_target_types.aliases,
                object_aliases=build_configuration.registered_aliases,
            )

        @rule
        def build_configuration_singleton() -> BuildConfiguration:
            return build_configuration

        @rule
        def registered_target_types_singleton() -> RegisteredTargetTypes:
            return registered_target_types

        @rule
        def union_membership_singleton() -> UnionMembership:
            return union_membership

        @rule
        def build_root_singleton() -> BuildRoot:
            return cast(BuildRoot, BuildRoot.instance)

        # Create a Scheduler containing graph and filesystem rules, with no installed goals.
        rules = FrozenOrderedSet((
            *collect_rules(locals()),
            *build_files.rules(),
            *fs.rules(),
            *environment.rules(),
            *desktop.rules(),
            *graph.rules(),
            *options_parsing.rules(),
            *process.rules(),
            *platform.rules(),
            *changed_rules(),
            *streaming_workunit_handler_rules(),
            *specs_calculator.rules(),
            *rules,
        ))
        goal_map = EngineInitializer._make_goal_map_from_rules(rules)
        rules = FrozenOrderedSet((
            *rules,
            # Install queries for each Goal.
            *(QueryRule(goal_type, GraphSession.goal_param_types)
              for goal_type in goal_map.values()),
            QueryRule(Snapshot, [PathGlobs]),  # Used by the SchedulerService.
        ))

        def ensure_absolute_path(v: str) -> str:
            return Path(v).resolve().as_posix()

        def ensure_optional_absolute_path(v: Optional[str]) -> Optional[str]:
            if v is None:
                return None
            return ensure_absolute_path(v)

        scheduler = Scheduler(
            native=native,
            ignore_patterns=pants_ignore_patterns,
            use_gitignore=use_gitignore,
            build_root=build_root,
            local_store_dir=ensure_absolute_path(local_store_dir),
            local_execution_root_dir=ensure_absolute_path(
                local_execution_root_dir),
            named_caches_dir=ensure_absolute_path(named_caches_dir),
            ca_certs_path=ensure_optional_absolute_path(ca_certs_path),
            rules=rules,
            union_membership=union_membership,
            executor=executor,
            execution_options=execution_options,
            include_trace_on_error=include_trace_on_error,
            visualize_to_dir=native_engine_visualize_to,
        )

        return GraphScheduler(scheduler, goal_map)
def test_get_all_help_info():
    class Global(Subsystem):
        options_scope = GLOBAL_SCOPE
        help = "Global options."

        opt1 = IntOption("-o", "--opt1", default=42, help="Option 1")

    class Foo(Subsystem):
        options_scope = "foo"
        help = "A foo."

        opt2 = BoolOption("--opt2",
                          default=True,
                          advanced=True,
                          help="Option 2")

    class Bar(GoalSubsystem):
        name = "bar"
        help = "The bar goal."
        deprecated_options_scope = "bar-old"
        deprecated_options_scope_removal_version = "9.9.999"

    class QuxField(StringField):
        alias = "qux"
        default = "blahblah"
        help = "A qux string."

    class QuuxField(IntField):
        alias = "quux"
        required = True
        help = "A quux int.\n\nMust be non-zero. Or zero. Whatever you like really."

    class BazLibrary(Target):
        alias = "baz_library"
        help = "A library of baz-es.\n\nUse it however you like."

        core_fields = [QuxField, QuuxField]

    options = Options.create(
        env={},
        config=Config.load([]),
        known_scope_infos=[
            Global.get_scope_info(),
            Foo.get_scope_info(),
            Bar.get_scope_info()
        ],
        args=["./pants"],
        bootstrap_option_values=None,
    )
    Global.register_options_on_scope(options)
    Foo.register_options_on_scope(options)
    Bar.register_options_on_scope(options)

    @rule
    def rule_info_test(foo: Foo) -> Target:
        """This rule is for testing info extraction only."""

    def fake_consumed_scopes_mapper(scope: str) -> Tuple[str, ...]:
        return ("somescope", f"used_by_{scope or 'GLOBAL_SCOPE'}")

    bc_builder = BuildConfiguration.Builder()
    bc_builder.register_subsystems("help_info_extracter_test", (Foo, Bar))
    bc_builder.register_target_types("help_info_extracter_test",
                                     (BazLibrary, ))
    bc_builder.register_rules("help_info_extracter_test",
                              collect_rules(locals()))

    all_help_info = HelpInfoExtracter.get_all_help_info(
        options,
        UnionMembership({}),
        fake_consumed_scopes_mapper,
        RegisteredTargetTypes({BazLibrary.alias: BazLibrary}),
        bc_builder.create(),
    )

    all_help_info_dict = all_help_info.asdict()
    expected_all_help_info_dict = {
        "scope_to_help_info": {
            GLOBAL_SCOPE: {
                "scope":
                GLOBAL_SCOPE,
                "description":
                "Global options.",
                "provider":
                "",
                "is_goal":
                False,
                "deprecated_scope":
                None,
                "basic": ({
                    "display_args": ("-o=<int>", "--opt1=<int>"),
                    "comma_separated_display_args": "-o=<int>, --opt1=<int>",
                    "scoped_cmd_line_args": ("-o", "--opt1"),
                    "unscoped_cmd_line_args": ("-o", "--opt1"),
                    "config_key": "opt1",
                    "env_var": "PANTS_OPT1",
                    "value_history": {
                        "ranked_values": (
                            {
                                "rank": Rank.NONE,
                                "value": None,
                                "details": None
                            },
                            {
                                "rank": Rank.HARDCODED,
                                "value": 42,
                                "details": None
                            },
                        ),
                    },
                    "typ": int,
                    "default": 42,
                    "help": "Option 1",
                    "deprecation_active": False,
                    "deprecated_message": None,
                    "removal_version": None,
                    "removal_hint": None,
                    "choices": None,
                    "comma_separated_choices": None,
                }, ),
                "advanced":
                tuple(),
                "deprecated":
                tuple(),
            },
            "foo": {
                "scope":
                "foo",
                "provider":
                "help_info_extracter_test",
                "description":
                "A foo.",
                "is_goal":
                False,
                "deprecated_scope":
                None,
                "basic": (),
                "advanced": ({
                    "display_args": ("--[no-]foo-opt2", ),
                    "comma_separated_display_args":
                    "--[no-]foo-opt2",
                    "scoped_cmd_line_args": ("--foo-opt2", "--no-foo-opt2"),
                    "unscoped_cmd_line_args": ("--opt2", "--no-opt2"),
                    "config_key":
                    "opt2",
                    "env_var":
                    "PANTS_FOO_OPT2",
                    "value_history": {
                        "ranked_values": (
                            {
                                "rank": Rank.NONE,
                                "value": None,
                                "details": None
                            },
                            {
                                "rank": Rank.HARDCODED,
                                "value": True,
                                "details": None
                            },
                        ),
                    },
                    "typ":
                    bool,
                    "default":
                    True,
                    "help":
                    "Option 2",
                    "deprecation_active":
                    False,
                    "deprecated_message":
                    None,
                    "removal_version":
                    None,
                    "removal_hint":
                    None,
                    "choices":
                    None,
                    "comma_separated_choices":
                    None,
                }, ),
                "deprecated":
                tuple(),
            },
            "bar": {
                "scope": "bar",
                "provider": "help_info_extracter_test",
                "description": "The bar goal.",
                "is_goal": True,
                "deprecated_scope": "bar-old",
                "basic": tuple(),
                "advanced": tuple(),
                "deprecated": tuple(),
            },
            "bar-old": {
                "scope": "bar-old",
                "provider": "help_info_extracter_test",
                "description": "The bar goal.",
                "is_goal": True,
                "deprecated_scope": "bar-old",
                "basic": tuple(),
                "advanced": tuple(),
                "deprecated": tuple(),
            },
        },
        "rule_output_type_to_rule_infos": {
            "Foo": ({
                "description": None,
                "help": "A foo.",
                "input_gets": ("Get(ScopedOptions, Scope, ..)", ),
                "input_types": (),
                "name": "construct_scope_foo",
                "output_desc": None,
                "output_type": "Foo",
                "provider": "help_info_extracter_test",
            }, ),
            "Target": ({
                "description":
                None,
                "help":
                "This rule is for testing info extraction only.",
                "input_gets": (),
                "input_types": ("Foo", ),
                "name":
                "pants.help.help_info_extracter_test.rule_info_test",
                "output_desc":
                ("A Target represents an addressable set of metadata.\n\n    Set the "
                 "`help` class property with a description, which will be used in "
                 "`./pants help`. For the\n    best rendering, use soft wrapping (e.g. "
                 "implicit string concatenation) within paragraphs, but\n    hard wrapping "
                 "(`\n`) to separate distinct paragraphs and/or lists.\n    "),
                "output_type":
                "Target",
                "provider":
                "help_info_extracter_test",
            }, ),
        },
        "name_to_goal_info": {
            "bar": {
                "name": "bar",
                "provider": "help_info_extracter_test",
                "description": "The bar goal.",
                "consumed_scopes": ("somescope", "used_by_bar"),
                "is_implemented": True,
            },
            "bar-old": {
                "name": "bar",
                "provider": "help_info_extracter_test",
                "description": "The bar goal.",
                "consumed_scopes": ("somescope", "used_by_bar-old"),
                "is_implemented": True,
            },
        },
        "name_to_target_type_info": {
            "baz_library": {
                "alias":
                "baz_library",
                "provider":
                "help_info_extracter_test",
                "summary":
                "A library of baz-es.",
                "description":
                "A library of baz-es.\n\nUse it however you like.",
                "fields": (
                    {
                        "alias": "qux",
                        "provider": "",
                        "default": "'blahblah'",
                        "description": "A qux string.",
                        "required": False,
                        "type_hint": "str | None",
                    },
                    {
                        "alias":
                        "quux",
                        "provider":
                        "",
                        "default":
                        None,
                        "description":
                        "A quux int.\n\nMust be non-zero. Or zero. "
                        "Whatever you like really.",
                        "required":
                        True,
                        "type_hint":
                        "int",
                    },
                ),
            }
        },
    }
    assert expected_all_help_info_dict == all_help_info_dict
Beispiel #20
0
    def setup_graph_extended(
        options_bootstrapper: OptionsBootstrapper,
        build_configuration: BuildConfiguration,
        execution_options: ExecutionOptions,
        native: Native,
        *,
        pants_ignore_patterns: List[str],
        use_gitignore: bool,
        local_store_dir: str,
        local_execution_root_dir: str,
        named_caches_dir: str,
        build_root: Optional[str] = None,
        include_trace_on_error: bool = True,
    ) -> GraphScheduler:
        build_root = build_root or get_buildroot()

        build_configuration = build_configuration or BuildConfigInitializer.get(
            options_bootstrapper)
        rules = build_configuration.rules
        union_membership = UnionMembership.from_rules(
            build_configuration.union_rules)
        registered_target_types = RegisteredTargetTypes.create(
            build_configuration.target_types)

        bootstrap_options = options_bootstrapper.bootstrap_options.for_global_scope(
        )
        execution_options = execution_options or DEFAULT_EXECUTION_OPTIONS

        @rule
        def parser_singleton() -> Parser:
            return Parser(
                target_type_aliases=registered_target_types.aliases,
                object_aliases=build_configuration.registered_aliases,
            )

        @rule
        def build_configuration_singleton() -> BuildConfiguration:
            return build_configuration

        @rule
        def registered_target_types_singleton() -> RegisteredTargetTypes:
            return registered_target_types

        @rule
        def union_membership_singleton() -> UnionMembership:
            return union_membership

        @rule
        def build_root_singleton() -> BuildRoot:
            return cast(BuildRoot, BuildRoot.instance)

        # Create a Scheduler containing graph and filesystem rules, with no installed goals.
        rules = FrozenOrderedSet((
            *collect_rules(locals()),
            RootRule(Console),
            *build_files.rules(),
            *fs.rules(),
            *graph.rules(),
            *uuid.rules(),
            *options_parsing.rules(),
            *process.rules(),
            *create_platform_rules(),
            *changed_rules(),
            *rules,
        ))

        goal_map = EngineInitializer._make_goal_map_from_rules(rules)

        def ensure_absolute_path(v: str) -> str:
            return Path(v).resolve().as_posix()

        scheduler = Scheduler(
            native=native,
            ignore_patterns=pants_ignore_patterns,
            use_gitignore=use_gitignore,
            build_root=build_root,
            local_store_dir=ensure_absolute_path(local_store_dir),
            local_execution_root_dir=ensure_absolute_path(
                local_execution_root_dir),
            named_caches_dir=ensure_absolute_path(named_caches_dir),
            rules=rules,
            union_membership=union_membership,
            execution_options=execution_options,
            include_trace_on_error=include_trace_on_error,
            visualize_to_dir=bootstrap_options.native_engine_visualize_to,
        )

        return GraphScheduler(scheduler, goal_map)
def test_get_all_help_info():
    class Global(Subsystem):
        options_scope = GLOBAL_SCOPE
        help = "Global options."

        @classmethod
        def register_options(cls, register):
            register("-o", "--opt1", type=int, default=42, help="Option 1")

    class Foo(Subsystem):
        options_scope = "foo"
        help = "A foo."

        @classmethod
        def register_options(cls, register):
            register("--opt2", type=bool, default=True, help="Option 2")
            register("--opt3", advanced=True, choices=["a", "b", "c"])

    class Bar(GoalSubsystem):
        name = "bar"
        help = "The bar goal."

    class QuxField(StringField):
        alias = "qux"
        default = "blahblah"
        help = "A qux string."

    class QuuxField(IntField):
        alias = "quux"
        required = True
        help = "A quux int.\n\nMust be non-zero. Or zero. Whatever you like really."

    class BazLibrary(Target):
        alias = "baz_library"
        help = "A library of baz-es.\n\nUse it however you like."

        core_fields = [QuxField, QuuxField]

    options = Options.create(
        env={},
        config=Config.load_file_contents(""),
        known_scope_infos=[
            Global.get_scope_info(),
            Foo.get_scope_info(),
            Bar.get_scope_info()
        ],
        args=["./pants"],
        bootstrap_option_values=None,
    )
    Global.register_options_on_scope(options)
    Foo.register_options_on_scope(options)
    Bar.register_options_on_scope(options)

    def fake_consumed_scopes_mapper(scope: str) -> Tuple[str, ...]:
        return ("somescope", f"used_by_{scope or 'GLOBAL_SCOPE'}")

    all_help_info = HelpInfoExtracter.get_all_help_info(
        options,
        UnionMembership({}),
        fake_consumed_scopes_mapper,
        RegisteredTargetTypes({BazLibrary.alias: BazLibrary}),
    )
    all_help_info_dict = dataclasses.asdict(all_help_info)
    expected_all_help_info_dict = {
        "scope_to_help_info": {
            GLOBAL_SCOPE: {
                "scope":
                GLOBAL_SCOPE,
                "description":
                "Global options.",
                "is_goal":
                False,
                "basic": ({
                    "display_args": ("-o=<int>", "--opt1=<int>"),
                    "comma_separated_display_args": "-o=<int>, --opt1=<int>",
                    "scoped_cmd_line_args": ("-o", "--opt1"),
                    "unscoped_cmd_line_args": ("-o", "--opt1"),
                    "config_key": "opt1",
                    "env_var": "PANTS_OPT1",
                    "value_history": {
                        "ranked_values": (
                            {
                                "rank": Rank.NONE,
                                "value": None,
                                "details": None
                            },
                            {
                                "rank": Rank.HARDCODED,
                                "value": 42,
                                "details": None
                            },
                        ),
                    },
                    "typ": int,
                    "default": 42,
                    "help": "Option 1",
                    "deprecation_active": False,
                    "deprecated_message": None,
                    "removal_version": None,
                    "removal_hint": None,
                    "choices": None,
                    "comma_separated_choices": None,
                }, ),
                "advanced":
                tuple(),
                "deprecated":
                tuple(),
            },
            "foo": {
                "scope":
                "foo",
                "description":
                "A foo.",
                "is_goal":
                False,
                "basic": ({
                    "display_args": ("--[no-]foo-opt2", ),
                    "comma_separated_display_args":
                    "--[no-]foo-opt2",
                    "scoped_cmd_line_args": ("--foo-opt2", "--no-foo-opt2"),
                    "unscoped_cmd_line_args": ("--opt2", "--no-opt2"),
                    "config_key":
                    "opt2",
                    "env_var":
                    "PANTS_FOO_OPT2",
                    "value_history": {
                        "ranked_values": (
                            {
                                "rank": Rank.NONE,
                                "value": None,
                                "details": None
                            },
                            {
                                "rank": Rank.HARDCODED,
                                "value": True,
                                "details": None
                            },
                        ),
                    },
                    "typ":
                    bool,
                    "default":
                    True,
                    "help":
                    "Option 2",
                    "deprecation_active":
                    False,
                    "deprecated_message":
                    None,
                    "removal_version":
                    None,
                    "removal_hint":
                    None,
                    "choices":
                    None,
                    "comma_separated_choices":
                    None,
                }, ),
                "advanced": ({
                    "display_args": ("--foo-opt3=<str>", ),
                    "comma_separated_display_args": "--foo-opt3=<str>",
                    "scoped_cmd_line_args": ("--foo-opt3", ),
                    "unscoped_cmd_line_args": ("--opt3", ),
                    "config_key": "opt3",
                    "env_var": "PANTS_FOO_OPT3",
                    "value_history": {
                        "ranked_values": ({
                            "rank": Rank.NONE,
                            "value": None,
                            "details": None
                        }, ),
                    },
                    "typ": str,
                    "default": None,
                    "help": "No help available.",
                    "deprecation_active": False,
                    "deprecated_message": None,
                    "removal_version": None,
                    "removal_hint": None,
                    "choices": ("a", "b", "c"),
                    "comma_separated_choices": "a, b, c",
                }, ),
                "deprecated":
                tuple(),
            },
            "bar": {
                "scope": "bar",
                "description": "The bar goal.",
                "is_goal": True,
                "basic": tuple(),
                "advanced": tuple(),
                "deprecated": tuple(),
            },
        },
        "name_to_goal_info": {
            "bar": {
                "name": "bar",
                "description": "The bar goal.",
                "consumed_scopes": ("somescope", "used_by_bar"),
                "is_implemented": True,
            }
        },
        "name_to_target_type_info": {
            "baz_library": {
                "alias":
                "baz_library",
                "summary":
                "A library of baz-es.",
                "description":
                "A library of baz-es.\n\nUse it however you like.",
                "fields": (
                    {
                        "alias": "qux",
                        "default": "'blahblah'",
                        "description": "A qux string.",
                        "required": False,
                        "type_hint": "str | None",
                    },
                    {
                        "alias":
                        "quux",
                        "default":
                        None,
                        "description":
                        "A quux int.\n\nMust be non-zero. Or zero. "
                        "Whatever you like really.",
                        "required":
                        True,
                        "type_hint":
                        "int",
                    },
                ),
            }
        },
    }
    assert expected_all_help_info_dict == all_help_info_dict