Werner Thumann
Werner Thumann

Reputation: 525

Incremental build support for output directory considering added files

The Gradle documentation tells this:

Note that if a task has an output directory specified, any files added to that directory since the last time it was executed are ignored and will NOT cause the task to be out of date. This is so unrelated tasks may share an output directory without interfering with each other. If this is not the behaviour you want for some reason, consider using TaskOutputs.upToDateWhen(groovy.lang.Closure)

Question: How does the solution with upToDateWhen look like (so that added files are considered). The main problem is that one has to access the build cache to retrieve the output directory content hash the last time the task ran.

Upvotes: 3

Views: 3036

Answers (1)

Chriki
Chriki

Reputation: 16378

Not sure if I understand the question correctly or why you mention the build cache. I assume you are not aware that the predicates added with upToDateWhen() are considered in addition to any other up-to-date checks like the ones added with TaskOutputs.dir()?

Take the following sample task:

task foo {
    def outDir = file('out')
    outputs.dir(outDir)
    outputs.upToDateWhen { outDir.listFiles().length == 1 }
    doLast {
       new File(outDir, 'foo.txt') << 'whatever'
    }
}

As long as there is only a single file in the output directory (as configured via upToDateWhen) and the file produced by the task (out/foo.txt) isn’t changed after the task has run, the task will be up-to-date. If you change/remove the file created by the task in the output directory or if you add further files to the output directory, then the task will run again.


Updated answer as per the updated question from the comments:

task foo {
    def outDir = file('out')

    /* sample task action: */
    doFirst {
        def numOutFiles = new Random().nextInt(5)
        for (int i = 1; i <= numOutFiles; i++) {
            new File(outDir, "foo${i}.txt") << 'whatever'
        }
    }

    /* up-to-date checking configuration: */
    def counterFile = new File(buildDir, 'counterFile.txt')
    outputs.dir(outDir)
    outputs.upToDateWhen {
        counterFile.isFile() \
          && counterFile.text as Integer == countFiles(outDir)
    }
    doLast {
        counterFile.text = countFiles(outDir)
    }
}

def countFiles(def dir) {
    def result = 0
    def files = dir.listFiles()
    if (files != null) {
        files.each {
            result++
            if (it.isDirectory()) {
                result += countFiles(it)
            }
        }
    }
    result
}

Upvotes: 3

Related Questions