From f08476cba94d60d917de67a433bd0567da7771ba Mon Sep 17 00:00:00 2001 From: ligee Date: Mon, 17 Aug 2015 12:47:14 +0200 Subject: [PATCH] Adding daemon stop command to kotlinr, minor fixes --- .../rmi/kotlinr/src/KotlinCompilerClient.kt | 145 +++++++++++------- .../org/jetbrains/kotlin/rmi/DaemonParams.kt | 12 +- 2 files changed, 99 insertions(+), 58 deletions(-) diff --git a/compiler/rmi/kotlinr/src/KotlinCompilerClient.kt b/compiler/rmi/kotlinr/src/KotlinCompilerClient.kt index c38fa555925..ef19a22b6cb 100644 --- a/compiler/rmi/kotlinr/src/KotlinCompilerClient.kt +++ b/compiler/rmi/kotlinr/src/KotlinCompilerClient.kt @@ -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 + get() = + if (stop) listOf("stop") else listOf() + + override val parsers: List> + 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") } } } diff --git a/compiler/rmi/rmi-interface/src/org/jetbrains/kotlin/rmi/DaemonParams.kt b/compiler/rmi/rmi-interface/src/org/jetbrains/kotlin/rmi/DaemonParams.kt index a1dfb866393..03ed6fc9ab9 100644 --- a/compiler/rmi/rmi-interface/src/org/jetbrains/kotlin/rmi/DaemonParams.kt +++ b/compiler/rmi/rmi-interface/src/org/jetbrains/kotlin/rmi/DaemonParams.kt @@ -33,16 +33,24 @@ public val COMPILE_DAEMON_ENABLED_PROPERTY: String ="kotlin.daemon.enabled" fun> C.propToParams(p: P, conv: ((v: V) -> String) = { it.toString() } ) = listOf("--daemon-" + p.name, conv(p.get(this))) -class PropParser>(val dest: C, val prop: P, val parse: (s: String) -> V) { +open class PropParser>(val dest: C, val prop: P, val parse: (s: String) -> V) { fun apply(s: String) = prop.set(dest, parse(s)) } +class BoolPropParser>(dest: C, prop: P): PropParser(dest, prop, { true }) + fun Iterable.propParseFilter(parsers: List>) : Iterable { 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 {