Support for both incremental and non-incremental input files

I have a transformation task which takes a some template files and transforms some source files to some output files. That’s all fine, and reports UP-TO-DATE if none of the input or output files have changed. But then I tried to add incremental file support, and can’t get it to work exactly as I’d like.

The problem boils down to:

  • If any of the template files change then I want to do a full rebuild.
  • If any of the source files change then I want to do an incremental build of the changed files only.

If I only had a single template file then I could probably specify it as an input property and (according to the docs) this would cause a full rebuild - haven’t tried this but that’s what it looks like to me. But as I have multiple template files (chained xsl transformations) I can’t see how to use this.

I have this mostly working by checking the incremental files against the known source files and forcing a full build if any non-source files are detected. However, this seems a bit messy, and doesn’t work properly for removed template files (that rarely happens, so I just do a clean / rebuild in that case).

class TransformTask extends DefaultTask {

  FileCollection templateFiles
  FileCollection sourceFiles

  @InputFiles
  FileCollection getTemplateFiles() {
    return templateFiles
  }

  @InputFiles
  FileCollection getSourceFiles() {
    return sourceFiles
  }

  @TaskAction
  void transform(IncrementalTaskInputs inputs) {

    boolean incremental = inputs.incremental

    def outOfDateFiles = []

    if (incremental) {
      inputs.outOfDate {
        if (sourceFiles.contains(it.file)) {
          outOfDateFiles.add(it.file)
        } else {
          incremental = false
        }
      }
    }

    if (incremental) {
      // process all outOfDateFiles
    } else {
      // process all sourceFiles
    }
  }
}

Is there a better way to approach this? My first though was a custom up to date check, but then I’m manually trying to detect any changes to the template files, which is duplicating exactly what the incremental file processing is doing.

One possibility would be to add a distinction on input files between full and incremental ones, something like:

@InputFiles  // if any of these change then do a full rebuild
FileCollection getTemplateFiles() {
  return templateFiles
}

@IncrementalFiles    // acts like InputFiles but are eligible for IncrementalTaskInputs
FileCollection getSourceFiles() {
  return sourceFiles
}

Of going the other way and forcing a rebuild if any of the template files change:

@InputFiles
@FullRebuild    // forces a full rebuild if any of these change
FileCollection getTemplateFiles() {
  return templateFiles
}

@InputFiles
FileCollection getSourceFiles() {
  return sourceFiles
}

Do either of those look reasonable, or any other ways of achieving this?