What is the best practice to handle the frequently API signature changes in Gradle? We need to compile our plugin for different Gradle versions again.
Without the recompile or if you use the wrong plugin version the users receive a java.lang.NoSuchMethodError at runtime. Currently we have already 4 different plugin versions for different Gradle versions. Can the plugin portal handle this?
I just had a look at the project and there is internal API usage everywhere. Anything containing the word internal is not supported.
Please refactor the plugin towards using only the public APIs. If there is something that you can’t do with the public API, please let us know. We’ll try to find a solution together.
First our tasks and extensions implements CopySpec. There is no default implementation. If you extends this interface we need to do it also.
Then we use DefaultExecAction because the java.lang.ProcessBuilder has produce problems inside from Gradle.
Get a FileResolver which self is internal.
Get a CopySpecResolver which self is internal
Theoretical your are right. We should not use internal. But then we need to implements all self like a CopySpec. Then the build scripts can not interact with other tasks harmonically.
If you try to implements a task like “zip” in your own plugin without the usage of the internal API then you will see where are the problems.
You don’t need to implement it for that. Here’s a rough sketch how to use CopySpec in a custom task:
task mytask(type: MyTask) {
outputDir = "$buildDir/foo"
content {
from 'dummy'
}
}
class MyTask extends DefaultTask {
CopySpec content
def outputDir
MyTask() {
content = project.copySpec()
}
@TaskAction
def doStuff() {
project.copy {
into outputDir
with content
}
}
def content(Action<? super CopySpec> config) {
config.execute(content)
}
}
Why iterate? You can execute the copy as shown in the custom task above. Then you can invoke some other tool on the copied directory, like invoking tar.
Legacy We wouldn’t do it like that again, but now users are used to having the from method directly on the Jar task, so it will be hard to change.
Calling a Closure from Java isn’t that hard. It’s definitely not a blocker. And we are adding Action methods for all Closure methods in recent Gradle versions. Here’s how to call a closure method:
project.exec(new Closure(null) {
public void doCall(ExecSpec spec) {
// your code here
}
}
Please don’t get me wrong by the way. I’m sure there are things that are only possible with internal Apis at the moment. We should talk about those use cases and then publish the necessary minimal Api.
But what I saw so far in the plugin could definitely be done with far less internals. So the first step should be refactoring to use as little internals as possible. The second step would be to look at the remaining internals together to see what needs to be public.
The “content” variable look not like typical Gradle code. The calling of a copy() method will produce a very large performance decrement. It is very bad practice to copy hundreds of megabytes to receive the directory structure and then delete it.
But we have lost touch the original question. It there any good option to handle the version of plugins depends on the Gradle version?
I don’t know what you mean. The distribution plugin does the same and this is how all copying/bundling tasks should look like.
As I said, you shouldn’t need to. Only use public APIs and tell us about the specific situations that don’t work, so we can fix them. How is Gradle supposed to get better if we don’t know the things that don’t work for you?
I’ve forwarded the bundling use case to the team. I’m sure we can make something happen there.