Skip to content

Commit 039d784

Browse files
authored
Convert ktlint integration to use a compile-only sourceset. (#1012, example of #524)
2 parents d041ba5 + c5600b5 commit 039d784

File tree

4 files changed

+100
-56
lines changed

4 files changed

+100
-56
lines changed

CHANGES.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ This document is intended for Spotless developers.
1010
We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`).
1111

1212
## [Unreleased]
13+
### Changed
14+
* Converted `ktlint` integration to use a compile-only source set. ([#524](https://github.com/diffplug/spotless/issues/524))
1315

1416
## [2.20.1] - 2021-12-01
15-
1617
### Changed
1718
* Added `named` option to `licenseHeader` to support alternate license header within same format (like java) ([872](https://github.com/diffplug/spotless/issues/872)).
1819
* Added `onlyIfContentMatches` option to `licenseHeader` to skip license header application based on source file content pattern ([#650](https://github.com/diffplug/spotless/issues/650)).

lib/build.gradle

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ apply from: rootProject.file('gradle/java-setup.gradle')
77
apply from: rootProject.file('gradle/java-publish.gradle')
88

99
def NEEDS_GLUE = [
10-
'sortPom'
10+
'sortPom',
11+
'ktlint'
1112
]
1213
for (glue in NEEDS_GLUE) {
1314
sourceSets.register(glue) {
@@ -20,12 +21,17 @@ for (glue in NEEDS_GLUE) {
2021
dependencies {
2122
// zero runtime reqs is a hard requirements for spotless-lib
2223
// if you need a dep, put it in lib-extra
23-
testImplementation "org.junit.jupiter:junit-jupiter:${VER_JUNIT}"
24-
testImplementation "org.assertj:assertj-core:${VER_ASSERTJ}"
25-
testImplementation "com.diffplug.durian:durian-testlib:${VER_DURIAN}"
24+
testImplementation "org.junit.jupiter:junit-jupiter:$VER_JUNIT"
25+
testImplementation "org.assertj:assertj-core:$VER_ASSERTJ"
26+
testImplementation "com.diffplug.durian:durian-testlib:$VER_DURIAN"
2627

2728
// used for pom sorting
2829
sortPomCompileOnly 'com.github.ekryd.sortpom:sortpom-sorter:3.0.0'
30+
31+
String VER_KTLINT='0.43.1'
32+
ktlintCompileOnly "com.pinterest:ktlint:$VER_KTLINT"
33+
ktlintCompileOnly "com.pinterest.ktlint:ktlint-core:$VER_KTLINT"
34+
ktlintCompileOnly "com.pinterest.ktlint:ktlint-ruleset-standard:$VER_KTLINT"
2935
}
3036

3137
// we'll hold the core lib to a high standard
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright 2021 DiffPlug
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.diffplug.spotless.glue.ktlint;
17+
18+
import java.io.File;
19+
import java.util.Collections;
20+
import java.util.List;
21+
import java.util.Map;
22+
import java.util.logging.Logger;
23+
24+
import com.pinterest.ktlint.core.KtLint;
25+
import com.pinterest.ktlint.core.KtLint.Params;
26+
import com.pinterest.ktlint.core.LintError;
27+
import com.pinterest.ktlint.core.RuleSet;
28+
import com.pinterest.ktlint.ruleset.standard.StandardRuleSetProvider;
29+
30+
import com.diffplug.spotless.FormatterFunc;
31+
32+
import kotlin.Unit;
33+
import kotlin.jvm.functions.Function2;
34+
35+
public class KtlintFormatterFunc implements FormatterFunc.NeedsFile {
36+
private static final Logger logger = Logger.getLogger(KtlintFormatterFunc.class.getName());
37+
38+
private final List<RuleSet> rulesets;
39+
private final Map<String, String> userData;
40+
private final Function2<? super LintError, ? super Boolean, Unit> formatterCallback;
41+
private final boolean isScript;
42+
43+
public KtlintFormatterFunc(boolean isScript, Map<String, String> userData) {
44+
rulesets = Collections.singletonList(new StandardRuleSetProvider().get());
45+
this.userData = userData;
46+
formatterCallback = new FormatterCallback();
47+
this.isScript = isScript;
48+
}
49+
50+
static class FormatterCallback implements Function2<LintError, Boolean, Unit> {
51+
@Override
52+
public Unit invoke(LintError lint, Boolean corrected) {
53+
if (!corrected) {
54+
throw new AssertionError("Error on line: " + lint.getLine() + ", column: " + lint.getCol() + "\n" + lint.getDetail());
55+
}
56+
return null;
57+
}
58+
}
59+
60+
@Override
61+
public String applyWithFile(String unix, File file) throws Exception {
62+
return KtLint.INSTANCE.format(new Params(
63+
file.getName(),
64+
unix,
65+
rulesets,
66+
userData,
67+
formatterCallback,
68+
isScript,
69+
null,
70+
false));
71+
}
72+
}

lib/src/main/java/com/diffplug/spotless/kotlin/KtLintStep.java

Lines changed: 16 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,13 @@ static final class State implements Serializable {
103103
}
104104

105105
FormatterFunc createFormat() throws Exception {
106-
ClassLoader classLoader = jarState.getClassLoader();
106+
if (useParams) {
107+
Class<?> formatterFunc = jarState.getClassLoader().loadClass("com.diffplug.spotless.glue.ktlint.KtlintFormatterFunc");
108+
Constructor<?> constructor = formatterFunc.getConstructor(boolean.class, Map.class);
109+
return (FormatterFunc.NeedsFile) constructor.newInstance(isScript, userData);
110+
}
107111

112+
ClassLoader classLoader = jarState.getClassLoader();
108113
// String KtLint::format(String input, Iterable<RuleSet> rules, Function2 errorCallback)
109114

110115
// first, we get the standard rules
@@ -134,57 +139,17 @@ FormatterFunc createFormat() throws Exception {
134139
// grab the KtLint singleton
135140
Class<?> ktlintClass = classLoader.loadClass(pkg + ".ktlint.core.KtLint");
136141
Object ktlint = ktlintClass.getDeclaredField("INSTANCE").get(null);
137-
FormatterFunc formatterFunc;
138-
if (useParams) {
139-
//
140-
// In KtLint 0.34+ there is a new "format(params: Params)" function. We create an
141-
// instance of the Params class with our configuration and invoke it here.
142-
//
143-
144-
// grab the Params class
145-
Class<?> paramsClass = classLoader.loadClass(pkg + ".ktlint.core.KtLint$Params");
146-
// and its constructor
147-
Constructor<?> constructor = paramsClass.getConstructor(
148-
/* fileName, nullable */ String.class,
149-
/* text */ String.class,
150-
/* ruleSets */ Iterable.class,
151-
/* userData */ Map.class,
152-
/* callback */ function2Interface,
153-
/* script */ boolean.class,
154-
/* editorConfigPath, nullable */ String.class,
155-
/* debug */ boolean.class);
156-
Method formatterMethod = ktlintClass.getMethod("format", paramsClass);
157-
FormatterFunc.NeedsFile needsFile = (input, file) -> {
158-
try {
159-
Object params = constructor.newInstance(
160-
/* fileName, nullable */ file.getName(),
161-
/* text */ input,
162-
/* ruleSets */ ruleSets,
163-
/* userData */ userData,
164-
/* callback */ formatterCallback,
165-
/* script */ isScript,
166-
/* editorConfigPath, nullable */ null,
167-
/* debug */ false);
168-
return (String) formatterMethod.invoke(ktlint, params);
169-
} catch (InvocationTargetException e) {
170-
throw ThrowingEx.unwrapCause(e);
171-
}
172-
};
173-
formatterFunc = FormatterFunc.needsFile(needsFile);
174-
} else {
175-
// and its format method
176-
String formatterMethodName = isScript ? "formatScript" : "format";
177-
Method formatterMethod = ktlintClass.getMethod(formatterMethodName, String.class, Iterable.class, Map.class, function2Interface);
178-
formatterFunc = input -> {
179-
try {
180-
return (String) formatterMethod.invoke(ktlint, input, ruleSets, userData, formatterCallback);
181-
} catch (InvocationTargetException e) {
182-
throw ThrowingEx.unwrapCause(e);
183-
}
184-
};
185-
}
186142

187-
return formatterFunc;
143+
// and its format method
144+
String formatterMethodName = isScript ? "formatScript" : "format";
145+
Method formatterMethod = ktlintClass.getMethod(formatterMethodName, String.class, Iterable.class, Map.class, function2Interface);
146+
return input -> {
147+
try {
148+
return (String) formatterMethod.invoke(ktlint, input, ruleSets, userData, formatterCallback);
149+
} catch (InvocationTargetException e) {
150+
throw ThrowingEx.unwrapCause(e);
151+
}
152+
};
188153
}
189154
}
190155
}

0 commit comments

Comments
 (0)