How do I make a FileCollection that contains all the files in a directory except for a select few?

I am making a task that runs JavaCC and can’t get the ‘up-to-date’ logic to work correctly. JavaCC generates files in a directory that already has some files in it. I want the generated files to count as output and the pre-existing files to count as input. I can enumerate the pre-existing files (there’s only 4 of them). I’ve tried many iterations, but none seem to work correctly. Here is my best guess so far:

task javaCC {
    // This directory starts with input in it and has output in it after the task.
    def ParserDir = "src/main/java/edu/stsci/hst/rps2/parser/javacc"
    def ParserFileName = "src/main/javacc/edu/stsci/hst/rps2/parser/javacc/DefaultPropParser.jj"
    def JavaCCHome = "../JavaCC"
    inputs.file ParserFileName
    // These are the files that count as input.
    def specialJavaCcGeneratedFiles =
  project.files(["${ParserDir}/ParseException.java",
 "${ParserDir}/Token.java",
 "${ParserDir}/TokenMgrError.java",
 "${ParserDir}/SimpleCharStream.java"])
    inputs.files specialJavaCcGeneratedFiles
    // This should be a FileCollection with all the files in ParserDir except for the input files.
    def tmp = project.files { new File(ParserDir).listFiles() } - specialJavaCcGeneratedFiles
    outputs.files tmp
    doLast {
        ant.taskdef(name:"javaCC", classname:"edu.stsci.apt.AptJavaCC"){
            classpath {
                pathelement(location: "../Libraries/Internal/CM.jar")
                pathelement(location: "../Libraries/jdom.jar")
            }
        }
        ant.javaCC(javacchome: JavaCCHome,
               target: ParserFileName,
               outputdirectory: ParserDir) {}
        // This is an attempt at debugging-- I can't figure out how to easily verify
        // what is registered as input and what is output.
 logger.error "================== " + tmp.files
    }
}

I can provide more details if I was unclear above.

It’s almost always better to use different directories for inputs and outputs. Does it solve your problem?

I should have mentioned that I know this is a bad design. I’m writing the build to replace an ant build. Splitting into two directories would require me to change the ant build which I’m reluctant to do. And now that I’ve found this problem, I’m curious how to solve it (even if I don’t use this solution).

I usually use something like this for defining exclude/include patterns in ‘legacy’ setups.

def javaCCFiles = ["ParseException.java",
    "Token.java",
    "TokenMgrError.java",
    "SimpleCharStream.java"]
inputs.files = fileTree(dir: ParserDir, includes : javaCCFiles)
outputs.files = fileTree(dir: ParserDir, excludes : javaCCFiles)

Hope that works for you.

1 Like

I broke down last night and split the input and output into two directories. That worked like a charm. I’m convinced that your suggestion would work. It’s also helpful general knowledge, thanks for helping.