Skip to content

Commit 90ca5bf

Browse files
committed
Cleanup.
1 parent 716722a commit 90ca5bf

File tree

4 files changed

+119
-113
lines changed

4 files changed

+119
-113
lines changed

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

Lines changed: 0 additions & 103 deletions
This file was deleted.
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Copyright 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.spotless;
17+
18+
import java.util.ArrayList;
19+
import java.util.Collection;
20+
import java.util.List;
21+
import java.util.Objects;
22+
23+
/**
24+
* Gradle requires three things:
25+
* - Gradle defines cache equality based on your serialized representation
26+
* - Combined with remote build cache, you cannot have any absolute paths in
27+
* your serialized representation
28+
* - Combined with configuration cache, you must be able to roundtrip yourself
29+
* through serialization
30+
*
31+
* These requirements are at odds with each other, as described in these issues
32+
* - Gradle issue to define custom equality
33+
* https://github.com/gradle/gradle/issues/29816
34+
* - Spotless plea for developer cache instead of configuration cache
35+
* https://github.com/diffplug/spotless/issues/987
36+
* - Spotless cache miss bug fixed by this class
37+
* https://github.com/diffplug/spotless/issues/2168
38+
*
39+
* This class is a `List<FormatterStep>` which can optimize the
40+
* serialized representation for either
41+
* - roundtrip integrity
42+
* - OR
43+
* - equality
44+
*
45+
* Because it is not possible to provide both at the same time.
46+
* It is a horrific hack, but it works, and it's the only way I can figure
47+
* to make Spotless work with all of Gradle's cache systems at once.
48+
*/
49+
public class ConfigurationCacheHackList implements java.io.Serializable {
50+
private final boolean optimizeForEquality;
51+
private final ArrayList<Object> backingList = new ArrayList<>();
52+
53+
public static ConfigurationCacheHackList forEquality() {
54+
return new ConfigurationCacheHackList(true);
55+
}
56+
57+
public static ConfigurationCacheHackList forRoundtrip() {
58+
return new ConfigurationCacheHackList(false);
59+
}
60+
61+
private ConfigurationCacheHackList(boolean optimizeForEquality) {
62+
this.optimizeForEquality = optimizeForEquality;
63+
}
64+
65+
public void clear() {
66+
backingList.clear();
67+
}
68+
69+
public void addAll(Collection<? extends FormatterStep> c) {
70+
for (FormatterStep step : c) {
71+
if (step instanceof FormatterStepSerializationRoundtrip) {
72+
var clone = ((FormatterStepSerializationRoundtrip) step).hackClone(optimizeForEquality);
73+
backingList.add(clone);
74+
} else {
75+
backingList.add(step);
76+
}
77+
}
78+
}
79+
80+
public List<FormatterStep> getSteps() {
81+
var result = new ArrayList<FormatterStep>(backingList.size());
82+
for (Object obj : backingList) {
83+
if (obj instanceof FormatterStepSerializationRoundtrip.HackClone) {
84+
result.add(((FormatterStepSerializationRoundtrip.HackClone) obj).rehydrate());
85+
} else {
86+
result.add((FormatterStep) obj);
87+
}
88+
}
89+
return result;
90+
}
91+
92+
@Override
93+
public boolean equals(Object o) {
94+
if (this == o)
95+
return true;
96+
if (o == null || getClass() != o.getClass())
97+
return false;
98+
ConfigurationCacheHackList stepList = (ConfigurationCacheHackList) o;
99+
return optimizeForEquality == stepList.optimizeForEquality &&
100+
backingList.equals(stepList.backingList);
101+
}
102+
103+
@Override
104+
public int hashCode() {
105+
return Objects.hash(optimizeForEquality, backingList);
106+
}
107+
}

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

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,13 @@ protected FormatterFunc stateToFormatter(EqualityState equalityState) throws Exc
6666
return new HackClone<>(this, optimizeForEquality);
6767
}
6868

69+
/**
70+
* This class has one setting (optimizeForEquality) and two pieces of data
71+
* - the original step, which is marked transient so it gets discarded during serialization
72+
* - the cleaned step, which is lazily created during serialization, and the serialized form is optimized for either equality or roundtrip integrity
73+
*
74+
* It works in conjunction with ConfigurationCacheHackList to allow Spotless to work with all of Gradle's cache systems.
75+
*/
6976
static class HackClone<RoundtripState extends Serializable, EqualityState extends Serializable> implements Serializable {
7077
transient FormatterStepSerializationRoundtrip<?, ?> original;
7178
boolean optimizeForEquality;
@@ -90,11 +97,6 @@ private void writeObject(java.io.ObjectOutputStream out) throws IOException {
9097
}
9198

9299
public FormatterStep rehydrate() {
93-
try {
94-
throw new Exception("rehydrate optimizeForEquality=" + optimizeForEquality + " orig=" + original + " cleaned=" + cleaned);
95-
} catch (Exception e) {
96-
e.printStackTrace();
97-
}
98100
return original != null ? original : Objects.requireNonNull(cleaned, "how is clean null if this has been serialized?");
99101
}
100102

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
import org.gradle.api.tasks.PathSensitivity;
3636
import org.gradle.work.Incremental;
3737

38-
import com.diffplug.spotless.ConfigurationCacheHack;
38+
import com.diffplug.spotless.ConfigurationCacheHackList;
3939
import com.diffplug.spotless.FormatExceptionPolicy;
4040
import com.diffplug.spotless.FormatExceptionPolicyStrict;
4141
import com.diffplug.spotless.Formatter;
@@ -149,16 +149,16 @@ public File getOutputDirectory() {
149149
return outputDirectory;
150150
}
151151

152-
private final ConfigurationCacheHack.StepList stepsInternalRoundtrip = new ConfigurationCacheHack.StepList(ConfigurationCacheHack.OptimizeFor.ROUNDTRIP);
153-
private final ConfigurationCacheHack.StepList stepsInternalEquality = new ConfigurationCacheHack.StepList(ConfigurationCacheHack.OptimizeFor.EQUALITY);
152+
private final ConfigurationCacheHackList stepsInternalRoundtrip = ConfigurationCacheHackList.forRoundtrip();
153+
private final ConfigurationCacheHackList stepsInternalEquality = ConfigurationCacheHackList.forEquality();
154154

155155
@Internal
156-
public ConfigurationCacheHack.StepList getStepsInternalRoundtrip() {
156+
public ConfigurationCacheHackList getStepsInternalRoundtrip() {
157157
return stepsInternalRoundtrip;
158158
}
159159

160160
@Input
161-
public ConfigurationCacheHack.StepList getStepsInternalEquality() {
161+
public ConfigurationCacheHackList getStepsInternalEquality() {
162162
return stepsInternalEquality;
163163
}
164164

0 commit comments

Comments
 (0)