diff --git a/plugins/cordformation/build.gradle b/plugins/cordformation/build.gradle new file mode 100644 index 0000000000..a747670d2f --- /dev/null +++ b/plugins/cordformation/build.gradle @@ -0,0 +1,21 @@ +apply plugin: 'maven-publish' +apply plugin: 'groovy' + +dependencies { + compile gradleApi() + compile localGroovy() +} + +repositories { + mavenCentral() +} + +publishing { + publications { + plugin(MavenPublication) { + from components.java + groupId 'com.r3corda.plugins' + artifactId 'cordformation' + } + } +} \ No newline at end of file diff --git a/plugins/cordformation/src/main/groovy/com/r3corda/plugins/Cordform.groovy b/plugins/cordformation/src/main/groovy/com/r3corda/plugins/Cordform.groovy new file mode 100644 index 0000000000..986085b9d7 --- /dev/null +++ b/plugins/cordformation/src/main/groovy/com/r3corda/plugins/Cordform.groovy @@ -0,0 +1,58 @@ +package com.r3corda.plugins + +import org.gradle.api.DefaultTask +import org.gradle.api.tasks.TaskAction + +import java.nio.file.Path +import java.nio.file.Paths + +class Cordform extends DefaultTask { + protected Path directory = Paths.get("./build/nodes") + protected List nodes = new ArrayList() + protected String networkMapNodeName + + public String directory(String directory) { + this.directory = Paths.get(directory) + } + + public String networkMap(String nodeName) { + networkMapNodeName = nodeName + } + + public void node(Closure configureClosure) { + nodes << project.configure(new Node(project), configureClosure) + } + + protected Node getNodeByName(String name) { + for(Node node : nodes) { + if(node.name.equals(networkMapNodeName)) { + return node + } + } + + return null + } + + protected void installRunScript() { + project.delete("${directory}/runnodes") + project.copy { + from "buildSrc/templates/runnodes" + filter { String line -> line.replace("JAR_NAME", Node.JAR_NAME) } + filter(org.apache.tools.ant.filters.FixCrLfFilter.class, eol: org.apache.tools.ant.filters.FixCrLfFilter.CrLf.newInstance("lf")) + into "${directory}/" + } + } + + @TaskAction + def build() { + installRunScript() + Node networkMapNode = getNodeByName(networkMapNodeName) + nodes.each { + if(it != networkMapNode) { + it.networkMapAddress(networkMapNode.getArtemisAddress()) + } + it.build(directory.toFile()) + } + } +} + diff --git a/plugins/cordformation/src/main/groovy/com/r3corda/plugins/Cordformation.groovy b/plugins/cordformation/src/main/groovy/com/r3corda/plugins/Cordformation.groovy new file mode 100644 index 0000000000..8b22db6a5c --- /dev/null +++ b/plugins/cordformation/src/main/groovy/com/r3corda/plugins/Cordformation.groovy @@ -0,0 +1,10 @@ +package com.r3corda.plugins + +import org.gradle.api.Plugin +import org.gradle.api.Project + +class Cordformation implements Plugin { + void apply(Project project) { + + } +} diff --git a/plugins/cordformation/src/main/groovy/com/r3corda/plugins/Node.groovy b/plugins/cordformation/src/main/groovy/com/r3corda/plugins/Node.groovy new file mode 100644 index 0000000000..6bfac8e1ca --- /dev/null +++ b/plugins/cordformation/src/main/groovy/com/r3corda/plugins/Node.groovy @@ -0,0 +1,162 @@ +package com.r3corda.plugins + +import org.gradle.api.file.FileCollection +import org.gradle.api.internal.file.AbstractFileCollection + +class Node { + static final String JAR_NAME = 'corda.jar' + + public String name + private String dirName + private String nearestCity + private Boolean isNotary = false + private Boolean isHttps = false + private List advertisedServices = [] + private Integer artemisPort + private Integer webPort + private String networkMapAddress = "" + protected List cordapps = [] + + private File nodeDir + private def project + + void name(String name) { + this.name = name + } + + void dirName(String dirName) { + this.dirName = dirName + } + + void nearestCity(String nearestCity) { + this.nearestCity = nearestCity + } + + void notary(Boolean isNotary) { + this.isNotary = isNotary + } + + void https(Boolean isHttps) { + this.isHttps = isHttps + } + + void advertisedServices(List advertisedServices) { + this.advertisedServices = advertisedServices + } + + void artemisPort(Integer artemisPort) { + this.artemisPort = artemisPort + } + + void webPort(Integer webPort) { + this.webPort = webPort + } + + void networkMapAddress(String networkMapAddress) { + this.networkMapAddress = networkMapAddress + } + + void cordapps(List cordapps) { + this.cordapps = cordapps + } + + Node(def project) { + this.project = project + } + + void build(File baseDir) { + nodeDir = new File(baseDir, dirName) + installCordaJAR() + installBuiltPlugin() + installCordapps() + installDependencies() + installConfig() + } + + String getArtemisAddress() { + return "localhost:" + artemisPort + } + + private void installCordaJAR() { + def cordaJar = verifyAndGetCordaJar() + project.copy { + from cordaJar + into nodeDir + rename cordaJar.name, JAR_NAME + } + } + + private void installBuiltPlugin() { + def pluginsDir = getAndCreateDirectory(nodeDir, "plugins") + project.copy { + from project.jar + into pluginsDir + } + } + + private void installCordapps() { + def pluginsDir = getAndCreateDirectory(nodeDir, "plugins") + def cordapps = getCordappList() + project.copy { + from cordapps + into pluginsDir + } + } + + private void installDependencies() { + def cordaJar = verifyAndGetCordaJar() + def cordappList = getCordappList() + def depsDir = getAndCreateDirectory(nodeDir, "dependencies") + def appDeps = project.configurations.runtime.filter { it != cordaJar && !cordappList.contains(it) } + project.copy { + from appDeps + into depsDir + } + } + + private void installConfig() { + project.copy { + from ('./buildSrc/templates/nodetemplate.conf') { + filter { it + .replaceAll('@@name@@', name) + .replaceAll('@@dirName@@', dirName) + .replaceAll('@@nearestCity@@', nearestCity) + .replaceAll('@@isNotary@@', isNotary.toString()) + .replaceAll('@@isHttps@@', isHttps.toString()) + .replaceAll('@@advertisedServices@@', advertisedServices.join(",")) + .replaceAll('@@networkMapAddress@@', networkMapAddress) + .replaceAll('@@artemisPort@@', artemisPort.toString()) + .replaceAll('@@webPort@@', webPort.toString()) + } + } + into nodeDir + rename 'nodetemplate.conf', 'node.conf' + } + } + + private File verifyAndGetCordaJar() { + def maybeCordaJAR = project.configurations.runtime.filter { it.toString().contains("corda-${project.corda_version}.jar")} + if(maybeCordaJAR.size() == 0) { + throw new RuntimeException("No Corda Capsule JAR found. Have you deployed the Corda project to Maven?") + } else { + def cordaJar = maybeCordaJAR.getSingleFile() + assert(cordaJar.isFile()) + return cordaJar + } + } + + private AbstractFileCollection getCordappList() { + def cordaJar = verifyAndGetCordaJar() + return project.configurations.runtime.filter { + def jarName = it.name.split('-').first() + return (it != cordaJar) && cordapps.contains(jarName) + } + } + + private static File getAndCreateDirectory(File baseDir, String subDirName) { + File dir = new File(baseDir, subDirName) + assert(!dir.exists() || dir.isDirectory()) + dir.mkdirs() + return dir + } +} diff --git a/plugins/cordformation/src/main/resources/META-INF/gradle-plugins/com.r3corda.plugins.cordformation.properties b/plugins/cordformation/src/main/resources/META-INF/gradle-plugins/com.r3corda.plugins.cordformation.properties new file mode 100644 index 0000000000..e8873b3702 --- /dev/null +++ b/plugins/cordformation/src/main/resources/META-INF/gradle-plugins/com.r3corda.plugins.cordformation.properties @@ -0,0 +1 @@ +implementation-class=com.r3corda.plugins.Cordformation \ No newline at end of file diff --git a/plugins/cordformation/src/main/resources/templates/nodetemplate.conf b/plugins/cordformation/src/main/resources/templates/nodetemplate.conf new file mode 100644 index 0000000000..7b78453ef4 --- /dev/null +++ b/plugins/cordformation/src/main/resources/templates/nodetemplate.conf @@ -0,0 +1,11 @@ +basedir : "@@dirName@@" +myLegalName : "@@name@@" +nearestCity : "@@nearestCity@@" +keyStorePassword : "cordacadevpass" +trustStorePassword : "trustpass" +artemisAddress : "localhost:@@artemisPort@@" +webAddress : "localhost:@@webPort@@" +hostNotaryServiceLocally: @@isNotary@@ +extraAdvertisedServiceIds: "@@advertisedServices@@" +networkMapAddress : "@@networkMapAddress@@" +useHTTPS : @@isHttps@@ diff --git a/plugins/cordformation/src/main/resources/templates/runnodes b/plugins/cordformation/src/main/resources/templates/runnodes new file mode 100644 index 0000000000..0e35591945 --- /dev/null +++ b/plugins/cordformation/src/main/resources/templates/runnodes @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# Will attempt to execute a corda node within all subdirectories in the current working directory. + +set -euo pipefail +trap 'kill $(jobs -p)' SIGINT SIGTERM EXIT +export CAPSULE_CACHE_DIR=cache + +function runNode { + pushd $1 + ( java -jar JAR_NAME )& + popd +} + +for dir in `ls`; do + if [ -d $dir ]; then + runNode $dir + fi +done + +read -p 'Any key to exit' +kill $(jobs -p) diff --git a/settings.gradle b/settings.gradle index 13565e83c8..3797582527 100644 --- a/settings.gradle +++ b/settings.gradle @@ -10,4 +10,5 @@ include 'network-simulator' include 'explorer' include 'plugins:quasar-utils' include 'plugins:publish-utils' +include 'plugins:cordformation' include 'docs/source/example-code'