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?