How to define a resolved configuration as a Gradle task input

Hi,

I have a Gradle task which must look up the compileClasspath to find properties file in the jar files and merge them in an output properties file. I defined the merged file as a task output, but I don’t know how to define the compileClasspath configuration as an input. The goal is to use the incremental build to execute the task only if the compileClasspath content has changed.

Is this something possible ? or maybe I don’t take the problem in the right way ?

A configuration is a file collection that can be used with inputs.files().

task usingConfig {
    ext {
        inConfig = configurations.compileClasspath
        outFile = layout.buildDirectory.file('myOut.file')
    }
    inputs.files( inConfig )
    outputs.file( outFile )
    doLast {
        logger.lifecycle( "Generating ${outFile.get().asFile.absolutePath} from:\n\t${inConfig.join('\n\t')}" )
        outFile.get().asFile.text = '...'
    }
}
1 Like

Thanks for your help! Indeed, that solves my problem.
I implemented it with a plugin this way:

import org.gradle.api.DefaultTask
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction

import org.gradle.api.DefaultTask
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction

abstract class MyTask extends DefaultTask {

    @InputFiles
    abstract ConfigurableFileCollection getCompileClasspath()

    @OutputFile
    abstract RegularFileProperty getOutputFile()

    MyTask() {
        getCompileClasspath().setFrom(project.configurations.compileClasspath)
        getOutputFile().set(project.layout.buildDirectory.file('myOut.file'))
    }
  
    @TaskAction
    process() {
        println('My Task !')
        def text = ''
        getCompileClasspath().getFiles().each {
            text += "${it.name}\n"
        }
        getOutputFile().get().asFile.text = text
    }
}

:+1: Glad you got it working.

Just a suggestion; It’s a little bit atypical to use the constructor for setting defaults of Gradle tasks. Typically that’s done as part of the plugin’s apply method or some other logic based on the plugin’s data model. Instead of using compileClasspath directly, you can use the java plugin’s model to get it. You want the compile classpath of the main source set, so your plugin could do something like:

MyTask myTask = project.tasks.register( "myTask", MyTask ) {
    JavaPluginExtension javaExtension = project.extensions.getByType(JavaPluginExtension)
    SourceSet mainSourceSet = javaExtension.sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME)
    compileClasspath.from(mainSourceSet.compileClasspath)
}

Also something to keep in mind, properties have a convention method that is useful for setting defaults of Gradle objects. The key difference between convention and set is that convention will not change the property’s value if it has already been set. This is useful in scenarios where your plugin code that sets defaults could possibly execute after the user or something else has called set, in that scenario convention won’t cause the value to be lost and overwritten by the default.

1 Like

Thanks for the suggestions!
I actually did things this way because my task is used by several plugins and I wanted to avoid duplicating this piece of code. Is there any drawback when using the constructor for setting defaults of Gradle tasks?

Not an actual “drawback”, it is just not fully idiomatic.
Idiomatic is, if extensions and tasks are fully unopinionated, so don’t have default values for properties set, so that they could be more easily reused (also by others) for other purposes you might not even foresee now.
The plugins then add the opinion by setting default values, wiring extension properties to task properties, and so on.
You can also have a “base” plugin that does the common configuration code that you then apply from your other plugins that need the same default values and thus also have no code duplication.

Ok, got it.
Thanks for your help!