How to get OutputDirectory of a task in another task?

How can we get the output directory defined with the annotation @OutputDirectory or outputs.dir(<dir>) in another task?

This doesnt work

task A {
   outputs.dir("/home/build")
}

task B {
   println A.outputs.dir
}

Since you’ll probably also want task B to depend on task A, I recommend you use “lazy properties” to help avoid issues related to missing task dependencies.

Here’s some examples of using both task classes and the groovy DSL. In both cases the output properties of the producer tasks carry a reference to their respective tasks. When those properties are used as inputs to another task, Gradle is smart enough to infer the task dependencies. For example, running gradlew consumer consumerDsl will execute all 4 tasks in the correct order (producer tasks before the corresponding consumer task).

abstract class MyProducerTask extends DefaultTask {
    @OutputDirectory
    abstract DirectoryProperty getOutDir()

    MyProducerTask() {
        // avoid up-to-date status for demo purposes
        outputs.upToDateWhen { false }
    }

    @TaskAction
    void doWork() {
        logger.lifecycle("Doing work into {}", outDir.get())
    }
}

abstract class MyConsumerTask extends DefaultTask {
    @InputDirectory
    abstract DirectoryProperty getInDir()

    @TaskAction
    void doWork() {
        logger.lifecycle("Doing work from {}", inDir.get())
    }
}

task producer(type: MyProducerTask) {
    outDir = layout.buildDirectory.dir("myOutDir")
}

task consumer(type: MyConsumerTask) {
    inDir = tasks.producer.outDir
}

task producerDsl {
    // avoid up-to-date status for demo purposes
    outputs.upToDateWhen { false }

    ext {
        outDir = objects.directoryProperty()
    }
    outDir.set(layout.buildDirectory.dir("myOutDir"))
    outputs.dir(outDir)

    doLast {
        logger.lifecycle("Doing DSL work into {}", outDir.get())
    }
}

task consumerDsl {
    ext {
        inDir = objects.directoryProperty()
    }
    inDir.set(tasks.producerDsl.outDir)
    inputs.dir(inDir)

    doLast {
        logger.lifecycle("Doing DSL work from {}", inDir.get())
    }
}

To more directly answer your question; you can generically get a task’s output files via <task>.outputs.files, which will return a FileCollection (a task could have more than one output directory or file).

task consumerDsl2 {
    dependsOn tasks.producerDsl
    doLast {
        logger.lifecycle("Doing DSL2 work from:\n\t{}", tasks.producerDsl.outputs.files.join('\n\t'))
    }
}

Thanks for answer. From your example you save the output directory of that task in A.ext.var and used that to read it back in task B. For my example it will be

task A {
   ext.outDir = file("/home/build")
}

task B {
   println A.outDir
}

And as you said, there can be more than one output directory I have to retrieve via <task>.outputs.files

So does it mean that from uses output.files when used in copy like this?

copy { 
   from A
   into "/another/folder"
}

Correct, when a task is given to CopySpec.from it is converted to the task’s output files.

However, in your example of:

task A {
   ext.outDir = file("/home/build")
}
copy { 
   from A
   into "/another/folder"
}

the copy would not copy anything from /home/build because task A has no declared outputs (ie outputs.dir(outDir).

1 Like