Distribution plugin task doesn't detect all dependent task in some cases

I have configured a custom distribution task (using distribution plugin) like this.

task exampleStartScripts(type: CreateStartScripts) {
  applicationName = "example"
  mainClass = "com.example.main"
  classpath = configurations.examplesRuntimeClasspath
  outputDir = file("$buildDir/tmp/exampleStartScript")
}

distributions {
    examples {
        contents {
            into('bin') {
                from exampleStartScripts.outputDir
            }
            into('lib') {
                from configurations.examplesRuntimeClasspath
                from sourceSets.main.runtimeClasspath
            }
            ...
        }
    }
}

Since I have used from exampleStartScripts.outputDir I expect gradle to detect the task exampleStartScripts as a dependency of examplesDistTar.

However it doesn’t do as I expect, but correctly identifies compile* tasks as dependents as I have also used from sourceSets.main.runtimeClasspath. Is this a bug in gradle that it doesn’t identify all dependent tasks or I am missing something ?

./gradlew examplesDistTar --dry-run

:compileJava SKIPPED
:compileScala SKIPPED
:processResources SKIPPED
:classes SKIPPED
:examplesDistTar SKIPPED

This is not how it works. When you provide exampleStartScripts.outputDir, you’re just providing a File. There’s no ability to infer anything from a File as that’s just a basic Java type.

Instead, you would have to say from exampleStartScripts, which allows Gradle to use the output directory of the task as the source and setup the task dependency.

Gradle needs the higher level abstraction to do these things. It can’t if you pull out and only provide the basic values.

1 Like

thanks @jjustinic for explaining, now I understand.

But now I am curious how below works:

task examplesJar(type: Jar) {
    archiveAppendix = "examples"
    from sourceSets.main.output
}

Since sourceSets outputs are file collection, how gradle is able to identify dependency on compile tasks ?

gradle examplesJar --dry-run
:compileJava SKIPPED
:compileScala SKIPPED
:processResources SKIPPED
:classes SKIPPED
:examplesJar SKIPPED

Both org.gradle.api.tasks.SourceSetOutput and org.gradle.api.file.FileCollection are Gradle types that allow more than just a collection of java.util.File. Specifically from the docs,

A file collection may contain task outputs. The file collection tracks not just a set of files, but also the tasks that produce those files. When a file collection is used as a task input property, Gradle will take care of automatically adding dependencies between the consuming task and the producing tasks.

There’s a very big difference between org.gradle.api.file.FileCollection and java.util.Collection<java.util.File> even though they sound like they’re essentially the same thing.

1 Like