Gradle Checks Hashes of Output Files

Gradle hashes file content for both inputs and outputs. - forum discuss.gradle.org

tasks.register("processData") {

    // Declare input and output for the task
    inputs.file("src/data/input.txt")   // Input file
    outputs.file("build/output.txt")    // Output file

    doLast {
        println("doLast Task executing, Processing input...")
        val inputFile = file("src/data/input.txt")
        val outputFile = file("build/output.txt")
        outputFile.writeText("""${Instant.now()} ${inputFile.readText().toUpperCase()}""")
        println("Task executed: Input processed.")
    }
}

In the following snapshot we have modified the output file and re-run then gradle build.

The gradle build correctly detected that output file has been modified and re-ran the task.

Glass thought Sandbox Snapshot

Command to reproduce:

gt.sandbox.checkout.commit d7ac1d1 \
&& cd "${GT_SANDBOX_REPO}" \
&& cmd.run.announce "./gradlew lib:processData --console=plain && echo "modified" >> ${GLASSTHOUGHT_SANDBOX:?}/lib/build/output.txt && ./gradlew lib:processData --console=plain && cat ${GLASSTHOUGHT_SANDBOX:?}/lib/build/output.txt"

Recorded output of command:

> Task :lib:processData UP-TO-DATE

BUILD SUCCESSFUL in 356ms
1 actionable task: 1 up-to-date

> Task :lib:processData
doLast Task executing, Processing input...
Task executed: Input processed.

BUILD SUCCESSFUL in 416ms
1 actionable task: 1 executed
2024-10-05T23:55:50.543629Z VAL-2

Also works with directories as output

Gradle also hashes the content of directories when checking for up-to-date tasks, when directories are registered as inputs.

tasks.register("generateFiles") {
    // Declare input and output
    inputs.file("src/data/input.txt")  // Input file
    outputs.dir("build/generated")     // Output directory

    doLast {
        val inputFile = file("src/data/input.txt")
        val outputDir = file("build/generated")

        // Ensure the output directory exists
        if (!outputDir.exists()) {
            outputDir.mkdirs()
        }

        // Generate some files in the output directory based on input file content
        val lines = inputFile.readLines()
        lines.forEachIndexed { index, line ->
            val outputFile = File(outputDir, "output_$index.txt")
            outputFile.writeText("Processed: $line")
            println("Generated ${outputFile.name}")
        }
    }
}
Glass thought Sandbox Snapshot

To check this can modify one of the output files in

${GLASSTHOUGHT_SANDBOX:?}/lib/build/generated/output_0.txt

After running the build and see that gradle detects that file was modified.

Command to reproduce:

gt.sandbox.checkout.commit e03c68d \
&& cd "${GT_SANDBOX_REPO}" \
&& cmd.run.announce "./gradlew lib:generateFiles --console=plain"

Recorded output of command:

> Task :lib:generateFiles UP-TO-DATE

BUILD SUCCESSFUL in 338ms
1 actionable task: 1 up-to-date

Detecting output modification works recursively when out Directories are tracked.

In this snapshot files were placed deeper into output directory and after modifying the file and re-running the build, gradle detected that the file was modified.

Glass thought Sandbox Snapshot

Command to reproduce:

gt.sandbox.checkout.commit f327c3d \
&& cd "${GT_SANDBOX_REPO}" \
&& cmd.run.announce "./gradlew lib:generateFiles --console=plain"

Recorded output of command:


> Task :lib:generateFiles
Generated output_0.txt
Generated output_1.txt
Generated output_2.txt

BUILD SUCCESSFUL in 420ms
1 actionable task: 1 executed

Backlinks