diff --git a/gradle/README.md b/gradle/README.md new file mode 100644 index 000000000..e11cffbbb --- /dev/null +++ b/gradle/README.md @@ -0,0 +1,75 @@ +This folder contains experimental Gradle scripts as an alternative to Bazel. +These are work-in-progress and are expected to evolve in the near future. + +## Current status + +Currently there are two sub-projects, third_party, which contains the +back-ported JUnit 4.13 code; and core, which contains all Nomulus source code. +Gradle can be used to compile and run all Java tests. + +Gradle is configured to use the existing Nomulus source tree. + +Dependencies are mostly the same as in Bazel, with a few exceptions: + +* org.slf4j:slf4j-simple is added to provide a logging implementation in + tests. Bazel does not need this. +* com.googlecode.java-diff-utils:diffutils is not included. Bazel needs it for + Truth's equality check, but Gradle works fine without it. +* jaxb 2.2.11 is used instead of 2.3 in Bazel, since the latter breaks the + ant.xjc task. The problem is reportedly fixed in jaxb 2.4. +* The other dependencies are copied from Nomulus' repository.bzl config. + * We still need to verify if there are unused dependencies. + * Many dependencies are behind their latest versions. + +### Notable Issues + +Only single-threaded test execution is allowed, due to race condition over +global resources, such as the local Datastore instance, or updates to the System +properties. This is a new problem with Gradle, which does not provide as much +test isolation as Bazel. We are exploring solutions to this problem. + +Test suites (RdeTestSuite and TmchTestSuite) are ignored to avoid duplicate +execution of tests. Neither suite performs any shared test setup routine, so it +is easier to exclude the suite classes than individual test classes. + +Since Gradle does not support hierarchical build files, all file sets (e.g., +resources) must be declared at the top, in root project config or the +sub-project configs. + +## Initial Setup + +Install Gradle 4.10.x on your local host, then run the following commands from +this directory: + +```shell +GRADLE_DIR="$(pwd)" + +(cd "${GRADLE_DIR}"; gradle init; mkdir third_party core) + +cp root.gradle "${GRADLE_DIR}/build.gradle" + +cp settings.gradle "${GRADLE_DIR}" + +cp third_party.gradle "${GRADLE_DIR}/third_party/build.gradle" + +cp core.gradle "${GRADLE_DIR}/core/build.gradle" + +cd "${GRADLE_DIR}" + +./gradlew build +``` + +The example above uses the directory with this file as working directory for +Gradle. You may use a different directory for Gradle, by assigning GRADLE_DIR to +the desired path. You will also need to update the following paths in the +.gradle files: + +* In "${GRADLE_DIR}/build.gradle", update allprojects > repositories > + flatDir > dirs to the correct location. +* In core/build.gradle, update 'javaSourceDir' and 'javatestSourceDir' to the + correct locations. +* In third_party/build.gradle, update SourceSets > main > java > srcDirs to + the correct locations. + +From now on, use './gradlew build' or './gradlew test' build and test your +changes. diff --git a/gradle/core.gradle b/gradle/core.gradle new file mode 100644 index 000000000..494c52384 --- /dev/null +++ b/gradle/core.gradle @@ -0,0 +1,206 @@ +def javaDir = "${rootDir}/../java" +def javatestsDir = "${rootDir}/../javatests" + +def generatedDir = "${project.buildDir}/generated-sources" + +sourceSets { + main { + java { + srcDirs = [ + "${javaDir}", + "${generatedDir}" + ] + } + resources { + srcDirs = [ + "${javaDir}" + ] + exclude '**/*.java', '**/*.xjb' + } + } + test { + java { + srcDirs = [ + "${javatestsDir}", + "${generatedDir}" + ] + } + resources { + srcDirs = [ + "${javatestsDir}" + ] + exclude '**/*.java', '**/*.xsd', '**/*.xjb' + } + } +} + +configurations { + css + jaxb + soy +} + +dependencies { + testImplementation project(':third_party') + + // Dependencies needed for jaxb compilation. + // Use jaxb 2.2.11 because 2.3 is known to break the Ant task we use. + // TODO: upgrade jaxb versions to 2.4.0, already in beta by Sept 2018 + jaxb 'javax.xml.bind:jaxb-api:2.2.11' + jaxb 'com.sun.xml.bind:jaxb-xjc:2.2.11' + jaxb 'com.sun.xml.bind:jaxb-impl:2.2.11' + jaxb 'com.sun.xml.bind:jaxb-osgi:2.2.11' + + // Dependency needed for soy to java compilation. + soy 'com.google.template:soy:2018-03-14' + + // Dependencies needed for compiling stylesheets to javascript + css 'com.google.closure-stylesheets:closure-stylesheets:1.5.0' + css 'args4j:args4j:2.0.26' +} + +task jaxbToJava() { + doLast { + file(generatedDir).mkdirs() + + // Temp dir to hold schema and bindings files. Files must be in the same directory because + // the bindings (.xjb) file does not declare relative paths to schema (.xsd) files. + def xjcTempSourceDir = file("${temporaryDir}/xjc") + xjcTempSourceDir.mkdirs() + ant.copy( + todir: "${xjcTempSourceDir}", + overwrite: true) { + fileSet( + dir: "${javaDir}/google/registry/xml/xsd", + includes: '**.xsd') + } + ant.copy( + todir: "${xjcTempSourceDir}", + overwrite: true, + file: + "${javaDir}/google/registry/xjc/bindings.xjb") + + ant.taskdef( + name: 'xjc', + classname: 'com.sun.tools.xjc.XJCTask', + classpath: configurations.jaxb.asPath) + ant.xjc( + destdir: "${generatedDir}", + binding: "${xjcTempSourceDir}/bindings.xjb", + removeOldOutput: 'yes', extension: 'true') { + project.fileTree( + dir: new File("$xjcTempSourceDir"), + include: ['**/*.xsd']) + .addToAntBuilder(ant, 'schema', FileCollection.AntType.FileSet) + // -npa: do not generate package-info.java files. They will be generated below. + arg(line: '-npa -quiet -extension') + } + exec { + workingDir "${generatedDir}" + + executable "${javaDir}/google/registry/xjc/make_pkginfo.sh" + args "${javaDir}/google/registry/xjc/package-info.java.in", + "${generatedDir}/google/registry/xjc" + } + } +} + +task soyToJava() { + ext.soyToJava = { javaPackage, outputDirectory, soyFiles -> + javaexec { + main = "com.google.template.soy.SoyParseInfoGenerator" + classpath configurations.soy + args "--javaPackage", "${javaPackage}", + "--outputDirectory", "${outputDirectory}", + "--javaClassNameSource", "filename", + "--allowExternalCalls", "true", + "--srcs", "${soyFiles.join(',')}" + } + } + + doLast { + + soyToJava('google.registry.tools.soy', "${generatedDir}/google/registry/tools/soy", + fileTree(dir: "${javaDir}/google/registry/tools/soy", include: ['**/*.soy'])) + + soyToJava('google.registry.ui.soy.registrar', + "${generatedDir}/google/registry/ui/soy/registrar", + fileTree(dir: "${javaDir}/google/registry/ui/soy/registrar", include: ['**/*.soy'])) + + soyToJava('google.registry.ui.soy', + "${generatedDir}/google/registry/ui/soy", + files { + file("${javaDir}/google/registry/ui/soy").listFiles() + }.filter { + it.name.endsWith(".soy") + }) + } +} + +task stylesheetsToJavascript { + ext.cssCompile = { outputName, debug, cssFiles -> + javaexec { + main = "com.google.common.css.compiler.commandline.ClosureCommandLineCompiler" + classpath configurations.css + + def argsBuffer = [ + "--output-file", "${outputName}.css", + "--output-source-map", "${outputName}.css.map", + "--input-orientation", "LTR", + "--output-orientation", "NOCHANGE", + "--output-renaming-map", "${outputName}.css.js", + "--output-renaming-map-format", "CLOSURE_COMPILED_SPLIT_HYPHENS" + ] + if (debug) { + argsBuffer.addAll(["--rename", "DEBUG", "--pretty-print"]) + } else { + argsBuffer.addAll(["--rename", "CLOSURE"]) + } + + argsBuffer.addAll(cssFiles) + args argsBuffer + } + } + + doLast { + def cssSourceDir = "${javaDir}/google/registry/ui/css" + def outputDir = "${project.buildDir}/resources/main/google/registry/ui/css" + file("${outputDir}").mkdirs() + def srcFiles = [ + "${cssSourceDir}/console.css", "${cssSourceDir}/contact-settings.css", + "${cssSourceDir}/contact-us.css", "${cssSourceDir}/dashboard.css", + "${cssSourceDir}/epp.css", "${cssSourceDir}/forms.css", + "${cssSourceDir}/kd_components.css", "${cssSourceDir}/registry.css", + "${cssSourceDir}/resources.css", "${cssSourceDir}/security-settings.css" + ] + cssCompile("${outputDir}/registrar_bin", false, srcFiles) + cssCompile("${outputDir}/registrar_dbg", true, srcFiles) + } +} + +compileJava.dependsOn jaxbToJava +compileJava.dependsOn soyToJava + +// stylesheetsToJavascript must happen after processResources, which wipes the resources folder +// before copying data into it. +stylesheetsToJavascript.dependsOn processResources +classes.dependsOn stylesheetsToJavascript + + +test { + // Test exclusion patterns: + // - *TestCase.java are inherited by concrete test classes. + // - *TestSuite.java are excluded to avoid duplicate execution of suite members. See README + // in this directory for more information. + exclude "**/*TestCase.*", "**/*TestSuite.*" + + // Use a single JVM to execute all tests. See README in this directory for more information. + maxParallelForks 1 + + // Use a single thread to execute all tests in a JVM. See README in this directory for more + // information. + forkEvery 1 + + // Uncomment to see test outputs in stdout. + //testLogging.showStandardStreams = true +} diff --git a/gradle/root.gradle b/gradle/root.gradle new file mode 100644 index 000000000..f7ca13bff --- /dev/null +++ b/gradle/root.gradle @@ -0,0 +1,175 @@ +buildscript { + repositories { + jcenter() + mavenCentral() + + maven { + url 'https://plugins.gradle.org/m2/' + } + } +} + +allprojects { + repositories { + jcenter() + mavenCentral() + flatDir { + // The objectify jar that comes with Nomulus. + dirs "${rootDir}/../third_party/objectify/v4_1" + } + } +} + +subprojects { subproject -> + version = '1.0' + + apply plugin: 'java' + apply plugin: 'java-library' + + dependencies { + implementation 'com.beust:jcommander:1.48' + implementation 'com.fasterxml.jackson.core:jackson-core:2.8.5' + implementation 'com.fasterxml.jackson.core:jackson-annotations:2.8.0' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.8.5' + implementation 'com.google.api-client:google-api-client:1.22.0' + implementation 'com.google.api-client:google-api-client-appengine:1.22.0' + implementation 'com.google.api-client:google-api-client-jackson2:1.20.0' + implementation 'com.google.monitoring-client:metrics:1.0.4' + implementation 'com.google.monitoring-client:stackdriver:1.0.4' + implementation 'com.google.monitoring-client:contrib:1.0.4' + implementation 'com.google.api-client:google-api-client-java6:1.20.0' + implementation 'com.google.api-client:google-api-client-servlet:1.22.0' + implementation 'com.google.apis:google-api-services-admin-directory:directory_v1-rev72-1.22.0' + implementation 'com.google.apis:google-api-services-bigquery:v2-rev325-1.22.0' + implementation 'com.google.apis:google-api-services-clouddebugger:v2-rev8-1.22.0' + implementation 'com.google.apis:google-api-services-cloudkms:v1-rev12-1.22.0' + implementation 'com.google.apis:google-api-services-cloudresourcemanager:v1-rev6-1.22.0' + implementation 'com.google.apis:google-api-services-dataflow:v1b3-rev196-1.22.0' + implementation 'com.google.apis:google-api-services-dns:v2beta1-rev6-1.22.0' + implementation 'com.google.apis:google-api-services-drive:v2-rev160-1.19.1' + implementation 'com.google.apis:google-api-services-groupssettings:v1-rev60-1.22.0' + implementation 'com.google.apis:google-api-services-monitoring:v3-rev11-1.22.0' + implementation 'com.google.apis:google-api-services-sheets:v4-rev483-1.22.0' + implementation 'com.google.apis:google-api-services-storage:v1-rev86-1.22.0' + implementation 'com.google.appengine:appengine-api-1.0-sdk:1.9.48' + implementation 'com.google.appengine:appengine-api-labs:1.9.48' + implementation 'com.google.appengine:appengine-api-stubs:1.9.48' + implementation 'com.google.appengine:appengine-remote-api:1.9.48' + implementation 'com.google.appengine.tools:appengine-gcs-client:0.6' + implementation 'com.google.appengine.tools:appengine-mapreduce:0.8.5' + implementation 'com.google.appengine.tools:appengine-pipeline:0.2.13' + implementation 'com.google.appengine:appengine-tools-sdk:1.9.48' + implementation 'com.google.auth:google-auth-library-credentials:0.7.1' + implementation 'com.google.auth:google-auth-library-oauth2-http:0.7.1' + implementation 'com.google.auto:auto-common:0.8' + implementation 'com.google.auto.factory:auto-factory:1.0-beta3' + implementation 'com.google.auto.service:auto-service:1.0-rc4' + implementation 'com.google.auto.value:auto-value-annotations:1.6.2' + annotationProcessor 'com.google.auto.value:auto-value:1.6.2' + implementation 'com.google.cloud.bigdataoss:gcsio:1.4.5' + implementation 'com.google.cloud.bigdataoss:util:1.4.5' + implementation 'com.google.code.findbugs:jsr305:3.0.2' + implementation 'com.google.dagger:dagger:2.15' + annotationProcessor 'com.google.dagger:dagger-compiler:2.15' + implementation 'com.google.dagger:dagger-producers:2.15' + implementation 'com.google.errorprone:error_prone_annotations:2.1.3' + implementation 'com.google.errorprone:javac-shaded:9-dev-r4023-3' + implementation 'com.google.flogger:flogger:0.1' + implementation 'com.google.flogger:flogger-system-backend:0.1' + implementation 'com.google.gdata:core:1.47.1' + implementation 'com.google.googlejavaformat:google-java-format:1.4' + implementation 'com.google.guava:guava:25.1-jre' + implementation 'com.google.http-client:google-http-client:1.22.0' + implementation 'com.google.http-client:google-http-client-appengine:1.22.0' + implementation 'com.google.http-client:google-http-client-jackson2:1.22.0' + implementation 'com.google.oauth-client:google-oauth-client:1.22.0' + implementation 'com.google.oauth-client:google-oauth-client-appengine:1.22.0' + implementation 'com.google.oauth-client:google-oauth-client-java6:1.22.0' + implementation 'com.google.oauth-client:google-oauth-client-jetty:1.22.0' + implementation 'com.google.oauth-client:google-oauth-client-servlet:1.22.0' + implementation 'com.google.protobuf:protobuf-java:2.6.0' + implementation 'com.google.re2j:re2j:1.1' + implementation 'com.google.template:soy:2018-03-14' // Bazel version (2017-06-22) not working + implementation 'com.googlecode.charts4j:charts4j:1.3' + implementation 'com.googlecode.json-simple:json-simple:1.1.1' + implementation 'com.ibm.icu:icu4j:57.1' + implementation 'com.jcraft:jsch:0.1.53' + implementation 'com.jcraft:jzlib:1.1.3' + implementation 'com.squareup:javapoet:1.8.0' + implementation 'com.squareup:javawriter:2.5.1' + implementation 'com.sun.activation:javax.activation:1.2.0' + implementation 'com.thoughtworks.paranamer:paranamer:2.7' + implementation 'commons-codec:commons-codec:1.6' + implementation 'commons-logging:commons-logging:1.1.1' + implementation 'dnsjava:dnsjava:2.1.7' + implementation 'io.netty:netty-buffer:4.1.28.Final' + implementation 'io.netty:netty-codec:4.1.28.Final' + implementation 'io.netty:netty-codec-http:4.1.28.Final' + implementation 'io.netty:netty-common:4.1.28.Final' + implementation 'io.netty:netty-handler:4.1.28.Final' + implementation 'io.netty:netty-resolver:4.1.28.Final' + implementation 'io.netty:netty-tcnative:2.0.12.Final' + implementation 'io.netty:netty-tcnative-boringssl-static:2.0.12.Final' + implementation 'io.netty:netty-transport:4.1.28.Final' + implementation 'it.unimi.dsi:fastutil:6.5.16' + implementation 'javax.annotation:jsr250-api:1.0' + implementation 'javax.inject:javax.inject:1' + implementation 'javax.mail:mail:1.4' + implementation 'javax.servlet:servlet-api:2.5' + implementation 'javax.xml.bind:jaxb-api:2.3.0' + implementation 'javax.xml.soap:javax.xml.soap-api:1.4.0' + implementation 'jline:jline:1.0' + implementation 'joda-time:joda-time:2.3' + implementation 'org.apache.avro:avro:1.8.2' + implementation 'org.apache.beam:beam-runners-direct-java:2.2.0' + implementation 'org.apache.beam:beam-runners-google-cloud-dataflow-java:2.1.0' + implementation 'org.apache.beam:beam-sdks-common-runner-api:2.1.0' + implementation 'org.apache.beam:beam-sdks-java-core:2.2.0' + implementation 'org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.1.0' + implementation 'org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.2.0' + implementation 'org.apache.commons:commons-compress:1.8.1' + implementation 'org.apache.ftpserver:ftpserver-core:1.0.6' + implementation 'org.apache.httpcomponents:httpclient:4.5.2' + implementation 'org.apache.httpcomponents:httpcore:4.4.4' + implementation 'org.apache.mina:mina-core:2.0.4' + implementation 'org.apache.sshd:sshd-core:1.2.0' + implementation 'org.apache.tomcat:servlet-api:6.0.45' + implementation 'org.apache.tomcat:tomcat-annotations-api:8.0.5' + implementation 'org.bouncycastle:bcpg-jdk15on:1.52' + implementation 'org.bouncycastle:bcpkix-jdk15on:1.52' + implementation 'org.bouncycastle:bcprov-jdk15on:1.52' + implementation 'org.codehaus.jackson:jackson-core-asl:1.9.13' + implementation 'org.codehaus.jackson:jackson-mapper-asl:1.9.13' + implementation 'org.hamcrest:hamcrest-all:1.3' + implementation 'org.hamcrest:hamcrest-core:1.3' + implementation 'org.hamcrest:hamcrest-library:1.3' + implementation 'org.joda:joda-money:0.10.0' + implementation 'org.json:json:20160810' + implementation 'org.khronos:opengl-api:gl1.1-android-2.1_r1' + implementation 'org.mortbay.jetty:jetty:6.1.26' + implementation 'org.mortbay.jetty:servlet-api:2.5-20081211' + implementation 'org.mortbay.jetty:jetty-util:6.1.26' + implementation 'org.osgi:org.osgi.core:4.3.0' + implementation 'org.slf4j:slf4j-api:1.7.16' + implementation 'org.tukaani:xz:1.5' + implementation 'org.xerial.snappy:snappy-java:1.1.4-M3' + implementation 'org.yaml:snakeyaml:1.17' + implementation 'xerces:xmlParserAPIs:2.6.2' + implementation 'xpp3:xpp3:1.1.4c' + + // Custom-built objectify jar at commit ecd5165, included in Nomulus release. + implementation name: 'objectify-4.1.3' + + // AnnotationProcessors must be declared again for tests. + testAnnotationProcessor 'com.google.auto.value:auto-value:1.6.2' + testAnnotationProcessor 'com.google.dagger:dagger-compiler:2.15' + testImplementation 'com.google.appengine:appengine-testing:1.9.58' + testImplementation 'com.google.guava:guava-testlib:25.0-jre' + testImplementation 'com.google.truth:truth:0.42' + testImplementation 'com.google.truth.extensions:truth-java8-extension:0.39' + testImplementation 'junit:junit:4.12' + testImplementation 'org.mockito:mockito-all:1.9.5' + testImplementation 'org.slf4j:slf4j-simple:1.7.16' // Not needed by Bazel + } +} + diff --git a/gradle/settings.gradle b/gradle/settings.gradle new file mode 100644 index 000000000..ac57b8028 --- /dev/null +++ b/gradle/settings.gradle @@ -0,0 +1,5 @@ +rootProject.name = 'gradle' + +include 'third_party' +include 'core' + diff --git a/gradle/third_party.gradle b/gradle/third_party.gradle new file mode 100644 index 000000000..ef278e9c7 --- /dev/null +++ b/gradle/third_party.gradle @@ -0,0 +1,10 @@ +sourceSets { + main { + java { + srcDirs = [ + "${rootDir}/../third_party/junit/" + ] + include '**/*.java' + } + } +}