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: 'groovy'
apply plugin: 'kotlin'
apply plugin: 'net.corda.plugins.publish-utils' 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.' description 'A small gradle plugin for adding some basic Quasar tasks and configurations to reduce build.gradle bloat.'
@ -7,12 +21,42 @@ repositories {
mavenCentral() mavenCentral()
} }
configurations {
noderunner
compile.extendsFrom noderunner
}
sourceSets {
runnodes {
kotlin {
srcDir file('src/noderunner/kotlin')
compileClasspath += configurations.noderunner
}
}
}
dependencies { dependencies {
compile gradleApi() compile gradleApi()
compile localGroovy() compile localGroovy()
noderunner "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
// TypeSafe Config: for simple and human friendly config files. // 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 // TODO: Add a common versions file between Corda and gradle plugins to de-duplicate this version number
compile "com.typesafe:config:1.3.1" 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. * Installs the run script into the nodes directory.
*/ */
protected void installRunScript() { protected void installRunScript() {
project.copy {
from Cordformation.getPluginFile(project, "net/corda/plugins/runnodes.jar")
fileMode 0755
into "${directory}/"
}
project.copy { project.copy {
from Cordformation.getPluginFile(project, "net/corda/plugins/runnodes") 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. // 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")) filter(FixCrLfFilter.class, eol: FixCrLfFilter.CrLf.newInstance("lf"))
fileMode 0755 fileMode 0755
@ -77,8 +81,6 @@ class Cordform extends DefaultTask {
project.copy { project.copy {
from Cordformation.getPluginFile(project, "net/corda/plugins/runnodes.bat") 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}/" into "${directory}/"
} }
} }

View File

@ -1,62 +1,13 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Will attempt to execute a corda node within all subdirectories in the current working directory.
set -euo pipefail set -euo pipefail
export CAPSULE_CACHE_DIR=cache
# Allow the script to be run from outside the nodes directory. # Allow the script to be run from outside the nodes directory.
basedir=$( dirname "$0" ) basedir=$( dirname "$0" )
cd "$basedir" cd "$basedir"
if which osascript >/dev/null; then if which osascript >/dev/null; then
# MacOS X: open each node in a in new tab. /usr/libexec/java_home -v 1.8 --exec java -jar runnodes.jar
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"
else else
# Some other UNIX, probably Linux (does not support msys or cygwin) java -jar runnodes.jar
# 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
fi fi

View File

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