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

SpotlessTaskService (towards configuration-cache) #982

Merged
merged 24 commits into from
Nov 9, 2021

Conversation

nedtwigg
Copy link
Member

@nedtwigg nedtwigg commented Nov 7, 2021

This PR is a step towards support for the configuration-cache, but it is not the full thing. It is intended to produce no changes in behavior, and just move us off of the forbidden APIs.

IMO it's a bummer. ObjectFactory does fileTrees, and FileSystemOperations does deleting, and if you want to know your project directory you've got to break code navigation / dataflow analysis and store it into your own bespoke property and hope that the name you pick isn't too different from what future PR contributors expect. I did quite a bit of refactoring to try to simplify as much as I could, but this PR basically just adds 300 lines of boilerplate.

…hashCode` without serialization."

This reverts commit 84101b9.
@nedtwigg nedtwigg changed the title SpotlessTaskService (towards configuration-cache) SpotlessTaskService (towards configuration-cache) (2 of 3) Nov 7, 2021
Copy link
Member

@jbduncan jbduncan left a comment

Choose a reason for hiding this comment

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

Wow, there's a lot going on here. I don't claim to understand what the code is doing yet, but I have seen a couple of nits that I believe could be fixed. Let me know what you think?

*/
public abstract class SpotlessTaskService implements BuildService<BuildServiceParameters.None> {
private final Map<String, SpotlessApply> apply = Collections.synchronizedMap(new HashMap<>());
private final Map<String, SpotlessTask> source = Collections.synchronizedMap(new HashMap<>());
Copy link
Member

@jbduncan jbduncan Nov 7, 2021

Choose a reason for hiding this comment

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

Have you considered using ConcurrentMap over synchronized maps here? I ask because if we ever need to loop, stream, or otherwise do some iteration operation over either of these maps (such an operation may not be obvious), then the map would need to be synchronized first to prevent concurrency problems.

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 think it's gonna stay pretty simple.

Copy link
Member Author

@nedtwigg nedtwigg Nov 8, 2021

Choose a reason for hiding this comment

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

Let me clarify -> our tasks don't need to coordinate across projects, they only coordinate within a single project. If we could specify a SpotlessTaskService per-project, then we wouldn't need it to be synchronized. So concurrent access is possible, but I see no risk of deadlock nor of inconsistent state, because the parts that need to coordinate are single-threaded.

Copy link
Member

Choose a reason for hiding this comment

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

Ah, gotcha. I'd still argue that ConcurrentMap is the better solution, but it looks like we'll have to agree to disagree. So I'm happy to defer to you once more. :)

@@ -59,6 +60,10 @@
}
}

public static <T> Provider<T> providerOf(T value) {
return org.gradle.api.internal.provider.Providers.of(value);
Copy link
Member

Choose a reason for hiding this comment

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

I remember having used the following in a Gradle build script recently:

val someList = provider {
    listOf(1, 2, 3)
}

So I was wondering if this provider function is available outside of the Gradle DSL. If so, it would mean we wouldn't need to use an internal API here.

Copy link
Member Author

Choose a reason for hiding this comment

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

This is a good question, and the answer is super surprising -interface org.gradle.api.provider.Provider is public, and has quite a few methods. But there are literally no implementations (abstract or not) in an api package, only internal (that I could find at least).

If you take the time to implement it yourself (which I did), then you actually get a ClassCastException! Because somewhere in Gradle's guts, they cast it to org.gradle.internal.ProviderImpl (I forget the exact name), which means you can't implement it yourself.

We have a code style rule that barfs at any .internal. imports, which is why I spelled-out the package inline like I did. I'm still a huge gradle fan, but I was pretty bummed when I found out that you can't actually implement Provider 😞

Copy link
Member

Choose a reason for hiding this comment

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

That is surprising! Maybe the Gradle developers wanted something like sealed classes for Provider but couldn't get it for the version of Java they're constrained to.

I would've also guessed that Provider was a single-method interface, where all the other methods were default. But maybe it's because the minimum Java version that Gradle runs on isn't Java 8 yet.

Having done some research just now, I see that provider { } is indeed only available in the DSL, specifically on Project.getProviders(), Settings.getProviders(), and through @Injecting a ProviderFactory into a plugin or extension. I suppose if we weren't constrained by the configuration cache we'd be able to use one of them, but alas.

Thanks for explaining!

Base automatically changed from feat/remove-ide-project to main November 8, 2021 10:28
@nedtwigg nedtwigg changed the title SpotlessTaskService (towards configuration-cache) (2 of 3) SpotlessTaskService (towards configuration-cache) Nov 9, 2021
@nedtwigg nedtwigg merged commit f52f7fd into main Nov 9, 2021
@nedtwigg nedtwigg deleted the feat/spotless-task-service branch November 9, 2021 05:59
@nedtwigg
Copy link
Member Author

nedtwigg commented Nov 9, 2021

Released in plugin-gradle 6.0.0.

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.

2 participants