Skip to content

Commit 9652e05

Browse files
authored
Speedup GIT_ATTRIBUTES (#1838)
2 parents 5d9f3b4 + 1a1fbfe commit 9652e05

File tree

9 files changed

+72
-26
lines changed

9 files changed

+72
-26
lines changed

CHANGES.md

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
1616
the version accordingly. ([#1804](https://github.com/diffplug/spotless/issues/1804)).
1717
* Support for `google-java-format`'s `skip-javadoc-formatting` option. ([#1793](https://github.com/diffplug/spotless/pull/1793))
1818
* Support configuration of mirrors for P2 repositories in maven DSL ([#1697](https://github.com/diffplug/spotless/issues/1697)).
19+
* New line endings mode `GIT_ATTRIBUTES_FAST_ALLSAME`. ([#1838](https://github.com/diffplug/spotless/pull/1838))
1920
### Fixed
2021
* Fix support for plugins when using Prettier version `3.0.0` and newer. ([#1802](https://github.com/diffplug/spotless/pull/1802))
2122
* Fix configuration cache issue around `external process started '/usr/bin/git --version'`. ([#1806](https://github.com/diffplug/spotless/issues/1806))

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

+36
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,42 @@ public final class GitAttributesLineEndings {
6868
// prevent direct instantiation
6969
private GitAttributesLineEndings() {}
7070

71+
/**
72+
* Creates a line-endings policy which matches {@link #create(File, Supplier)},
73+
* which is much faster at the cost that every file under the policy
74+
* is assumed to have the same line endings as the first file.
75+
*/
76+
public static LineEnding.Policy createFastAllSame(File projectDir, Supplier<Iterable<File>> toFormat) {
77+
return new LazyAllTheSame(projectDir, toFormat);
78+
}
79+
80+
static class LazyAllTheSame extends LazyForwardingEquality<String> implements LineEnding.Policy {
81+
private static final long serialVersionUID = 727912266173243664L;
82+
transient File projectDir;
83+
transient Supplier<Iterable<File>> toFormat;
84+
85+
public LazyAllTheSame(File projectDir, Supplier<Iterable<File>> toFormat) {
86+
this.projectDir = projectDir;
87+
this.toFormat = toFormat;
88+
}
89+
90+
@Override
91+
protected String calculateState() throws Exception {
92+
var files = toFormat.get().iterator();
93+
if (files.hasNext()) {
94+
Runtime runtime = new RuntimeInit(projectDir).atRuntime();
95+
return runtime.getEndingFor(files.next());
96+
} else {
97+
return LineEnding.UNIX.str();
98+
}
99+
}
100+
101+
@Override
102+
public String getEndingFor(File file) {
103+
return state();
104+
}
105+
}
106+
71107
/**
72108
* Creates a line-endings policy whose serialized state is relativized against projectDir,
73109
* at the cost of eagerly evaluating the line-ending state of every target file when the

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

+24-21
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2022 DiffPlug
2+
* Copyright 2016-2023 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,11 +19,8 @@
1919
import java.io.Serializable;
2020
import java.lang.reflect.Method;
2121
import java.util.Objects;
22-
import java.util.function.BiFunction;
2322
import java.util.function.Supplier;
2423

25-
import javax.annotation.Nullable;
26-
2724
/**
2825
* Represents the line endings which should be written by the tool.
2926
*/
@@ -37,6 +34,14 @@ public Policy createPolicy() {
3734
return super.createPolicy();
3835
}
3936
},
37+
/** Uses the same line endings as Git, and assumes that every single file being formatted will have the same line ending. */
38+
GIT_ATTRIBUTES_FAST_ALLSAME {
39+
/** .gitattributes is path-specific, so you must use {@link LineEnding#createPolicy(File, Supplier)}. */
40+
@Override @Deprecated
41+
public Policy createPolicy() {
42+
return super.createPolicy();
43+
}
44+
},
4045
/** {@code \n} on unix systems, {@code \r\n} on windows systems. */
4146
PLATFORM_NATIVE,
4247
/** {@code \r\n} */
@@ -51,33 +56,31 @@ public Policy createPolicy() {
5156
public Policy createPolicy(File projectDir, Supplier<Iterable<File>> toFormat) {
5257
Objects.requireNonNull(projectDir, "projectDir");
5358
Objects.requireNonNull(toFormat, "toFormat");
54-
if (this != GIT_ATTRIBUTES) {
55-
return createPolicy();
59+
String gitAttributesMethod;
60+
if (this == GIT_ATTRIBUTES) {
61+
gitAttributesMethod = "create";
62+
} else if (this == GIT_ATTRIBUTES_FAST_ALLSAME) {
63+
gitAttributesMethod = "createFastAllSame";
5664
} else {
57-
if (gitAttributesPolicyCreator == null) {
58-
try {
59-
Class<?> clazz = Class.forName("com.diffplug.spotless.extra.GitAttributesLineEndings");
60-
Method method = clazz.getMethod("create", File.class, Supplier.class);
61-
gitAttributesPolicyCreator = (proj, target) -> ThrowingEx.get(() -> (Policy) method.invoke(null, proj, target));
62-
} catch (ClassNotFoundException | NoSuchMethodException | SecurityException e) {
63-
throw new IllegalStateException("LineEnding.GIT_ATTRIBUTES requires the spotless-lib-extra library, but it is not on the classpath", e);
64-
}
65-
}
66-
// gitAttributesPolicyCreator will always be nonnull at this point
67-
return gitAttributesPolicyCreator.apply(projectDir, toFormat);
65+
return createPolicy();
66+
}
67+
try {
68+
Class<?> clazz = Class.forName("com.diffplug.spotless.extra.GitAttributesLineEndings");
69+
Method method = clazz.getMethod(gitAttributesMethod, File.class, Supplier.class);
70+
return ThrowingEx.get(() -> (Policy) method.invoke(null, projectDir, toFormat));
71+
} catch (ClassNotFoundException | NoSuchMethodException | SecurityException e) {
72+
throw new IllegalStateException("LineEnding.GIT_ATTRIBUTES requires the spotless-lib-extra library, but it is not on the classpath", e);
6873
}
6974
}
7075

71-
private static volatile @Nullable BiFunction<File, Supplier<Iterable<File>>, Policy> gitAttributesPolicyCreator;
72-
7376
// @formatter:off
7477
/** Should use {@link #createPolicy(File, Supplier)} instead, but this will work iff its a path-independent LineEnding policy. */
7578
public Policy createPolicy() {
7679
switch (this) {
7780
case PLATFORM_NATIVE: return _platformNativePolicy;
7881
case WINDOWS: return WINDOWS_POLICY;
7982
case UNIX: return UNIX_POLICY;
80-
case MAC_CLASSIC: return MAC_CLASSIC_POLICY;
83+
case MAC_CLASSIC: return MAC_CLASSIC_POLICY;
8184
default: throw new UnsupportedOperationException(this + " is a path-specific line ending.");
8285
}
8386
}
@@ -121,7 +124,7 @@ public String str() {
121124
case PLATFORM_NATIVE: return _platformNative;
122125
case WINDOWS: return "\r\n";
123126
case UNIX: return "\n";
124-
case MAC_CLASSIC: return "\r";
127+
case MAC_CLASSIC: return "\r";
125128
default: throw new UnsupportedOperationException(this + " is a path-specific line ending.");
126129
}
127130
}

plugin-gradle/CHANGES.md

+3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
1313
* Fixed support for plugins when using Prettier version `3.0.0` and newer. ([#1802](https://github.com/diffplug/spotless/pull/1802))
1414
### Changes
1515
* Bump default `ktlint` version to latest `0.50.0` -> `1.0.0`. ([#1808](https://github.com/diffplug/spotless/pull/1808))
16+
* **POSSIBLY BREAKING** the default line endings are now `GIT_ATTRIBUTES_FAST_ALLSAME` instead of `GIT_ATTRIBUTES`. ([#1838](https://github.com/diffplug/spotless/pull/1838))
17+
* If all the files within a format have the same line endings, then there is no change in behavior.
18+
* Fixes large performance regression. ([#1527](https://github.com/diffplug/spotless/issues/1527))
1619

1720
## [6.21.0] - 2023-08-29
1821
### Added

plugin-gradle/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -1425,12 +1425,12 @@ spotless {
14251425
encoding 'Cp1252' // except java, which will be Cp1252
14261426
```
14271427

1428-
Line endings can also be set globally or per-format using the `lineEndings` property. Spotless supports four line ending modes: `UNIX`, `WINDOWS`, `MAC_CLASSIC`, `PLATFORM_NATIVE`, and `GIT_ATTRIBUTES`. The default value is `GIT_ATTRIBUTES`, and *we highly recommend that you* ***do not change*** *this value*. Git has opinions about line endings, and if Spotless and git disagree, then you're going to have a bad time.
1428+
Line endings can also be set globally or per-format using the `lineEndings` property. Spotless supports four line ending modes: `UNIX`, `WINDOWS`, `MAC_CLASSIC`, `PLATFORM_NATIVE`, `GIT_ATTRIBUTES`, and `GIT_ATTRIBUTES_FAST_ALLSAME`. The default value is `GIT_ATTRIBUTES_FAST_ALLSAME`, and *we highly recommend that you* ***do not change*** *this value*. Git has opinions about line endings, and if Spotless and git disagree, then you're going to have a bad time. `FAST_ALLSAME` just means that Spotless can assume that every file being formatted has the same line endings ([more info](https://github.com/diffplug/spotless/pull/1838)).
14291429
14301430
You can easily set the line endings of different files using [a `.gitattributes` file](https://help.github.com/articles/dealing-with-line-endings/). Here's an example `.gitattributes` which sets all files to unix newlines: `* text eol=lf`.
14311431

14321432
<a name="custom"></a>
1433-
<a name="custom-rulwa"></a>
1433+
<a name="custom-steps"></a>
14341434

14351435
## Custom steps
14361436

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ RegisterDependenciesTask getRegisterDependenciesTask() {
5757
}
5858

5959
/** Line endings (if any). */
60-
LineEnding lineEndings = LineEnding.GIT_ATTRIBUTES;
60+
LineEnding lineEndings = LineEnding.GIT_ATTRIBUTES_FAST_ALLSAME;
6161

6262
public LineEnding getLineEndings() {
6363
return lineEndings;

plugin-maven/CHANGES.md

+3
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
2828
### Changes
2929
* Bump default `flexmark` version to latest `0.64.0` -> `0.64.8`. ([#1801](https://github.com/diffplug/spotless/pull/1801))
3030
* Bump default `ktlint` version to latest `0.50.0` -> `1.0.0`. ([#1808](https://github.com/diffplug/spotless/pull/1808))
31+
* **POSSIBLY BREAKING** the default line endings are now `GIT_ATTRIBUTES_FAST_ALLSAME` instead of `GIT_ATTRIBUTES`. ([#1838](https://github.com/diffplug/spotless/pull/1838))
32+
* If all the files within a format have the same line endings, then there is no change in behavior.
33+
* Fixes large performance regression. ([#1527](https://github.com/diffplug/spotless/issues/1527))
3134

3235
## [2.39.0] - 2023-08-29
3336
### Added

plugin-maven/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1586,7 +1586,7 @@ Spotless uses UTF-8 by default, but you can use [any encoding which Java support
15861586
</configuration>
15871587
```
15881588

1589-
Line endings can also be set globally or per-format using the `lineEndings` property. Spotless supports four line ending modes: `UNIX`, `WINDOWS`, `MAC_CLASSIC`, `PLATFORM_NATIVE`, and `GIT_ATTRIBUTES`. The default value is `GIT_ATTRIBUTES`, and *we highly recommend that you* ***do not change*** *this value*. Git has opinions about line endings, and if Spotless and git disagree, then you're going to have a bad time.
1589+
Line endings can also be set globally or per-format using the `lineEndings` property. Spotless supports four line ending modes: `UNIX`, `WINDOWS`, `MAC_CLASSIC`, `PLATFORM_NATIVE`, `GIT_ATTRIBUTES`, and `GIT_ATTRIBUTES_FAST_ALLSAME`. The default value is `GIT_ATTRIBUTES_FAST_ALLSAME`, and *we highly recommend that you* ***do not change*** *this value*. Git has opinions about line endings, and if Spotless and git disagree, then you're going to have a bad time. `FAST_ALLSAME` just means that Spotless can assume that every file being formatted has the same line endings ([more info](https://github.com/diffplug/spotless/pull/1838)).
15901590

15911591
You can easily set the line endings of different files using [a `.gitattributes` file](https://help.github.com/articles/dealing-with-line-endings/). Here's an example `.gitattributes` which sets all files to unix newlines: `* text eol=lf`.
15921592

plugin-maven/src/main/java/com/diffplug/spotless/maven/AbstractSpotlessMojo.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@
8080
public abstract class AbstractSpotlessMojo extends AbstractMojo {
8181
private static final String DEFAULT_INDEX_FILE_NAME = "spotless-index";
8282
private static final String DEFAULT_ENCODING = "UTF-8";
83-
private static final String DEFAULT_LINE_ENDINGS = "GIT_ATTRIBUTES";
83+
private static final String DEFAULT_LINE_ENDINGS = "GIT_ATTRIBUTES_FAST_ALLSAME";
8484

8585
/** Value to allow unsetting the ratchet inherited from parent pom configuration. */
8686
static final String RATCHETFROM_NONE = "NONE";

0 commit comments

Comments
 (0)