Пример #1
0
async def generate_pants_ini(console: Console, workspace: Workspace) -> GeneratePantsIni:
  pants_ini_content = dedent(f"""\
    [GLOBAL]
    pants_version: {pants_version}
    """)

  preexisting_snapshot = await Get[Snapshot](PathGlobs(include=('pants.ini',)))
  if preexisting_snapshot.files:
    console.print_stderr(
      "./pants.ini already exists. This goal is only meant to be run the first time you run Pants "
      "in a project.\n\nTo update config values, please directly modify the file."
    )
    return GeneratePantsIni(exit_code=1)

  console.print_stdout(dedent(f"""\
    Adding sensible defaults to ./pants.ini:
      * Pinning `pants_version` to `{pants_version}`.
    """))

  digest = await Get[Digest](InputFilesContent([
    FileContent(path='pants.ini', content=pants_ini_content.encode())
  ]))
  workspace.materialize_directory(DirectoryToMaterialize(digest))

  console.print_stdout(
    "You may modify these values directly in the file at any time. The ./pants script will detect "
    "any changes the next time you run it.\n\nYou are now ready to use Pants!"
  )
  return GeneratePantsIni(exit_code=0)
Пример #2
0
async def create_binary(addresses: BuildFileAddresses, console: Console,
                        workspace: Workspace, options: Binary.Options,
                        options_bootstrapper: OptionsBootstrapper,
                        build_root: BuildRoot) -> Binary:
    with Binary.line_oriented(options, console) as print_stdout:
        global_options = options_bootstrapper.bootstrap_options.for_global_scope(
        )
        pants_distdir = Path(global_options.pants_distdir)
        if not is_child_of(pants_distdir, build_root.pathlib_path):
            console.print_stderr(
                f"When set to an absolute path, `--pants-distdir` must be relative to the build root."
                "You set it to {pants_distdir}. Instead, use a relative path or an absolute path relative to the build root."
            )
            return Binary(exit_code=1)

        relative_distdir = pants_distdir.relative_to(
            build_root.pathlib_path) if pants_distdir.is_absolute(
            ) else pants_distdir
        print_stdout(f"Generating binaries in `./{relative_distdir}`")

        binaries = await MultiGet(
            Get[CreatedBinary](Address, address.to_address())
            for address in addresses)
        merged_digest = await Get[Digest](DirectoriesToMerge(
            tuple(binary.digest for binary in binaries)))
        result = workspace.materialize_directory(
            DirectoryToMaterialize(merged_digest,
                                   path_prefix=str(relative_distdir)))
        for path in result.output_paths:
            print_stdout(f"Wrote {path}")
    return Binary(exit_code=0)
Пример #3
0
async def run_tests(
  console: Console, options: TestOptions, runner: InteractiveRunner, addresses: BuildFileAddresses,
) -> Test:
  if options.values.debug:
    address = await Get[BuildFileAddress](BuildFileAddresses, addresses)
    addr_debug_request = await Get[AddressAndDebugRequest](Address, address.to_address())
    result = runner.run_local_interactive_process(addr_debug_request.request.ipr)
    return Test(result.process_exit_code)

  results = await MultiGet(Get[AddressAndTestResult](Address, addr.to_address()) for addr in addresses)
  did_any_fail = False
  filtered_results = [(x.address, x.test_result) for x in results if x.test_result is not None]

  for address, test_result in filtered_results:
    if test_result.status == Status.FAILURE:
      did_any_fail = True
    if test_result.stdout:
      console.write_stdout(f"{address.reference()} stdout:\n{test_result.stdout}\n")
    if test_result.stderr:
      # NB: we write to stdout, rather than to stderr, to avoid potential issues interleaving the
      # two streams.
      console.write_stdout(f"{address.reference()} stderr:\n{test_result.stderr}\n")

  console.write_stdout("\n")

  for address, test_result in filtered_results:
    console.print_stdout(f'{address.reference():80}.....{test_result.status.value:>10}')

  if did_any_fail:
    console.print_stderr(console.red('\nTests failed'))
    exit_code = PANTS_FAILED_EXIT_CODE
  else:
    exit_code = PANTS_SUCCEEDED_EXIT_CODE

  return Test(exit_code)
Пример #4
0
async def fmt(console: Console, targets: HydratedTargets, workspace: Workspace,
              union_membership: UnionMembership) -> Fmt:
    results = await MultiGet(
        Get[FmtResult](TargetWithSources, target.adaptor) for target in targets
        if TargetWithSources.is_formattable_and_lintable(
            target.adaptor, union_membership=union_membership))

    if not results:
        return Fmt(exit_code=0)

    # NB: this will fail if there are any conflicting changes, which we want to happen rather than
    # silently having one result override the other.
    # TODO(#8722): how should we handle multiple auto-formatters touching the same files?
    merged_formatted_digest = await Get[Digest](DirectoriesToMerge(
        tuple(result.digest for result in results)))
    workspace.materialize_directory(
        DirectoryToMaterialize(merged_formatted_digest))
    for result in results:
        if result.stdout:
            console.print_stdout(result.stdout)
        if result.stderr:
            console.print_stderr(result.stderr)

    # Since the rules to produce FmtResult should use ExecuteRequest, rather than
    # FallibleExecuteProcessRequest, we assume that there were no failures.
    return Fmt(exit_code=0)
Пример #5
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)
Пример #6
0
def fast_test(console: Console, addresses: BuildFileAddresses) -> Test:
  test_results = yield [Get(TestResult, Address, address.to_address()) for address in addresses]
  did_any_fail = False
  for address, test_result in zip(addresses, test_results):
    if test_result.status == Status.FAILURE:
      did_any_fail = True
    if test_result.stdout:
      console.write_stdout(
        "{} stdout:\n{}\n".format(
          address.reference(),
          console.red(test_result.stdout) if test_result.status == Status.FAILURE else test_result.stdout
        )
      )
    if test_result.stderr:
      # NB: we write to stdout, rather than to stderr, to avoid potential issues interleaving the
      # two streams.
      console.write_stdout(
        "{} stderr:\n{}\n".format(
          address.reference(),
          console.red(test_result.stderr) if test_result.status == Status.FAILURE else test_result.stderr
        )
      )

  console.write_stdout("\n")

  for address, test_result in zip(addresses, test_results):
    console.print_stdout('{0:80}.....{1:>10}'.format(address.reference(), test_result.status.value))

  if did_any_fail:
    console.print_stderr(console.red('Tests failed'))
    exit_code = PANTS_FAILED_EXIT_CODE
  else:
    exit_code = PANTS_SUCCEEDED_EXIT_CODE

  yield Test(exit_code)
Пример #7
0
async def coursier_resolve_lockfiles(
    console: Console,
    targets: Targets,
    resolve_subsystem: CoursierResolveSubsystem,
    workspace: Workspace,
) -> CoursierResolve:
    jvm_lockfile_targets = Targets(
        target for target in targets if target.has_field(JvmLockfileSources)
    )
    results = await MultiGet(
        Get(CoursierGenerateLockfileResult, CoursierGenerateLockfileRequest(target=target))
        for target in jvm_lockfile_targets
    )
    # For performance reasons, avoid writing out files to the workspace that haven't changed.
    results_to_write = tuple(result for result in results if result.digest != EMPTY_DIGEST)
    if results_to_write:
        merged_digest = await Get(
            Digest, MergeDigests(result.digest for result in results_to_write)
        )
        workspace.write_digest(merged_digest)
        merged_digest_snapshot = await Get(Snapshot, Digest, merged_digest)
        for path in merged_digest_snapshot.files:
            console.print_stderr(f"Updated lockfile at: {path}")

    return CoursierResolve(exit_code=0)
Пример #8
0
async def fmt(console: Console, targets: HydratedTargets, workspace: Workspace,
              union_membership: UnionMembership) -> Fmt:
    aggregated_results = await MultiGet(
        Get[AggregatedFmtResults](FormatTarget, target.adaptor)
        for target in targets
        if FormatTarget.is_formattable(target.adaptor,
                                       union_membership=union_membership))
    individual_results = [
        result for aggregated_result in aggregated_results
        for result in aggregated_result.results
    ]

    if not individual_results:
        return Fmt(exit_code=0)

    # NB: this will fail if there are any conflicting changes, which we want to happen rather than
    # silently having one result override the other. In practicality, this should never happen due
    # to our use of an aggregator rule for each distinct language.
    merged_formatted_digest = await Get[Digest](DirectoriesToMerge(
        tuple(aggregated_result.combined_digest
              for aggregated_result in aggregated_results)))
    workspace.materialize_directory(
        DirectoryToMaterialize(merged_formatted_digest))
    for result in individual_results:
        if result.stdout:
            console.print_stdout(result.stdout)
        if result.stderr:
            console.print_stderr(result.stderr)

    # Since the rules to produce FmtResult should use ExecuteRequest, rather than
    # FallibleExecuteProcessRequest, we assume that there were no failures.
    return Fmt(exit_code=0)
Пример #9
0
def fmt(console: Console, targets: HydratedTargets) -> Fmt:
    results = yield [
        Get(FmtResult, FmtTarget, target.adaptor) for target in targets
        # @union assumes that all targets passed implement the union, so we manually
        # filter the targets we know do; this should probably no-op or log or something
        # configurable for non-matching targets.
        # We also would want to remove the workaround that filters adaptors which have a
        # `sources` attribute.
        # See https://github.com/pantsbuild/pants/issues/4535
        if isinstance(target.adaptor, (
            PythonAppAdaptor, PythonTargetAdaptor, PythonTestsAdaptor,
            PythonBinaryAdaptor)) 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)
Пример #10
0
async def run_setup_pys(targets: HydratedTargets, options: SetupPyOptions, console: Console,
                        provenance_map: AddressProvenanceMap,
                        distdir: DistDir, workspace: Workspace) -> SetupPy:
  """Run setup.py commands on all exported targets addressed."""
  args = tuple(options.values.args)
  validate_args(args)

  # Get all exported targets, ignoring any non-exported targets that happened to be
  # globbed over, but erroring on any explicitly-requested non-exported targets.

  exported_targets: List[ExportedTarget] = []
  explicit_nonexported_targets: List[HydratedTarget] = []

  for hydrated_target in targets:
    if _is_exported(hydrated_target):
      exported_targets.append(ExportedTarget(hydrated_target))
    elif provenance_map.is_single_address(hydrated_target.address):
      explicit_nonexported_targets.append(hydrated_target)
  if explicit_nonexported_targets:
    raise TargetNotExported(
      'Cannot run setup.py on these targets, because they have no `provides=` clause: '
      f'{", ".join(so.address.reference() for so in explicit_nonexported_targets)}')

  if options.values.transitive:
    # Expand out to all owners of the entire dep closure.
    tht = await Get[TransitiveHydratedTargets](
      BuildFileAddresses([et.hydrated_target.address for et in exported_targets]))
    owners = await MultiGet(
      Get[ExportedTarget](OwnedDependency(ht)) for ht in tht.closure if is_ownable_target(ht)
    )
    exported_targets = list(set(owners))

  chroots = await MultiGet(Get[SetupPyChroot](SetupPyChrootRequest(target))
                           for target in exported_targets)

  if args:
    setup_py_results = await MultiGet(
      Get[RunSetupPyResult](RunSetupPyRequest(exported_target, chroot, tuple(args)))
      for exported_target, chroot in zip(exported_targets, chroots)
    )

    for exported_target, setup_py_result in zip(exported_targets, setup_py_results):
      addr = exported_target.hydrated_target.address.reference()
      console.print_stderr(f'Writing contents of dist dir for {addr} to {distdir.relpath}')
      workspace.materialize_directory(
        DirectoryToMaterialize(setup_py_result.output, path_prefix=str(distdir.relpath))
      )
  else:
    # Just dump the chroot.
    for exported_target, chroot in zip(exported_targets, chroots):
      addr = exported_target.hydrated_target.address.reference()
      provides = exported_target.hydrated_target.adaptor.provides
      setup_py_dir = distdir.relpath / f'{provides.name}-{provides.version}'
      console.print_stderr(f'Writing setup.py chroot for {addr} to {setup_py_dir}')
      workspace.materialize_directory(
        DirectoryToMaterialize(chroot.digest, path_prefix=str(setup_py_dir))
      )

  return SetupPy(0)
Пример #11
0
 def materialize(self, console: Console, workspace: Workspace) -> Optional[PurePath]:
     workspace.write_digest(
         self.result_snapshot.digest, path_prefix=str(self.directory_to_materialize_to)
     )
     console.print_stderr(
         f"\nWrote {self.report_type} coverage report to `{self.directory_to_materialize_to}`"
     )
     return self.report_file
Пример #12
0
async def list_targets(console: Console, list_options: ListOptions, addresses: Addresses) -> List:
    provides = list_options.values.provides
    provides_columns = list_options.values.provides_columns
    documented = list_options.values.documented
    collection: Union[HydratedTargets, Addresses]
    if provides or documented:
        # To get provides clauses or documentation, we need hydrated targets.
        collection = await Get[HydratedTargets](Addresses, addresses)
        if provides:
            extractors = dict(
                address=lambda adaptor: adaptor.address.spec,
                artifact_id=lambda adaptor: str(adaptor.provides),
                repo_name=lambda adaptor: adaptor.provides.repo.name,
                repo_url=lambda adaptor: adaptor.provides.repo.url,
                push_db_basedir=lambda adaptor: adaptor.provides.repo.push_db_basedir,
            )

            def print_provides(col_extractors, target):
                if getattr(target.adaptor, "provides", None):
                    return " ".join(extractor(target.adaptor) for extractor in col_extractors)

            try:
                column_extractors = [extractors[col] for col in (provides_columns.split(","))]
            except KeyError:
                raise Exception(
                    "Invalid columns specified: {0}. Valid columns are: address, artifact_id, "
                    "repo_name, repo_url, push_db_basedir.".format(provides_columns)
                )

            print_fn = lambda target: print_provides(column_extractors, target)
        else:

            def print_documented(target):
                description = getattr(target.adaptor, "description", None)
                if description:
                    return "{0}\n  {1}".format(
                        target.adaptor.address.spec, "\n  ".join(description.strip().split("\n"))
                    )

            print_fn = print_documented
    else:
        # Otherwise, we can use only addresses.
        collection = addresses
        print_fn = lambda address: address.spec

    with list_options.line_oriented(console) as print_stdout:
        if not collection:
            console.print_stderr("WARNING: No targets were matched in goal `{}`.".format("list"))

        for item in collection:
            result = print_fn(item)
            if result:
                print_stdout(result)

    return List(exit_code=0)
Пример #13
0
async def lint(
    console: Console,
    targets_with_origins: TargetsWithOrigins,
    options: LintOptions,
    union_membership: UnionMembership,
) -> Lint:
    config_collection_types: Iterable[
        Type[LinterConfigurations]] = union_membership.union_rules[
            LinterConfigurations]

    config_collections: Iterable[LinterConfigurations] = tuple(
        config_collection_type(
            config_collection_type.config_type.create(target_with_origin)
            for target_with_origin in targets_with_origins
            if config_collection_type.config_type.is_valid(
                target_with_origin.target))
        for config_collection_type in config_collection_types)
    config_collections_with_sources: Iterable[
        ConfigurationsWithSources] = await MultiGet(
            Get[ConfigurationsWithSources](ConfigurationsWithSourcesRequest(
                config_collection))
            for config_collection in config_collections)
    # NB: We must convert back the generic ConfigurationsWithSources objects back into their
    # corresponding LinterConfigurations, e.g. back to IsortConfigurations, in order for the union
    # rule to work.
    valid_config_collections: Iterable[LinterConfigurations] = tuple(
        config_collection_cls(config_collection)
        for config_collection_cls, config_collection in zip(
            config_collection_types, config_collections_with_sources)
        if config_collection)

    if options.values.per_target_caching:
        results = await MultiGet(
            Get[LintResult](LinterConfigurations,
                            config_collection.__class__([config]))
            for config_collection in valid_config_collections
            for config in config_collection)
    else:
        results = await MultiGet(
            Get[LintResult](LinterConfigurations, config_collection)
            for config_collection in valid_config_collections)

    if not results:
        return Lint(exit_code=0)

    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

    return Lint(exit_code)
Пример #14
0
async def run_repl(
    console: Console,
    workspace: Workspace,
    repl_subsystem: ReplSubsystem,
    all_specified_addresses: Addresses,
    build_root: BuildRoot,
    union_membership: UnionMembership,
    global_options: GlobalOptions,
    complete_env: CompleteEnvironment,
) -> Repl:
    transitive_targets = await Get(
        TransitiveTargets, TransitiveTargetsRequest(all_specified_addresses))

    # TODO: When we support multiple languages, detect the default repl to use based
    #  on the targets.  For now we default to the python repl.
    repl_shell_name = repl_subsystem.shell or "python"
    implementations = {
        impl.name: impl
        for impl in union_membership[ReplImplementation]
    }
    repl_implementation_cls = implementations.get(repl_shell_name)
    if repl_implementation_cls is None:
        available = sorted(implementations.keys())
        console.print_stderr(
            f"{repr(repl_shell_name)} is not a registered REPL. Available REPLs (which may "
            f"be specified through the option `--repl-shell`): {available}")
        return Repl(-1)

    with temporary_dir(root_dir=global_options.options.pants_workdir,
                       cleanup=False) as tmpdir:
        repl_impl = repl_implementation_cls(targets=Targets(
            transitive_targets.closure),
                                            chroot=tmpdir)
        request = await Get(ReplRequest, ReplImplementation, repl_impl)

        workspace.write_digest(
            request.digest,
            path_prefix=PurePath(tmpdir).relative_to(
                build_root.path).as_posix(),
            # We don't want to influence whether the InteractiveProcess is able to restart. Because
            # we're writing into a temp directory, we can safely mark this side_effecting=False.
            side_effecting=False,
        )
        env = {**complete_env, **request.extra_env}
        result = await Effect(
            InteractiveProcessResult,
            InteractiveProcess(
                argv=request.args,
                env=env,
                run_in_workspace=True,
                restartable=repl_subsystem.restartable,
            ),
        )
    return Repl(result.exit_code)
Пример #15
0
async def check(
    console: Console,
    workspace: Workspace,
    targets: Targets,
    dist_dir: DistDir,
    union_membership: UnionMembership,
) -> Check:
    typecheck_request_types = cast("Iterable[type[StyleRequest]]",
                                   union_membership[CheckRequest])
    requests = tuple(
        typecheck_request_type(
            typecheck_request_type.field_set_type.create(target)
            for target in targets
            if typecheck_request_type.field_set_type.is_applicable(target))
        for typecheck_request_type in typecheck_request_types)
    field_sets_with_sources = await MultiGet(
        Get(FieldSetsWithSources,
            FieldSetsWithSourcesRequest(request.field_sets))
        for request in requests)
    valid_requests = tuple(
        request_cls(request) for request_cls, request in zip(
            typecheck_request_types, field_sets_with_sources) if request)
    all_results = await MultiGet(
        Get(CheckResults, CheckRequest, request) for request in valid_requests)

    def get_tool_name(res: CheckResults) -> str:
        return res.checker_name

    write_reports(
        all_results,
        workspace,
        dist_dir,
        goal_name=CheckSubsystem.name,
        get_tool_name=get_tool_name,
    )

    exit_code = 0
    if all_results:
        console.print_stderr("")
    for results in sorted(all_results,
                          key=lambda results: results.checker_name):
        if results.skipped:
            sigil = console.sigil_skipped()
            status = "skipped"
        elif results.exit_code == 0:
            sigil = console.sigil_succeeded()
            status = "succeeded"
        else:
            sigil = console.sigil_failed()
            status = "failed"
            exit_code = results.exit_code
        console.print_stderr(f"{sigil} {results.checker_name} {status}.")

    return Check(exit_code)
Пример #16
0
async def check(
    console: Console,
    workspace: Workspace,
    targets: FilteredTargets,
    dist_dir: DistDir,
    union_membership: UnionMembership,
    check_subsystem: CheckSubsystem,
) -> Check:
    request_types = cast("Iterable[type[StyleRequest]]", union_membership[CheckRequest])
    specified_names = determine_specified_tool_names("check", check_subsystem.only, request_types)

    requests = tuple(
        request_type(
            request_type.field_set_type.create(target)
            for target in targets
            if (
                request_type.name in specified_names
                and request_type.field_set_type.is_applicable(target)
            )
        )
        for request_type in request_types
    )
    all_results = await MultiGet(
        Get(CheckResults, CheckRequest, request) for request in requests if request.field_sets
    )

    def get_name(res: CheckResults) -> str:
        return res.checker_name

    write_reports(
        all_results,
        workspace,
        dist_dir,
        goal_name=CheckSubsystem.name,
        get_name=get_name,
    )

    exit_code = 0
    if all_results:
        console.print_stderr("")
    for results in sorted(all_results, key=lambda results: results.checker_name):
        if results.skipped:
            continue
        elif results.exit_code == 0:
            sigil = console.sigil_succeeded()
            status = "succeeded"
        else:
            sigil = console.sigil_failed()
            status = "failed"
            exit_code = results.exit_code
        console.print_stderr(f"{sigil} {results.checker_name} {status}.")

    return Check(exit_code)
Пример #17
0
async def run_repl(
    console: Console,
    workspace: Workspace,
    runner: InteractiveRunner,
    options: ReplOptions,
    transitive_targets: TransitiveTargets,
    build_root: BuildRoot,
    union_membership: UnionMembership,
    global_options: GlobalOptions,
) -> Repl:

    # We can guarantee that we will only even enter this `goal_rule` if there exists an implementer
    # of the `ReplImplementation` union because `LegacyGraphSession.run_goal_rules()` will not
    # execute this rule's body if there are no implementations registered.
    membership: Iterable[Type[
        ReplImplementation]] = union_membership.union_rules[ReplImplementation]
    implementations = {impl.name: impl for impl in membership}

    default_repl = "python"
    repl_shell_name = cast(str, options.values.shell or default_repl)

    repl_implementation_cls = implementations.get(repl_shell_name)
    if repl_implementation_cls is None:
        available = sorted(set(implementations.keys()))
        console.print_stderr(
            f"{repr(repl_shell_name)} is not a registered REPL. Available REPLs (which may "
            f"be specified through the option `--repl-shell`): {available}")
        return Repl(-1)

    repl_impl = repl_implementation_cls(targets=Targets(
        tgt for tgt in transitive_targets.closure
        if repl_implementation_cls.is_valid(tgt)))
    repl_binary = await Get[ReplBinary](ReplImplementation, repl_impl)

    with temporary_dir(root_dir=global_options.options.pants_workdir,
                       cleanup=False) as tmpdir:
        path_relative_to_build_root = PurePath(tmpdir).relative_to(
            build_root.path).as_posix()
        workspace.materialize_directory(
            DirectoryToMaterialize(repl_binary.digest,
                                   path_prefix=path_relative_to_build_root))

        full_path = PurePath(tmpdir, repl_binary.binary_name).as_posix()
        run_request = InteractiveProcessRequest(
            argv=(full_path, ),
            run_in_workspace=True,
        )

    result = runner.run_local_interactive_process(run_request)
    return Repl(result.process_exit_code)
Пример #18
0
async def run(
    run_subsystem: RunSubsystem,
    global_options: GlobalOptions,
    console: Console,
    interactive_runner: InteractiveRunner,
    workspace: Workspace,
    build_root: BuildRoot,
    complete_env: CompleteEnvironment,
) -> Run:
    targets_to_valid_field_sets = await Get(
        TargetRootsToFieldSets,
        TargetRootsToFieldSetsRequest(
            RunFieldSet,
            goal_description="the `run` goal",
            no_applicable_targets_behavior=NoApplicableTargetsBehavior.error,
            expect_single_field_set=True,
        ),
    )
    field_set = targets_to_valid_field_sets.field_sets[0]
    request = await Get(RunRequest, RunFieldSet, field_set)

    with temporary_dir(root_dir=global_options.options.pants_workdir,
                       cleanup=True) as tmpdir:
        workspace.write_digest(request.digest,
                               path_prefix=PurePath(tmpdir).relative_to(
                                   build_root.path).as_posix())

        args = (arg.format(chroot=tmpdir) for arg in request.args)
        env = {
            **complete_env,
            **{
                k: v.format(chroot=tmpdir)
                for k, v in request.extra_env.items()
            }
        }
        try:
            result = interactive_runner.run(
                InteractiveProcess(
                    argv=(*args, *run_subsystem.args),
                    env=env,
                    run_in_workspace=True,
                ))
            exit_code = result.exit_code
        except Exception as e:
            console.print_stderr(
                f"Exception when attempting to run {field_set.address}: {e!r}")
            exit_code = -1

    return Run(exit_code)
Пример #19
0
async def validate(
    console: Console,
    sources_snapshots: SourcesSnapshots,
    validate_options: ValidateOptions,
) -> Validate:
    per_snapshot_rmrs = await MultiGet(
        Get[RegexMatchResults](SourcesSnapshot, source_snapshot)
        for source_snapshot in sources_snapshots)
    regex_match_results = list(itertools.chain(*per_snapshot_rmrs))

    detail_level = validate_options.values.detail_level
    regex_match_results = sorted(regex_match_results, key=lambda x: x.path)
    num_matched_all = 0
    num_nonmatched_some = 0
    for rmr in regex_match_results:
        if not rmr.matching and not rmr.nonmatching:
            continue
        if rmr.nonmatching:
            icon = "X"
            num_nonmatched_some += 1
        else:
            icon = "V"
            num_matched_all += 1
        matched_msg = " Matched: {}".format(",".join(
            rmr.matching)) if rmr.matching else ""
        nonmatched_msg = (" Didn't match: {}".format(",".join(rmr.nonmatching))
                          if rmr.nonmatching else "")
        if detail_level == DetailLevel.all or (
                detail_level == DetailLevel.nonmatching and nonmatched_msg):
            console.print_stdout("{} {}:{}{}".format(icon, rmr.path,
                                                     matched_msg,
                                                     nonmatched_msg))

    if detail_level != DetailLevel.none:
        console.print_stdout(
            "\n{} files matched all required patterns.".format(
                num_matched_all))
        console.print_stdout(
            "{} files failed to match at least one required pattern.".format(
                num_nonmatched_some))

    if num_nonmatched_some:
        console.print_stderr("Files failed validation.")
        exit_code = PANTS_FAILED_EXIT_CODE
    else:
        exit_code = PANTS_SUCCEEDED_EXIT_CODE
    return Validate(exit_code)
Пример #20
0
Файл: lint.py Проект: wiwa/pants
async def lint(
    console: Console,
    targets_with_origins: TargetsWithOrigins,
    options: LintOptions,
    union_membership: UnionMembership,
) -> Lint:
    lint_request_types = union_membership[LintRequest]
    lint_requests: Iterable[StyleRequest] = tuple(
        lint_request_type(
            lint_request_type.field_set_type.create(target_with_origin)
            for target_with_origin in targets_with_origins
            if lint_request_type.field_set_type.is_valid(target_with_origin.target)
        )
        for lint_request_type in union_membership[LintRequest]
    )
    field_sets_with_sources: Iterable[FieldSetsWithSources] = await MultiGet(
        Get[FieldSetsWithSources](FieldSetsWithSourcesRequest(lint_request.field_sets))
        for lint_request in lint_requests
    )
    valid_lint_requests: Iterable[StyleRequest] = tuple(
        lint_request_cls(lint_request)
        for lint_request_cls, lint_request in zip(lint_request_types, field_sets_with_sources)
        if lint_request
    )

    if options.values.per_target_caching:
        results = await MultiGet(
            Get[LintResults](LintRequest, lint_request.__class__([field_set]))
            for lint_request in valid_lint_requests
            for field_set in lint_request.field_sets
        )
    else:
        results = await MultiGet(
            Get[LintResults](LintRequest, lint_request) for lint_request in valid_lint_requests
        )

    if not results:
        return Lint(exit_code=0)

    exit_code = 0
    sorted_results = sorted(itertools.chain.from_iterable(results), key=lambda res: res.linter_name)
    for result in sorted_results:
        console.print_stderr(
            f"{console.green('✓')} {result.linter_name} succeeded."
            if result.exit_code == 0
            else f"{console.red('𐄂')} {result.linter_name} failed."
        )
        if result.stdout:
            console.print_stderr(result.stdout)
        if result.stderr:
            console.print_stderr(result.stderr)
        if result != sorted_results[-1]:
            console.print_stderr("")
        if result.exit_code != 0:
            exit_code = result.exit_code

    return Lint(exit_code)
Пример #21
0
async def run_repl(
    console: Console,
    workspace: Workspace,
    runner: InteractiveRunner,
    options: ReplOptions,
    transitive_targets: TransitiveTargets,
    build_root: BuildRoot,
    union_membership: UnionMembership,
    global_options: GlobalOptions,
) -> Repl:
    default_repl = "python"
    repl_shell_name = cast(str, options.values.shell) or default_repl

    implementations: Dict[str, Type[ReplImplementation]] = {
        impl.name: impl
        for impl in union_membership[ReplImplementation]
    }
    repl_implementation_cls = implementations.get(repl_shell_name)
    if repl_implementation_cls is None:
        available = sorted(implementations.keys())
        console.print_stderr(
            f"{repr(repl_shell_name)} is not a registered REPL. Available REPLs (which may "
            f"be specified through the option `--repl-shell`): {available}")
        return Repl(-1)

    repl_impl = repl_implementation_cls(targets=Targets(
        tgt for tgt in transitive_targets.closure
        if repl_implementation_cls.is_valid(tgt)))
    repl_binary = await Get[ReplBinary](ReplImplementation, repl_impl)

    with temporary_dir(root_dir=global_options.options.pants_workdir,
                       cleanup=False) as tmpdir:
        path_relative_to_build_root = PurePath(tmpdir).relative_to(
            build_root.path).as_posix()
        workspace.materialize_directory(
            DirectoryToMaterialize(repl_binary.digest,
                                   path_prefix=path_relative_to_build_root))

        full_path = PurePath(tmpdir, repl_binary.binary_name).as_posix()
        run_request = InteractiveProcessRequest(
            argv=(full_path, ),
            run_in_workspace=True,
        )

    result = runner.run_local_interactive_process(run_request)
    return Repl(result.process_exit_code)
Пример #22
0
async def run_repl(
    console: Console,
    workspace: Workspace,
    interactive_runner: InteractiveRunner,
    repl_subsystem: ReplSubsystem,
    all_specified_addresses: Addresses,
    build_root: BuildRoot,
    union_membership: UnionMembership,
    global_options: GlobalOptions,
) -> Repl:
    transitive_targets = await Get(
        TransitiveTargets, TransitiveTargetsRequest(all_specified_addresses))

    # TODO: When we support multiple languages, detect the default repl to use based
    #  on the targets.  For now we default to the python repl.
    repl_shell_name = repl_subsystem.shell or "python"

    implementations: Dict[str, Type[ReplImplementation]] = {
        impl.name: impl
        for impl in union_membership[ReplImplementation]
    }
    repl_implementation_cls = implementations.get(repl_shell_name)
    if repl_implementation_cls is None:
        available = sorted(implementations.keys())
        console.print_stderr(
            f"{repr(repl_shell_name)} is not a registered REPL. Available REPLs (which may "
            f"be specified through the option `--repl-shell`): {available}")
        return Repl(-1)

    with temporary_dir(root_dir=global_options.options.pants_workdir,
                       cleanup=False) as tmpdir:
        repl_impl = repl_implementation_cls(targets=Targets(
            transitive_targets.closure),
                                            chroot=tmpdir)
        request = await Get(ReplRequest, ReplImplementation, repl_impl)

        workspace.write_digest(request.digest,
                               path_prefix=PurePath(tmpdir).relative_to(
                                   build_root.path).as_posix())
        result = interactive_runner.run(
            InteractiveProcess(argv=request.args,
                               env=request.extra_env,
                               run_in_workspace=True,
                               hermetic_env=False))
    return Repl(result.exit_code)
Пример #23
0
async def list_targets(addresses: Addresses, list_subsystem: ListSubsystem,
                       console: Console) -> List:
    if not addresses:
        console.print_stderr(
            f"WARNING: No targets were matched in goal `{list_subsystem.name}`."
        )
        return List(exit_code=0)

    if list_subsystem.provides and list_subsystem.documented:
        raise ValueError(
            "Cannot specify both `--list-documented` and `--list-provides` at the same time. "
            "Please choose one.")

    if list_subsystem.provides:
        targets = await Get(UnexpandedTargets, Addresses, addresses)
        addresses_with_provide_artifacts = {
            tgt.address: tgt[ProvidesField].value
            for tgt in targets if tgt.get(ProvidesField).value is not None
        }
        with list_subsystem.line_oriented(console) as print_stdout:
            for address, artifact in addresses_with_provide_artifacts.items():
                print_stdout(f"{address.spec} {artifact}")
        return List(exit_code=0)

    if list_subsystem.documented:
        targets = await Get(UnexpandedTargets, Addresses, addresses)
        addresses_with_descriptions = cast(
            Dict[Address, str],
            {
                tgt.address: tgt[DescriptionField].value
                for tgt in targets
                if tgt.get(DescriptionField).value is not None
            },
        )
        with list_subsystem.line_oriented(console) as print_stdout:
            for address, description in addresses_with_descriptions.items():
                formatted_description = "\n  ".join(
                    description.strip().split("\n"))
                print_stdout(f"{address.spec}\n  {formatted_description}")
        return List(exit_code=0)

    with list_subsystem.line_oriented(console) as print_stdout:
        for address in sorted(addresses):
            print_stdout(address.spec)
    return List(exit_code=0)
Пример #24
0
def ui_open(console: Console, runner: InteractiveRunner, files: Iterable[PurePath]) -> None:
    """Opens the given files with the appropriate application for the current operating system.

    Any failures to either locate an appropriate application to open the files with or else execute
    that program are reported to the console stderr.
    """
    osname = get_os_name()
    opener_type = _OPENERS_BY_OSNAME.get(osname)
    if opener_type is None:
        console.print_stderr(f"Could not open {' '.join(map(str, files))} for viewing.")
        console.print_stderr(
            f"Opening files for viewing is currently not supported for the "
            f"{osname} operating system."
        )
        return

    opener = opener_type(console, runner)
    opener.open(files)
Пример #25
0
def validate(console: Console, hydrated_targets: HydratedTargets,
             validate_options: Validate.Options) -> Validate:
    per_tgt_rmrs = yield [
        Get(RegexMatchResults, HydratedTarget, ht) for ht in hydrated_targets
    ]
    regex_match_results = list(itertools.chain(*per_tgt_rmrs))

    detail_level = validate_options.values.detail_level
    regex_match_results = sorted(regex_match_results, key=lambda x: x.path)
    num_matched_all = 0
    num_nonmatched_some = 0
    for rmr in regex_match_results:
        if not rmr.matching and not rmr.nonmatching:
            continue
        if rmr.nonmatching:
            icon = 'X'
            num_nonmatched_some += 1
        else:
            icon = 'V'
            num_matched_all += 1
        matched_msg = ' Matched: {}'.format(','.join(
            rmr.matching)) if rmr.matching else ''
        nonmatched_msg = (" Didn't match: {}".format(','.join(rmr.nonmatching))
                          if rmr.nonmatching else '')
        if (detail_level == DetailLevel.all or
            (detail_level == DetailLevel.nonmatching and nonmatched_msg)):
            console.print_stdout("{} {}:{}{}".format(icon, rmr.path,
                                                     matched_msg,
                                                     nonmatched_msg))

    if detail_level != DetailLevel.none:
        console.print_stdout(
            '\n{} files matched all required patterns.'.format(
                num_matched_all))
        console.print_stdout(
            '{} files failed to match at least one required pattern.'.format(
                num_nonmatched_some))

    if num_nonmatched_some:
        console.print_stderr('Files failed validation.')
        exit_code = PANTS_FAILED_EXIT_CODE
    else:
        exit_code = PANTS_SUCCEEDED_EXIT_CODE
    yield Validate(exit_code)
Пример #26
0
async def lint(
    console: Console,
    targets_with_origins: HydratedTargetsWithOrigins,
    options: LintOptions,
    union_membership: UnionMembership,
) -> Lint:
    adaptors_with_origins = tuple(
        TargetAdaptorWithOrigin.create(target_with_origin.target.adaptor,
                                       target_with_origin.origin)
        for target_with_origin in targets_with_origins
        if target_with_origin.target.adaptor.has_sources())

    linters: Iterable[Type[Linter]] = union_membership.union_rules[Linter]
    if options.values.per_target_caching:
        results = await MultiGet(
            Get[LintResult](Linter, linter((adaptor_with_origin, )))
            for adaptor_with_origin in adaptors_with_origins
            for linter in linters
            if linter.is_valid_target(adaptor_with_origin))
    else:
        linters_with_valid_targets = {
            linter: tuple(adaptor_with_origin
                          for adaptor_with_origin in adaptors_with_origins
                          if linter.is_valid_target(adaptor_with_origin))
            for linter in linters
        }
        results = await MultiGet(
            Get[LintResult](Linter, linter(valid_targets))
            for linter, valid_targets in linters_with_valid_targets.items()
            if valid_targets)

    if not results:
        return Lint(exit_code=0)

    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

    return Lint(exit_code)
Пример #27
0
async def lint(
    console: Console,
    workspace: Workspace,
    targets: Targets,
    lint_subsystem: LintSubsystem,
    union_membership: UnionMembership,
) -> Lint:
    request_types = union_membership[LintRequest]
    requests: Iterable[StyleRequest] = tuple(
        request_type(
            request_type.field_set_type.create(target) for target in targets
            if request_type.field_set_type.is_valid(target))
        for request_type in request_types)
    field_sets_with_sources: Iterable[FieldSetsWithSources] = await MultiGet(
        Get(FieldSetsWithSources,
            FieldSetsWithSourcesRequest(request.field_sets))
        for request in requests)
    valid_requests: Iterable[StyleRequest] = tuple(
        request_cls(request)
        for request_cls, request in zip(request_types, field_sets_with_sources)
        if request)

    if lint_subsystem.per_target_caching:
        results = await MultiGet(
            Get(LintResults, LintRequest, request.__class__([field_set]))
            for request in valid_requests for field_set in request.field_sets)
    else:
        results = await MultiGet(
            Get(LintResults, LintRequest, lint_request)
            for lint_request in valid_requests)

    sorted_results = sorted(itertools.chain.from_iterable(results),
                            key=lambda res: res.linter_name)
    if not sorted_results:
        return Lint(exit_code=0)

    exit_code = 0
    for result in sorted_results:
        console.print_stderr(
            f"{console.green('✓')} {result.linter_name} succeeded." if result.
            exit_code ==
            0 else f"{console.red('𐄂')} {result.linter_name} failed.")
        if result.stdout:
            console.print_stderr(result.stdout)
        if result.stderr:
            console.print_stderr(result.stderr)
        if result != sorted_results[-1]:
            console.print_stderr("")
        result.materialize(console, workspace)
        if result.exit_code != 0:
            exit_code = result.exit_code

    return Lint(exit_code)
Пример #28
0
async def run_repl(
    console: Console,
    workspace: Workspace,
    interactive_runner: InteractiveRunner,
    repl_subsystem: ReplSubsystem,
    transitive_targets: TransitiveTargets,
    build_root: BuildRoot,
    union_membership: UnionMembership,
    global_options: GlobalOptions,
) -> Repl:
    repl_shell_name = repl_subsystem.shell or "python"

    implementations: Dict[str, Type[ReplImplementation]] = {
        impl.name: impl
        for impl in union_membership[ReplImplementation]
    }
    repl_implementation_cls = implementations.get(repl_shell_name)
    if repl_implementation_cls is None:
        available = sorted(implementations.keys())
        console.print_stderr(
            f"{repr(repl_shell_name)} is not a registered REPL. Available REPLs (which may "
            f"be specified through the option `--repl-shell`): {available}")
        return Repl(-1)

    repl_impl = repl_implementation_cls(targets=Targets(
        tgt for tgt in transitive_targets.closure
        if repl_implementation_cls.is_valid(tgt)))
    request = await Get(ReplRequest, ReplImplementation, repl_impl)

    with temporary_dir(root_dir=global_options.options.pants_workdir,
                       cleanup=False) as tmpdir:
        tmpdir_relative_path = PurePath(tmpdir).relative_to(
            build_root.path).as_posix()
        exe_path = PurePath(tmpdir, request.binary_name).as_posix()
        workspace.write_digest(request.digest,
                               path_prefix=tmpdir_relative_path)
        result = interactive_runner.run(
            InteractiveProcess(argv=(exe_path, ),
                               env=request.env,
                               run_in_workspace=True))

    return Repl(result.exit_code)
Пример #29
0
async def run(
    run_subsystem: RunSubsystem,
    global_options: GlobalOptions,
    console: Console,
    interactive_runner: InteractiveRunner,
    workspace: Workspace,
    build_root: BuildRoot,
) -> Run:
    targets_to_valid_field_sets = await Get(
        TargetsToValidFieldSets,
        TargetsToValidFieldSetsRequest(
            BinaryFieldSet,
            goal_description="the `run` goal",
            error_if_no_valid_targets=True,
            expect_single_field_set=True,
        ),
    )
    field_set = targets_to_valid_field_sets.field_sets[0]
    request = await Get(RunRequest, BinaryFieldSet, field_set)

    with temporary_dir(root_dir=global_options.options.pants_workdir,
                       cleanup=True) as tmpdir:
        tmpdir_relative_path = PurePath(tmpdir).relative_to(
            build_root.path).as_posix()
        workspace.write_digest(request.digest,
                               path_prefix=tmpdir_relative_path)

        exe_path = PurePath(tmpdir, request.binary_name).as_posix()
        process = InteractiveProcess(
            argv=(exe_path, *request.prefix_args, *run_subsystem.args),
            env=request.env,
            run_in_workspace=True,
        )
        try:
            result = interactive_runner.run(process)
            exit_code = result.exit_code
        except Exception as e:
            console.print_stderr(
                f"Exception when attempting to run {field_set.address}: {e!r}")
            exit_code = -1

    return Run(exit_code)
Пример #30
0
async def typecheck(
    console: Console, targets: Targets, union_membership: UnionMembership
) -> Typecheck:
    typecheck_request_types = union_membership[TypecheckRequest]
    requests: Iterable[StyleRequest] = tuple(
        lint_request_type(
            lint_request_type.field_set_type.create(target)
            for target in targets
            if lint_request_type.field_set_type.is_applicable(target)
        )
        for lint_request_type in typecheck_request_types
    )
    field_sets_with_sources: Iterable[FieldSetsWithSources] = await MultiGet(
        Get(FieldSetsWithSources, FieldSetsWithSourcesRequest(request.field_sets))
        for request in requests
    )
    valid_requests: Iterable[StyleRequest] = tuple(
        request_cls(request)
        for request_cls, request in zip(typecheck_request_types, field_sets_with_sources)
        if request
    )
    all_results = await MultiGet(
        Get(TypecheckResults, TypecheckRequest, request) for request in valid_requests
    )

    exit_code = 0
    if all_results:
        console.print_stderr("")
    for results in sorted(all_results, key=lambda results: results.typechecker_name):
        if results.skipped:
            sigil = console.yellow("-")
            status = "skipped"
        elif results.exit_code == 0:
            sigil = console.green("✓")
            status = "succeeded"
        else:
            sigil = console.red("𐄂")
            status = "failed"
            exit_code = results.exit_code
        console.print_stderr(f"{sigil} {results.typechecker_name} {status}.")

    return Typecheck(exit_code)