MrQBerrt
MrQBerrt

Reputation: 1379

Wiring two Gradle tasks together via a property

The question:

In Gradle, how do I make the output of one task be a property and the input of another task be that same property? Especially in the context of that property being needed at configuration time.

What I'm trying to accomplish:

I'm attempting to write a Tar task that depends on user input. I'm having trouble with the need for lazy configuration given that the "baseName" is not known at configuration time.

Code

Here's what I would like to work but it doesn't.

task saveDb(type: Tar, dependsOn: getTarBaseName) {
    // Next line doesn't work but does if I surround 2nd param with '{}'
    inputs.property("baseName", getTarBaseName.baseName) // Doesn't work

    from file("$dbsDir/data")
    destinationDir = file(project.dbsBackupDir)
    baseName = getTarBaseName.baseName // Doesn't work
    extension = 'tar'
    compression = Compression.NONE
}

task getTarBaseName() {
    doFirst {
        def result = BuildUtil.promptForName() // Uses Swing to prompt for a name
        getTarBaseName.ext.baseName = result
    }
}

As you can see I'm using ext to try to pass information between tasks, but that is just incidental not a requirement. Also I'm using 2 tasks, I'm completely willing to use only 1, however, that wouldn't really answer the general question which is one I hit against fairly often when attempting to use Gradle as a cross platform bash replacement for project related tasks.

Upvotes: 0

Views: 288

Answers (1)

Lukas Körfer
Lukas Körfer

Reputation: 14503

To solve your specific problem (if I did not miss something), you don't need a second task. Just add a doFirst closure to your Tar task and set the baseName property there to whatever you want:

task saveDb(type: Tar) {
    // static configuration
    doFirst {
        baseName = BuildUtil.promptForName()
        // or for another task (don't forget to depend on that task)
        baseName = otherTask.myProperty
    }
}

task otherTask {
    doFirst {
        ext.myProperty = BuildUtil.promptForName()
    }
}

However, your question boils down a general difficulty in Gradle: when to apply a specific piece of configuration.

Gradle just introduced a rather new feature for lazy configuration: Provider and Property

Gradle provides lazy properties, which delay the calculation of a property’s value until it’s absolutely required.

Before Gradle 4.0, only files could be lazy evaluated (via ConfigurableFileCollection), as an example:

task myZip(type: Zip) {
    // zip some files
}

task copyMyZip(type: Copy) {
    from myZip
}

myZip.baseName = 'myZip'

Even if the name of the zip file is defined after the Zip task is added to the Copy task configuration, its correct path will be used for the copy operation.

Now, with Gradle 4.0 and up, all configuration parameters that implement Property or Provider can be bound easily (check out the link above) and you can also lazily read a configuration parameter by wrapping it into a Provider, but it's difficult to put a provider value into an old configuration parameter. You still need to specify the moment when to evaluate (inside the task action, in a doFirst closure or an afterEvaluate handler). This problem is the topic of this discussion on GitHub.

Upvotes: 1

Related Questions