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.concurrent.write
import kotlin.platform.platformStatic import kotlin.platform.platformStatic
val DAEMON_STARTUP_TIMEOUT_MILIS = 10000L val DAEMON_STARTUP_TIMEOUT_MS = 10000L
val DAEMON_STARTUP_CHECH_INTERVAL_MILIS = 100L val DAEMON_STARTUP_CHECK_INTERVAL_MS = 100L
public class KotlinCompilerClient { public class KotlinCompilerClient {
@@ -54,7 +54,7 @@ public class KotlinCompilerClient {
errStream.println("[daemon client] daemon not found") errStream.println("[daemon client] daemon not found")
} }
catch (e: ConnectException) { 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 // ignoring it - processing below
} }
return null return null
@@ -97,27 +97,31 @@ public class KotlinCompilerClient {
errStream.println("[daemon] " + it) errStream.println("[daemon] " + it)
} }
} }
try {
// trying to wait for process // trying to wait for process
if (daemonOptions.startEcho.isNotEmpty()) { if (daemonOptions.startEcho.isNotEmpty()) {
errStream.println("[daemon client] waiting for daemon to respond") errStream.println("[daemon client] waiting for daemon to respond")
var waitMillis: Long = DAEMON_STARTUP_TIMEOUT_MILIS / DAEMON_STARTUP_CHECH_INTERVAL_MILIS var waitMillis: Long = DAEMON_STARTUP_TIMEOUT_MS / DAEMON_STARTUP_CHECK_INTERVAL_MS
while (waitMillis-- > 0) { while (waitMillis-- > 0) {
Thread.sleep(DAEMON_STARTUP_CHECH_INTERVAL_MILIS) Thread.sleep(DAEMON_STARTUP_CHECK_INTERVAL_MS)
if (!daemon.isAlive() || lock.read { isEchoRead } == true) break; if (!daemon.isAlive() || lock.read { isEchoRead } == true) break;
} }
if (!daemon.isAlive()) if (!daemon.isAlive())
throw Exception("Daemon terminated unexpectedly") throw Exception("Daemon terminated unexpectedly")
if (lock.read { isEchoRead } == false) if (lock.read { isEchoRead } == false)
throw Exception("Unable to get response from daemon in $DAEMON_STARTUP_TIMEOUT_MILIS ms") throw Exception("Unable to get response from daemon in $DAEMON_STARTUP_TIMEOUT_MS ms")
} }
else else
// without startEcho defined waiting for max timeout // without startEcho defined waiting for max timeout
Thread.sleep(DAEMON_STARTUP_TIMEOUT_MILIS) 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 // assuming that all important output is already done, the rest should be routed to the log by the daemon itself
if (stdouThread.isAlive) if (stdouThread.isAlive)
// TODO: find better method to stop the thread, but seems it will require asynchronous consuming of the stream // 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 { public fun checkCompilerId(compiler: CompileService, localId: CompilerId, errStream: PrintStream): Boolean {
val remoteId = compiler.getCompilerId() val remoteId = compiler.getCompilerId()
@@ -127,22 +131,26 @@ public class KotlinCompilerClient {
(localId.compilerClasspath.all { remoteId.compilerClasspath.contains(it) }) (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) val service = connectToService(compilerId, daemonOptions, errStream)
if (service != null) { if (service != null) {
if (checkCompilerId(service, compilerId, errStream)) { if (!checkId || checkCompilerId(service, compilerId, errStream)) {
errStream.println("[daemon client] found the suitable daemon") errStream.println("[daemon client] found the suitable daemon")
return service return service
} }
errStream.println("[daemon client] compiler identity don't match: " + compilerId.asParams.joinToString(" ")) errStream.println("[daemon client] compiler identity don't match: " + compilerId.asParams.joinToString(" "))
if (!autostart) return null;
errStream.println("[daemon client] shutdown the daemon") errStream.println("[daemon client] shutdown the daemon")
service.shutdown() service.shutdown()
// TODO: find more reliable way // TODO: find more reliable way
Thread.sleep(1000) Thread.sleep(1000)
errStream.println("[daemon client] daemon shut down correctly, restarting") errStream.println("[daemon client] daemon shut down correctly, restarting")
} }
else else {
errStream.println("[daemon client] cannot connect to Compile Daemon, trying to start") if (!autostart) return null;
else errStream.println("[daemon client] cannot connect to Compile Daemon, trying to start")
}
startDaemon(compilerId, daemonOptions, errStream) startDaemon(compilerId, daemonOptions, errStream)
errStream.println("[daemon client] daemon started, trying to connect") errStream.println("[daemon client] daemon started, trying to connect")
return connectToService(compilerId, daemonOptions, errStream) return connectToService(compilerId, daemonOptions, errStream)
@@ -165,12 +173,24 @@ public class KotlinCompilerClient {
public fun isDaemonEnabled(): Boolean = System.getProperty(COMPILE_DAEMON_ENABLED_PROPERTY) != null 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) { platformStatic public fun main(vararg args: String) {
val compilerId = CompilerId() val compilerId = CompilerId()
val daemonOptions = DaemonOptions() val daemonOptions = DaemonOptions()
val filteredArgs = args.asIterable().propParseFilter(compilerId, daemonOptions) val clientOptions = ClientOptions()
val filteredArgs = args.asIterable().propParseFilter(compilerId, daemonOptions, clientOptions)
if (!clientOptions.stop) {
if (compilerId.compilerClasspath.none()) { if (compilerId.compilerClasspath.none()) {
// attempt to find compiler to use // attempt to find compiler to use
println("compiler wasn't explicitly specified, attempt to find appropriate jar") println("compiler wasn't explicitly specified, attempt to find appropriate jar")
@@ -178,8 +198,10 @@ public class KotlinCompilerClient {
?.split(File.pathSeparator) ?.split(File.pathSeparator)
?.map { File(it).parent } ?.map { File(it).parent }
?.distinct() ?.distinct()
?.map { it?.walk() ?.map {
?.firstOrNull { it.getName().equals(COMPILER_JAR_NAME, ignoreCase = true) } } it?.walk()
?.firstOrNull { it.getName().equals(COMPILER_JAR_NAME, ignoreCase = true) }
}
?.filterNotNull() ?.filterNotNull()
?.firstOrNull() ?.firstOrNull()
?.let { compilerId.compilerClasspath = listOf(it.absolutePath) } ?.let { compilerId.compilerClasspath = listOf(it.absolutePath) }
@@ -188,8 +210,16 @@ public class KotlinCompilerClient {
throw IllegalArgumentException("Cannot find compiler jar") throw IllegalArgumentException("Cannot find compiler jar")
else else
println("desired compiler classpath: " + compilerId.compilerClasspath.joinToString(File.pathSeparator)) println("desired compiler classpath: " + compilerId.compilerClasspath.joinToString(File.pathSeparator))
}
connectToCompileService(compilerId, daemonOptions, System.out)?.let { 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")
}
else -> {
println("Executing daemon compilation with args: " + args.joinToString(" ")) println("Executing daemon compilation with args: " + args.joinToString(" "))
val outStrm = RemoteOutputStreamServer(System.out) val outStrm = RemoteOutputStreamServer(System.out)
try { try {
@@ -206,7 +236,10 @@ public class KotlinCompilerClient {
outStrm.disconnect() 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() } ) = 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))) 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)) 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> { fun Iterable<String>.propParseFilter(parsers: List<PropParser<*,*,*>>) : Iterable<String> {
var currentParser: PropParser<*,*,*>? = null var currentParser: PropParser<*,*,*>? = null
return filter { param -> return filter { param ->
if (currentParser == null) { if (currentParser == null) {
currentParser = parsers.find { param.equals("--daemon-" + it.prop.name) } 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 true
} }
else { else {