Communication between gradle methods and tasks - methods

I can't seem to get my collection from the method to a state where generateWadleTasks can iterate over it. At least not in a way such that I can access it. I've tried properties, parameters and return values. What's wrong with this picture? I seem to have some misconceptions about how information is passed around either in Groovy or in Gradle... or perhaps both. An explanation of the scopes involved might help. This is a subproject.
buildscript{
...
}
ext.collectionOfObjects = []
class WadleProfile {
def File wadleFile;
def wadlArgs;
}
ext.factoryMethod = {
//supposed to create and add WadleProfiles to collectionOfWadleProfiles
}
compileJava {
doFirst { factoryMethod() }
}
task generateWadlTasks {
println "Executing generateWadlTasks"
project.ext.collectionOfObjects.each { wadlProfile ->
task("wadl2java" + wadlProfile.id, type: JavaExec, dependsOn: 'classes') {
main = project.wadlBaseMain
...
}
}
}

Related

Gradle : use a task to disable another task

I have three gradle tasks (this is kotlin code inside a plugin):
project.task<Task>("checkNeeded") {
doLast {
if (someTest()) {
listOf("SomeCopy", "SomeAction")
.map { project.tasks[it] as AbstractTask }
.forEach { it.isEnabled = false }
}
}
}
project.task<Copy>("SomeCopy") {
dependsOn("checkNeeded")
from(wherever)
into(whatever)
}
project.task<Task>("SomeAction") {
dependsOn("checkNeeded")
doLast {
/* something magical */
}
}
So, both tasks SomeCopy and someAction depend on checkNeeded. The role of checkNeeded is to disable these two task if it finds that they are not needed.
However, this crashes with the following exception: Cannot call Task.setEnabled(boolean) on task ':SomeCopy' after task has started execution.
So, how can I have a task guaranteed to run before other tasks that can disable other tasks if they are not needed?
I ended up fixing this issue with onlyIf:
var needed by Delegates.notNull<Boolean>()
project.task<Task>("checkNeeded") {
doLast {
needed = !someTest()
}
}
project.task<Copy>("SomeCopy") {
dependsOn("checkNeeded")
onlyIf { needed }
from(wherever)
into(whatever)
}
project.task<Task>("SomeAction") {
dependsOn("checkNeeded")
onlyIf { needed }
doLast {
/* something magical */
}
}
Note that the checkNeeded task is not really necessary, but I like to have it to know, in the process, when the check is made. I could have done:
val needed by lazy { !someTest() }
project.task<Copy>("SomeCopy") {
onlyIf { needed }
from(wherever)
into(whatever)
}
project.task<Task>("SomeAction") {
onlyIf { needed }
doLast {
/* something magical */
}
}
The dependsOn does set the order. It may make sense to move the if outside the checkNeeded task and place it either in the build script (it will be executed in the configuration phase) or in the afterEvaluate {...} block (it will still be executed in the configuration phase, but later)
Another option is to execute checkNeeded task explicitly before running one of the SomeCopy or SomeAction

refer to Gradle task which is defined later in build

Our build has some generic logic to create tasks from configuration data. There are also several Gradle files on whose execution order I do not want to depend.
Now I need to add a task dependency to a task without knowing if that task will be defined before my part of the build script runs (at configuration time) or after my part.
[Edit: as #canillas writes I can say myTask.dependsOn "otherTask" and "lazily" depend on yet undefined "otherTask", but I need it the other way around.]
Since I can't write tasks["otherTask"].dependsOn myNewTask before "otherTask" is defined, I made the following helper function:
void safelyDoWithTask(String taskName, Closure func) {
def task = tasks.findByName(taskName)
if (task != null) {
func(task)
} else {
project.tasks.whenTaskAdded { task_ ->
if (taskName.equals(task_.getName())) {
func(task_)
}
}
}
}
safelyDoWithTask('otherTask', { it.dependsOn myNewTask })
Now I wonder if there is more canonical way to achieve this?
Consider the following:
// section 1
def dynamicDependencies = [:]
dynamicDependencies['otherTask'] = 'myNewTask'
// section 2
afterEvaluate { project ->
// taskA dependsOn taskB
dynamicDependencies.each { taskA, taskB ->
def task = project.tasks.findByName(taskA)
if (task) { task.dependsOn "${taskB}" }
}
}
// section 3
task myNewTask() {
doLast {
println 'myNewTask !'
}
}
task otherTask() {
doLast {
println 'otherTask !'
}
}
The gist is:
section 1 defines our dependency info in a custom map
section 2 uses the afterEvaluate hook to process the map
because the above is decoupled from the task definitions, we can simply put them in section 3 (or wherever)

How do I create my own configuration block with a Gradle script plugin?

Our company has a Gradle script plugin with a number of tasks in it. For instance, it includes the Jacoco afterEvaluate block from this answer:
def pathsToExclude = ["**/*Example*"]
jacocoTestReport {
afterEvaluate {
classDirectories = files(classDirectories.files.collect {
fileTree(dir: it, exclude: pathsToExclude)
})
}
}
We would like to take that pathsToExclude variable and define that in our build.gradle file and have the rest of the logic in a script plugin (let's call it company-script-plugin.gradle. For instance:
apply from: http://example.com/company-script-plugin.gradle
companyConfiguration {
pathsToExclude = ["**/*Example*"]
}
Our initial thought was to add a task in the build script so that we could get a companyConfiguration
task companyConfiguration {
ext.pathsToExclude = []
}
However, we think that this is a hacky workaround because running the task doesn't do anything. What is the proper way to create my own configuration block?
We'd like it to be as simple as possible, and to be a script plugin (rather than binary plugin) if possible.
Here you've an example how it can be done:
apply plugin: CompanyPlugin
companyConfiguration {
pathsToExclude = ['a', 'b', 'c']
}
class CompanyPlugin implements Plugin<Project> {
void apply(Project p) {
println "Plugin ${getClass().simpleName} applied"
p.extensions.create('companyConfiguration', CompanyConfigurationExtension, p)
}
}
class CompanyConfigurationExtension {
List<String> pathsToExclude
CompanyConfigurationExtension(Project p) {
}
}
task printCompanyConfiguration {
doLast {
println "Path to exclide $companyConfiguration.pathsToExclude"
}
}
Also, please have a look at the docs.

Null dependency in gradle? (workaround for lazy downloads?)

I would like to be able to write something like this:
dependencies {
myConfig computeMyDependency()
}
and I want to be able to say "there is no dependency". Returning null or an empty map doesn't work. I suppose I can return files('/dev/null'), but that is weird, hacky and not portable. Is there some sort of null dependency constructor I can use?
Some background:
What I'm really trying to do is to defer dependency download to actual execution time. It appears that if a write a task, for example a copy task like so:
task copyMyDependencyFile(type: Copy) {
from { configurations.myConfig
.grep { it.name.endsWith("zip") }
.collect() { zipTree it }
}
into targetDir
}
Then running ./gradlew tasks will actually execute the from closure, which makes me very sad. (Using Gradle 2.4)
A quick workaround might be also:
task copyMyDependencyFile << {
copy {
from {
configurations.
compile.
grep { it.name.endsWith("jar") }.
collect { zipTree it }
}
into targetDir
}
}
It should be portable.
Not sure but maybe from and into maybe configured in doLast closure of task with type Copy:
task copyMyDependencyFile(type: Copy) {
doLast {
from {
configurations.
compile.
grep { it.name.endsWith("jar") }.
collect { zipTree it }
}
into targetDir
}
}
Please try the latter yourself.

Gradle - publish artifacts

I want to publish artifacts to ivy repository but it doesn't work. I read this article and after read created this sample build:
task ivyPublishTest << {
def buildDir = new File("build")
buildDir.mkdirs()
def fileToPublish = new File("build/file.abc")
fileToPublish.write("asdasdasd")
}
artifacts {
archives(ivyPublishTest.fileToPublish) {
name 'gradle-test-artifact'
builtBy ivyPublishTest
}
}
uploadArchives {
repositories {
ivy {
url "http://my.ivy.repo/ivyrep/shared"
}
}
}
Of course the problem is that it doesn't work. I get this error Could not find property 'fileToPublish' on task ':ivyPublishTest'
In Groovy, def creates a local variable, which is lexically scoped. Therefore, fileToPublish is not visible outside the task action. Additionally, configuration has to be done in the configuration phase (i.e. the declaration and assignment of fileToPublish in your task action would come too late). Here is a correct solution:
task ivyPublishTest {
// configuration (always evaluated)
def buildDir = new File("build")
ext.fileToPublish = new File("build/file.abc")
doLast {
// execution (only evaluated if and when the task executes)
buildDir.mkdirs()
fileToPublish.write("asdasdasd")
}
}
artifacts {
// configuration (always evaluated)
archives(ivyPublishTest.fileToPublish) {
name 'gradle-test-artifact'
builtBy ivyPublishTest
}
}
ext.fileToPublish = ... declares an extra property, a new property attached to an existing object that's visible everywhere the object (task in this case) is visible. You can read more about extra properties here in the Gradle User Guide.

Resources