Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add clang-format support for the experimental c/cpp plugin #15395

Merged
merged 9 commits into from
May 12, 2022
2 changes: 2 additions & 0 deletions build-support/bin/_generate_all_lockfiles_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import sys
from dataclasses import dataclass

from pants.backend.cc.lint.clangformat.subsystem import ClangFormat
from pants.backend.codegen.avro.java.subsystem import AvroSubsystem
from pants.backend.codegen.protobuf.python.python_protobuf_subsystem import PythonProtobufMypyPlugin
from pants.backend.codegen.protobuf.scala.subsystem import ScalaPBSubsystem
Expand Down Expand Up @@ -114,6 +115,7 @@ def jvm(cls, tool: type[JvmToolBase], *, backend: str | None = None) -> DefaultT
DefaultTool.python(TerraformHcl2Parser, backend="pants.backend.experimental.terraform"),
DefaultTool.python(DockerfileParser, backend="pants.backend.docker"),
DefaultTool.python(TwineSubsystem),
DefaultTool.python(ClangFormat, backend="pants.backend.experimental.cc.lint.clangformat"),
# JVM
DefaultTool.jvm(JUnit),
DefaultTool.jvm(GoogleJavaFormatSubsystem),
Expand Down
4 changes: 4 additions & 0 deletions src/python/pants/backend/cc/lint/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright 2022 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).

python_sources()
Empty file.
11 changes: 11 additions & 0 deletions src/python/pants/backend/cc/lint/clangformat/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Copyright 2022 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).

python_sources(dependencies=[":lockfile"])
resource(name="lockfile", source="clangformat.lock")

python_tests(
name="rules_integration_test",
sources=["rules_integration_test.py"],
timeout=240,
)
Empty file.
100 changes: 100 additions & 0 deletions src/python/pants/backend/cc/lint/clangformat/clangformat.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// This lockfile was autogenerated by Pants. To regenerate, run:
//
// build-support/bin/generate_all_lockfiles.sh
//
// --- BEGIN PANTS LOCKFILE METADATA: DO NOT EDIT OR REMOVE ---
// {
// "version": 2,
// "valid_for_interpreter_constraints": [
// "CPython<4,>=3.7"
// ],
// "generated_with_requirements": [
// "clang-format==14.0.3"
// ]
// }
// --- END PANTS LOCKFILE METADATA ---

{
"allow_builds": true,
"allow_prereleases": false,
"allow_wheels": true,
"build_isolation": true,
"constraints": [],
"locked_resolves": [
{
"locked_requirements": [
{
"artifacts": [
{
"algorithm": "sha256",
"hash": "a084aa5a8b56b07893014790c8b051e795977b24980fda3af5eb193539a9653c",
"url": "https://files.pythonhosted.org/packages/aa/3f/00a6ca37de9a08b0d6717910c8479ade1aa5cb33d0a0897d1236447c2d36/clang_format-14.0.3-py2.py3-none-win_amd64.whl"
},
{
"algorithm": "sha256",
"hash": "2c7da4ff143146fe7b80894efd32842f45d58a3bd30e8fb559ce86b961700a3c",
"url": "https://files.pythonhosted.org/packages/2f/a7/01eebdafa44ca579383eb088dd6aa2179aa8c0bd661db17a6e52a5c5032b/clang_format-14.0.3-py2.py3-none-macosx_10_9_universal2.whl"
},
{
"algorithm": "sha256",
"hash": "7dce28e40f2af48b1d0d5a0211562e592395d32c58483c0cafd75e7cf3297b55",
"url": "https://files.pythonhosted.org/packages/4f/9e/be1a223599b501a116048fdb5ed3e96fee68ae5afcac4608f885b04265f5/clang_format-14.0.3-py2.py3-none-manylinux_2_12_i686.manylinux2010_i686.whl"
},
{
"algorithm": "sha256",
"hash": "00afee65c015d4c017d5b56524fc4a59829e5986ac159f0ab2c2147540a2b31a",
"url": "https://files.pythonhosted.org/packages/65/56/eb18d61a085ba018395155a2d658e0ee3aff0821a0b16d3d431b5ecec83b/clang_format-14.0.3-py2.py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl"
},
{
"algorithm": "sha256",
"hash": "b15a04d5c6ca463104518c461ef203f62f2a0b639d4e49d1362e2344ce25ec89",
"url": "https://files.pythonhosted.org/packages/66/91/52e3e26b31945dd2e58f0cdbd0697f424cb4bbd9ad254a3f800a3d3d2993/clang_format-14.0.3-py2.py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"
},
{
"algorithm": "sha256",
"hash": "ae9746b024d900b3f2a5181fc9b1412a92a5df003793222cf9b646f21cb6f9eb",
"url": "https://files.pythonhosted.org/packages/6e/88/9b6497ed42b6b7ce06fb6da65f31f63ce87ccaa97d2acd2c6f31d63777ec/clang_format-14.0.3-py2.py3-none-win32.whl"
},
{
"algorithm": "sha256",
"hash": "73bc0bd21eacdee30b85e1315a6cff5685531d89905c3411de91816fc7cbce75",
"url": "https://files.pythonhosted.org/packages/91/19/b484a5df518e83fdf45482ce2396392932c5636c4a785b5d9c57d965b305/clang-format-14.0.3.tar.gz"
},
{
"algorithm": "sha256",
"hash": "778e4acc74e1dcbd8197dcf49142b4102242a83881fb117b86727c01e74c6941",
"url": "https://files.pythonhosted.org/packages/a3/4d/866c1f4bafd8ab2b957c7713aa2ae4db1363f781fb02fdd77ff531813abf/clang_format-14.0.3-py2.py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.whl"
},
{
"algorithm": "sha256",
"hash": "0925179fa10c444a07bdff5db6981868d07f109f1d8b5e5eaecc4f3b028e48a1",
"url": "https://files.pythonhosted.org/packages/b1/42/1a523349b0ae0ebcedb6278fade1fa5e0b303f9a18a480a342e4242d30bc/clang_format-14.0.3-py2.py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"
}
],
"project_name": "clang-format",
"requires_dists": [],
"requires_python": null,
"version": "14.0.3"
}
],
"platform_tag": [
"cp39",
"cp39",
"macosx_12_0_x86_64"
]
}
],
"path_mappings": {},
"pex_version": "2.1.84",
"prefer_older_binary": false,
"requirements": [
"clang-format==14.0.3"
],
"requires_python": [
"<4,>=3.7"
],
"resolver_version": "pip-2020-resolver",
"style": "universal",
"transitive": true,
"use_pep517": null
}
101 changes: 101 additions & 0 deletions src/python/pants/backend/cc/lint/clangformat/rules.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Copyright 2022 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).

from __future__ import annotations

import logging
from dataclasses import dataclass
from typing import Iterable

from pants.backend.cc.lint.clangformat.subsystem import ClangFormat
from pants.backend.cc.target_types import CCSourceField
from pants.backend.python.util_rules.pex import Pex, PexProcess, PexRequest
from pants.core.goals.fmt import FmtRequest, FmtResult
from pants.core.util_rules.config_files import ConfigFiles, ConfigFilesRequest
from pants.engine.fs import Digest, MergeDigests, Snapshot
from pants.engine.process import ProcessResult
from pants.engine.rules import Get, MultiGet, Rule, collect_rules, rule
from pants.engine.target import FieldSet
from pants.engine.unions import UnionRule
from pants.util.logging import LogLevel
from pants.util.strutil import pluralize

logger = logging.getLogger(__name__)


@dataclass(frozen=True)
class ClangFormatFmtFieldSet(FieldSet):
required_fields = (CCSourceField,)

sources: CCSourceField


class ClangFormatRequest(FmtRequest):
field_set_type = ClangFormatFmtFieldSet
name = ClangFormat.options_scope


@rule(level=LogLevel.DEBUG)
async def clangformat_fmt(request: ClangFormatRequest, clangformat: ClangFormat) -> FmtResult:
if clangformat.skip:
return FmtResult.skip(formatter_name=request.name)

clangformat_pex_get = Get(
Pex,
PexRequest(
output_filename="clangformat.pex",
internal_only=True,
requirements=clangformat.pex_requirements(),
interpreter_constraints=clangformat.interpreter_constraints,
main=clangformat.main,
),
)
sureshjoshi marked this conversation as resolved.
Show resolved Hide resolved

# 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(clangformat_pex_get, 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)


def rules() -> Iterable[Rule | UnionRule]:
return (
*collect_rules(),
UnionRule(FmtRequest, ClangFormatRequest),
)
Loading