buildscript { repositories { mavenLocal() jcenter() mavenCentral() } } plugins { id 'me.champeau.gradle.jmh' version '0.3.0' } import org.gradle.internal.jvm.Jvm import org.apache.tools.ant.util.TeeOutputStream boolean debug = false class Tags { Boolean hasMainMethod = false Boolean compileTimeError = false Boolean throwsException = false Boolean errorOutputExpected = false Boolean validateByHand = false Boolean ignoreOutput = false // This tag isn't used in the build... String fileRoot String mainClass String javaCmd = null List args = [] List jVMArgs = [] String javap = null String runFirst = null String outputLine = null private String block def Tags(File file) { block = file.text hasMainMethod = block.contains('main(String[] args)') def firstLine = block.substring(0, block.indexOf("\n")) fileRoot = (firstLine.split("/")[-1] - ".java").trim() // Remove \r if it exists mainClass = fileRoot javaCmd = extract('java') if(javaCmd) { def pieces = javaCmd.split() mainClass = pieces[0] if(pieces.size() > 1) for(p in pieces[1..-1]) if(p.startsWith("-")) jVMArgs << p else args << p } compileTimeError = hasTag('CompileTimeError') throwsException = hasTag('ThrowsException') errorOutputExpected = hasTag('ErrorOutputExpected') validateByHand = hasTag('ValidateByHand') ignoreOutput = hasTag('IgnoreOutput') javap = extract('javap') // Includes only arguments to command runFirst = extract('RunFirst:') outputLine = extractOutputLine() } private def hasTag(String marker) { return block.contains("// {" + marker + "}") } def extractOutputLine() { def matcher = (block =~ /(?m)^(\/\* Output:.*)$/) if (matcher) { return matcher[0][1] } else { return null } } private def extract(String marker) { // Assume some whitespace is after marker if(!block.contains("// {${marker} ")) return null def matcher = (block =~ /\/\/ \{${marker}\s+([^}]+)/) if (matcher) { def matched = matcher[0][1].trim() return matched.replaceAll("\n?//", "") } else { println "Searching for: " + matcher println block System.exit(1) } } public boolean hasTags() { return compileTimeError || throwsException || errorOutputExpected || validateByHand || ignoreOutput || javaCmd || args || jVMArgs || javap || runFirst } public String toString() { String result = "" block.eachLine{ ln -> if(ln.startsWith("//") || ln.startsWith("package ")) result += ln + "\n" } """ hasMainMethod compileTimeError throwsException errorOutputExpected validateByHand ignoreOutput fileRoot mainClass javaCmd args jVMArgs javap runFirst """.split().each { str -> if(this[str]) result += str + ": " + this[str] + "\n" } result } } subprojects { apply plugin: 'me.champeau.gradle.jmh' apply plugin: 'java' sourceCompatibility = '1.8' targetCompatibility = '1.8' repositories { mavenLocal() jcenter() mavenCentral() } sourceSets { main { java { srcDir projectDir } } jmh { java { srcDir projectDir } } } jmh { jmhVersion = '1.13' } List createdTasks = [] projectDir.eachFileRecurse { file -> if (file.name.endsWith('.java')) { Tags tags = new Tags(file) if(debug && tags.hasTags()) println tags // Exclude java sources that will not compile if (tags.compileTimeError) { sourceSets.main.java.excludes.add(file.name) } else { JavaExec javaTask = null // Add tasks for java sources with main methods if (tags.hasMainMethod || tags.javaCmd) { javaTask = tasks.create(name: tags.fileRoot, type: JavaExec, dependsOn: tags.runFirst) { main = tags.mainClass classpath = sourceSets.main.runtimeClasspath args = tags.args jvmArgs = tags.jVMArgs } } else if (tags.javap) { // Create task for running javap javaTask = tasks.create(name: "${tags.fileRoot}", type: JavaExec, dependsOn: tags.runFirst) { main = "com.sun.tools.javap.Main" classpath = sourceSets.main.runtimeClasspath + files(Jvm.current().toolsJar) // Assuming javap represents all the args and there's no need to jVMArgs args tags.javap.split() } } if (javaTask) { def baseName = file.name.substring(0, file.name.lastIndexOf('.')) File outFile = new File(file.parentFile, baseName + '.out') File errFile = new File(file.parentFile, baseName + '.err') javaTask.configure { ignoreExitValue = tags.validateByHand || tags.throwsException doFirst { if(outFile.exists()) outFile.delete() if(tags.outputLine) outFile << tags.outputLine + "\n" standardOutput = new TeeOutputStream(new FileOutputStream(outFile, true), System.out) errorOutput = new TeeOutputStream(new FileOutputStream(errFile), System.err) } doLast { if(outFile.size() == 0) outFile.delete() else if(!outFile.text.contains("/* Output:")) outFile.delete() if(errFile.size() == 0) errFile.delete() } } if (!tags.validateByHand) { // Only add tasks that we know we can run successfully to the task list createdTasks.add(javaTask) } } } } } task run(dependsOn: createdTasks) } project(':verifying') { dependencies { compile 'junit:junit:4.12' } jmh { include = 'verifying.jmhtests.*' } } project(':understandingcollections') { dependencies { compile project(':typeinfo') compile project(':collections') } jmh { include = 'understandingcollections.jmhtests.*' } } project(':threads') { dependencies { compile project(':enums') } } project(':strings') { dependencies { compile project(':generics') } } project(':serialization') { configurations.all { resolutionStrategy { force 'xml-apis:xml-apis:1.0.b2' } } dependencies { compile 'com.io7m.xom:xom:1.2.10' } } project(':references') { dependencies { compile 'junit:junit:4.12' } } project(':interfaces') { dependencies { compile project(':polymorphism') } } project(':hiding') { dependencies { compile project(':com') } } project(':generics') { dependencies { compile project(':typeinfo') } } project(':collections') { dependencies { compile project(':typeinfo') } } configure(subprojects - project(':onjava')) { dependencies { compile project(':onjava') compile group: 'com.google.guava', name: 'guava', version: '19.0' compile "org.openjdk.jmh:jmh-core:${jmh.jmhVersion}" compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.6.2' compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.6.2' } } task verify(type:Exec) { description 'Uses Python tool to verify example output' commandLine 'python', 'verify_output.py' doFirst { println("execute 'gradlew run' first") } }