From 1661cea816b7ed3ec432d713028188a998b45425 Mon Sep 17 00:00:00 2001 From: Anthony Keenan <34482776+anthonykr3@users.noreply.github.com> Date: Fri, 5 Jan 2018 09:21:59 +0000 Subject: [PATCH] CORDA-892: Make cordform test use new network bootstrapper logic (#2307) * Make cordform test use new network bootstrapper logic * Fixing review comments * Fix issue with backwards compatibility * Fix issue with setup not being called from CordformDefinitions * Make sure node dir is created (as CordformDefinition uses it directly if setup is overridden Make sure tmp dir is created * Don't crash if node dir is already created * Stop overwriting errors --- constants.properties | 2 +- .../main/kotlin/net/corda/plugins/Cordform.kt | 22 ++++- .../kotlin/net/corda/plugins/Cordformation.kt | 25 ++++- .../src/main/kotlin/net/corda/plugins/Node.kt | 96 +++++++------------ .../internal/network/NetworkBootstrapper.kt | 12 ++- 5 files changed, 85 insertions(+), 72 deletions(-) diff --git a/constants.properties b/constants.properties index 5613b91279..019e9d8e1a 100644 --- a/constants.properties +++ b/constants.properties @@ -1,4 +1,4 @@ -gradlePluginsVersion=3.0.2 +gradlePluginsVersion=3.0.3 kotlinVersion=1.1.60 platformVersion=2 guavaVersion=21.0 diff --git a/gradle-plugins/cordformation/src/main/kotlin/net/corda/plugins/Cordform.kt b/gradle-plugins/cordformation/src/main/kotlin/net/corda/plugins/Cordform.kt index dc131cc8b5..1d44484eb2 100644 --- a/gradle-plugins/cordformation/src/main/kotlin/net/corda/plugins/Cordform.kt +++ b/gradle-plugins/cordformation/src/main/kotlin/net/corda/plugins/Cordform.kt @@ -22,6 +22,7 @@ import java.util.jar.JarInputStream @Suppress("unused") open class Cordform : DefaultTask() { private companion object { + val nodeJarName = "corda.jar" private val defaultDirectory: Path = Paths.get("build", "nodes") } @@ -132,9 +133,26 @@ open class Cordform : DefaultTask() { fun build() { project.logger.info("Running Cordform task") initializeConfiguration() + nodes.forEach(Node::installConfig) + installCordaJar() installRunScript() - nodes.forEach(Node::build) bootstrapNetwork() + nodes.forEach(Node::build) + } + + /** + * Installs the corda fat JAR to the root directory, for the network bootstrapper to use. + */ + private fun installCordaJar() { + val cordaJar = Cordformation.verifyAndGetRuntimeJar(project, "corda") + project.copy { + it.apply { + from(cordaJar) + into(directory) + rename(cordaJar.name, nodeJarName) + fileMode = Cordformation.executableFileMode + } + } } private fun initializeConfiguration() { @@ -150,8 +168,8 @@ open class Cordform : DefaultTask() { cd.nodeConfigurers.forEach { val node = node { } it.accept(node) + node.additionalCordapps.addAll(cordapps) node.rootDir(directory) - node.installCordapps(cordapps) } cd.setup { nodeName -> project.projectDir.toPath().resolve(getNodeByName(nodeName)!!.nodeDir.toPath()) } } else { diff --git a/gradle-plugins/cordformation/src/main/kotlin/net/corda/plugins/Cordformation.kt b/gradle-plugins/cordformation/src/main/kotlin/net/corda/plugins/Cordformation.kt index 4b722a7f03..26878fa357 100644 --- a/gradle-plugins/cordformation/src/main/kotlin/net/corda/plugins/Cordformation.kt +++ b/gradle-plugins/cordformation/src/main/kotlin/net/corda/plugins/Cordformation.kt @@ -20,14 +20,35 @@ class Cordformation : Plugin { * @return A file handle to the file in the JAR. */ fun getPluginFile(project: Project, filePathInJar: String): File { - val archive: File? = project.rootProject.buildscript.configurations + val archive = project.rootProject.buildscript.configurations .single { it.name == "classpath" } - .find { it.name.contains("cordformation") } + .first { it.name.contains("cordformation") } return project.rootProject.resources.text .fromArchiveEntry(archive, filePathInJar) .asFile() } + /** + * Gets a current built corda jar file + * + * @param project The project environment this plugin executes in. + * @param jarName The name of the JAR you wish to access. + * @return A file handle to the file in the JAR. + */ + fun verifyAndGetRuntimeJar(project: Project, jarName: String): File { + val releaseVersion = project.rootProject.ext("corda_release_version") + val maybeJar = project.configuration("runtime").filter { + "$jarName-$releaseVersion.jar" in it.toString() || "$jarName-enterprise-$releaseVersion.jar" in it.toString() + } + if (maybeJar.isEmpty) { + throw IllegalStateException("No $jarName JAR found. Have you deployed the Corda project to Maven? Looked for \"$jarName-$releaseVersion.jar\"") + } else { + val jar = maybeJar.singleFile + require(jar.isFile) + return jar + } + } + val executableFileMode = "0755".toInt(8) } diff --git a/gradle-plugins/cordformation/src/main/kotlin/net/corda/plugins/Node.kt b/gradle-plugins/cordformation/src/main/kotlin/net/corda/plugins/Node.kt index bd3842d3fa..bb16a654f8 100644 --- a/gradle-plugins/cordformation/src/main/kotlin/net/corda/plugins/Node.kt +++ b/gradle-plugins/cordformation/src/main/kotlin/net/corda/plugins/Node.kt @@ -15,8 +15,6 @@ import java.nio.file.Path */ class Node(private val project: Project) : CordformNode() { companion object { - @JvmStatic - val nodeJarName = "corda.jar" @JvmStatic val webJarName = "corda-webserver.jar" private val configFileProperty = "configFile" @@ -30,10 +28,11 @@ class Node(private val project: Project) : CordformNode() { * @note Type is any due to gradle's use of "GStrings" - each value will have "toString" called on it */ var cordapps = mutableListOf() - - private val releaseVersion = project.rootProject.ext("corda_release_version") + var additionalCordapps = mutableListOf() internal lateinit var nodeDir: File private set + internal lateinit var rootDir: File + private set /** * Sets whether this node will use HTTPS communication. @@ -65,16 +64,12 @@ class Node(private val project: Project) : CordformNode() { } internal fun build() { - configureProperties() - installCordaJar() if (config.hasPath("webAddress")) { installWebserverJar() } installAgentJar() installBuiltCordapp() installCordapps() - installConfig() - appendOptionalConfig() } internal fun rootDir(rootDir: Path) { @@ -86,7 +81,9 @@ class Node(private val project: Project) : CordformNode() { // with loading our custom X509EdDSAEngine. val organizationName = name.trim().split(",").firstOrNull { it.startsWith("O=") }?.substringAfter("=") val dirName = organizationName ?: name - nodeDir = File(rootDir.toFile(), dirName) + this.rootDir = rootDir.toFile() + nodeDir = File(this.rootDir, dirName) + Files.createDirectories(nodeDir.toPath()) } private fun configureProperties() { @@ -99,26 +96,11 @@ class Node(private val project: Project) : CordformNode() { } } - /** - * Installs the corda fat JAR to the node directory. - */ - private fun installCordaJar() { - val cordaJar = verifyAndGetRuntimeJar("corda") - project.copy { - it.apply { - from(cordaJar) - into(nodeDir) - rename(cordaJar.name, nodeJarName) - fileMode = Cordformation.executableFileMode - } - } - } - /** * Installs the corda webserver JAR to the node directory */ private fun installWebserverJar() { - val webJar = verifyAndGetRuntimeJar("corda-webserver") + val webJar = Cordformation.verifyAndGetRuntimeJar(project, "corda-webserver") project.copy { it.apply { from(webJar) @@ -141,19 +123,6 @@ class Node(private val project: Project) : CordformNode() { } } - /** - * Installs other cordapps to this node's cordapps directory. - */ - internal fun installCordapps(cordapps: Collection = getCordappList()) { - val cordappsDir = File(nodeDir, "cordapps") - project.copy { - it.apply { - from(cordapps) - into(cordappsDir) - } - } - } - /** * Installs the jolokia monitoring agent JAR to the node/drivers directory */ @@ -161,8 +130,8 @@ class Node(private val project: Project) : CordformNode() { val jolokiaVersion = project.rootProject.ext("jolokia_version") val agentJar = project.configuration("runtime").files { (it.group == "org.jolokia") && - (it.name == "jolokia-jvm") && - (it.version == jolokiaVersion) + (it.name == "jolokia-jvm") && + (it.version == jolokiaVersion) // TODO: revisit when classifier attribute is added. eg && (it.classifier = "agent") }.first() // should always be the jolokia agent fat jar: eg. jolokia-jvm-1.3.7-agent.jar project.logger.info("Jolokia agent jar: $agentJar") @@ -177,10 +146,7 @@ class Node(private val project: Project) : CordformNode() { } } - /** - * Installs the configuration file to this node's directory and detokenises it. - */ - private fun installConfig() { + private fun createTempConfigFile(): File { val options = ConfigRenderOptions .defaults() .setOriginComments(false) @@ -188,16 +154,26 @@ class Node(private val project: Project) : CordformNode() { .setFormatted(true) .setJson(false) val configFileText = config.root().render(options).split("\n").toList() - // Need to write a temporary file first to use the project.copy, which resolves directories correctly. val tmpDir = File(project.buildDir, "tmp") - val tmpConfFile = File(tmpDir, "node.conf") + Files.createDirectories(tmpDir.toPath()) + var fileName = "${nodeDir.getName()}.conf" + val tmpConfFile = File(tmpDir, fileName) Files.write(tmpConfFile.toPath(), configFileText, StandardCharsets.UTF_8) + return tmpConfFile + } + /** + * Installs the configuration file to the root directory and detokenises it. + */ + internal fun installConfig() { + configureProperties() + val tmpConfFile = createTempConfigFile() + appendOptionalConfig(tmpConfFile) project.copy { it.apply { from(tmpConfFile) - into(nodeDir) + into(rootDir) } } } @@ -205,7 +181,7 @@ class Node(private val project: Project) : CordformNode() { /** * Appends installed config file with properties from an optional file. */ - private fun appendOptionalConfig() { + private fun appendOptionalConfig(confFile: File) { val optionalConfig: File? = when { project.findProperty(configFileProperty) != null -> //provided by -PconfigFile command line property when running Gradle task File(project.findProperty(configFileProperty) as String) @@ -217,28 +193,22 @@ class Node(private val project: Project) : CordformNode() { if (!optionalConfig.exists()) { project.logger.error("$configFileProperty '$optionalConfig' not found") } else { - val confFile = File(project.buildDir.path + "/../" + nodeDir, "node.conf") confFile.appendBytes(optionalConfig.readBytes()) } } } /** - * Find the given JAR amongst the dependencies - * @param jarName JAR name without the version part, for example for corda-2.0-SNAPSHOT.jar provide only "corda" as jarName - * - * @return A file representing found JAR + * Installs other cordapps to this node's cordapps directory. */ - private fun verifyAndGetRuntimeJar(jarName: String): File { - val maybeJar = project.configuration("runtime").filter { - "$jarName-$releaseVersion.jar" in it.toString() || "$jarName-enterprise-$releaseVersion.jar" in it.toString() - } - if (maybeJar.isEmpty) { - throw IllegalStateException("No $jarName JAR found. Have you deployed the Corda project to Maven? Looked for \"$jarName-$releaseVersion.jar\"") - } else { - val jar = maybeJar.singleFile - require(jar.isFile) - return jar + internal fun installCordapps() { + additionalCordapps.addAll(getCordappList()) + val cordappsDir = File(nodeDir, "cordapps") + project.copy { + it.apply { + from(additionalCordapps) + into(cordappsDir) + } } } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/NetworkBootstrapper.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/NetworkBootstrapper.kt index af625adae5..a9b16f61e9 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/NetworkBootstrapper.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/NetworkBootstrapper.kt @@ -83,16 +83,20 @@ class NetworkBootstrapper { for (confFile in confFiles) { val nodeName = confFile.fileName.toString().removeSuffix(".conf") println("Generating directory for $nodeName") - val nodeDir = (directory / nodeName).createDirectory() - confFile.moveTo(nodeDir / "node.conf") - Files.copy(cordaJar, (nodeDir / "corda.jar")) + val nodeDir = (directory / nodeName) + if (!nodeDir.exists()) { nodeDir.createDirectory() } + confFile.moveTo(nodeDir / "node.conf", StandardCopyOption.REPLACE_EXISTING) + Files.copy(cordaJar, (nodeDir / "corda.jar"), StandardCopyOption.REPLACE_EXISTING) } Files.delete(cordaJar) } private fun extractCordaJarTo(directory: Path): Path { val cordaJarPath = (directory / "corda.jar") - Thread.currentThread().contextClassLoader.getResourceAsStream("corda.jar").copyTo(cordaJarPath) + if (!cordaJarPath.exists()) { + println("No corda jar found in root directory. Extracting from jar") + Thread.currentThread().contextClassLoader.getResourceAsStream("corda.jar").copyTo(cordaJarPath) + } return cordaJarPath }