From daa0ef4751515971420fc579a188e30ad5598c0d Mon Sep 17 00:00:00 2001 From: Emiel Matthys Date: Sat, 15 Jul 2023 23:56:17 +0200 Subject: [PATCH 1/4] Use full path in clang-format --assume-filename --- .../main/java/com/diffplug/spotless/cpp/ClangFormatStep.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/main/java/com/diffplug/spotless/cpp/ClangFormatStep.java b/lib/src/main/java/com/diffplug/spotless/cpp/ClangFormatStep.java index 5591045505..3962c50234 100644 --- a/lib/src/main/java/com/diffplug/spotless/cpp/ClangFormatStep.java +++ b/lib/src/main/java/com/diffplug/spotless/cpp/ClangFormatStep.java @@ -111,7 +111,7 @@ String format(ProcessRunner runner, String input, File file) throws IOException, args = tmpArgs; } final String[] processArgs = args.toArray(new String[args.size() + 1]); - processArgs[processArgs.length - 1] = "--assume-filename=" + file.getName(); + processArgs[processArgs.length - 1] = "--assume-filename=" + file.getAbsolutePath(); return runner.exec(input.getBytes(StandardCharsets.UTF_8), processArgs).assertExitZero(StandardCharsets.UTF_8); } From b7cd49198e1503a111bb11125b96f5cadce322fe Mon Sep 17 00:00:00 2001 From: Emiel Matthys Date: Sun, 16 Jul 2023 12:14:02 +0200 Subject: [PATCH 2/4] Update documentation --- plugin-gradle/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index 704e3b694a..58df43a878 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -1014,7 +1014,9 @@ spotless { // can also specify a code style clangFormat().style('LLVM') // or Google, Chromium, Mozilla, WebKit - // TODO: support arbitrary .clang-format + + // you can also indicate to use a local .clang-format file + clangFormat().style('file') // if clang-format is not on your path, you must specify its location manually clangFormat().pathToExe('/usr/local/Cellar/clang-format/10.0.1/bin/clang-format') From 34ff3c0e70b9cecbd057d1bc21fbb117b6cbf9f1 Mon Sep 17 00:00:00 2001 From: Emiel Matthys Date: Sun, 16 Jul 2023 12:27:34 +0200 Subject: [PATCH 3/4] Add changes.md --- CHANGES.md | 1 + plugin-gradle/CHANGES.md | 2 ++ 2 files changed, 3 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 6484eadf77..4d62bc9058 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -19,6 +19,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( * Bump default `ktlint` version to latest `0.49.1` -> `0.50.0`. ([#1741](https://github.com/diffplug/spotless/issues/1741)) * Dropped support for `ktlint 0.47.x` following our policy of supporting two breaking changes at a time. * Dropped support for deprecated `useExperimental` parameter in favor of the `ktlint_experimental` property. +* Use full path for clang-format's `--assume-filename` parameter, allowing disovery of .clang-format files. ([#1759](https://github.com/diffplug/spotless/pull/1759)) ## [2.39.0] - 2023-05-24 ### Added diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index b3b700691a..c329f190a1 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -6,6 +6,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ### Added * Add target option `targetExcludeIfContentContains` and `targetExcludeIfContentContainsRegex` to exclude files based on their text content. ([#1749](https://github.com/diffplug/spotless/pull/1749)) * Add an overload for `FormatExtension.addStep` which provides access to the `FormatExtension`'s `Provisioner`, enabling custom steps to make use of third-party dependencies. +* Add option to specify `file` as `clangFormat` style to use local `.clang-format` files. ([#1759](https://github.com/diffplug/spotless/pull/1759)) + ### Fixed * Correctly support the syntax ``` From e5d09fe2fdb2a80927b9d934d7f2d5f58c59fedb Mon Sep 17 00:00:00 2001 From: Emiel Matthys Date: Wed, 9 Aug 2023 14:27:03 +0200 Subject: [PATCH 4/4] Add FileSignature field to ClangFormatStep State --- .../spotless/cpp/ClangFormatStep.java | 54 ++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/lib/src/main/java/com/diffplug/spotless/cpp/ClangFormatStep.java b/lib/src/main/java/com/diffplug/spotless/cpp/ClangFormatStep.java index 3962c50234..b8a99dd979 100644 --- a/lib/src/main/java/com/diffplug/spotless/cpp/ClangFormatStep.java +++ b/lib/src/main/java/com/diffplug/spotless/cpp/ClangFormatStep.java @@ -20,11 +20,16 @@ import java.io.Serializable; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Optional; +import java.util.Set; import javax.annotation.Nullable; +import com.diffplug.spotless.FileSignature; import com.diffplug.spotless.ForeignExe; import com.diffplug.spotless.FormatterFunc; import com.diffplug.spotless.FormatterStep; @@ -88,20 +93,66 @@ private State createState() throws IOException, InterruptedException { @SuppressFBWarnings("SE_TRANSIENT_FIELD_NOT_RESTORED") static class State implements Serializable { private static final long serialVersionUID = -1825662356883926318L; + private static final String DOT_FILE_NAME = ".clang-format"; // used for up-to-date checks and caching final String version; final @Nullable String style; final transient ForeignExe exe; + final Set dotFiles; + FileSignature dotFileSig; // used for executing private transient @Nullable List args; - State(ClangFormatStep step, ForeignExe pathToExe) { + State(ClangFormatStep step, ForeignExe pathToExe, @Nullable FileSignature sig) { this.version = step.version; this.style = step.style; this.exe = Objects.requireNonNull(pathToExe); + this.dotFiles = new HashSet<>(); + this.dotFileSig = sig; + } + + State(ClangFormatStep step, ForeignExe pathToExe) { + this(step, pathToExe, null); } + /** + * If relevant, locates the `.clang-format` file that will be used as config + * for clang-format and stores its signature in dotFile. + * @param targetFile file to be formatted. + */ + private void resolveDotFile(File targetFile) throws IOException + { + // The dot file is irrelevant if a specific style other than "file" is supplied. + if (style != null && !style.equals("file")) { + return; + } + + File directory = targetFile.getParentFile(); + Optional dotFile = Optional.empty(); + while (dotFile.isEmpty() && readableDirectory(directory)) { + dotFile = Arrays.stream(directory.listFiles()).filter(file -> file.getName().equals(DOT_FILE_NAME)).findAny(); + directory = directory.getParentFile(); + } + + System.out.println("dotFile: " + dotFile); + // Every target file can have a different .clang-format file (in theory). + // Keep track of the ones we've covered and build the sig as we go. + if (dotFile.isPresent() && !dotFiles.contains(dotFile.get())) { + dotFiles.add(dotFile.get()); + dotFileSig = FileSignature.signAsSet(dotFiles); + } + System.out.println("Signature" + dotFileSig); + } + + + private static boolean readableDirectory(File directory) + { + return directory != null && directory.exists() && directory.isDirectory() && directory.canRead(); + } + + String format(ProcessRunner runner, String input, File file) throws IOException, InterruptedException { + resolveDotFile(file); if (args == null) { final List tmpArgs = new ArrayList<>(); tmpArgs.add(exe.confirmVersionAndGetAbsolutePath()); @@ -112,6 +163,7 @@ String format(ProcessRunner runner, String input, File file) throws IOException, } final String[] processArgs = args.toArray(new String[args.size() + 1]); processArgs[processArgs.length - 1] = "--assume-filename=" + file.getAbsolutePath(); + System.out.println(String.join(", ", processArgs)); return runner.exec(input.getBytes(StandardCharsets.UTF_8), processArgs).assertExitZero(StandardCharsets.UTF_8); }