Skip to content

Commit

Permalink
Speedup GIT_ATTRIBUTES (#1838)
Browse files Browse the repository at this point in the history
  • Loading branch information
nedtwigg authored Sep 28, 2023
2 parents 5d9f3b4 + 1a1fbfe commit 9652e05
Show file tree
Hide file tree
Showing 9 changed files with 72 additions and 26 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
the version accordingly. ([#1804](https://github.com/diffplug/spotless/issues/1804)).
* Support for `google-java-format`'s `skip-javadoc-formatting` option. ([#1793](https://github.com/diffplug/spotless/pull/1793))
* Support configuration of mirrors for P2 repositories in maven DSL ([#1697](https://github.com/diffplug/spotless/issues/1697)).
* New line endings mode `GIT_ATTRIBUTES_FAST_ALLSAME`. ([#1838](https://github.com/diffplug/spotless/pull/1838))
### Fixed
* Fix support for plugins when using Prettier version `3.0.0` and newer. ([#1802](https://github.com/diffplug/spotless/pull/1802))
* Fix configuration cache issue around `external process started '/usr/bin/git --version'`. ([#1806](https://github.com/diffplug/spotless/issues/1806))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,42 @@ public final class GitAttributesLineEndings {
// prevent direct instantiation
private GitAttributesLineEndings() {}

/**
* Creates a line-endings policy which matches {@link #create(File, Supplier)},
* which is much faster at the cost that every file under the policy
* is assumed to have the same line endings as the first file.
*/
public static LineEnding.Policy createFastAllSame(File projectDir, Supplier<Iterable<File>> toFormat) {
return new LazyAllTheSame(projectDir, toFormat);
}

static class LazyAllTheSame extends LazyForwardingEquality<String> implements LineEnding.Policy {
private static final long serialVersionUID = 727912266173243664L;
transient File projectDir;
transient Supplier<Iterable<File>> toFormat;

public LazyAllTheSame(File projectDir, Supplier<Iterable<File>> toFormat) {
this.projectDir = projectDir;
this.toFormat = toFormat;
}

@Override
protected String calculateState() throws Exception {
var files = toFormat.get().iterator();
if (files.hasNext()) {
Runtime runtime = new RuntimeInit(projectDir).atRuntime();
return runtime.getEndingFor(files.next());
} else {
return LineEnding.UNIX.str();
}
}

@Override
public String getEndingFor(File file) {
return state();
}
}

/**
* Creates a line-endings policy whose serialized state is relativized against projectDir,
* at the cost of eagerly evaluating the line-ending state of every target file when the
Expand Down
45 changes: 24 additions & 21 deletions lib/src/main/java/com/diffplug/spotless/LineEnding.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2022 DiffPlug
* Copyright 2016-2023 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -19,11 +19,8 @@
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Supplier;

import javax.annotation.Nullable;

/**
* Represents the line endings which should be written by the tool.
*/
Expand All @@ -37,6 +34,14 @@ public Policy createPolicy() {
return super.createPolicy();
}
},
/** Uses the same line endings as Git, and assumes that every single file being formatted will have the same line ending. */
GIT_ATTRIBUTES_FAST_ALLSAME {
/** .gitattributes is path-specific, so you must use {@link LineEnding#createPolicy(File, Supplier)}. */
@Override @Deprecated
public Policy createPolicy() {
return super.createPolicy();
}
},
/** {@code \n} on unix systems, {@code \r\n} on windows systems. */
PLATFORM_NATIVE,
/** {@code \r\n} */
Expand All @@ -51,33 +56,31 @@ public Policy createPolicy() {
public Policy createPolicy(File projectDir, Supplier<Iterable<File>> toFormat) {
Objects.requireNonNull(projectDir, "projectDir");
Objects.requireNonNull(toFormat, "toFormat");
if (this != GIT_ATTRIBUTES) {
return createPolicy();
String gitAttributesMethod;
if (this == GIT_ATTRIBUTES) {
gitAttributesMethod = "create";
} else if (this == GIT_ATTRIBUTES_FAST_ALLSAME) {
gitAttributesMethod = "createFastAllSame";
} else {
if (gitAttributesPolicyCreator == null) {
try {
Class<?> clazz = Class.forName("com.diffplug.spotless.extra.GitAttributesLineEndings");
Method method = clazz.getMethod("create", File.class, Supplier.class);
gitAttributesPolicyCreator = (proj, target) -> ThrowingEx.get(() -> (Policy) method.invoke(null, proj, target));
} catch (ClassNotFoundException | NoSuchMethodException | SecurityException e) {
throw new IllegalStateException("LineEnding.GIT_ATTRIBUTES requires the spotless-lib-extra library, but it is not on the classpath", e);
}
}
// gitAttributesPolicyCreator will always be nonnull at this point
return gitAttributesPolicyCreator.apply(projectDir, toFormat);
return createPolicy();
}
try {
Class<?> clazz = Class.forName("com.diffplug.spotless.extra.GitAttributesLineEndings");
Method method = clazz.getMethod(gitAttributesMethod, File.class, Supplier.class);
return ThrowingEx.get(() -> (Policy) method.invoke(null, projectDir, toFormat));
} catch (ClassNotFoundException | NoSuchMethodException | SecurityException e) {
throw new IllegalStateException("LineEnding.GIT_ATTRIBUTES requires the spotless-lib-extra library, but it is not on the classpath", e);
}
}

private static volatile @Nullable BiFunction<File, Supplier<Iterable<File>>, Policy> gitAttributesPolicyCreator;

// @formatter:off
/** Should use {@link #createPolicy(File, Supplier)} instead, but this will work iff its a path-independent LineEnding policy. */
public Policy createPolicy() {
switch (this) {
case PLATFORM_NATIVE: return _platformNativePolicy;
case WINDOWS: return WINDOWS_POLICY;
case UNIX: return UNIX_POLICY;
case MAC_CLASSIC: return MAC_CLASSIC_POLICY;
case MAC_CLASSIC: return MAC_CLASSIC_POLICY;
default: throw new UnsupportedOperationException(this + " is a path-specific line ending.");
}
}
Expand Down Expand Up @@ -121,7 +124,7 @@ public String str() {
case PLATFORM_NATIVE: return _platformNative;
case WINDOWS: return "\r\n";
case UNIX: return "\n";
case MAC_CLASSIC: return "\r";
case MAC_CLASSIC: return "\r";
default: throw new UnsupportedOperationException(this + " is a path-specific line ending.");
}
}
Expand Down
3 changes: 3 additions & 0 deletions plugin-gradle/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
* Fixed support for plugins when using Prettier version `3.0.0` and newer. ([#1802](https://github.com/diffplug/spotless/pull/1802))
### Changes
* Bump default `ktlint` version to latest `0.50.0` -> `1.0.0`. ([#1808](https://github.com/diffplug/spotless/pull/1808))
* **POSSIBLY BREAKING** the default line endings are now `GIT_ATTRIBUTES_FAST_ALLSAME` instead of `GIT_ATTRIBUTES`. ([#1838](https://github.com/diffplug/spotless/pull/1838))
* If all the files within a format have the same line endings, then there is no change in behavior.
* Fixes large performance regression. ([#1527](https://github.com/diffplug/spotless/issues/1527))

## [6.21.0] - 2023-08-29
### Added
Expand Down
4 changes: 2 additions & 2 deletions plugin-gradle/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1425,12 +1425,12 @@ spotless {
encoding 'Cp1252' // except java, which will be Cp1252
```

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.
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)).
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`.

<a name="custom"></a>
<a name="custom-rulwa"></a>
<a name="custom-steps"></a>

## Custom steps

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ RegisterDependenciesTask getRegisterDependenciesTask() {
}

/** Line endings (if any). */
LineEnding lineEndings = LineEnding.GIT_ATTRIBUTES;
LineEnding lineEndings = LineEnding.GIT_ATTRIBUTES_FAST_ALLSAME;

public LineEnding getLineEndings() {
return lineEndings;
Expand Down
3 changes: 3 additions & 0 deletions plugin-maven/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
### Changes
* Bump default `flexmark` version to latest `0.64.0` -> `0.64.8`. ([#1801](https://github.com/diffplug/spotless/pull/1801))
* Bump default `ktlint` version to latest `0.50.0` -> `1.0.0`. ([#1808](https://github.com/diffplug/spotless/pull/1808))
* **POSSIBLY BREAKING** the default line endings are now `GIT_ATTRIBUTES_FAST_ALLSAME` instead of `GIT_ATTRIBUTES`. ([#1838](https://github.com/diffplug/spotless/pull/1838))
* If all the files within a format have the same line endings, then there is no change in behavior.
* Fixes large performance regression. ([#1527](https://github.com/diffplug/spotless/issues/1527))

## [2.39.0] - 2023-08-29
### Added
Expand Down
2 changes: 1 addition & 1 deletion plugin-maven/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1586,7 +1586,7 @@ Spotless uses UTF-8 by default, but you can use [any encoding which Java support
</configuration>
```

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.
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)).

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`.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
public abstract class AbstractSpotlessMojo extends AbstractMojo {
private static final String DEFAULT_INDEX_FILE_NAME = "spotless-index";
private static final String DEFAULT_ENCODING = "UTF-8";
private static final String DEFAULT_LINE_ENDINGS = "GIT_ATTRIBUTES";
private static final String DEFAULT_LINE_ENDINGS = "GIT_ATTRIBUTES_FAST_ALLSAME";

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

0 comments on commit 9652e05

Please sign in to comment.