예제 #1
0
async def run_buf_format(request: BufFormatRequest,
                         buf: BufSubsystem) -> FmtResult:
    if buf.skip_format:
        return FmtResult.skip(formatter_name=request.name)
    result = await Get(ProcessResult, BufFormatRequest, request)
    output_snapshot = await Get(Snapshot, Digest, result.output_digest)
    return FmtResult.create(request, result, output_snapshot)
예제 #2
0
async def yapf_fmt(request: YapfRequest, yapf: Yapf) -> FmtResult:
    if yapf.skip:
        return FmtResult.skip(formatter_name=request.name)
    yapf_pex_get = Get(VenvPex, PexRequest, yapf.to_pex_request())
    config_files_get = Get(ConfigFiles, ConfigFilesRequest,
                           yapf.config_request(request.snapshot.dirs))
    yapf_pex, config_files = await MultiGet(yapf_pex_get, config_files_get)

    input_digest = await Get(
        Digest,
        MergeDigests((request.snapshot.digest, config_files.snapshot.digest)))

    result = await Get(
        ProcessResult,
        VenvPexProcess(
            yapf_pex,
            argv=(
                *yapf.args,
                "--in-place",
                *(("--style", yapf.config) if yapf.config else ()),
                *request.snapshot.files,
            ),
            input_digest=input_digest,
            output_files=request.snapshot.files,
            description=
            f"Run yapf on {pluralize(len(request.field_sets), 'file')}.",
            level=LogLevel.DEBUG,
        ),
    )
    output_snapshot = await Get(Snapshot, Digest, result.output_digest)
    return FmtResult.create(request, result, output_snapshot)
예제 #3
0
async def autoflake_fmt(request: AutoflakeRequest,
                        autoflake: Autoflake) -> FmtResult:
    if autoflake.skip:
        return FmtResult.skip(formatter_name=request.name)
    autoflake_pex = await Get(VenvPex, PexRequest, autoflake.to_pex_request())

    result = await Get(
        ProcessResult,
        VenvPexProcess(
            autoflake_pex,
            argv=(
                "--in-place",
                "--remove-all-unused-imports",
                *autoflake.args,
                *request.snapshot.files,
            ),
            input_digest=request.snapshot.digest,
            output_files=request.snapshot.files,
            description=
            f"Run Autoflake on {pluralize(len(request.field_sets), 'file')}.",
            level=LogLevel.DEBUG,
        ),
    )
    output_snapshot = await Get(Snapshot, Digest, result.output_digest)
    return FmtResult.create(request,
                            result,
                            output_snapshot,
                            strip_chroot_path=True)
예제 #4
0
async def google_java_format_fmt(
    request: GoogleJavaFormatRequest,
    tool: GoogleJavaFormatSubsystem,
    jdk: InternalJdk,
) -> FmtResult:
    if tool.skip:
        return FmtResult.skip(formatter_name=request.name)
    lockfile_request = await Get(GenerateJvmLockfileFromTool,
                                 GoogleJavaFormatToolLockfileSentinel())
    tool_classpath = await Get(ToolClasspath,
                               ToolClasspathRequest(lockfile=lockfile_request))

    toolcp_relpath = "__toolcp"
    extra_immutable_input_digests = {
        toolcp_relpath: tool_classpath.digest,
    }

    maybe_java11_or_higher_options = []
    if jdk.jre_major_version >= 11:
        maybe_java11_or_higher_options = [
            "--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED",
            "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED",
            "--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED",
            "--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
            "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
        ]

    args = [
        *maybe_java11_or_higher_options,
        "com.google.googlejavaformat.java.Main",
        *(["--aosp"] if tool.aosp else []),
        "--replace",
        *request.snapshot.files,
    ]

    result = await Get(
        ProcessResult,
        JvmProcess(
            jdk=jdk,
            argv=args,
            classpath_entries=tool_classpath.classpath_entries(toolcp_relpath),
            input_digest=request.snapshot.digest,
            extra_jvm_options=tool.jvm_options,
            extra_immutable_input_digests=extra_immutable_input_digests,
            extra_nailgun_keys=extra_immutable_input_digests,
            output_files=request.snapshot.files,
            description=
            f"Run Google Java Format on {pluralize(len(request.field_sets), 'file')}.",
            level=LogLevel.DEBUG,
        ),
    )
    output_snapshot = await Get(Snapshot, Digest, result.output_digest)
    return FmtResult.create(request,
                            result,
                            output_snapshot,
                            strip_chroot_path=True)
예제 #5
0
async def clangformat_fmt(request: ClangFormatRequest,
                          clangformat: ClangFormat) -> FmtResult:
    if clangformat.skip:
        return FmtResult.skip(formatter_name=request.name)

    # Look for any/all of the clang-format configuration files (recurse sub-dirs)
    config_files_get = Get(
        ConfigFiles,
        ConfigFilesRequest,
        clangformat.config_request(request.snapshot.dirs),
    )

    clangformat_pex, config_files = await MultiGet(
        Get(Pex, PexRequest, clangformat.to_pex_request()), config_files_get)

    # Merge source files, config files, and clang-format pex process
    input_digest = await Get(
        Digest,
        MergeDigests([
            request.snapshot.digest,
            config_files.snapshot.digest,
            clangformat_pex.digest,
        ]),
    )

    result = await Get(
        ProcessResult,
        PexProcess(
            clangformat_pex,
            argv=(
                "--style=file",  # Look for .clang-format files
                "--fallback-style=webkit",  # Use WebKit if there is no config file
                "-i",  # In-place edits
                "--Werror",  # Formatting warnings as errors
                *clangformat.args,  # User-added arguments
                *request.snapshot.files,
            ),
            input_digest=input_digest,
            output_files=request.snapshot.files,
            description=
            f"Run clang-format on {pluralize(len(request.snapshot.files), 'file')}.",
            level=LogLevel.DEBUG,
        ),
    )
    output_snapshot = await Get(Snapshot, Digest, result.output_digest)
    return FmtResult.create(request,
                            result,
                            output_snapshot,
                            strip_chroot_path=True)
예제 #6
0
async def ktlint_fmt(request: KtlintRequest, tool: KtlintSubsystem,
                     jdk: InternalJdk) -> FmtResult:
    if tool.skip:
        return FmtResult.skip(formatter_name=request.name)

    lockfile_request = await Get(GenerateJvmLockfileFromTool,
                                 KtlintToolLockfileSentinel())
    tool_classpath = await Get(ToolClasspath,
                               ToolClasspathRequest(lockfile=lockfile_request))

    toolcp_relpath = "__toolcp"
    extra_immutable_input_digests = {
        toolcp_relpath: tool_classpath.digest,
    }

    args = [
        "com.pinterest.ktlint.Main",
        "-F",
        *request.snapshot.files,
    ]

    result = await Get(
        ProcessResult,
        JvmProcess(
            jdk=jdk,
            argv=args,
            classpath_entries=tool_classpath.classpath_entries(toolcp_relpath),
            input_digest=request.snapshot.digest,
            extra_jvm_options=tool.jvm_options,
            extra_immutable_input_digests=extra_immutable_input_digests,
            extra_nailgun_keys=extra_immutable_input_digests,
            output_files=request.snapshot.files,
            description=
            f"Run Ktlint on {pluralize(len(request.field_sets), 'file')}.",
            level=LogLevel.DEBUG,
        ),
    )

    output_snapshot = await Get(Snapshot, Digest, result.output_digest)
    return FmtResult.create(request,
                            result,
                            output_snapshot,
                            strip_chroot_path=True)
예제 #7
0
async def prettier_fmt(request: PrettierFmtRequest,
                       prettier: Prettier) -> FmtResult:
    if prettier.skip:
        return FmtResult.skip(formatter_name=request.name)

    # Look for any/all of the Prettier configuration files
    config_files = await Get(
        ConfigFiles,
        ConfigFilesRequest,
        prettier.config_request(request.snapshot.dirs),
    )

    # Merge source files, config files, and prettier_tool process
    input_digest = await Get(
        Digest,
        MergeDigests((
            request.snapshot.digest,
            config_files.snapshot.digest,
        )),
    )

    result = await Get(
        ProcessResult,
        NpxProcess(
            npm_package=prettier.default_version,
            args=(
                "--write",
                *request.snapshot.files,
            ),
            input_digest=input_digest,
            output_files=request.snapshot.files,
            description=
            f"Run Prettier on {pluralize(len(request.snapshot.files), 'file')}.",
            level=LogLevel.DEBUG,
        ),
    )
    output_snapshot = await Get(Snapshot, Digest, result.output_digest)
    return FmtResult.create(request,
                            result,
                            output_snapshot,
                            strip_chroot_path=True)
예제 #8
0
async def docformatter_fmt(request: DocformatterRequest, docformatter: Docformatter) -> FmtResult:
    if docformatter.skip:
        return FmtResult.skip(formatter_name=request.name)
    docformatter_pex = await Get(VenvPex, PexRequest, docformatter.to_pex_request())
    result = await Get(
        ProcessResult,
        VenvPexProcess(
            docformatter_pex,
            argv=(
                "--in-place",
                *docformatter.args,
                *request.snapshot.files,
            ),
            input_digest=request.snapshot.digest,
            output_files=request.snapshot.files,
            description=(f"Run Docformatter on {pluralize(len(request.field_sets), 'file')}."),
            level=LogLevel.DEBUG,
        ),
    )
    output_snapshot = await Get(Snapshot, Digest, result.output_digest)
    return FmtResult.create(request, result, output_snapshot)
예제 #9
0
async def pyupgrade_fmt(request: PyUpgradeRequest,
                        pyupgrade: PyUpgrade) -> FmtResult:
    if pyupgrade.skip:
        return FmtResult.skip(formatter_name=request.name)

    pyupgrade_pex = await Get(VenvPex, PexRequest, pyupgrade.to_pex_request())

    result = await Get(
        FallibleProcessResult,
        VenvPexProcess(
            pyupgrade_pex,
            argv=(*pyupgrade.args, *request.snapshot.files),
            input_digest=request.snapshot.digest,
            output_files=request.snapshot.files,
            description=
            f"Run pyupgrade on {pluralize(len(request.field_sets), 'file')}.",
            level=LogLevel.DEBUG,
        ),
    )
    output_snapshot = await Get(Snapshot, Digest, result.output_digest)
    return FmtResult.create(request, result, output_snapshot)
예제 #10
0
async def gofmt_fmt(request: GofmtRequest, gofmt: GofmtSubsystem,
                    goroot: GoRoot) -> FmtResult:
    if gofmt.skip:
        return FmtResult.skip(formatter_name=request.name)
    argv = (
        os.path.join(goroot.path, "bin/gofmt"),
        "-w",
        *request.snapshot.files,
    )
    result = await Get(
        ProcessResult,
        Process(
            argv=argv,
            input_digest=request.snapshot.digest,
            output_files=request.snapshot.files,
            description=
            f"Run gofmt on {pluralize(len(request.snapshot.files), 'file')}.",
            level=LogLevel.DEBUG,
        ),
    )
    output_snapshot = await Get(Snapshot, Digest, result.output_digest)
    return FmtResult.create(request, result, output_snapshot)
예제 #11
0
async def isort_fmt(request: IsortRequest, isort: Isort) -> FmtResult:
    if isort.skip:
        return FmtResult.skip(formatter_name=request.name)
    isort_pex_get = Get(VenvPex, PexRequest, isort.to_pex_request())
    config_files_get = Get(ConfigFiles, ConfigFilesRequest,
                           isort.config_request(request.snapshot.dirs))
    isort_pex, config_files = await MultiGet(isort_pex_get, config_files_get)

    # Isort 5+ changes how config files are handled. Determine which semantics we should use.
    is_isort5 = False
    if isort.config:
        isort_info = await Get(PexResolveInfo, VenvPex, isort_pex)
        is_isort5 = any(
            dist_info.project_name == "isort" and dist_info.version.major >= 5
            for dist_info in isort_info)

    input_digest = await Get(
        Digest,
        MergeDigests((request.snapshot.digest, config_files.snapshot.digest)))

    result = await Get(
        ProcessResult,
        VenvPexProcess(
            isort_pex,
            argv=generate_argv(request.snapshot.files,
                               isort,
                               is_isort5=is_isort5),
            input_digest=input_digest,
            output_files=request.snapshot.files,
            description=
            f"Run isort on {pluralize(len(request.field_sets), 'file')}.",
            level=LogLevel.DEBUG,
        ),
    )
    output_snapshot = await Get(Snapshot, Digest, result.output_digest)
    return FmtResult.create(request,
                            result,
                            output_snapshot,
                            strip_chroot_path=True)
예제 #12
0
async def shfmt_fmt(request: ShfmtRequest, shfmt: Shfmt) -> FmtResult:
    if shfmt.skip:
        return FmtResult.skip(formatter_name=request.name)

    download_shfmt_get = Get(DownloadedExternalTool, ExternalToolRequest,
                             shfmt.get_request(Platform.current))
    config_files_get = Get(ConfigFiles, ConfigFilesRequest,
                           shfmt.config_request(request.snapshot.dirs))
    downloaded_shfmt, config_files = await MultiGet(download_shfmt_get,
                                                    config_files_get)

    input_digest = await Get(
        Digest,
        MergeDigests((request.snapshot.digest, downloaded_shfmt.digest,
                      config_files.snapshot.digest)),
    )

    argv = [
        downloaded_shfmt.exe,
        "-l",
        "-w",
        *shfmt.args,
        *request.snapshot.files,
    ]

    result = await Get(
        ProcessResult,
        Process(
            argv=argv,
            input_digest=input_digest,
            output_files=request.snapshot.files,
            description=
            f"Run shfmt on {pluralize(len(request.field_sets), 'file')}.",
            level=LogLevel.DEBUG,
        ),
    )
    output_snapshot = await Get(Snapshot, Digest, result.output_digest)
    return FmtResult.create(request, result, output_snapshot)
예제 #13
0
async def black_fmt(request: BlackRequest, black: Black, python_setup: PythonSetup) -> FmtResult:
    if black.skip:
        return FmtResult.skip(formatter_name=request.name)
    # Black requires 3.6+ but uses the typed-ast library to work with 2.7, 3.4, 3.5, 3.6, and 3.7.
    # However, typed-ast does not understand 3.8+, so instead we must run Black with Python 3.8+
    # when relevant. We only do this if if <3.8 can't be used, as we don't want a loose requirement
    # like `>=3.6` to result in requiring Python 3.8, which would error if 3.8 is not installed on
    # the machine.
    tool_interpreter_constraints = black.interpreter_constraints
    if black.options.is_default("interpreter_constraints"):
        try:
            # Don't compute this unless we have to, since it might fail.
            all_interpreter_constraints = InterpreterConstraints.create_from_compatibility_fields(
                (field_set.interpreter_constraints for field_set in request.field_sets),
                python_setup,
            )
        except ValueError:
            raise ValueError(
                softwrap(
                    """
                    Could not compute an interpreter to run Black on, due to conflicting requirements
                    in the repo.

                    Please set `[black].interpreter_constraints` explicitly in pants.toml to a
                    suitable interpreter.
                    """
                )
            )
        if all_interpreter_constraints.requires_python38_or_newer(
            python_setup.interpreter_universe
        ):
            tool_interpreter_constraints = all_interpreter_constraints

    black_pex_get = Get(
        VenvPex,
        PexRequest,
        black.to_pex_request(interpreter_constraints=tool_interpreter_constraints),
    )
    config_files_get = Get(
        ConfigFiles, ConfigFilesRequest, black.config_request(request.snapshot.dirs)
    )

    black_pex, config_files = await MultiGet(black_pex_get, config_files_get)

    input_digest = await Get(
        Digest, MergeDigests((request.snapshot.digest, config_files.snapshot.digest))
    )

    result = await Get(
        ProcessResult,
        VenvPexProcess(
            black_pex,
            argv=(
                *(("--config", black.config) if black.config else ()),
                "-W",
                "{pants_concurrency}",
                *black.args,
                *request.snapshot.files,
            ),
            input_digest=input_digest,
            output_files=request.snapshot.files,
            concurrency_available=len(request.field_sets),
            description=f"Run Black on {pluralize(len(request.field_sets), 'file')}.",
            level=LogLevel.DEBUG,
        ),
    )
    output_snapshot = await Get(Snapshot, Digest, result.output_digest)
    return FmtResult.create(request, result, output_snapshot, strip_chroot_path=True)