-
Notifications
You must be signed in to change notification settings - Fork 459
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Up-to-date index for Maven plugin #935
Conversation
Hi @nedtwigg, this PR demonstrates an approach that could make the Maven plugin faster. It makes the Maven plugin maintain an index |
I think that the
You could do just a |
I really want this. 😆 But I think the index also needs to be invalidated, if the configuration of the spotless plugin (or the plugin version) changes. So the index would need a hash or something of the current configuration settings. I don't know if they can be read out as a whole. |
@tisoft good point, I agree! I will investigate how to include configuration settings into the index. |
For this, you can copy the properties marked |
ff06fe8
to
792a9ef
Compare
Force-pushed a few refinements to this PR. The code structure has improved, but tests are still largely missing. Introduced a PluginFingerprint to handle plugin version/configuration changes. It uses a serialized This PR is still a draft. I'll keep working on unit and integration tests. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great progress!
plugin-maven/src/main/java/com/diffplug/spotless/maven/AbstractSpotlessMojo.java
Outdated
Show resolved
Hide resolved
plugin-maven/src/main/java/com/diffplug/spotless/maven/incremental/IndexBasedChecker.java
Outdated
Show resolved
Hide resolved
plugin-maven/src/main/java/com/diffplug/spotless/maven/incremental/IndexBasedChecker.java
Outdated
Show resolved
Hide resolved
plugin-maven/src/main/java/com/diffplug/spotless/maven/incremental/PluginFingerprint.java
Show resolved
Hide resolved
plugin-maven/src/main/java/com/diffplug/spotless/maven/incremental/PluginFingerprint.java
Outdated
Show resolved
Hide resolved
plugin-maven/src/main/java/com/diffplug/spotless/maven/AbstractSpotlessMojo.java
Outdated
Show resolved
Hide resolved
And another feature request from me: Can you make the index file location/name configurable? I would like to have it outside of the target directory, so a |
@tisoft sounds reasonable. The first version will probably not support this but I will adjust the configuration to be more extensible, something like: <configuration>
<upToDateCheck>
<enabled>true</enabled>
<indexLocation>/tmp</indexLocation> <!-- easier to add this when config is an object -->
</upToDateCheck>
</configuration> |
plugin-maven/src/main/java/com/diffplug/spotless/maven/AbstractSpotlessMojo.java
Outdated
Show resolved
Hide resolved
This looks mergeable to me. I resolved the convos that have been solved. The remaining open convos are:
Anything else you think needs to happen before we merge and release this? |
Hi @nedtwigg, I would like to address the following few items before merging:
This PR is already pretty big, sorry about this. I couldn't think of a good way to split it into meaningful parts. I will address the remaining items in separate commits to simplify the review. |
Sounds great! PR size not a problem :) |
Hi @nedtwigg, I refactored the code to avoid I think this PR is now ready for review. I can squash all commits and rebase before merging. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great! I'd prefer no squash, the history is helpful. I think changelog, docs, and we can merge and release!
e5efef3
to
590553d
Compare
POC of a component that allows the Maven plugin to skip already formatted and unchanged files. The code is not production-ready and probably does not work. It is only to illustrate the approach and gather feedback. A new `UpToDateChecker` maintains an index file in the build directory (`<project>/target`). The index file has the following structure: ``` <source file 1> <last modified time 1> <source file 2> <last modified time 2> ... <source file n> <last modified time n> ``` `UpToDateChecker` loads or creates an index file at creation time into an in-memory map. Method `#isUpToDate(File)` checks the file's current last modified time against the last modified time from the in-memory map. Method `#setUpToDate(File)` updates or adds the file and its last modified time to the in-memory map. Method `#close()` writes the complete in-memory map into the index file. Spotless apply goal uses `UpToDateChecker` to determine if a file needs to be formatted. It also notifies the checker if the file has was formatted.
Instead of creating/opening an index for every source file.
Include the list of serialized formatters in PluginFingerprint. It makes the file index sensitive to changes in configuration files referenced by the POM (e.g. `eclipseformat.xml` and `.gitattributes`). To achieve this, Maven plugin has to instantiate all formatters upfront. It builds a map of formatters and files that need formatting. The formatters are then used to calculate a PluginFingerprint.
It is useful for local development only.
Add a dedicated POM XML element for up-to-date checking: ``` <plugin> <groupId>com.diffplug.spotless</groupId> <artifactId>spotless-maven-plugin</artifactId> <version>${spotless.version}</version> <configuration> <upToDateChecking> <enabled>true</enabled> </upToDateChecking> <java> <googleJavaFormat/> </java> </configuration> <plugin> ``` It makes the configuration more flexible and allows adding more options related to up-to-date checking in the future.
Introduce `FileIndexConfig` that abstracts away some directory manipulations and file naming. Fix two issues: * ensure the parent dir for the index file exists before writing the file itself * relativize files against the project dir, not against the target dir
Instead, use `@Nullable` to simplify the API. This requires adding a new dependency to the POM when building the Maven plugin.
Instead of using a mix of File and Path. Path has more suitable API for: * Relativizing file paths * Getting last modified time. `File#lastModified()` may return zero. It is also not very clear about overflows
This conversion is needed because FileIndex stores human-readable timestamps in the index file. There's a way to convert FileTime to String but no way to convert String to FileTime when reading an index from a file. Thus, we convert to Instant that has well-defined `#toString()` and `#parse()` methods. Conversion from FileTime to Instant can be lossy because FileTime can represent timestamps further in the past/future than Instant. Such timestamps are saturated to Instant.MIN and Instant.MAX. It is not safe to record such timestamps in the index file because they are lossy. IndexBasedChecker will not record overflown Instants in the index. It will also log a warning for every file with a small/large last modified time that overflows an Instant.
The added tests assert on debug logging output of the apply and check goals.
Path#getParent() can return null. This should not happen for the maven plugin up-to-date index. Thus, the fix is to check for null and throw an IllegalStateException.
590553d
to
25f70e0
Compare
Added documentation and a changelog entry. Hope both make sense :) |
25f70e0
to
fc1f9cc
Compare
fc1f9cc
to
a50a58f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great, huzzah!
Published in |
Thanks for releasing this change! <plugin>
<groupId>com.diffplug.spotless</groupId>
<artifactId>spotless-maven-plugin</artifactId>
<version>2.18.0</version>
<configuration>
<upToDateChecking>
<enabled>true</enabled>
</upToDateChecking>
<java>
<googleJavaFormat/>
</java>
</configuration>
</plugin> On my machine with 8 cores:
|
POC of a component that allows the Maven plugin to skip already formatted and unchanged files. The code is not production-ready and probably does not work. It is only to illustrate the approach and gather feedback.
A new
UpToDateChecker
maintains an index file in the build directory (<project>/target
). The index file has the following structure:UpToDateChecker
loads or creates an index file at creation time into an in-memory map.Method
#isUpToDate(File)
checks the file's current last modified time against the last modified time from the in-memory map.Method
#setUpToDate(File)
updates or adds the file and its last modified time to the in-memory map.Method
#close()
writes the complete in-memory map into the index file.Spotless apply goal uses
UpToDateChecker
to determine if a file needs to be formatted. It also notifies the checker if the file has was formatted.