Skip to content

Commit ca1a338

Browse files
authored
feat: supply Eclipse config properties from string (#2343)
2 parents 1804930 + b79dfad commit ca1a338

File tree

10 files changed

+177
-6
lines changed

10 files changed

+177
-6
lines changed

CHANGES.md

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
1111

1212
## [Unreleased]
1313
### Changed
14+
* Allow setting Eclipse config from a string, not only from files ([#2337](https://github.com/diffplug/spotless/pull/2337))
1415
* Bump default `ktlint` version to latest `1.3.0` -> `1.4.0`. ([#2314](https://github.com/diffplug/spotless/pull/2314))
1516
* Add _Sort Members_ feature based on [Eclipse JDT](plugin-gradle/README.md#eclipse-jdt) implementation. ([#2312](https://github.com/diffplug/spotless/pull/2312))
1617
* Bump default `jackson` version to latest `2.18.0` -> `2.18.1`. ([#2319](https://github.com/diffplug/spotless/pull/2319))

lib-extra/src/main/java/com/diffplug/spotless/extra/EquoBasedStepBuilder.java

+17-4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.Collection;
2525
import java.util.List;
2626
import java.util.Map;
27+
import java.util.Optional;
2728
import java.util.Properties;
2829

2930
import javax.annotation.Nullable;
@@ -54,6 +55,7 @@ public abstract class EquoBasedStepBuilder {
5455
private final ImmutableMap.Builder<String, String> stepProperties;
5556
private String formatterVersion;
5657
private Iterable<File> settingsFiles = new ArrayList<>();
58+
private List<String> settingProperties = new ArrayList<>();
5759
private Map<String, String> p2Mirrors = Map.of();
5860
private File cacheDirectory;
5961

@@ -80,6 +82,10 @@ public void setPreferences(Iterable<File> settingsFiles) {
8082
this.settingsFiles = settingsFiles;
8183
}
8284

85+
public void setPropertyPreferences(List<String> propertyPreferences) {
86+
this.settingProperties = propertyPreferences;
87+
}
88+
8389
public void setP2Mirrors(Map<String, String> p2Mirrors) {
8490
this.p2Mirrors = Map.copyOf(p2Mirrors);
8591
}
@@ -113,7 +119,7 @@ protected void addPlatformRepo(P2Model model, String version) {
113119

114120
/** Returns the FormatterStep (whose state will be calculated lazily). */
115121
public FormatterStep build() {
116-
var roundtrippableState = new EquoStep(formatterVersion, FileSignature.promise(settingsFiles), JarState.promise(() -> {
122+
var roundtrippableState = new EquoStep(formatterVersion, settingProperties, FileSignature.promise(settingsFiles), JarState.promise(() -> {
117123
P2QueryResult query;
118124
try {
119125
if (null != cacheDirectory) {
@@ -167,21 +173,24 @@ static class EquoStep implements Serializable {
167173
private final FileSignature.Promised settingsPromise;
168174
private final JarState.Promised jarPromise;
169175
private final ImmutableMap<String, String> stepProperties;
176+
private List<String> settingProperties;
170177

171178
EquoStep(
172179
String semanticVersion,
180+
List<String> settingProperties,
173181
FileSignature.Promised settingsPromise,
174182
JarState.Promised jarPromise,
175183
ImmutableMap<String, String> stepProperties) {
176184

177185
this.semanticVersion = semanticVersion;
186+
this.settingProperties = Optional.ofNullable(settingProperties).orElse(new ArrayList<>());
178187
this.settingsPromise = settingsPromise;
179188
this.jarPromise = jarPromise;
180189
this.stepProperties = stepProperties;
181190
}
182191

183192
private State state() {
184-
return new State(semanticVersion, jarPromise.get(), settingsPromise.get(), stepProperties);
193+
return new State(semanticVersion, jarPromise.get(), settingProperties, settingsPromise.get(), stepProperties);
185194
}
186195
}
187196

@@ -195,10 +204,12 @@ public static class State implements Serializable {
195204
final JarState jarState;
196205
final FileSignature settingsFiles;
197206
final ImmutableMap<String, String> stepProperties;
207+
private List<String> settingProperties;
198208

199-
public State(String semanticVersion, JarState jarState, FileSignature settingsFiles, ImmutableMap<String, String> stepProperties) {
209+
public State(String semanticVersion, JarState jarState, List<String> settingProperties, FileSignature settingsFiles, ImmutableMap<String, String> stepProperties) {
200210
this.semanticVersion = semanticVersion;
201211
this.jarState = jarState;
212+
this.settingProperties = Optional.ofNullable(settingProperties).orElse(new ArrayList<>());
202213
this.settingsFiles = settingsFiles;
203214
this.stepProperties = stepProperties;
204215
}
@@ -212,7 +223,9 @@ public String getSemanticVersion() {
212223
}
213224

214225
public Properties getPreferences() {
215-
return FormatterProperties.from(settingsFiles.files()).getProperties();
226+
FormatterProperties fromFiles = FormatterProperties.from(settingsFiles.files());
227+
FormatterProperties fromPropertiesContent = FormatterProperties.fromPropertiesContent(settingProperties);
228+
return FormatterProperties.merge(fromFiles.getProperties(), fromPropertiesContent.getProperties()).getProperties();
216229
}
217230

218231
public ImmutableMap<String, String> getStepProperties() {

lib/src/main/java/com/diffplug/spotless/FormatterProperties.java

+22-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2021 DiffPlug
2+
* Copyright 2016-2024 DiffPlug
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,10 +17,12 @@
1717

1818
import static com.diffplug.spotless.MoreIterables.toNullHostileList;
1919

20+
import java.io.ByteArrayInputStream;
2021
import java.io.File;
2122
import java.io.FileInputStream;
2223
import java.io.IOException;
2324
import java.io.InputStream;
25+
import java.nio.charset.StandardCharsets;
2426
import java.util.Arrays;
2527
import java.util.LinkedList;
2628
import java.util.List;
@@ -75,6 +77,25 @@ public static FormatterProperties from(Iterable<File> files) throws IllegalArgum
7577
return properties;
7678
}
7779

80+
public static FormatterProperties fromPropertiesContent(Iterable<String> content) throws IllegalArgumentException {
81+
List<String> nonNullElements = toNullHostileList(content);
82+
FormatterProperties properties = new FormatterProperties();
83+
nonNullElements.forEach(contentElement -> {
84+
try (InputStream is = new ByteArrayInputStream(contentElement.getBytes(StandardCharsets.UTF_8))) {
85+
properties.properties.load(is);
86+
} catch (IOException e) {
87+
throw new IllegalArgumentException("Unable to load properties: " + contentElement);
88+
}
89+
});
90+
return properties;
91+
}
92+
93+
public static FormatterProperties merge(Properties... properties) {
94+
FormatterProperties merged = new FormatterProperties();
95+
List.of(properties).stream().forEach((source) -> merged.properties.putAll(source));
96+
return merged;
97+
}
98+
7899
/**
79100
* Import settings from given file. New settings (with the same ID/key)
80101
* override existing once.

plugin-gradle/CHANGES.md

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
44

55
## [Unreleased]
66
### Changed
7+
* Allow setting Eclipse config from a string, not only from files ([#2337](https://github.com/diffplug/spotless/pull/2337))
78
* Bump default `ktlint` version to latest `1.3.0` -> `1.4.0`. ([#2314](https://github.com/diffplug/spotless/pull/2314))
89
* Bump default `jackson` version to latest `2.18.0` -> `2.18.1`. ([#2319](https://github.com/diffplug/spotless/pull/2319))
910
* Bump default `ktfmt` version to latest `0.52` -> `0.53`. ([#2320](https://github.com/diffplug/spotless/pull/2320))

plugin-gradle/README.md

+12
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,10 @@ spotless {
262262
eclipse()
263263
// optional: you can specify a specific version and/or config file
264264
eclipse('4.26').configFile('eclipse-prefs.xml')
265+
// Or supply the configuration as a string
266+
eclipse('4.26').configProperties("""
267+
...
268+
""")
265269
// if the access to the p2 repositories is restricted, mirrors can be
266270
// specified using a URI prefix map as follows:
267271
eclipse().withP2Mirrors(['https://download.eclipse.org/eclipse/updates/4.29/':'https://some.internal.mirror/4-29-updates-p2/'])
@@ -418,6 +422,10 @@ spotless {
418422
greclipse()
419423
// optional: you can specify a specific version or config file(s), version matches the Eclipse Platform
420424
greclipse('4.26').configFile('spotless.eclipseformat.xml', 'org.codehaus.groovy.eclipse.ui.prefs')
425+
// Or supply the configuration as a string
426+
greclipse('4.26').configProperties("""
427+
...
428+
""")
421429
```
422430

423431
Groovy-Eclipse formatting errors/warnings lead per default to a build failure. This behavior can be changed by adding the property/key value `ignoreFormatterProblems=true` to a configuration file. In this scenario, files causing problems, will not be modified by this formatter step.
@@ -572,6 +580,10 @@ spotles {
572580
cpp {
573581
// version and configFile are both optional
574582
eclipseCdt('4.13.0').configFile('eclipse-cdt.xml')
583+
// Or supply the configuration as a string
584+
eclipseCdt('4.13.0').configProperties("""
585+
...
586+
""")
575587
}
576588
}
577589
```

plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BaseGroovyExtension.java

+8
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import static com.diffplug.gradle.spotless.PluginGradlePreconditions.requireElementsNonNull;
1919

20+
import java.util.List;
2021
import java.util.Map;
2122
import java.util.Objects;
2223

@@ -72,6 +73,13 @@ public GrEclipseConfig configFile(Object... configFiles) {
7273
return this;
7374
}
7475

76+
public GrEclipseConfig configProperties(String... configs) {
77+
requireElementsNonNull(configs);
78+
builder.setPropertyPreferences(List.of(configs));
79+
extension.replaceStep(builder.build());
80+
return this;
81+
}
82+
7583
public GrEclipseConfig withP2Mirrors(Map<String, String> mirrors) {
7684
builder.setP2Mirrors(mirrors);
7785
extension.replaceStep(builder.build());

plugin-gradle/src/main/java/com/diffplug/gradle/spotless/CppExtension.java

+9
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,14 @@
1717

1818
import static com.diffplug.gradle.spotless.PluginGradlePreconditions.requireElementsNonNull;
1919

20+
import java.util.List;
2021
import java.util.Map;
2122

2223
import javax.inject.Inject;
2324

2425
import org.gradle.api.Project;
2526

27+
import com.diffplug.gradle.spotless.JavaExtension.EclipseConfig;
2628
import com.diffplug.spotless.cpp.CppDefaults;
2729
import com.diffplug.spotless.extra.EquoBasedStepBuilder;
2830
import com.diffplug.spotless.extra.cpp.EclipseCdtFormatterStep;
@@ -60,6 +62,13 @@ public EclipseConfig configFile(Object... configFiles) {
6062
return this;
6163
}
6264

65+
public EclipseConfig configProperties(String... configs) {
66+
requireElementsNonNull(configs);
67+
builder.setPropertyPreferences(List.of(configs));
68+
replaceStep(builder.build());
69+
return this;
70+
}
71+
6372
public EclipseConfig withP2Mirrors(Map<String, String> mirrors) {
6473
builder.setP2Mirrors(mirrors);
6574
replaceStep(builder.build());

plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java

+7
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,13 @@ public EclipseConfig configFile(Object... configFiles) {
305305
return this;
306306
}
307307

308+
public EclipseConfig configProperties(String... configs) {
309+
requireElementsNonNull(configs);
310+
builder.setPropertyPreferences(List.of(configs));
311+
replaceStep(builder.build());
312+
return this;
313+
}
314+
308315
public EclipseConfig sortMembersDoNotSortFields(boolean doNotSortFields) {
309316
builder.sortMembersDoNotSortFields(doNotSortFields);
310317
replaceStep(builder.build());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright 2016-2024 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.gradle.spotless;
17+
18+
import java.io.IOException;
19+
20+
import org.junit.jupiter.api.Test;
21+
22+
class JavaEclipseTest extends GradleIntegrationHarness {
23+
@Test
24+
void settingsWithContentWithoutFile() throws IOException {
25+
setFile("build.gradle").toLines(
26+
"plugins {",
27+
" id 'com.diffplug.spotless'",
28+
" id 'java'",
29+
"}",
30+
"repositories { mavenCentral() }",
31+
"",
32+
"spotless {",
33+
" java { eclipse().configProperties(\"\"\"",
34+
"valid_line_oriented.prefs.string=string",
35+
"\"\"\") }",
36+
"}");
37+
38+
gradleRunner().withArguments("spotlessApply").build();
39+
}
40+
}

testlib/src/test/java/com/diffplug/spotless/FormatterPropertiesTest.java

+60-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2021 DiffPlug
2+
* Copyright 2016-2024 DiffPlug
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,9 +19,12 @@
1919

2020
import java.io.File;
2121
import java.io.IOException;
22+
import java.nio.file.Files;
2223
import java.util.Collection;
2324
import java.util.LinkedList;
25+
import java.util.List;
2426
import java.util.Properties;
27+
import java.util.stream.Collectors;
2528

2629
import org.assertj.core.api.AbstractAssert;
2730
import org.assertj.core.api.Assertions;
@@ -45,6 +48,14 @@ class FormatterPropertiesTest extends ResourceHarness {
4548
RESOURCES_ROOT_DIR + "invalid_xml_properties.xml"
4649
};
4750

51+
private List<String> validPropertiesResources() {
52+
return List.of(VALID_SETTINGS_RESOURCES).stream().filter(it -> !it.endsWith(".xml")).collect(Collectors.toList());
53+
}
54+
55+
private List<String> invalidPropertiesResources() {
56+
return List.of(INVALID_SETTINGS_RESOURCES).stream().filter(it -> !it.endsWith(".xml")).collect(Collectors.toList());
57+
}
58+
4859
private static final String[] VALID_VALUES = {
4960
"string",
5061
"true",
@@ -63,6 +74,18 @@ void differentPropertyFileTypes() throws IOException {
6374
}
6475
}
6576

77+
@Test
78+
void differentPropertyFileTypes_content_properties() throws IOException {
79+
for (String settingsResource : validPropertiesResources()) {
80+
File settingsFile = createTestFile(settingsResource);
81+
String content = Files.readString(settingsFile.toPath());
82+
FormatterProperties preferences = FormatterProperties.fromPropertiesContent(List.of(content));
83+
assertFor(preferences)
84+
.containsSpecificValuesOf(settingsFile)
85+
.containsCommonValueOf(settingsFile);
86+
}
87+
}
88+
6689
@Test
6790
void multiplePropertyFiles() throws IOException {
6891
LinkedList<File> settingsFiles = new LinkedList<>();
@@ -77,6 +100,22 @@ void multiplePropertyFiles() throws IOException {
77100
.containsCommonValueOf(settingsFiles.getLast());
78101
}
79102

103+
@Test
104+
void multiplePropertyFiles_content_properties() throws IOException {
105+
LinkedList<File> settingsFiles = new LinkedList<>();
106+
LinkedList<String> content = new LinkedList<>();
107+
for (String settingsResource : validPropertiesResources()) {
108+
File settingsFile = createTestFile(settingsResource);
109+
content.add(Files.readString(settingsFile.toPath()));
110+
settingsFiles.add(settingsFile);
111+
}
112+
FormatterProperties preferences = FormatterProperties.fromPropertiesContent(content);
113+
/* Settings are loaded / overridden in the sequence they are configured. */
114+
assertFor(preferences)
115+
.containsSpecificValuesOf(settingsFiles)
116+
.containsCommonValueOf(settingsFiles.getLast());
117+
}
118+
80119
@Test
81120
void invalidPropertyFiles() throws IOException {
82121
for (String settingsResource : INVALID_SETTINGS_RESOURCES) {
@@ -96,6 +135,26 @@ void invalidPropertyFiles() throws IOException {
96135
}
97136
}
98137

138+
@Test
139+
void invalidPropertyFiles_content_properties() throws IOException {
140+
for (String settingsResource : invalidPropertiesResources()) {
141+
File settingsFile = createTestFile(settingsResource);
142+
String content = Files.readString(settingsFile.toPath());
143+
boolean exceptionCaught = false;
144+
try {
145+
FormatterProperties.fromPropertiesContent(List.of(content));
146+
} catch (IllegalArgumentException ex) {
147+
exceptionCaught = true;
148+
assertThat(ex.getMessage())
149+
.as("IllegalArgumentException does not contain absolute path of file '%s'", settingsFile.getName())
150+
.contains(settingsFile.getAbsolutePath());
151+
}
152+
assertThat(exceptionCaught)
153+
.as("No IllegalArgumentException thrown when parsing '%s'", settingsFile.getName())
154+
.isTrue();
155+
}
156+
}
157+
99158
@Test
100159
void nonExistingFile() throws IOException {
101160
String filePath = FileSignature.pathUnixToNative("does/not/exist.properties");

0 commit comments

Comments
 (0)