Adding daemon stop command to kotlinr, minor fixes

This commit is contained in:
ligee
2015-08-17 12:47:14 +02:00
committed by Ilya Chernikov
parent d8be831339
commit f08476cba9
2 changed files with 99 additions and 58 deletions
@@ -31,8 +31,8 @@ import kotlin.concurrent.thread
import kotlin.concurrent.write
import kotlin.platform.platformStatic
val DAEMON_STARTUP_TIMEOUT_MILIS = 10000L
val DAEMON_STARTUP_CHECH_INTERVAL_MILIS = 100L
val DAEMON_STARTUP_TIMEOUT_MS = 10000L
val DAEMON_STARTUP_CHECK_INTERVAL_MS = 100L
public class KotlinCompilerClient {
@@ -54,7 +54,7 @@ public class KotlinCompilerClient {
errStream.println("[daemon client] daemon not found")
}
catch (e: ConnectException) {
errStream.println("[daemon client] cannot connect to registry: " + e.getMessage())
errStream.println("[daemon client] cannot connect to registry: " + (e.getCause()?.getMessage() ?: e.getMessage() ?: "unknown exception"))
// ignoring it - processing below
}
return null
@@ -97,26 +97,30 @@ public class KotlinCompilerClient {
errStream.println("[daemon] " + it)
}
}
// trying to wait for process
if (daemonOptions.startEcho.isNotEmpty()) {
errStream.println("[daemon client] waiting for daemon to respond")
var waitMillis: Long = DAEMON_STARTUP_TIMEOUT_MILIS / DAEMON_STARTUP_CHECH_INTERVAL_MILIS
while (waitMillis-- > 0) {
Thread.sleep(DAEMON_STARTUP_CHECH_INTERVAL_MILIS)
if (!daemon.isAlive() || lock.read { isEchoRead } == true) break;
try {
// trying to wait for process
if (daemonOptions.startEcho.isNotEmpty()) {
errStream.println("[daemon client] waiting for daemon to respond")
var waitMillis: Long = DAEMON_STARTUP_TIMEOUT_MS / DAEMON_STARTUP_CHECK_INTERVAL_MS
while (waitMillis-- > 0) {
Thread.sleep(DAEMON_STARTUP_CHECK_INTERVAL_MS)
if (!daemon.isAlive() || lock.read { isEchoRead } == true) break;
}
if (!daemon.isAlive())
throw Exception("Daemon terminated unexpectedly")
if (lock.read { isEchoRead } == false)
throw Exception("Unable to get response from daemon in $DAEMON_STARTUP_TIMEOUT_MS ms")
}
if (!daemon.isAlive())
throw Exception("Daemon terminated unexpectedly")
if (lock.read { isEchoRead } == false)
throw Exception("Unable to get response from daemon in $DAEMON_STARTUP_TIMEOUT_MILIS ms")
}
else
else
// without startEcho defined waiting for max timeout
Thread.sleep(DAEMON_STARTUP_TIMEOUT_MILIS)
// assuming that all important output is already done, the rest should be routed to the log by the daemon itself
if (stdouThread.isAlive)
Thread.sleep(DAEMON_STARTUP_TIMEOUT_MS)
}
finally {
// assuming that all important output is already done, the rest should be routed to the log by the daemon itself
if (stdouThread.isAlive)
// TODO: find better method to stop the thread, but seems it will require asynchronous consuming of the stream
lock.write { stdouThread.stop() }
lock.write { stdouThread.stop() }
}
}
public fun checkCompilerId(compiler: CompileService, localId: CompilerId, errStream: PrintStream): Boolean {
@@ -127,22 +131,26 @@ public class KotlinCompilerClient {
(localId.compilerClasspath.all { remoteId.compilerClasspath.contains(it) })
}
public fun connectToCompileService(compilerId: CompilerId, daemonOptions: DaemonOptions, errStream: PrintStream): CompileService? {
public fun connectToCompileService(compilerId: CompilerId, daemonOptions: DaemonOptions, errStream: PrintStream, autostart: Boolean = true, checkId: Boolean = true): CompileService? {
val service = connectToService(compilerId, daemonOptions, errStream)
if (service != null) {
if (checkCompilerId(service, compilerId, errStream)) {
if (!checkId || checkCompilerId(service, compilerId, errStream)) {
errStream.println("[daemon client] found the suitable daemon")
return service
}
errStream.println("[daemon client] compiler identity don't match: " + compilerId.asParams.joinToString(" "))
if (!autostart) return null;
errStream.println("[daemon client] shutdown the daemon")
service.shutdown()
// TODO: find more reliable way
Thread.sleep(1000)
errStream.println("[daemon client] daemon shut down correctly, restarting")
}
else
errStream.println("[daemon client] cannot connect to Compile Daemon, trying to start")
else {
if (!autostart) return null;
else errStream.println("[daemon client] cannot connect to Compile Daemon, trying to start")
}
startDaemon(compilerId, daemonOptions, errStream)
errStream.println("[daemon client] daemon started, trying to connect")
return connectToService(compilerId, daemonOptions, errStream)
@@ -165,48 +173,73 @@ public class KotlinCompilerClient {
public fun isDaemonEnabled(): Boolean = System.getProperty(COMPILE_DAEMON_ENABLED_PROPERTY) != null
data class ClientOptions(
public var stop: Boolean = false
) :CmdlineParams {
override val asParams: Iterable<String>
get() =
if (stop) listOf("stop") else listOf()
override val parsers: List<PropParser<*,*,*>>
get() = listOf( BoolPropParser(this, ::stop))
}
platformStatic public fun main(vararg args: String) {
val compilerId = CompilerId()
val daemonOptions = DaemonOptions()
val filteredArgs = args.asIterable().propParseFilter(compilerId, daemonOptions)
val clientOptions = ClientOptions()
val filteredArgs = args.asIterable().propParseFilter(compilerId, daemonOptions, clientOptions)
if (compilerId.compilerClasspath.none()) {
// attempt to find compiler to use
println("compiler wasn't explicitly specified, attempt to find appropriate jar")
System.getProperty("java.class.path")
?.split(File.pathSeparator)
?.map { File(it).parent }
?.distinct()
?.map { it?.walk()
?.firstOrNull { it.getName().equals(COMPILER_JAR_NAME, ignoreCase = true) } }
?.filterNotNull()
?.firstOrNull()
?.let { compilerId.compilerClasspath = listOf(it.absolutePath)}
if (!clientOptions.stop) {
if (compilerId.compilerClasspath.none()) {
// attempt to find compiler to use
println("compiler wasn't explicitly specified, attempt to find appropriate jar")
System.getProperty("java.class.path")
?.split(File.pathSeparator)
?.map { File(it).parent }
?.distinct()
?.map {
it?.walk()
?.firstOrNull { it.getName().equals(COMPILER_JAR_NAME, ignoreCase = true) }
}
?.filterNotNull()
?.firstOrNull()
?.let { compilerId.compilerClasspath = listOf(it.absolutePath) }
}
if (compilerId.compilerClasspath.none())
throw IllegalArgumentException("Cannot find compiler jar")
else
println("desired compiler classpath: " + compilerId.compilerClasspath.joinToString(File.pathSeparator))
}
if (compilerId.compilerClasspath.none())
throw IllegalArgumentException("Cannot find compiler jar")
else
println("desired compiler classpath: " + compilerId.compilerClasspath.joinToString(File.pathSeparator))
connectToCompileService(compilerId, daemonOptions, System.out)?.let {
println("Executing daemon compilation with args: " + args.joinToString(" "))
val outStrm = RemoteOutputStreamServer(System.out)
try {
val memBefore = it.getUsedMemory() / 1024
val startTime = System.nanoTime()
val res = it.remoteCompile(args, outStrm, CompileService.OutputFormat.PLAIN)
val endTime = System.nanoTime()
println("Compilation result code: $res")
val memAfter = it.getUsedMemory() / 1024
println("Compilation time: " + TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms")
println("Used memory $memAfter (${"%+d".format(memAfter - memBefore)} kb)")
connectToCompileService(compilerId, daemonOptions, System.out, autostart = !clientOptions.stop, checkId = !clientOptions.stop)?.let {
when {
clientOptions.stop -> {
println("Shutdown the daemon")
it.shutdown()
println("Daemon shut down successfully")
}
finally {
outStrm.disconnect()
else -> {
println("Executing daemon compilation with args: " + args.joinToString(" "))
val outStrm = RemoteOutputStreamServer(System.out)
try {
val memBefore = it.getUsedMemory() / 1024
val startTime = System.nanoTime()
val res = it.remoteCompile(args, outStrm, CompileService.OutputFormat.PLAIN)
val endTime = System.nanoTime()
println("Compilation result code: $res")
val memAfter = it.getUsedMemory() / 1024
println("Compilation time: " + TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms")
println("Used memory $memAfter (${"%+d".format(memAfter - memBefore)} kb)")
}
finally {
outStrm.disconnect()
}
}
}
?: throw Exception("Unable to connect to daemon")
}
?: if (clientOptions.stop) println("No daemon found to shut down")
else throw Exception("Unable to connect to daemon")
}
}
}
@@ -33,16 +33,24 @@ public val COMPILE_DAEMON_ENABLED_PROPERTY: String ="kotlin.daemon.enabled"
fun<C, V, P: KProperty1<C,V>> C.propToParams(p: P, conv: ((v: V) -> String) = { it.toString() } ) =
listOf("--daemon-" + p.name, conv(p.get(this)))
class PropParser<C, V, P: KMutableProperty1<C, V>>(val dest: C, val prop: P, val parse: (s: String) -> V) {
open class PropParser<C, V, P: KMutableProperty1<C, V>>(val dest: C, val prop: P, val parse: (s: String) -> V) {
fun apply(s: String) = prop.set(dest, parse(s))
}
class BoolPropParser<C, P: KMutableProperty1<C, Boolean>>(dest: C, prop: P): PropParser<C, Boolean, P>(dest, prop, { true })
fun Iterable<String>.propParseFilter(parsers: List<PropParser<*,*,*>>) : Iterable<String> {
var currentParser: PropParser<*,*,*>? = null
return filter { param ->
if (currentParser == null) {
currentParser = parsers.find { param.equals("--daemon-" + it.prop.name) }
if (currentParser != null) false
if (currentParser != null) {
if (currentParser is BoolPropParser<*,*>) {
currentParser!!.apply("")
currentParser = null
}
false
}
else true
}
else {