Skip to content
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

Fix issue #31 #45

Closed
wants to merge 16 commits into from
Closed

Fix issue #31 #45

wants to merge 16 commits into from

Conversation

jbduncan
Copy link
Member

No description provided.

Copy link

@oehme oehme left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a great first step! I added some tips on up-to-date checking inline.

public boolean paddedCell = false;
@InputFiles
@OutputFiles
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You will have to split the task into two classes:

  • a CheckFormat task
  • an ApplyFormat task

Only the CheckFormat task can be up-to-date checked. The ApplyFormat task changes its own inputs, so it can't be cached/up-to-date checked. Also, if the ApplyFormat task declared the inputs as an output, then cleanApplyFormat would delete your source code ;)

public Iterable<File> target;
@Input
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you have a List of complex objects as an input, these objects must:

  • implement Serializable so Gradle can write them to the cache
  • implement equals/hashcode, so Gradle can compare them to the previous value

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if FormatterStep can even be serialized, as all the impls contain a reference to a Throwing.Function and/or another functional interface...

@nedtwigg @oehme Do you have any thoughts on this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One idea (I think from @oehme in the issue discussion) is looking at the bytecode of the function, but I'm inclined to declare bankruptcy on input properties being clean w.r.t. incremental compilation. That leaves two options:

A) spotlessCheck will be wrong sometimes after you've changed your format
B) Have three tasks: spotlessCheck/spotlessApply and spotlessFastCheck. check/apply can use the same dumb logic from before, and fastCheck will be faster (using incremental stuff) but user beware that it might be wrong if you're using a custom function that you've changed.

I see Spotless' priorities as such:

  1. Be correct and repeatable.
  2. Make it easy to write a one-liner function to tweak a formatting issue.
  3. Be as fast as possible.

Based on these priorities, I'm inclined to go with option B. It lets us implement spotlessFastCheck without making a full correctness guarantee. We can add a section to the readme Speeding up Spotless which lists the spotlessCheckFast function and lists any provisos, e.g.

spotlessCheckFast will be incorrect if you just changed the format rules. But if the rules have not changed, then it will be much faster than plain-old spotlessCheck.

If we get it to the point that we don't need an asterisk around correctness, then we can dump the old spotlessCheck entirely and promote spotlessCheckFast to the sole check task.

Copy link

@oehme oehme Oct 31, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure nobody would use a spotlessFastCheck if you have to run spotlessCheck to be sure it's correct anyway.

The only real alternative I see is properly supporting up-to-date checks. Instead of referencing Throwing.Function directly, we should reference a serializable sub-interface of it. Maybe call it FormatterFunction. Then implement the default functions (like regex) in such a way that they properly support equals/hashcode too.

The worst thing that could happen after that is that the task is out-of-date unnecessarily when users use inline steps. The readme about "Making spotless faster" could then explain that users should write real classes with equals/hashcode instead to make the task fast.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree it's easy to implement all of Spotless' existing formatters in a serializable way. But I don't see an easy way to do this for custom user functions. #46 is a great example of why these custom functions are so useful, and why it's important for them to be easy.

We've got this custom function up-to-date wrinkle, and we can push it onto users in two ways:

A) We can make custom rule-writers deal with it

You can write a custom rule by implementing such-and-such class and then calling the constructor here, and if you change the rule be sure to change the serialVersionUID

B) We can make people who are optimizing their build deal with it

If you want to speed up spotlessCheck, you can fix it with spotlessFastCheck. Here are the provisos:

If somebody's code has formatting problems, it's probably not because running the formatter is too slow, but because it was hard to find or write a formatting rule that did what they want. So I don't think we should take a mild performance issue and turn it into a correctness/customizability issue.

I'm pretty sure nobody would use a spotlessFastCheck if you have to run spotlessCheck to be sure it's correct anyway.

It would still be very useful for --continuous. And imo, that's the only place this optimization makes sense anyway. spotlessCheck is much faster than even a very small unit test suite. And if we're able to remove this wrinkle later, then spotlessFastCheck is better than spotlessCheck in every way, and we can promote it to the job of sole-checker at that time.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can write a custom rule by implementing such-and-such class and then calling the constructor here, and if you change the rule be sure to change the serialVersionUID

I think you misunderstood my point above.

  • if the author implements an inline rule it will always be out-of-date and thus correct
  • if the author wants extra performance, they can write a class with equals/hashcode

This gives you the best of both worlds: Ease of use by default, performance on demand. No need for a 2-task solution.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And imo, that's the only place this optimization makes sense anyway.

This is only true in very small projects. In a large project, when you change a single module, you want the other modules to be up-to-date, not spend time re-executing the formatter.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahhh. Thanks for clarification, I misunderstood. In the approach you describe, a spotlessCheckFast would still be valuable for the --continuous case where you have custom rules which don't implement the full up-to-date contract.

But the simplicity of having only a single "check" class is very valuable, and it's a great feature for all tasks to always be correct. My gut is quite unhappy that Spotless' formatters are no longer just Function<String, String>, but I agree this would be a big speedup for large projects. You've convinced me :) I've got an idea for an easy and mostly-correct way to handle simple rules, which I've described in #47.

problemFiles.add(file);
}
}
Errors.rethrow()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you give a short explanation why this wrapping needed now?

Copy link
Member Author

@jbduncan jbduncan Oct 30, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's to do with how, in Java 8, lambdas cannot throw checked exceptions unless the interface they target declares that it throws Throwable. IncrementalTaskInputs.outOfDate(Action) accepts a Groovy Action, which doesn't throw Throwable, so all checked exceptions thrown within the Action have to be wrapped in unchecked exceptions. Therefore, since !formatter.isClean(file) throws IOException - a checked exception - it has to be wrapped in an unchecked exception of sorts, otherwise it won't compile.

In this case, I decided to use Durian's Errors.rethrow() mechanism to wrap all IOExceptions as Errors.WrappedAsRuntimeExceptions, although I could have just as easily wrapped them in UncheckedIOExceptions instead (but that would arguably be less readable, as it would have required try { ... } catch(IOException e) { throw new UncheckedIOException(e); }).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, that was a longer explanation than I expected to write. :)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, makes perfect sense. Didn't know that method threw a checked exception. It could possibly be changed to use an unchecked exception further down.

@@ -272,7 +272,7 @@ public void licenseHeaderFile(Object licenseHeaderFile, String delimiter) {
/** Sets up a FormatTask according to the values in this extension. */
protected void setupTask(FormatTask task) throws Exception {
task.paddedCell = paddedCell;
task.lineEndingsPolicy = getLineEndingPolicy();
task.lineEndingPolicy = getLineEndingPolicy();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't care which name we use, but this is a public member of a public class documented in the README, so changing it breaks API compat for everyday buildscripts. These changes are likely going to require a major version bump anyway, but I'd rather not churn the lineEndingsPolicy name.

aside: I've enjoyed learning about a lot of Stream methods I didn't know about before, lots of good cleanup in various parts 👍

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm glad you're enjoying learning more about Stream methods. :D

@nedtwigg
Copy link
Member

I checked out the code and ran the tests, and it seems the mocks are not working properly. Easiest example is FormatTaskTest.testLineEndingsCheckFail(). The test supplies a single file with "\r\n", and the only rule is to use unix line endings, so it should fail. If you put a breakpoint in CheckFormatTask.formatCheck(), you'll see that the incremental inputs contain no files, so there are no violations. I don't know if the broken mocks are the only problem or the root problem, but it was the first simple problem I saw so I stopped there - I don't know much about mockito or incremental tasks, so that's as far as I'm useful. Feel free to call my attention elsewhere if I'm looking at the wrong thing.

import java.util.ArrayList;
import java.util.List;

public class ApplyFormatTask extends DefaultTask {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This task and CheckFormat have quite some duplication, we should extract a base class. This base class can then also be used to get rid of the duplicated configuration logic in the plugin.

jbduncan and others added 13 commits October 31, 2016 21:38
Will squash all commits at the end!
…asses which captured their parameters in non-transient fields. Thanks to FindBugs for spotting the error! New implementation ensures that the *only state* is the serializable key.
Note that in the case where the license header and delimiter are supplied as strings, it makes sense to store the state eagerly, whereas when the license header is supplied in a file, we load that file lazily, only if we actually need to.
… utility NonUpToDateCheckingTasks because they're still useful there.
@jbduncan
Copy link
Member Author

jbduncan commented Nov 1, 2016

I've pushed commit 4262b2b in an attempt to exclude build and cache dirs from the input files passed to Spotless. However, the tests no longer pass, and I think it's because I'm using getProject().fileTree(Map) incorrectly, but I can't see where or how. The project docs don't seem to have any info that can help me in this case.

@oehme Do you have any thoughts on where I might be going wrong?

…e using the serialized form of the state. This means that formats which extend FormatExtension.Strict don't have to implement equals or hashCode.
@nedtwigg
Copy link
Member

nedtwigg commented Nov 1, 2016

These commits have all been merged into 3.x. I'm going to close this PR, and I've given you both write access to the repo. Feel free to push directly to 3.x if you'd like, but please leave master alone :) We can also continue to do the PR workflow, but it seems like there's gonna be a steady churn for a little while, so feel free to just push to 3.x if you prefer.

@nedtwigg nedtwigg closed this Nov 1, 2016
@nedtwigg
Copy link
Member

nedtwigg commented Nov 1, 2016

Also, re: the current error in the filetree, here's the error message:

> Cannot convert the provided notation to a File or URI: {dir=C:\Users\ntwigg\AppData\Local\Temp\junit6574720301344841445, excludes=[C:\Users\ntwigg\AppData\Local\Temp\junit6574720301344841445\build\**, C:\Users\ntwigg\AppData\Local\Temp\junit6574720301344841445\.gradle\**], include=**/*.md}.
  The following types/formats are supported:
    - A String or CharSequence path, for example 'src/main/java' or '/usr/include'.
    - A String or CharSequence URI, for example 'file:/usr/include'.
    - A File instance.
    - A URI or URL instance.

@jbduncan
Copy link
Member Author

jbduncan commented Nov 1, 2016

Sorry, it seems I wasn't clear earlier. I actually did see that error message you linked in my own logs, but it's not clear to me from the message why it cannot convert the "provided notation into a File or URI".

Is it because of the Ant-style paths e.g. C:\Users\ntwigg\AppData\Local\Temp\junit6574720301344841445\.gradle\**?

If so, is there a way I can tell a fileTree to include the Gradle project folder, but exclude the build/ and .gradle/ dirs within the project folder?

@jbduncan
Copy link
Member Author

jbduncan commented Nov 1, 2016

Oh, and thank you very much for giving me write access to the Spotless repository!

I'll do my best to maintain the trust you've put in me. 😄

@oehme
Copy link

oehme commented Nov 1, 2016

Can you please provide the full stacktrace?

@jbduncan
Copy link
Member Author

jbduncan commented Nov 1, 2016

Certainly! Here it is.

Testing started at 21:00 ...
21:00:51: Executing external task 'check'...
:compileJava UP-TO-DATE
:pluginDescriptors UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:findbugsMain UP-TO-DATE
:pluginUnderTestMetadata UP-TO-DATE
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:spotlessCheck
:spotlessFreshmarkCheck FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':spotlessFreshmarkCheck'.
> Cannot convert the provided notation to a File or URI: {dir=C:\Users\Jonathan\dev\Java\IntelliJ Projects\spotless, excludes=[C:\Users\Jonathan\dev\Java\IntelliJ Projects\spotless\build\**, C:\Users\Jonathan\dev\Java\IntelliJ Projects\spotless\.gradle\**], include=**/*.md}.
  The following types/formats are supported:
    - A String or CharSequence path, for example 'src/main/java' or '/usr/include'.
    - A String or CharSequence URI, for example 'file:/usr/include'.
    - A File instance.
    - A URI or URL instance.
* Try:
Run with --info or --debug option to get more log output.
* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':spotlessFreshmarkCheck'.
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:69)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:46)
    at org.gradle.api.internal.tasks.execution.PostExecutionAnalysisTaskExecuter.execute(PostExecutionAnalysisTaskExecuter.java:35)
    at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:66)
    at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
    at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:52)
    at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
    at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:53)
    at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:203)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:185)
    at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.processTask(AbstractTaskPlanExecutor.java:66)
    at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.run(AbstractTaskPlanExecutor.java:50)
    at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor.process(DefaultTaskPlanExecutor.java:25)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:110)
    at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:37)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
    at org.gradle.execution.DefaultBuildExecuter.access$000(DefaultBuildExecuter.java:23)
    at org.gradle.execution.DefaultBuildExecuter$1.proceed(DefaultBuildExecuter.java:43)
    at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:30)
    at org.gradle.initialization.DefaultGradleLauncher$4.run(DefaultGradleLauncher.java:153)
    at org.gradle.internal.Factories$1.create(Factories.java:22)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:91)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:53)
    at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:150)
    at org.gradle.initialization.DefaultGradleLauncher.access$200(DefaultGradleLauncher.java:32)
    at org.gradle.initialization.DefaultGradleLauncher$1.create(DefaultGradleLauncher.java:98)
    at org.gradle.initialization.DefaultGradleLauncher$1.create(DefaultGradleLauncher.java:92)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:91)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:63)
    at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:92)
    at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:83)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter$DefaultBuildController.run(InProcessBuildActionExecuter.java:99)
    at org.gradle.tooling.internal.provider.runner.BuildModelActionRunner.run(BuildModelActionRunner.java:46)
    at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
    at org.gradle.tooling.internal.provider.runner.SubscribableBuildActionRunner.run(SubscribableBuildActionRunner.java:58)
    at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:48)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:30)
    at org.gradle.launcher.exec.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:81)
    at org.gradle.launcher.exec.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:46)
    at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:52)
    at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:37)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:26)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:34)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:74)
    at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:72)
    at org.gradle.util.Swapper.swap(Swapper.java:38)
    at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:72)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.health.DaemonHealthTracker.execute(DaemonHealthTracker.java:47)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:60)
    at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:72)
    at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.health.HintGCAfterBuild.execute(HintGCAfterBuild.java:41)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:50)
    at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:237)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54)
    at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:40)
Caused by: org.gradle.internal.typeconversion.UnsupportedNotationException: Cannot convert the provided notation to a File or URI: {dir=C:\Users\Jonathan\dev\Java\IntelliJ Projects\spotless, excludes=[C:\Users\Jonathan\dev\Java\IntelliJ Projects\spotless\build\**, C:\Users\Jonathan\dev\Java\IntelliJ Projects\spotless\.gradle\**], include=**/*.md}.
The following types/formats are supported:
  - A String or CharSequence path, for example 'src/main/java' or '/usr/include'.
  - A String or CharSequence URI, for example 'file:/usr/include'.
  - A File instance.
  - A URI or URL instance.
    at org.gradle.internal.typeconversion.ErrorHandlingNotationParser.parseNotation(ErrorHandlingNotationParser.java:56)
    at org.gradle.api.internal.file.AbstractFileResolver.convertObjectToFile(AbstractFileResolver.java:118)
    at org.gradle.api.internal.file.BaseDirFileResolver.doResolve(BaseDirFileResolver.java:71)
    at org.gradle.api.internal.file.AbstractFileResolver.resolve(AbstractFileResolver.java:80)
    at org.gradle.api.internal.file.AbstractFileResolver.resolve(AbstractFileResolver.java:62)
    at org.gradle.api.internal.file.collections.DefaultConfigurableFileTree.getDir(DefaultConfigurableFileTree.java:75)
    at org.gradle.api.internal.file.collections.DefaultConfigurableFileTree.visitContents(DefaultConfigurableFileTree.java:156)
    at org.gradle.api.internal.file.CompositeFileCollection.getSourceCollections(CompositeFileCollection.java:161)
    at org.gradle.api.internal.file.CompositeFileTree.getSourceCollections(CompositeFileTree.java:34)
    at org.gradle.api.internal.file.CompositeFileCollection.getFiles(CompositeFileCollection.java:45)
    at org.gradle.api.internal.file.AbstractFileCollection.iterator(AbstractFileCollection.java:65)
    at com.diffplug.gradle.spotless.CheckFormatTask.formatCheck(CheckFormatTask.java:37)
    at com.diffplug.gradle.spotless.CheckFormatTask.doTask(CheckFormatTask.java:30)
    at com.diffplug.gradle.spotless.BaseFormatTask.run(BaseFormatTask.java:59)
    at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:75)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.doExecute(AnnotationProcessingTaskFactory.java:228)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:221)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:210)
    at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:621)
    at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:604)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:80)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:61)
    ... 70 more
BUILD FAILED
Total time: 5.344 secs

@oehme
Copy link

oehme commented Nov 2, 2016

The method takes a Map<String, Object>, not Map<Object, Object>. As a result the Java compiler chooses the other overload which tries to treat the whole map as a path.

Why don't you use the fluent, staticallly typed API?

fileTree(root).include(...).exclude(...)

@jbduncan
Copy link
Member Author

jbduncan commented Nov 2, 2016

Thanks @oehme, that seems to work! I'll submit a fix to branch 3.x as soon as I can.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants