I’m writing a custom plugin for packaging different ‘applications’ for our project. The DSL ends up like below (simplified version of the the real DSL):
myApplications {
trials {
artifactName = 'trials-app'
}
}
This is basically saying “creating a trials application with the name ‘trials-app’”. A ‘application’ is basically a ‘fat’ jar created from archives of sub projects.
The application domain object is very simple like below:
class MyApplication {
String name
String artifactName
MyApplication(String name) {
this.name = name
}
}
The plugin generates a corresponding ‘Jar’ task, a configuration object and declares a artifact:
class MyApplicationPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
NamedDomainObjectContainer<MyApplication> myApplicationsContainer = project.container(MyApplication)
project.extensions.add("myApplications", myApplicationsContainer)
myApplicationsContainer.all(new Action<MyApplication>() {
@Override
void execute(MyApplication application) {
// create a matching configuration
String configurationName = application.name + "Application"
Configuration configuration = project.configurations.create(configurationName)
// create the Jar task
String taskName = "jar" + configurationName.capitalize()
Jar applicationTask = project.tasks.create(taskName, Jar)
applicationTask.dependsOn configuration
// declare a artifact created from the task
project.artifacts.add(configurationName, applicationTask)
// configure the task
project.afterEvaluate(new Action<Project>() {
@Override
void execute(Project p) {
applicationTask.baseName = application.artifactName
applicationTask.from configuration.collect {
it.isDirectory() ? it : p.zipTree(it)
}
}
})
}
})
}
}
For the DSL at the beginning, this plugin will generate a jarTrialsApplication
task, a configuration called trialsApplication and also adds a artifact.
Notice, the task is configured only after the project is evaluated. I got this from this Gradle documentation. I also tried to configure the project right after it’s created but all the property on my domain object are null:
Jar applicationTask = project.tasks.create(taskName, Jar)
applicationTask.configure {
applicationTask.baseName = application.artifactName // this is always null
.......
}
I think this must have something to do with the build lifecycle but I just can’t see why I can’t configure the task during configuration phase (I suppose the DSL was evaluated at configuration phase) . This is essentially my first question. Any pointers?
The second questions is related to tasks that depends on the generated tasks. I’ve got a ‘dist’ task in my main build script, which is not part of the plugin, like below together with the DSL:
myApplications {
trials {
artifactName = 'trials-app'
}
}
dependencies {
trialsApplication project(':A')
trialsApplication project(':B')
}
task dist(type: Copy) {
dependsOn jarTrialsApplication
from jarTrialsApplication.archivePath
into "${project.buildDir}/dist/trials-app.jar"
doFirst {
mkdir "${project.buildDir}/dist"
}
}
This task basically copies the ‘application’ to another location. The problem with this task is that jarTrialsApplication.archivePath
is always set to{my project name}.jar
rather than the expected trials-app.jar
.
Again, I guess this has is to do with the fact that jarTrialsApplication task is only going to be configured after the whole project is evaluated, which is too late for ‘dist’ task.
I know I can pass a closure to the from
method, but this is like I have to ‘expose’ the internal behavior of the plugin to the users of the plugin which is not ideal from end users point of view. And it might not be possible to pass a closure at all in some scenarios, e.g. the task doesn’t not accept closure.
So the second question is that am I doing something anti-pattern/practice here when writing the custom plugin? Especially when you need to reference the generate tasks later on during configuration?
Thanks in advance!