Beispiel #1
0
 def test_single_non_test_target(self):
     bfaddr = BuildFileAddress(None, 'bin', 'some/dir')
     target_adaptor = PythonBinaryAdaptor(type_alias='python_binary')
     with self.captured_logging(logging.INFO):
         # Note that this is not the same error message the end user will see, as we're resolving
         # union Get requests in run_rule, not the real engine.  But this test still asserts that
         # we error when we expect to error.
         with self.assertRaisesRegex(
                 AssertionError,
                 r'Rule requested: .* which cannot be satisfied.'):
             run_rule(
                 coordinator_of_tests,
                 rule_args=[
                     HydratedTarget(bfaddr.to_address(), target_adaptor,
                                    ()),
                     UnionMembership(
                         union_rules={TestTarget: [PythonTestsAdaptor]}),
                     AddressProvenanceMap(
                         bfaddr_to_spec={
                             bfaddr:
                             SingleAddress(directory='some/dir',
                                           name='bin'),
                         }),
                 ],
                 mock_gets=[
                     MockGet(
                         product_type=TestResult,
                         subject_type=PythonTestsAdaptor,
                         mock=lambda _: TestResult(status=Status.SUCCESS,
                                                   stdout='foo',
                                                   stderr=''),
                     ),
                 ],
             )
Beispiel #2
0
 def run_lint_rule(
     *,
     linters: List[Type[Linter]],
     targets: List[HydratedTargetWithOrigin],
     per_target_caching: bool,
 ) -> Tuple[int, str]:
     console = MockConsole(use_colors=False)
     union_membership = UnionMembership(
         OrderedDict({Linter: OrderedSet(linters)}))
     result: Lint = run_rule(
         lint,
         rule_args=[
             console,
             HydratedTargetsWithOrigins(targets),
             MockOptions(per_target_caching=per_target_caching),
             union_membership,
         ],
         mock_gets=[
             MockGet(
                 product_type=LintResult,
                 subject_type=Linter,
                 mock=lambda linter: linter.lint_result,
             ),
         ],
         union_membership=union_membership,
     )
     return result.exit_code, console.stdout.getvalue()
Beispiel #3
0
def fmt(console: Console, targets: HydratedTargets,
        union_membership: UnionMembership) -> Fmt:
    results = yield [
        Get(FmtResult, TargetWithSources, target.adaptor) for target in targets
        # TODO: make TargetAdaptor return a 'sources' field with an empty snapshot instead of
        # raising to remove the hasattr() checks here!
        if union_membership.is_member(TargetWithSources, target.adaptor)
        and hasattr(target.adaptor, "sources")
    ]

    for result in results:
        files_content = yield Get(FilesContent, Digest, result.digest)
        # TODO: This is hacky and inefficient, and should be replaced by using the Workspace type
        # once that is available on master.
        # Blocked on: https://github.com/pantsbuild/pants/pull/8329
        for file_content in files_content:
            with Path(get_buildroot(), file_content.path).open('wb') as f:
                f.write(file_content.content)

        if result.stdout:
            console.print_stdout(result.stdout)
        if result.stderr:
            console.print_stderr(result.stderr)

    # Since we ran an ExecuteRequest, any failure would already have interrupted our flow
    exit_code = 0
    yield Fmt(exit_code)
Beispiel #4
0
    def test_coordinator_python_test(self):
        addr = Address.parse("some/target")
        target_adaptor = PythonTestsAdaptor(type_alias='python_tests')
        with self.captured_logging(logging.INFO):
            result = run_rule(
                coordinator_of_tests,
                rule_args=[
                    HydratedTarget(addr, target_adaptor, ()),
                    UnionMembership(
                        union_rules={TestTarget: [PythonTestsAdaptor]}),
                    AddressProvenanceMap(bfaddr_to_spec={}),
                ],
                mock_gets=[
                    MockGet(
                        product_type=TestResult,
                        subject_type=PythonTestsAdaptor,
                        mock=lambda _: TestResult(
                            status=Status.FAILURE, stdout='foo', stderr=''),
                    ),
                ],
            )

        self.assertEqual(
            result,
            AddressAndTestResult(
                addr, TestResult(status=Status.FAILURE,
                                 stdout='foo',
                                 stderr='')))
Beispiel #5
0
    def test_globbed_non_test_target(self):
        bfaddr = BuildFileAddress(None, 'bin', 'some/dir')
        target_adaptor = PythonBinaryAdaptor(type_alias='python_binary')
        with self.captured_logging(logging.INFO):
            result = run_rule(
                coordinator_of_tests,
                rule_args=[
                    HydratedTarget(bfaddr.to_address(), target_adaptor, ()),
                    UnionMembership(
                        union_rules={TestTarget: [PythonTestsAdaptor]}),
                    AddressProvenanceMap(
                        bfaddr_to_spec={
                            bfaddr: DescendantAddresses(directory='some/dir')
                        }),
                ],
                mock_gets=[
                    MockGet(
                        product_type=TestResult,
                        subject_type=PythonTestsAdaptor,
                        mock=lambda _: TestResult(
                            status=Status.SUCCESS, stdout='foo', stderr=''),
                    ),
                ],
            )

            self.assertEqual(result,
                             AddressAndTestResult(bfaddr.to_address(), None))
Beispiel #6
0
def test_has_fields() -> None:
    empty_union_membership = UnionMembership({})
    tgt = FortranTarget({}, address=Address.parse(":lib"))

    assert tgt.field_types == (FortranExtensions, FortranSources)
    assert tgt.class_field_types(union_membership=empty_union_membership) == (
        FortranExtensions,
        FortranSources,
    )

    assert tgt.has_fields([]) is True
    assert FortranTarget.class_has_fields(
        [], union_membership=empty_union_membership) is True

    assert tgt.has_fields([FortranExtensions]) is True
    assert tgt.has_field(FortranExtensions) is True
    assert (FortranTarget.class_has_fields(
        [FortranExtensions], union_membership=empty_union_membership) is True)
    assert (FortranTarget.class_has_field(
        FortranExtensions, union_membership=empty_union_membership) is True)

    assert tgt.has_fields([UnrelatedField]) is False
    assert tgt.has_field(UnrelatedField) is False
    assert (FortranTarget.class_has_fields(
        [UnrelatedField], union_membership=empty_union_membership) is False)
    assert (FortranTarget.class_has_field(
        UnrelatedField, union_membership=empty_union_membership) is False)

    assert tgt.has_fields([FortranExtensions, UnrelatedField]) is False
    assert (FortranTarget.class_has_fields(
        [FortranExtensions, UnrelatedField],
        union_membership=empty_union_membership) is False)
Beispiel #7
0
def test_add_custom_fields() -> None:
    class CustomField(BoolField):
        alias: ClassVar = "custom_field"
        default: ClassVar = False

    union_membership = UnionMembership(
        {FortranTarget.PluginField: OrderedSet([CustomField])})
    tgt_values = {CustomField.alias: True}
    tgt = FortranTarget(tgt_values,
                        address=Address.parse(":lib"),
                        union_membership=union_membership)

    assert tgt.field_types == (FortranExtensions, FortranSources, CustomField)
    assert tgt.core_fields == (FortranExtensions, FortranSources)
    assert tgt.plugin_fields == (CustomField, )
    assert tgt.has_field(CustomField) is True

    assert FortranTarget.class_field_types(
        union_membership=union_membership) == (
            FortranExtensions,
            FortranSources,
            CustomField,
        )
    assert FortranTarget.class_has_field(
        CustomField, union_membership=union_membership) is True

    assert tgt[CustomField].value is True

    default_tgt = FortranTarget({},
                                address=Address.parse(":default"),
                                union_membership=union_membership)
    assert default_tgt[CustomField].value is False
Beispiel #8
0
 def run_fmt_rule(self, *,
                  targets: List[HydratedTarget]) -> Tuple[Fmt, str]:
     result_digest = self.request_single_product(
         Digest,
         InputFilesContent([
             FileContent(path=str(self.formatted_file),
                         content=self.formatted_content.encode())
         ]))
     console = MockConsole(use_colors=False)
     result: Fmt = run_rule(
         fmt,
         rule_args=[
             console,
             HydratedTargets(targets),
             Workspace(self.scheduler),
             UnionMembership(
                 union_rules={FormatTarget: [PythonTargetAdaptor]})
         ],
         mock_gets=[
             MockGet(product_type=AggregatedFmtResults,
                     subject_type=PythonTargetAdaptor,
                     mock=lambda adaptor: AggregatedFmtResults(
                         (FmtResult(digest=result_digest,
                                    stdout=f"Formatted `{adaptor.name}`",
                                    stderr=""), ),
                         combined_digest=result_digest)),
             MockGet(product_type=Digest,
                     subject_type=DirectoriesToMerge,
                     mock=lambda _: result_digest),
         ],
     )
     return result, console.stdout.getvalue()
Beispiel #9
0
    def __init__(
        self,
        unhydrated_values: Dict[str, Any],
        *,
        address: Address,
        # NB: `union_membership` is only optional to facilitate tests. In production, we should
        # always provide this parameter. This should be safe to do because production code should
        # rarely directly instantiate Targets and should instead use the engine to request them.
        union_membership: Optional[UnionMembership] = None,
    ) -> None:
        self.address = address
        self.plugin_fields = self._find_plugin_fields(union_membership
                                                      or UnionMembership({}))

        field_values = {}
        aliases_to_field_types = {
            field_type.alias: field_type
            for field_type in self.field_types
        }
        for alias, value in unhydrated_values.items():
            if alias not in aliases_to_field_types:
                raise InvalidFieldException(
                    f"Unrecognized field `{alias}={value}` in target {address}. Valid fields for "
                    f"the target type `{self.alias}`: {sorted(aliases_to_field_types.keys())}.",
                )
            field_type = aliases_to_field_types[alias]
            field_values[field_type] = field_type(value, address=address)
        # For undefined fields, mark the raw value as None.
        for field_type in set(self.field_types) - set(field_values.keys()):
            field_values[field_type] = field_type(raw_value=None,
                                                  address=address)
        self.field_values = FrozenDict(field_values)
Beispiel #10
0
def test_has_fields() -> None:
    class UnrelatedField(BoolField):
        alias: ClassVar = "unrelated"
        default: ClassVar = False

    empty_union_membership = UnionMembership({})

    tgt = HaskellTarget({}, address=Address.parse(":lib"))
    assert tgt.has_fields([]) is True
    assert HaskellTarget.class_has_fields(
        [], union_membership=empty_union_membership) is True

    assert tgt.has_fields([HaskellGhcExtensions]) is True
    assert tgt.has_field(HaskellGhcExtensions) is True
    assert (HaskellTarget.class_has_fields(
        [HaskellGhcExtensions], union_membership=empty_union_membership) is
            True)
    assert (HaskellTarget.class_has_field(
        HaskellGhcExtensions, union_membership=empty_union_membership) is True)

    assert tgt.has_fields([UnrelatedField]) is False
    assert tgt.has_field(UnrelatedField) is False
    assert (HaskellTarget.class_has_fields(
        [UnrelatedField], union_membership=empty_union_membership) is False)
    assert (HaskellTarget.class_has_field(
        UnrelatedField, union_membership=empty_union_membership) is False)

    assert tgt.has_fields([HaskellGhcExtensions, UnrelatedField]) is False
    assert (HaskellTarget.class_has_fields(
        [HaskellGhcExtensions, UnrelatedField],
        union_membership=empty_union_membership) is False)
Beispiel #11
0
 def is_testable(
     adaptor_with_origin: TargetAdaptorWithOrigin, *, union_membership: UnionMembership,
 ) -> bool:
     is_test_target = union_membership.is_member(TestTarget, adaptor_with_origin)
     is_not_a_glob = isinstance(
         adaptor_with_origin.origin, (SingleAddress, FilesystemLiteralSpec)
     )
     return adaptor_with_origin.adaptor.has_sources() and (is_test_target or is_not_a_glob)
Beispiel #12
0
    def run_test_rule(
        self,
        *,
        test_runner: Type[TestRunner],
        targets: List[HydratedTargetWithOrigin],
        debug: bool = False,
    ) -> 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(
            {TestRunner: OrderedSet([test_runner])})

        def mock_coordinator_of_tests(
            wrapped_test_runner: WrappedTestRunner, ) -> AddressAndTestResult:
            runner = wrapped_test_runner.runner
            return AddressAndTestResult(
                address=runner.adaptor_with_origin.adaptor.address,
                test_result=runner.test_result,  # type: ignore[attr-defined]
            )

        result: Test = run_rule(
            run_tests,
            rule_args=[
                console,
                options,
                interactive_runner,
                HydratedTargetsWithOrigins(targets),
                workspace,
                union_membership,
            ],
            mock_gets=[
                MockGet(
                    product_type=AddressAndTestResult,
                    subject_type=WrappedTestRunner,
                    mock=lambda wrapped_test_runner: mock_coordinator_of_tests(
                        wrapped_test_runner),
                ),
                MockGet(
                    product_type=TestDebugRequest,
                    subject_type=TestRunner,
                    mock=lambda _: TestDebugRequest(self.make_ipr()),
                ),
                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 #13
0
    def run_goal_rules(
        self,
        *,
        options_bootstrapper: OptionsBootstrapper,
        union_membership: UnionMembership,
        options: Options,
        goals: Iterable[str],
        specs: Specs,
    ):
        """Runs @goal_rules sequentially and interactively by requesting their implicit Goal
        products.

        For retryable failures, raises scheduler.ExecutionError.

        :returns: An exit code.
        """

        global_options = options.for_global_scope()

        console = Console(
            use_colors=global_options.colors,
            session=self.scheduler_session
            if global_options.get("v2_ui") else None,
        )
        workspace = Workspace(self.scheduler_session)
        interactive_runner = InteractiveRunner(self.scheduler_session)

        for goal in goals:
            goal_product = self.goal_map[goal]
            # NB: We no-op for goals that have no V2 implementation because no relevant backends are
            # registered. This allows us to safely set `--v1 --v2`, even if no V2 backends are registered.
            # Once V1 is removed, we might want to reconsider the behavior to instead warn or error when
            # trying to run something like `./pants run` without any backends registered.
            is_implemented = union_membership.has_members_for_all(
                goal_product.subsystem_cls.required_union_implementations)
            if not is_implemented:
                continue
            params = Params(
                specs.provided_specs,
                options_bootstrapper,
                console,
                workspace,
                interactive_runner,
            )
            logger.debug(
                f"requesting {goal_product} to satisfy execution of `{goal}` goal"
            )
            try:
                exit_code = self.scheduler_session.run_goal_rule(
                    goal_product, params)
            finally:
                console.flush()

            if exit_code != PANTS_SUCCEEDED_EXIT_CODE:
                return exit_code

        return PANTS_SUCCEEDED_EXIT_CODE
Beispiel #14
0
 def is_lintable(target_adaptor: TargetAdaptor, *,
                 union_membership: UnionMembership) -> bool:
     return (
         union_membership.is_member(LintTarget, target_adaptor)
         # TODO: make TargetAdaptor return a 'sources' field with an empty snapshot instead of
         #  raising to remove the hasattr() checks here!
         and hasattr(target_adaptor, "sources") and
         target_adaptor.sources.snapshot.files  # i.e., sources is not empty
     )
Beispiel #15
0
 def is_testable(target: HydratedTarget, *,
                 union_membership: UnionMembership,
                 provenance_map: AddressProvenanceMap) -> bool:
     is_valid_target_type = (
         provenance_map.is_single_address(target.address)
         or union_membership.is_member(TestTarget, target.adaptor))
     has_sources = hasattr(
         target.adaptor,
         "sources") and target.adaptor.sources.snapshot.files
     return is_valid_target_type and has_sources
def test_list_single() -> None:
    class CustomField(BoolField):
        """My custom field!

        Use this field to...
        """

        alias = "custom_field"
        required = True

    tests_target_stdout = run_goal(
        union_membership=UnionMembership(
            {FortranTests.PluginField: OrderedSet([CustomField])}),
        details_target=FortranTests.alias,
    )
    assert tests_target_stdout == dedent("""\

        fortran_tests
        -------------

        Tests for Fortran code.
        
        This assumes that you use the FRUIT test framework.

        Valid fields:

            custom_field
                type: bool, required
                My custom field! Use this field to...

            fortran_version
                type: str | None, default: None
            
            timeout
                type: int | None, default: None
                The number of seconds to run before timing out.
        """)

    binary_target_stdout = run_goal(details_target=FortranBinary.alias)
    assert binary_target_stdout == dedent("""\

        fortran_binary
        --------------

        Valid fields:

            archive_format
                type: '.tar' | '.tgz' | None, default: '.tgz'

            error_behavior
                type: 'error' | 'ignore' | 'warn', required

            fortran_version
                type: str | None, default: None
        """)
Beispiel #17
0
 def run_coordinator_of_tests(
     self,
     *,
     address: Address,
     origin: Optional[OriginSpec] = None,
     test_target_type: bool = True,
     include_sources: bool = True,
 ) -> AddressAndTestResult:
     mocked_fileset = EagerFilesetWithSpec(
         "src",
         {"globs": []},
         snapshot=Snapshot(
             # TODO: this is not robust to set as an empty digest. Add a test util that provides
             #  some premade snapshots and possibly a generalized make_hydrated_target function.
             directory_digest=EMPTY_DIRECTORY_DIGEST,
             files=tuple(["test.py"] if include_sources else []),
             dirs=(),
         ),
     )
     adaptor_cls = PythonTestsAdaptor if test_target_type else PythonBinaryAdaptor
     type_alias = "python_tests" if test_target_type else "python_binary"
     adaptor = adaptor_cls(address=address,
                           type_alias=type_alias,
                           sources=mocked_fileset)
     union_membership = UnionMembership(union_rules=OrderedDict(
         {TestTarget: OrderedSet([PythonTestsAdaptorWithOrigin])}))
     with self.captured_logging(logging.INFO):
         result: AddressAndTestResult = run_rule(
             coordinator_of_tests,
             rule_args=[
                 HydratedTargetWithOrigin(
                     target=HydratedTarget(adaptor),
                     origin=(origin
                             or SingleAddress(directory=address.spec_path,
                                              name=address.target_name)),
                 ),
                 union_membership,
             ],
             mock_gets=[
                 MockGet(
                     product_type=TestResult,
                     subject_type=TestTarget,
                     mock=lambda _: TestResult(
                         status=Status.SUCCESS, stdout="foo", stderr=""),
                 ),
             ],
             union_membership=union_membership,
         )
     return result
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 #19
0
def run_lint_rule(
  *,
  targets: List[HydratedTarget],
  mock_linter: Callable[[PythonTargetAdaptor], LintResult],
) -> Tuple[Lint, MockConsole]:
  console = MockConsole(use_colors=False)
  result: Lint = run_rule(
    lint,
    rule_args=[
      console,
      HydratedTargets(targets),
      UnionMembership(union_rules={TargetWithSources: [PythonTargetAdaptor]})
    ],
    mock_gets=[
      MockGet(product_type=LintResult, subject_type=PythonTargetAdaptor, mock=mock_linter),
    ],
  )
  return result, console
Beispiel #20
0
        def create(cls, options_bootstrapper, full_init=True) -> "PantsDaemon":
            """
            :param OptionsBootstrapper options_bootstrapper: The bootstrap options.
            :param bool full_init: Whether or not to fully initialize an engine et al for the purposes
                                   of spawning a new daemon. `full_init=False` is intended primarily
                                   for lightweight lifecycle checks (since there is a ~1s overhead to
                                   initialize the engine). See the impl of `maybe_launch` for an example
                                   of the intended usage.
            """
            bootstrap_options = options_bootstrapper.bootstrap_options
            bootstrap_options_values = bootstrap_options.for_global_scope()
            # TODO: https://github.com/pantsbuild/pants/issues/3479
            watchman = WatchmanLauncher.create(
                bootstrap_options_values).watchman

            native: Optional[Native] = None
            build_root: Optional[str] = None

            if full_init:
                build_root = get_buildroot()
                native = Native()
                build_config = BuildConfigInitializer.get(options_bootstrapper)
                legacy_graph_scheduler = EngineInitializer.setup_legacy_graph(
                    native, options_bootstrapper, build_config)
                services = cls._setup_services(
                    build_root,
                    bootstrap_options_values,
                    legacy_graph_scheduler,
                    watchman,
                    union_membership=UnionMembership(
                        build_config.union_rules()),
                )
            else:
                services = PantsServices()

            return PantsDaemon(
                native=native,
                build_root=build_root,
                work_dir=bootstrap_options_values.pants_workdir,
                log_level=bootstrap_options_values.level,
                services=services,
                metadata_base_dir=bootstrap_options_values.pants_subprocessdir,
                bootstrap_options=bootstrap_options,
            )
Beispiel #21
0
 def run_coordinator_of_tests(
     self,
     *,
     address: Address,
     bfaddr_to_address_spec: Optional[Dict[BuildFileAddress,
                                           AddressSpec]] = None,
     test_target_type: bool = True,
     include_sources: bool = True,
 ) -> AddressAndTestResult:
     mocked_fileset = EagerFilesetWithSpec(
         "src",
         {"globs": []},
         snapshot=Snapshot(
             # TODO: this is not robust to set as an empty digest. Add a test util that provides
             #  some premade snapshots and possibly a generalized make_hydrated_target function.
             directory_digest=EMPTY_DIRECTORY_DIGEST,
             files=tuple(["test.py"] if include_sources else []),
             dirs=()))
     target_adaptor = (PythonTestsAdaptor(type_alias='python_tests',
                                          sources=mocked_fileset)
                       if test_target_type else PythonBinaryAdaptor(
                           type_alias='python_binary',
                           sources=mocked_fileset))
     with self.captured_logging(logging.INFO):
         result: AddressAndTestResult = run_rule(
             coordinator_of_tests,
             rule_args=[
                 HydratedTarget(address, target_adaptor, ()),
                 UnionMembership(
                     union_rules={TestTarget: [PythonTestsAdaptor]}),
                 AddressProvenanceMap(
                     bfaddr_to_address_spec=bfaddr_to_address_spec or {}),
             ],
             mock_gets=[
                 MockGet(
                     product_type=TestResult,
                     subject_type=PythonTestsAdaptor,
                     mock=lambda _: TestResult(
                         status=Status.SUCCESS, stdout='foo', stderr=''),
                 ),
             ],
         )
     return result
Beispiel #22
0
def run_fmt_rule(
  *,
  targets: List[HydratedTarget],
  mock_formatter: Callable[[PythonTargetAdaptor], FmtResult],
) -> Tuple[Fmt, MockConsole]:
  console = MockConsole(use_colors=False)
  result: Fmt = run_rule(
    fmt,
    rule_args=[
      console,
      HydratedTargets(targets),
      UnionMembership(union_rules={TargetWithSources: [PythonTargetAdaptor]})
    ],
    mock_gets=[
      MockGet(product_type=FmtResult, subject_type=PythonTargetAdaptor, mock=mock_formatter),
      MockGet(product_type=FilesContent, subject_type=Digest, mock=lambda _: FilesContent([]))
    ],
  )
  return result, console
Beispiel #23
0
def coordinator_of_tests(
        target: HydratedTarget, union_membership: UnionMembership,
        provenance_map: AddressProvenanceMap) -> AddressAndTestResult:
    # TODO(#6004): when streaming to live TTY, rely on V2 UI for this information. When not a
    # live TTY, periodically dump heavy hitters to stderr. See
    # https://github.com/pantsbuild/pants/issues/6004#issuecomment-492699898.
    if (provenance_map.is_single_address(target.address)
            or union_membership.is_member(TestTarget, target.adaptor)):
        logger.info("Starting tests: {}".format(target.address.reference()))
        # NB: This has the effect of "casting" a TargetAdaptor to a member of the TestTarget union.
        # The adaptor will always be a member because of the union membership check above, but if
        # it were not it would fail at runtime with a useful error message.
        result = yield Get(TestResult, TestTarget, target.adaptor)
        logger.info("Tests {}: {}".format(
            "succeeded" if result.status == Status.SUCCESS else "failed",
            target.address.reference(),
        ))
    else:
        result = None  # Not a test target.
    yield AddressAndTestResult(target.address, result)
Beispiel #24
0
  def test_globbed_test_target(self):
    bfaddr = BuildFileAddress(None, 'tests', 'some/dir')
    target_adaptor = PythonTestsAdaptor(type_alias='python_tests')
    with self.captured_logging(logging.INFO):
      result = run_rule(
        coordinator_of_tests,
        HydratedTarget(bfaddr.to_address(), target_adaptor, ()),
        UnionMembership(union_rules={TestTarget: [PythonTestsAdaptor]}),
        AddressProvenanceMap(bfaddr_to_spec={
          bfaddr: DescendantAddresses(directory='some/dir')
        }),
        {
          (TestResult, PythonTestsAdaptor):
            lambda _: TestResult(status=Status.SUCCESS, stdout='foo', stderr=''),
        })

      self.assertEqual(
        result,
        AddressAndTestResult(bfaddr.to_address(),
                             TestResult(status=Status.SUCCESS, stdout='foo', stderr=''))
      )
Beispiel #25
0
def lint(console: Console, targets: HydratedTargets,
         union_membership: UnionMembership) -> Lint:
    results = yield [
        Get(LintResult, TargetWithSources, target.adaptor)
        for target in targets
        # TODO: make TargetAdaptor return a 'sources' field with an empty snapshot instead of
        # raising to remove the hasattr() checks here!
        if union_membership.is_member(TargetWithSources, target.adaptor)
        and hasattr(target.adaptor, "sources")
    ]

    exit_code = 0
    for result in results:
        if result.stdout:
            console.print_stdout(result.stdout)
        if result.stderr:
            console.print_stderr(result.stderr)
        if result.exit_code != 0:
            exit_code = result.exit_code

    yield Lint(exit_code)
Beispiel #26
0
 def run_lint_rule(
   *,
   targets: List[HydratedTarget],
   mock_linter: Optional[Callable[[PythonTargetAdaptor], LintResult]] = None,
 ) -> Tuple[Lint, str]:
   if mock_linter is None:
     mock_linter = lambda target_adaptor: LintResult(
       exit_code=1, stdout=f"Linted the target `{target_adaptor.name}`", stderr=""
     )
   console = MockConsole(use_colors=False)
   result: Lint = run_rule(
     lint,
     rule_args=[
       console,
       HydratedTargets(targets),
       UnionMembership(union_rules={TargetWithSources: [PythonTargetAdaptor]})
     ],
     mock_gets=[
       MockGet(product_type=LintResult, subject_type=PythonTargetAdaptor, mock=mock_linter),
     ],
   )
   return result, console.stdout.getvalue()
Beispiel #27
0
 def run_fmt_rule(
     self,
     *,
     language_formatters: List[Type[LanguageFormatters]],
     targets: List[HydratedTargetWithOrigin],
     result_digest: Digest,
     per_target_caching: bool,
 ) -> str:
     console = MockConsole(use_colors=False)
     union_membership = UnionMembership(
         OrderedDict({LanguageFormatters: OrderedSet(language_formatters)}))
     result: Fmt = run_rule(
         fmt,
         rule_args=[
             console,
             HydratedTargetsWithOrigins(targets),
             MockOptions(per_target_caching=per_target_caching),
             Workspace(self.scheduler),
             union_membership,
         ],
         mock_gets=[
             MockGet(
                 product_type=LanguageFmtResults,
                 subject_type=LanguageFormatters,
                 mock=lambda language_formatters: language_formatters.
                 language_fmt_results,
             ),
             MockGet(
                 product_type=Digest,
                 subject_type=DirectoriesToMerge,
                 mock=lambda _: result_digest,
             ),
         ],
         union_membership=union_membership,
     )
     assert result.exit_code == 0
     return cast(str, console.stdout.getvalue())
Beispiel #28
0
    def create(
        cls,
        env: Mapping[str, str],
        options_bootstrapper: OptionsBootstrapper,
        specs: Optional[Specs] = None,
        daemon_graph_session: Optional[LegacyGraphSession] = None,
    ) -> "LocalPantsRunner":
        """Creates a new LocalPantsRunner instance by parsing options.

        :param env: The environment (e.g. os.environ) for this run.
        :param options_bootstrapper: The OptionsBootstrapper instance to reuse.
        :param specs: The specs for this run, i.e. either the address or filesystem specs.
        :param daemon_graph_session: The graph helper for this session.
        """
        build_root = get_buildroot()

        options, build_config = LocalPantsRunner.parse_options(
            options_bootstrapper)
        global_options = 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.
        setup_logging_from_options(global_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 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,
        )
Beispiel #29
0
 def union_membership_singleton() -> UnionMembership:
     return UnionMembership(build_configuration.union_rules())
Beispiel #30
0
    def run(self):
        # Ensure anything referencing sys.argv inherits the Pailgun'd args.
        sys.argv = self.args

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

            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)