import org.apache.tools.ant.util.TeeOutputStream class Tags { Boolean mainMethod = false Boolean compileTimeError = false Boolean throwsException = false Boolean errorOutputExpected = false Boolean validateByHand = false Boolean ignoreOutput = false // probably don't need this tag String javaCmd = null String args = null String jVMArgs = null String exec = null String runFirst = null private List lines private String block def Tags(List lines) { this.lines = lines block = lines.join('') mainMethod = block.contains('main(String[] args)') compileTimeError = testFor('CompileTimeError') throwsException = testFor('ThrowsException') errorOutputExpected = testFor('ErrorOutputExpected') validateByHand = testFor('ValidateByHand') ignoreOutput = testFor('IgnoreOutput') javaCmd = extract('main:') args = extract('Args:') jVMArgs = extract('JVMArgs:') exec = extract('Exec:') runFirst = extract('RunFirst:') } private def testFor(String marker) { return block.contains("// {" + marker + "}") } private def extract(String marker) { if(!block.contains("// {" + marker)) return null def re = "\\/\\/ \\{" + marker + /[^}]+}/ def tagline = block =~ re if(tagline.getCount()) { def rtrim = tagline[0] - "}" def ltrim = rtrim - ("// {" + marker) return ltrim.trim() } else { println "Searching for: " + re println block System.exit(1) } } public boolean hasTags() { return compileTimeError || throwsException || errorOutputExpected || validateByHand || ignoreOutput || javaCmd || args || jVMArgs || exec || runFirst } public String toString() { String result = "" for(ln in lines) if(ln.startsWith("//") || ln.startsWith("package ")) result += ln + "\n" else break if(mainMethod) result += "mainMethod: " + mainMethod + "\n" if(compileTimeError) result += "compileTimeError: " + compileTimeError + "\n" if(throwsException) result += "throwsException: " + throwsException + "\n" if(errorOutputExpected) result += "errorOutputExpected: " + errorOutputExpected + "\n" if(validateByHand) result += "validateByHand: " + validateByHand + "\n" if(ignoreOutput) result += "ignoreOutput: " + ignoreOutput + "\n" if(javaCmd) result += "javaCmd: " + javaCmd + "\n" if(args) result += "args: " + args + "\n" if(jVMArgs) result += "jVMArgs: " + jVMArgs + "\n" if(exec) result += "exec: " + exec + "\n" if(runFirst) result += "runFirst: " + runFirst + "\n" return result } } subprojects { apply plugin: 'java' sourceCompatibility = '1.8' targetCompatibility = '1.8' repositories { mavenLocal() mavenCentral() } sourceSets { main { java { srcDir projectDir } } } List tasks = [] projectDir.eachFileRecurse { if (it.name.endsWith('.java')) { List lines = it.readLines() Tags tags = new Tags(lines) // Not used yet; just for demo if(tags.hasTags()) println tags Boolean hasMainMethod = lines.join('').contains('main(String[] args)') Boolean hasMainParam = lines.find { it.startsWith('// {main: ')} Boolean willNotCompile = lines.find { it.startsWith('// {CompileTimeError') } Boolean validateByHand = lines.find { it.startsWith('// {ValidateByHand}') } Boolean throwsException = lines.find { it.startsWith('// {ThrowsException}') } // Add tasks for java sources with main methods if ((hasMainMethod || hasMainParam) && (!willNotCompile)) { String maybeArgsLine = lines.find { it.startsWith('// {Args: ')} List maybeArgs = [] if (maybeArgsLine != null) { maybeArgs = maybeArgsLine.trim().replaceAll('\\/\\/ \\{Args: ', '').reverse().replaceFirst('}', '').reverse().split(' ') } String mainClass = it.name.replaceAll('.java', '') String taskName = mainClass if (!validateByHand) { // only add tasks that we know we can run successfully to the task list tasks.add(taskName) } // some java sources with a main method specify a different main class String maybeMainLine = lines.find { it.startsWith('// {main: ')} if (maybeMainLine != null) { mainClass = maybeMainLine.trim().replaceAll('\\/\\/ \\{main: ', '').replaceAll('}', '') } // some java sources with JVM args List maybeJvmArgs = [] String maybeJvmArgsLine = lines.find { it.startsWith('// {JVMArgs: ')} if (maybeJvmArgsLine != null) { maybeJvmArgs = maybeJvmArgsLine.trim().replaceAll('\\/\\/ \\{JVMArgs: ', '').replaceAll('}', '').split(' ') } // some java sources depend on others to be run first String maybeRunFirst = null String maybeRunFirstLine = lines.find { it.startsWith('// {RunFirst: ')} if (maybeRunFirstLine != null) { maybeRunFirst = maybeRunFirstLine.trim().replaceAll('\\/\\/ \\{RunFirst: ', '').replaceAll('}', '') } // some java apps intentionally throw an exception Boolean maybeIgnoreExitValue = (validateByHand || throwsException) // some java apps need a timeout Boolean timeOutDuringTesting = false if (lines.find { it.startsWith('// {TimeOutDuringTesting}') } != null) { timeOutDuringTesting = true } // create run and test tasks if (timeOutDuringTesting) { // todo: apps with timeOutDuringTesting need special handling task "$taskName" << { println "not implemented" } } else { String basePath = it.absolutePath.replaceAll('\\.java', '') File outFile = new File(basePath + '.out') File errFile = new File(basePath + '.err') OutputStream runStandardOutput = new TeeOutputStream(new FileOutputStream(outFile), System.out) OutputStream runErrorOutput = new TeeOutputStream(new FileOutputStream(errFile), System.err) task "$taskName"(type: JavaExec, dependsOn: maybeRunFirst) { main = mainClass classpath = sourceSets.main.runtimeClasspath args = maybeArgs jvmArgs = maybeJvmArgs ignoreExitValue = maybeIgnoreExitValue standardOutput = runStandardOutput errorOutput = runErrorOutput } << { runStandardOutput.close() runErrorOutput.close() if (outFile.size() == 0) outFile.delete() if (errFile.size() == 0) errFile.delete() } } } // exclude java sources that will not compile if (willNotCompile) { sourceSets.main.java.excludes.add(it.name) } } } task run(dependsOn: tasks) } configure(subprojects - project(':onjava')) { dependencies { compile project(':onjava') } }