Created a Kotlin node runner (#367)

* Added a cross platform node runner to replace scripts.

* Added runnodes shell and batch files back.

* Node runner supports new webserver format.

* Runnodes now runs correctly on OSX

* Intermediate commit. Squash me.

* Upgdated gradle plugins version number to 0.10.1

* Further inlined more functions.

* Text display changes for noderunner.
This commit is contained in:
Clinton 2017-03-22 14:08:23 +00:00 committed by GitHub
parent 7532ae763f
commit 9a5bba9c04
6 changed files with 133 additions and 64 deletions

View File

@ -1,4 +1,18 @@
buildscript {
// TODO: Unify with the one in the main project
ext.kotlin_version = '1.0.5-2'
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
apply plugin: 'groovy'
apply plugin: 'kotlin'
apply plugin: 'net.corda.plugins.publish-utils'
description 'A small gradle plugin for adding some basic Quasar tasks and configurations to reduce build.gradle bloat.'
@ -7,12 +21,42 @@ repositories {
mavenCentral()
}
configurations {
noderunner
compile.extendsFrom noderunner
}
sourceSets {
runnodes {
kotlin {
srcDir file('src/noderunner/kotlin')
compileClasspath += configurations.noderunner
}
}
}
dependencies {
compile gradleApi()
compile localGroovy()
noderunner "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
// TypeSafe Config: for simple and human friendly config files.
// TODO: Add a common versions file between Corda and gradle plugins to de-duplicate this version number
compile "com.typesafe:config:1.3.1"
}
task createNodeRunner(type: Jar, dependsOn: [classes]) {
manifest {
attributes('Main-Class': 'net.corda.plugins.NodeRunnerKt')
}
baseName = project.name + '-fatjar'
from { configurations.noderunner.collect { it.isDirectory() ? it : zipTree(it) } }
from sourceSets.runnodes.output
}
jar {
from(createNodeRunner) {
rename { 'net/corda/plugins/runnodes.jar' }
}
}

View File

@ -65,10 +65,14 @@ class Cordform extends DefaultTask {
* Installs the run script into the nodes directory.
*/
protected void installRunScript() {
project.copy {
from Cordformation.getPluginFile(project, "net/corda/plugins/runnodes.jar")
fileMode 0755
into "${directory}/"
}
project.copy {
from Cordformation.getPluginFile(project, "net/corda/plugins/runnodes")
filter { String line -> line.replace("NODEJAR_NAME", Node.NODEJAR_NAME) }
filter { String line -> line.replace("WEBJAR_NAME", Node.WEBJAR_NAME) }
// Replaces end of line with lf to avoid issues with the bash interpreter and Windows style line endings.
filter(FixCrLfFilter.class, eol: FixCrLfFilter.CrLf.newInstance("lf"))
fileMode 0755
@ -77,8 +81,6 @@ class Cordform extends DefaultTask {
project.copy {
from Cordformation.getPluginFile(project, "net/corda/plugins/runnodes.bat")
filter { String line -> line.replace("NODEJAR_NAME", Node.NODEJAR_NAME) }
filter { String line -> line.replace("WEBJAR_NAME", Node.WEBJAR_NAME) }
into "${directory}/"
}
}

View File

@ -1,62 +1,13 @@
#!/usr/bin/env bash
# Will attempt to execute a corda node within all subdirectories in the current working directory.
set -euo pipefail
export CAPSULE_CACHE_DIR=cache
# Allow the script to be run from outside the nodes directory.
basedir=$( dirname "$0" )
cd "$basedir"
if which osascript >/dev/null; then
# MacOS X: open each node in a in new tab.
first=true
script='tell app "Terminal"
activate'
rootdir=`pwd`
for dir in `ls`; do
if [ -d $dir ]; then
cmd="bash -c 'cd $rootdir/$dir; exec ./NODEJAR_NAME && exit'"
script="$script
tell application \"System Events\" to tell process \"Terminal\" to keystroke \"t\" using command down
delay 0.5
do script \"$cmd\" in window 1"
first=false
fi
done
# Now do the web servers.
if [[ "${NO_WEB_SERVER:-}" == "" ]]; then
for dir in `ls`; do
if [ -d $dir ]; then
cmd="bash -c 'cd $rootdir/$dir; /usr/libexec/java_home -v 1.8 --exec java -jar WEBJAR_NAME && exit'"
script="$script
tell application \"System Events\" to tell process \"Terminal\" to keystroke \"t\" using command down
delay 0.5
do script \"$cmd\" in window 1"
first=false
fi
done
fi
script="$script
end tell"
osascript -e "$script"
/usr/libexec/java_home -v 1.8 --exec java -jar runnodes.jar
else
# Some other UNIX, probably Linux (does not support msys or cygwin)
# TODO: msys and cygwin support
#
# If it is set, it means that java overrides the default system java, which is what we want.
if [ -n "${JAVA_HOME-}" ]; then
export PATH="$JAVA_HOME/bin:$PATH"
fi
for dir in `ls`; do
if [ -d $dir ]; then
pushd $dir >/dev/null
xterm -T "`basename $dir`" -e './NODEJAR_NAME' &
if [[ "${NO_WEB_SERVER:-}" == "" ]]; then
xterm -T "`basename $dir` Web Server" -e 'java -jar WEBJAR_NAME' &
fi
popd >/dev/null
fi
done
java -jar runnodes.jar
fi

View File

@ -3,13 +3,6 @@
REM Change to the directory of this script (%~dp0)
Pushd %~dp0
FOR /D %%G in (.\*) DO (
Pushd %%G
start java -jar NODEJAR_NAME
IF NOT DEFINED NO_WEB_SERVER (
start java -jar WEBJAR_NAME
)
Popd
)
java -jar runnodes.jar
Popd

View File

@ -0,0 +1,79 @@
package net.corda.plugins
import java.awt.GraphicsEnvironment
import java.io.File
import java.nio.file.Files
import java.nio.file.Paths
import java.util.Locale
private val nodeJarName = "corda.jar"
private val webJarName = "corda-webserver.jar"
private val nodeConfName = "node.conf"
fun main(args: Array<String>) {
val startedProcesses = mutableListOf<Process>()
val headless = (GraphicsEnvironment.isHeadless() || (!args.isEmpty() && (args[0] == "--headless")))
val runJar = getJarRunner(headless)
val workingDir = Paths.get(System.getProperty("user.dir")).toFile()
val javaArgs = listOf<String>() // TODO: Add args passthrough
println("Starting nodes in $workingDir")
workingDir.list().map { File(workingDir, it) }.forEach {
if (isNode(it)) {
println("Starting node in $it")
startedProcesses.add(runJar(nodeJarName, it, javaArgs))
}
if (isWebserver(it)) {
println("Starting webserver in $it")
startedProcesses.add(runJar(webJarName, it, javaArgs))
}
}
println("Started ${startedProcesses.size} processes")
println("Finished starting nodes")
}
private fun isNode(maybeNodeDir: File) = maybeNodeDir.isDirectory
&& File(maybeNodeDir, nodeJarName).exists()
&& File(maybeNodeDir, webJarName).exists()
&& File(maybeNodeDir, nodeConfName).exists()
private fun isWebserver(maybeWebserverDir: File) = isNode(maybeWebserverDir) && hasWebserverPort(maybeWebserverDir)
// TODO: Add a webserver.conf, or use TypeSafe config instead of this hack
private fun hasWebserverPort(nodeConfDir: File) = Files.readAllLines(File(nodeConfDir, nodeConfName).toPath()).joinToString { it }.contains("webAddress")
private fun getJarRunner(headless: Boolean): (String, File, List<String>) -> Process = if (headless) ::execJar else ::execJarInTerminalWindow
private fun execJar(jarName: String, dir: File, args: List<String> = listOf()): Process {
val nodeName = dir.toPath().fileName
val separator = System.getProperty("file.separator")
val path = System.getProperty("java.home") + separator + "bin" + separator + "java"
val builder = ProcessBuilder(listOf(path, "-Dname=$nodeName", "-jar", jarName) + args)
builder.redirectError(Paths.get("error.${dir.toPath().fileName}.log").toFile())
builder.inheritIO()
builder.directory(dir)
return builder.start()
}
private fun execJarInTerminalWindow(jarName: String, dir: File, args: List<String> = listOf()): Process {
val javaCmd = "java -jar $jarName " + args.joinToString(" ") { it }
val nodeName = dir.toPath().fileName + " " + jarName
val osName = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH)
val cmd = if ((osName.indexOf("mac") >= 0) || (osName.indexOf("darwin") >= 0)) {
"""osascript -e "tell app "Terminal
activate
tell application \"System Events\" to tell process \"Terminal\" to keystroke \"t\" using command down
delay 0.5
do script "bash -c 'cd $dir; /usr/libexec/java_home -v 1.8 --exec $javaCmd && exit'" in window 1"
"""
} else if (osName.indexOf("win") >= 0) {
"""cmd /C "start $javaCmd""""
} else {
// Assume Linux
"""xterm -T "$nodeName" -e $javaCmd"""
}
return Runtime.getRuntime().exec(cmd, null, dir)
}

View File

@ -1 +1 @@
gradlePluginsVersion=0.10.0
gradlePluginsVersion=0.10.1