How to find which task produced a specific file and the property name that's annotated as OutputFile?

I have a Scala project that eventually produces a jar file and want to create a task that uses that jar file. Rather than hard-coding the jar filename in the new task, I’d like to use the property of the task that created that file.

More than just finding the answer to this specific question (which happens to be tasks.jar.archivePath), I’d like to be able to perform such investigations even with no prior knowledge of the tasks being used. Better still would be to be able to investigate without having to read task documentation (eg Gradle can perform the necessary tracking and reflection to indicate which task produced which file and which task properties are annotated and how).

Nothing like this exists. Gradle doesn’t track the creation of every file and map it to a task currently. Somewhere you need to model this jar and what creates it. Even if we did track this information, you’d still need some kind of model of it.

The general solution to this problem (to date) is to use a domain model to describe what is going on. Then the producer encodes the model with the information that they produce the thing, and the consumers refer to the model.

Gradle’s only out of the box modelling for things like jars, at this point, is as artifacts of a configuration. It’s unclear if this would work in your situation as I don’t know what the nature of your downstream task is.

I have the following so far:

task outputs() << {

tasks.each { task ->

task.properties.each { property ->

task.getClass().declaredFields.each { field ->

println “${task.name}.${property.key}: ${field.name}: ${field.declaredAnnotations*.annotationType()}”

}

}

}

}

but I’m not getting any annotations. All I’m getting is something like:

$ gradle outputs | grep ‘jar.archivePath=’

jar.archivePath=/Users/nyap/proj/setter-for-catan/build/libs/setter-for-catan.jar: copyActionSet: []

jar.archivePath=/Users/nyap/proj/setter-for-catan/build/libs/setter-for-catan.jar: appendixSet: []

jar.archivePath=/Users/nyap/proj/setter-for-catan/build/libs/setter-for-catan.jar: caseSensitiveSet: []

jar.archivePath=/Users/nyap/proj/setter-for-catan/build/libs/setter-for-catan.jar: includeEmptyDirsSet: []

jar.archivePath=/Users/nyap/proj/setter-for-catan/build/libs/setter-for-catan.jar: rootSpecSet: []

jar.archivePath=/Users/nyap/proj/setter-for-catan/build/libs/setter-for-catan.jar: extensionSet: []

jar.archivePath=/Users/nyap/proj/setter-for-catan/build/libs/setter-for-catan.jar: includesSet: []

jar.archivePath=/Users/nyap/proj/setter-for-catan/build/libs/setter-for-catan.jar: destinationDirSet: []

jar.archivePath=/Users/nyap/proj/setter-for-catan/build/libs/setter-for-catan.jar: dirModeSet: []

jar.archivePath=/Users/nyap/proj/setter-for-catan/build/libs/setter-for-catan.jar: versionSet: []

jar.archivePath=/Users/nyap/proj/setter-for-catan/build/libs/setter-for-catan.jar: baseNameSet: []

jar.archivePath=/Users/nyap/proj/setter-for-catan/build/libs/setter-for-catan.jar: sourceSet: []

jar.archivePath=/Users/nyap/proj/setter-for-catan/build/libs/setter-for-catan.jar: mainSpecSet: []

jar.archivePath=/Users/nyap/proj/setter-for-catan/build/libs/setter-for-catan.jar: manifestSet: []

jar.archivePath=/Users/nyap/proj/setter-for-catan/build/libs/setter-for-catan.jar: archiveNameSet: []

jar.archivePath=/Users/nyap/proj/setter-for-catan/build/libs/setter-for-catan.jar: defaultSourceSet: []

jar.archivePath=/Users/nyap/proj/setter-for-catan/build/libs/setter-for-catan.jar: excludesSet: []

jar.archivePath=/Users/nyap/proj/setter-for-catan/build/libs/setter-for-catan.jar: fileModeSet: []

jar.archivePath=/Users/nyap/proj/setter-for-catan/build/libs/setter-for-catan.jar: entryCompressionSet: []

jar.archivePath=/Users/nyap/proj/setter-for-catan/build/libs/setter-for-catan.jar: metaInfSet: []

jar.archivePath=/Users/nyap/proj/setter-for-catan/build/libs/setter-for-catan.jar: classifierSet: []

jar.archivePath=/Users/nyap/proj/setter-for-catan/build/libs/setter-for-catan.jar: archivePathSet: []

I’m thinking if we can get at the annotations, we can start filtering on specific ones.

It turns out there seems to be no need to reflect on the annotations. The following outputs all tasks and their outputs:

task outputs() << {

tasks.each { task ->

println “${task.name}.outputs: ${task.outputs.getFiles().asType(Collection)}”

}

}

It’s then just a matter of looking for the file one wants.

Of course, this only works for tasks that aren’t generated from rules.

I don’t see what this is buying you. You are going to need to know the path of the file that was created, or the task, in order to pull it from this list.

This is also going to perform poorly on large builds.

Yes, it’ll perform poorly on large builds. OTOH, it’s better than nothing. Also, I don’t see why it would be any less performant than ‘gradle tasks’ except possibly for tasks that have lots of outputs.

One only needs to know the name of the file they want, not the entire path.

For example:

$ gradle outputs | grep ‘some-output-file’