What is allowed to be used from gradle for a plugin developer?

Take for example a recent change in GUtil. Now I cannot easily support 1.2 and 1.3. I think this is an issue, because minor versions shouldn’t break things. Neither user facing nor for other plugin devs. And GUtil is not marked as private!

Please advise!

The public API is what’s documented in the Javadoc and Groovydoc. Everything else (including ‘GUtil’) is private.


Does that mean that plugin authors have to reinvent everything afresh? Eg. DefaultSourceDirectorySet and the like?

If you want to be on the safe side, yes. There should probably be some API for adding source directory sets, but currently there isn’t.

This is really painful. May I include parts of the gradle source in a MIT licensed plugin project? To get a local DefaultSourceDirectorySet for example. Or does Apache conflict with MIT or vice versa?

Hint: Implement all plugins using only the public plugin API.

MIT and Apache are both very permissive licenses, but I don’t know the answer to your question.

Then I will take the usual approach: include a copy of the DefaultDirectorySet and dependencies, document the fact clearly in code and README, and wait till someone sues me.

But to be honest: I don’t think this is a solution. In particular central concepts like source sets should not depend on custom implementations by random plugin authors.

You shouldn’t need to implement ‘SourceSet’. Instead, you can (and should) use the ‘SourceSetContainer.add()’ factory method.As I said, there should probably be a similar factory method for source directory sets. It’s much less common to add your own source directory sets than it is to add your own source sets, but nevertheless it would be good to support it in the public API.

I need a SourceDirectorySet, because I need the source directories for the clojure part. Those have to be on the classpath for compilation to work.

On the other hand I want to provide methods “includeNamespaces” resp. “excludeNamespaces” which would act like include or exclude but on clojure namespaces names. The namespace pattern are then translated to the corresponding file patterns. So I have to provide my own ClojureSourceSet which delegates under the covers to a SourceDirectorySet which was up to now a DefaultSourceDirectorySet.

The groovy plugin does something similar.

If there was a way to add source directory sets like there is for source sets, you would get the delegation for free, and it wouldn’t be necessary to implement your own source set. To add additional methods, you can use an extension object. The ‘DefaultSourceSet’ and ‘DefaultDirectorySourceSet’ classes will likely stay private.

I think that is already going on: I use a convention(?) object to add methods to the source set. So the new clojure method will return the clojure SourceDirectorySet, the excludeNamespaces method is added, etc. Nonetheless I have to create a SourceDirectorySet at some point.

If there is a just a factory method missing…

I’ve added GRADLE-2596 to track this.

Cool. Thank you!

Ok. The copy-half-of-gradle approach just failed. I need a FileResolver service which is also private and which I cannot replace. So I have to bite the bullet and live with random incompatibilities between gradle versions and my plugin. Bleh. :frowning:

What do you need it for, and why can’t you replace it?

PS: Classes that have “internal” in the package name are always private.

Yes. I’m aware of “internal” stuff being private. As the name suggests. And up to know I never complained about internal stuff changing under me. But with being past 1.0 this starts to get painful. So I figured to ask about what I should do instead.

I need it to instantiate the DefaultSourceDirectorySet. Even if I copy that over into a private copy. And I need to instantiate a DefaultJavaExecAction thingy which I use to provide a ClojureExec. This is basically a JavaExec underneath with a hardwired main class which knows what to do with the provided main “class” (actually a clojure function). Both need a FileResolver.

I cannot replace it because it is provided by a call that looks like this: getServices().get(FileResolver.class). So obviously I won’t get the right thing, when I pass in “my” FileResolver.

Internal classes can always change. That’s the whole point behind making them internal. 1.0 doesn’t make a difference here.

Your first usage of ‘FileResolver’ will go away once the source directory set problem is solved. Regarding the second usage, instantiating ‘DefaultJavaExecAction’ is the wrong approach. What exactly are you trying to accomplish? Why not just configure a plain ‘JavaExec’ task or write your own task that uses ‘Project.javaexec’?

In don’t dispute the change of internal classes. That’s why I want to get away of them.

I want an exec task á la JavaExec, where manipulating “main” does not change the main class of the Java execution, but the first argument. But you are right. I can probably get away with a task which calls a custom javaexec during its execution.