[Daemon] Apply autoformatting to KotlinCompilerClient.kt
This commit is contained in:
committed by
Space Team
parent
628f6e981d
commit
02b1f9854f
+206
-134
@@ -25,7 +25,6 @@ import org.jetbrains.kotlin.incremental.components.LookupTracker
|
|||||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
|
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
|
||||||
import org.jetbrains.kotlin.progress.CompilationCanceledStatus
|
import org.jetbrains.kotlin.progress.CompilationCanceledStatus
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.OutputStream
|
|
||||||
import java.io.PrintStream
|
import java.io.PrintStream
|
||||||
import java.net.SocketException
|
import java.net.SocketException
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
@@ -38,65 +37,70 @@ import java.util.concurrent.TimeUnit
|
|||||||
import kotlin.concurrent.thread
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
class CompilationServices(
|
class CompilationServices(
|
||||||
val incrementalCompilationComponents: IncrementalCompilationComponents? = null,
|
val incrementalCompilationComponents: IncrementalCompilationComponents? = null,
|
||||||
val lookupTracker: LookupTracker? = null,
|
val lookupTracker: LookupTracker? = null,
|
||||||
val compilationCanceledStatus: CompilationCanceledStatus? = null
|
val compilationCanceledStatus: CompilationCanceledStatus? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class CompileServiceSession(val compileService: CompileService, val sessionId: Int)
|
data class CompileServiceSession(val compileService: CompileService, val sessionId: Int)
|
||||||
|
|
||||||
object KotlinCompilerClient {
|
object KotlinCompilerClient {
|
||||||
|
|
||||||
val DAEMON_DEFAULT_STARTUP_TIMEOUT_MS = 10000L
|
private const val DAEMON_DEFAULT_STARTUP_TIMEOUT_MS = 10000L
|
||||||
val DAEMON_CONNECT_CYCLE_ATTEMPTS = 3
|
private const val DAEMON_CONNECT_CYCLE_ATTEMPTS = 3
|
||||||
|
|
||||||
val verboseReporting = CompilerSystemProperties.COMPILE_DAEMON_VERBOSE_REPORT_PROPERTY.value != null
|
val verboseReporting = CompilerSystemProperties.COMPILE_DAEMON_VERBOSE_REPORT_PROPERTY.value != null
|
||||||
|
|
||||||
fun getOrCreateClientFlagFile(daemonOptions: DaemonOptions): File =
|
fun getOrCreateClientFlagFile(daemonOptions: DaemonOptions): File =
|
||||||
// for jps property is passed from IDEA to JPS in KotlinBuildProcessParametersProvider
|
// for jps property is passed from IDEA to JPS in KotlinBuildProcessParametersProvider
|
||||||
CompilerSystemProperties.COMPILE_DAEMON_CLIENT_ALIVE_PATH_PROPERTY.value
|
CompilerSystemProperties.COMPILE_DAEMON_CLIENT_ALIVE_PATH_PROPERTY.value
|
||||||
?.let(String::trimQuotes)
|
?.let(String::trimQuotes)
|
||||||
?.takeUnless(String::isBlank)
|
?.takeUnless(String::isBlank)
|
||||||
?.let(::File)
|
?.let(::File)
|
||||||
?.takeIf(File::exists)
|
?.takeIf(File::exists)
|
||||||
?: makeAutodeletingFlagFile(baseDir = File(daemonOptions.runFilesPathOrDefault))
|
?: makeAutodeletingFlagFile(baseDir = File(daemonOptions.runFilesPathOrDefault))
|
||||||
|
|
||||||
fun connectToCompileService(compilerId: CompilerId,
|
fun connectToCompileService(
|
||||||
daemonJVMOptions: DaemonJVMOptions,
|
compilerId: CompilerId,
|
||||||
daemonOptions: DaemonOptions,
|
daemonJVMOptions: DaemonJVMOptions,
|
||||||
reportingTargets: DaemonReportingTargets,
|
daemonOptions: DaemonOptions,
|
||||||
autostart: Boolean = true,
|
reportingTargets: DaemonReportingTargets,
|
||||||
@Suppress("UNUSED_PARAMETER") checkId: Boolean = true
|
autostart: Boolean = true,
|
||||||
|
@Suppress("UNUSED_PARAMETER") checkId: Boolean = true,
|
||||||
): CompileService? {
|
): CompileService? {
|
||||||
val flagFile = getOrCreateClientFlagFile(daemonOptions)
|
val flagFile = getOrCreateClientFlagFile(daemonOptions)
|
||||||
return connectToCompileService(compilerId, flagFile, daemonJVMOptions, daemonOptions, reportingTargets, autostart)
|
return connectToCompileService(compilerId, flagFile, daemonJVMOptions, daemonOptions, reportingTargets, autostart)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun connectToCompileService(compilerId: CompilerId,
|
fun connectToCompileService(
|
||||||
clientAliveFlagFile: File,
|
compilerId: CompilerId,
|
||||||
daemonJVMOptions: DaemonJVMOptions,
|
clientAliveFlagFile: File,
|
||||||
daemonOptions: DaemonOptions,
|
daemonJVMOptions: DaemonJVMOptions,
|
||||||
reportingTargets: DaemonReportingTargets,
|
daemonOptions: DaemonOptions,
|
||||||
autostart: Boolean = true
|
reportingTargets: DaemonReportingTargets,
|
||||||
|
autostart: Boolean = true,
|
||||||
): CompileService? =
|
): CompileService? =
|
||||||
connectAndLease(compilerId,
|
connectAndLease(
|
||||||
clientAliveFlagFile,
|
compilerId,
|
||||||
daemonJVMOptions,
|
clientAliveFlagFile,
|
||||||
daemonOptions,
|
daemonJVMOptions,
|
||||||
reportingTargets,
|
daemonOptions,
|
||||||
autostart,
|
reportingTargets,
|
||||||
leaseSession = false,
|
autostart,
|
||||||
sessionAliveFlagFile = null)?.compileService
|
leaseSession = false,
|
||||||
|
sessionAliveFlagFile = null
|
||||||
|
)?.compileService
|
||||||
|
|
||||||
|
|
||||||
fun connectAndLease(compilerId: CompilerId,
|
fun connectAndLease(
|
||||||
clientAliveFlagFile: File,
|
compilerId: CompilerId,
|
||||||
daemonJVMOptions: DaemonJVMOptions,
|
clientAliveFlagFile: File,
|
||||||
daemonOptions: DaemonOptions,
|
daemonJVMOptions: DaemonJVMOptions,
|
||||||
reportingTargets: DaemonReportingTargets,
|
daemonOptions: DaemonOptions,
|
||||||
autostart: Boolean,
|
reportingTargets: DaemonReportingTargets,
|
||||||
leaseSession: Boolean,
|
autostart: Boolean,
|
||||||
sessionAliveFlagFile: File? = null
|
leaseSession: Boolean,
|
||||||
|
sessionAliveFlagFile: File? = null,
|
||||||
): CompileServiceSession? = connectLoop(reportingTargets, autostart) { isLastAttempt ->
|
): CompileServiceSession? = connectLoop(reportingTargets, autostart) { isLastAttempt ->
|
||||||
|
|
||||||
fun CompileService.leaseImpl(): CompileServiceSession? {
|
fun CompileService.leaseImpl(): CompileServiceSession? {
|
||||||
@@ -112,12 +116,15 @@ object KotlinCompilerClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ensureServerHostnameIsSetUp()
|
ensureServerHostnameIsSetUp()
|
||||||
val (service, newJVMOptions) = tryFindSuitableDaemonOrNewOpts(File(daemonOptions.runFilesPath), compilerId, daemonJVMOptions, { cat, msg -> reportingTargets.report(cat, msg) })
|
val (service, newJVMOptions) = tryFindSuitableDaemonOrNewOpts(
|
||||||
|
File(daemonOptions.runFilesPath),
|
||||||
|
compilerId,
|
||||||
|
daemonJVMOptions
|
||||||
|
) { cat, msg -> reportingTargets.report(cat, msg) }
|
||||||
|
|
||||||
if (service != null) {
|
if (service != null) {
|
||||||
service.leaseImpl()
|
service.leaseImpl()
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (!isLastAttempt && autostart) {
|
if (!isLastAttempt && autostart) {
|
||||||
if (startDaemon(compilerId, newJVMOptions, daemonOptions, reportingTargets)) {
|
if (startDaemon(compilerId, newJVMOptions, daemonOptions, reportingTargets)) {
|
||||||
reportingTargets.report(DaemonReportCategory.DEBUG, "new daemon started, trying to find it")
|
reportingTargets.report(DaemonReportCategory.DEBUG, "new daemon started, trying to find it")
|
||||||
@@ -128,8 +135,15 @@ object KotlinCompilerClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun shutdownCompileService(compilerId: CompilerId, daemonOptions: DaemonOptions): Unit {
|
fun shutdownCompileService(compilerId: CompilerId, daemonOptions: DaemonOptions): Unit {
|
||||||
connectToCompileService(compilerId, DaemonJVMOptions(), daemonOptions, DaemonReportingTargets(out = System.out), autostart = false, checkId = false)
|
connectToCompileService(
|
||||||
?.shutdown()
|
compilerId,
|
||||||
|
DaemonJVMOptions(),
|
||||||
|
daemonOptions,
|
||||||
|
DaemonReportingTargets(out = System.out),
|
||||||
|
autostart = false,
|
||||||
|
checkId = false
|
||||||
|
)
|
||||||
|
?.shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -139,40 +153,47 @@ object KotlinCompilerClient {
|
|||||||
|
|
||||||
|
|
||||||
fun leaseCompileSession(compilerService: CompileService, aliveFlagPath: String?): Int =
|
fun leaseCompileSession(compilerService: CompileService, aliveFlagPath: String?): Int =
|
||||||
compilerService.leaseCompileSession(aliveFlagPath).get()
|
compilerService.leaseCompileSession(aliveFlagPath).get()
|
||||||
|
|
||||||
fun releaseCompileSession(compilerService: CompileService, sessionId: Int): Unit {
|
fun releaseCompileSession(compilerService: CompileService, sessionId: Int): Unit {
|
||||||
compilerService.releaseCompileSession(sessionId)
|
compilerService.releaseCompileSession(sessionId)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun compile(compilerService: CompileService,
|
fun compile(
|
||||||
sessionId: Int,
|
compilerService: CompileService,
|
||||||
targetPlatform: CompileService.TargetPlatform,
|
sessionId: Int,
|
||||||
args: Array<out String>,
|
targetPlatform: CompileService.TargetPlatform,
|
||||||
messageCollector: MessageCollector,
|
args: Array<out String>,
|
||||||
outputsCollector: ((File, List<File>) -> Unit)? = null,
|
messageCollector: MessageCollector,
|
||||||
compilerMode: CompilerMode = CompilerMode.NON_INCREMENTAL_COMPILER,
|
outputsCollector: ((File, List<File>) -> Unit)? = null,
|
||||||
reportSeverity: ReportSeverity = ReportSeverity.INFO,
|
compilerMode: CompilerMode = CompilerMode.NON_INCREMENTAL_COMPILER,
|
||||||
port: Int = SOCKET_ANY_FREE_PORT,
|
reportSeverity: ReportSeverity = ReportSeverity.INFO,
|
||||||
profiler: Profiler = DummyProfiler()
|
port: Int = SOCKET_ANY_FREE_PORT,
|
||||||
|
profiler: Profiler = DummyProfiler(),
|
||||||
): Int = profiler.withMeasure(this) {
|
): Int = profiler.withMeasure(this) {
|
||||||
val services = BasicCompilerServicesWithResultsFacadeServer(messageCollector, outputsCollector, port)
|
val services = BasicCompilerServicesWithResultsFacadeServer(messageCollector, outputsCollector, port)
|
||||||
compilerService.compile(
|
compilerService.compile(
|
||||||
sessionId,
|
sessionId,
|
||||||
args,
|
args,
|
||||||
CompilationOptions(
|
CompilationOptions(
|
||||||
compilerMode,
|
compilerMode,
|
||||||
targetPlatform,
|
targetPlatform,
|
||||||
arrayOf(ReportCategory.COMPILER_MESSAGE.code, ReportCategory.DAEMON_MESSAGE.code, ReportCategory.EXCEPTION.code, ReportCategory.OUTPUT_MESSAGE.code),
|
arrayOf(
|
||||||
reportSeverity.code,
|
ReportCategory.COMPILER_MESSAGE.code,
|
||||||
emptyArray()),
|
ReportCategory.DAEMON_MESSAGE.code,
|
||||||
services,
|
ReportCategory.EXCEPTION.code,
|
||||||
null
|
ReportCategory.OUTPUT_MESSAGE.code
|
||||||
|
),
|
||||||
|
reportSeverity.code,
|
||||||
|
emptyArray()
|
||||||
|
),
|
||||||
|
services,
|
||||||
|
null
|
||||||
).get()
|
).get()
|
||||||
}
|
}
|
||||||
|
|
||||||
data class ClientOptions(
|
data class ClientOptions(
|
||||||
var stop: Boolean = false
|
var stop: Boolean = false,
|
||||||
) : OptionsGroup {
|
) : OptionsGroup {
|
||||||
override val mappers: List<PropMapper<*, *, *>>
|
override val mappers: List<PropMapper<*, *, *>>
|
||||||
get() = listOf(BoolPropMapper(this, ClientOptions::stop))
|
get() = listOf(BoolPropMapper(this, ClientOptions::stop))
|
||||||
@@ -183,8 +204,11 @@ object KotlinCompilerClient {
|
|||||||
val unrecognized = it.trimQuotes().split(",").filterExtractProps(opts.mappers, "")
|
val unrecognized = it.trimQuotes().split(",").filterExtractProps(opts.mappers, "")
|
||||||
if (unrecognized.any())
|
if (unrecognized.any())
|
||||||
throw IllegalArgumentException(
|
throw IllegalArgumentException(
|
||||||
"Unrecognized client options passed via property ${CompilerSystemProperties.COMPILE_DAEMON_CLIENT_OPTIONS_PROPERTY.property}: " + unrecognized.joinToString(" ") +
|
"Unrecognized client options passed via property ${CompilerSystemProperties.COMPILE_DAEMON_CLIENT_OPTIONS_PROPERTY.property}: " + unrecognized.joinToString(
|
||||||
"\nSupported options: " + opts.mappers.joinToString(", ", transform = { it.names.first() }))
|
" "
|
||||||
|
) +
|
||||||
|
"\nSupported options: " + opts.mappers.joinToString(", ", transform = { it.names.first() })
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return opts
|
return opts
|
||||||
}
|
}
|
||||||
@@ -196,16 +220,23 @@ object KotlinCompilerClient {
|
|||||||
fun main(vararg args: String) {
|
fun main(vararg args: String) {
|
||||||
val compilerId = CompilerId()
|
val compilerId = CompilerId()
|
||||||
val daemonOptions = configureDaemonOptions()
|
val daemonOptions = configureDaemonOptions()
|
||||||
val daemonLaunchingOptions = configureDaemonJVMOptions(inheritMemoryLimits = true, inheritOtherJvmOptions = false, inheritAdditionalProperties = true)
|
val daemonLaunchingOptions =
|
||||||
|
configureDaemonJVMOptions(inheritMemoryLimits = true, inheritOtherJvmOptions = false, inheritAdditionalProperties = true)
|
||||||
val clientOptions = configureClientOptions()
|
val clientOptions = configureClientOptions()
|
||||||
val filteredArgs = args.asIterable().filterExtractProps(compilerId, daemonOptions, daemonLaunchingOptions, clientOptions, prefix = COMPILE_DAEMON_CMDLINE_OPTIONS_PREFIX)
|
val filteredArgs = args.asIterable().filterExtractProps(
|
||||||
|
compilerId,
|
||||||
|
daemonOptions,
|
||||||
|
daemonLaunchingOptions,
|
||||||
|
clientOptions,
|
||||||
|
prefix = COMPILE_DAEMON_CMDLINE_OPTIONS_PREFIX
|
||||||
|
)
|
||||||
|
|
||||||
if (!clientOptions.stop) {
|
if (!clientOptions.stop) {
|
||||||
if (compilerId.compilerClasspath.none()) {
|
if (compilerId.compilerClasspath.none()) {
|
||||||
// attempt to find compiler to use
|
// attempt to find compiler to use
|
||||||
System.err.println("compiler wasn't explicitly specified, attempt to find appropriate jar")
|
System.err.println("compiler wasn't explicitly specified, attempt to find appropriate jar")
|
||||||
detectCompilerClasspath()
|
detectCompilerClasspath()
|
||||||
?.let { compilerId.compilerClasspath = it }
|
?.let { compilerId.compilerClasspath = it }
|
||||||
}
|
}
|
||||||
if (compilerId.compilerClasspath.none())
|
if (compilerId.compilerClasspath.none())
|
||||||
throw IllegalArgumentException("Cannot find compiler jar")
|
throw IllegalArgumentException("Cannot find compiler jar")
|
||||||
@@ -213,15 +244,20 @@ object KotlinCompilerClient {
|
|||||||
println("desired compiler classpath: " + compilerId.compilerClasspath.joinToString(File.pathSeparator))
|
println("desired compiler classpath: " + compilerId.compilerClasspath.joinToString(File.pathSeparator))
|
||||||
}
|
}
|
||||||
|
|
||||||
val daemon = connectToCompileService(compilerId, daemonLaunchingOptions, daemonOptions, DaemonReportingTargets(out = System.out), autostart = !clientOptions.stop, checkId = !clientOptions.stop)
|
val daemon = connectToCompileService(
|
||||||
|
compilerId,
|
||||||
|
daemonLaunchingOptions,
|
||||||
|
daemonOptions,
|
||||||
|
DaemonReportingTargets(out = System.out),
|
||||||
|
autostart = !clientOptions.stop,
|
||||||
|
checkId = !clientOptions.stop
|
||||||
|
)
|
||||||
|
|
||||||
if (daemon == null) {
|
if (daemon == null) {
|
||||||
if (clientOptions.stop) {
|
if (clientOptions.stop) {
|
||||||
System.err.println("No daemon found to shut down")
|
System.err.println("No daemon found to shut down")
|
||||||
}
|
} else throw Exception("Unable to connect to daemon")
|
||||||
else throw Exception("Unable to connect to daemon")
|
} else when {
|
||||||
}
|
|
||||||
else when {
|
|
||||||
clientOptions.stop -> {
|
clientOptions.stop -> {
|
||||||
println("Shutdown the daemon")
|
println("Shutdown the daemon")
|
||||||
daemon.shutdown()
|
daemon.shutdown()
|
||||||
@@ -229,7 +265,13 @@ object KotlinCompilerClient {
|
|||||||
}
|
}
|
||||||
filteredArgs.none() -> {
|
filteredArgs.none() -> {
|
||||||
// so far used only in tests
|
// so far used only in tests
|
||||||
println("Warning: empty arguments list, only daemon check is performed: checkCompilerId() returns ${daemon.checkCompilerId(compilerId)}")
|
println(
|
||||||
|
"Warning: empty arguments list, only daemon check is performed: checkCompilerId() returns ${
|
||||||
|
daemon.checkCompilerId(
|
||||||
|
compilerId
|
||||||
|
)
|
||||||
|
}"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
println("Executing daemon compilation with args: " + filteredArgs.joinToString(" "))
|
println("Executing daemon compilation with args: " + filteredArgs.joinToString(" "))
|
||||||
@@ -247,7 +289,7 @@ object KotlinCompilerClient {
|
|||||||
override fun hasErrors() = hasErrors
|
override fun hasErrors() = hasErrors
|
||||||
}
|
}
|
||||||
|
|
||||||
val outputsCollector = { x: File, y: List<File> -> println("$x $y") }
|
val outputsCollector = { x: File, y: List<File> -> println("$x $y") }
|
||||||
val servicesFacade = BasicCompilerServicesWithResultsFacadeServer(messageCollector, outputsCollector)
|
val servicesFacade = BasicCompilerServicesWithResultsFacadeServer(messageCollector, outputsCollector)
|
||||||
try {
|
try {
|
||||||
val memBefore = daemon.getUsedMemory().get() / 1024
|
val memBefore = daemon.getUsedMemory().get() / 1024
|
||||||
@@ -256,7 +298,12 @@ object KotlinCompilerClient {
|
|||||||
val compilationOptions = CompilationOptions(
|
val compilationOptions = CompilationOptions(
|
||||||
CompilerMode.NON_INCREMENTAL_COMPILER,
|
CompilerMode.NON_INCREMENTAL_COMPILER,
|
||||||
CompileService.TargetPlatform.JVM,
|
CompileService.TargetPlatform.JVM,
|
||||||
arrayOf(ReportCategory.COMPILER_MESSAGE.code, ReportCategory.DAEMON_MESSAGE.code, ReportCategory.EXCEPTION.code, ReportCategory.OUTPUT_MESSAGE.code),
|
arrayOf(
|
||||||
|
ReportCategory.COMPILER_MESSAGE.code,
|
||||||
|
ReportCategory.DAEMON_MESSAGE.code,
|
||||||
|
ReportCategory.EXCEPTION.code,
|
||||||
|
ReportCategory.OUTPUT_MESSAGE.code
|
||||||
|
),
|
||||||
ReportSeverity.INFO.code,
|
ReportSeverity.INFO.code,
|
||||||
emptyArray()
|
emptyArray()
|
||||||
)
|
)
|
||||||
@@ -275,8 +322,7 @@ object KotlinCompilerClient {
|
|||||||
val memAfter = daemon.getUsedMemory().get() / 1024
|
val memAfter = daemon.getUsedMemory().get() / 1024
|
||||||
println("Compilation time: " + TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms")
|
println("Compilation time: " + TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms")
|
||||||
println("Used memory $memAfter (${"%+d".format(memAfter - memBefore)} kb)")
|
println("Used memory $memAfter (${"%+d".format(memAfter - memBefore)} kb)")
|
||||||
}
|
} finally {
|
||||||
finally {
|
|
||||||
// forcing RMI to unregister all objects and stop
|
// forcing RMI to unregister all objects and stop
|
||||||
UnicastRemoteObject.unexportObject(servicesFacade, true)
|
UnicastRemoteObject.unexportObject(servicesFacade, true)
|
||||||
}
|
}
|
||||||
@@ -291,7 +337,7 @@ object KotlinCompilerClient {
|
|||||||
?.distinct()
|
?.distinct()
|
||||||
?.mapNotNull {
|
?.mapNotNull {
|
||||||
it?.walk()
|
it?.walk()
|
||||||
?.firstOrNull { it.name.equals(COMPILER_JAR_NAME, ignoreCase = true) }
|
?.firstOrNull { it.name.equals(COMPILER_JAR_NAME, ignoreCase = true) }
|
||||||
}
|
}
|
||||||
?.firstOrNull()
|
?.firstOrNull()
|
||||||
?.let { listOf(it.absolutePath) }
|
?.let { listOf(it.absolutePath) }
|
||||||
@@ -299,81 +345,100 @@ object KotlinCompilerClient {
|
|||||||
// --- Implementation ---------------------------------------
|
// --- Implementation ---------------------------------------
|
||||||
|
|
||||||
private inline fun <R> connectLoop(
|
private inline fun <R> connectLoop(
|
||||||
reportingTargets: DaemonReportingTargets, autostart: Boolean, body: (Boolean) -> R?
|
reportingTargets: DaemonReportingTargets, autostart: Boolean, body: (Boolean) -> R?,
|
||||||
): R? = synchronized(this) {
|
): R? = synchronized(this) {
|
||||||
try {
|
try {
|
||||||
var attempts = 1
|
var attempts = 1
|
||||||
while (true) {
|
while (true) {
|
||||||
val (res, err) = try {
|
val (res, err) = try {
|
||||||
body(attempts >= DAEMON_CONNECT_CYCLE_ATTEMPTS) to null
|
body(attempts >= DAEMON_CONNECT_CYCLE_ATTEMPTS) to null
|
||||||
|
} catch (e: SocketException) {
|
||||||
|
null to e
|
||||||
|
} catch (e: ConnectException) {
|
||||||
|
null to e
|
||||||
|
} catch (e: ConnectIOException) {
|
||||||
|
null to e
|
||||||
|
} catch (e: UnmarshalException) {
|
||||||
|
null to e
|
||||||
|
} catch (e: RuntimeException) {
|
||||||
|
null to e
|
||||||
}
|
}
|
||||||
catch (e: SocketException) { null to e }
|
|
||||||
catch (e: ConnectException) { null to e }
|
|
||||||
catch (e: ConnectIOException) { null to e }
|
|
||||||
catch (e: UnmarshalException) { null to e }
|
|
||||||
catch (e: RuntimeException) { null to e }
|
|
||||||
|
|
||||||
if (res != null) return res
|
if (res != null) return res
|
||||||
|
|
||||||
if (err != null) {
|
if (err != null) {
|
||||||
reportingTargets.report(DaemonReportCategory.INFO,
|
reportingTargets.report(
|
||||||
(if (attempts >= DAEMON_CONNECT_CYCLE_ATTEMPTS || !autostart) "no more retries on: " else "retrying($attempts) on: ")
|
DaemonReportCategory.INFO,
|
||||||
+ err.toString())
|
(if (attempts >= DAEMON_CONNECT_CYCLE_ATTEMPTS || !autostart) "no more retries on: " else "retrying($attempts) on: ")
|
||||||
|
+ err.toString()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attempts++ > DAEMON_CONNECT_CYCLE_ATTEMPTS || !autostart) {
|
if (attempts++ > DAEMON_CONNECT_CYCLE_ATTEMPTS || !autostart) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} catch (e: Throwable) {
|
||||||
catch (e: Throwable) {
|
|
||||||
reportingTargets.report(DaemonReportCategory.EXCEPTION, e.toString())
|
reportingTargets.report(DaemonReportCategory.EXCEPTION, e.toString())
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun tryFindSuitableDaemonOrNewOpts(registryDir: File, compilerId: CompilerId, daemonJVMOptions: DaemonJVMOptions, report: (DaemonReportCategory, String) -> Unit): Pair<CompileService?, DaemonJVMOptions> {
|
private fun tryFindSuitableDaemonOrNewOpts(
|
||||||
|
registryDir: File,
|
||||||
|
compilerId: CompilerId,
|
||||||
|
daemonJVMOptions: DaemonJVMOptions,
|
||||||
|
report: (DaemonReportCategory, String) -> Unit,
|
||||||
|
): Pair<CompileService?, DaemonJVMOptions> {
|
||||||
registryDir.mkdirs()
|
registryDir.mkdirs()
|
||||||
val timestampMarker = Files.createTempFile(registryDir.toPath(), "kotlin-daemon-client-tsmarker", null).toFile()
|
val timestampMarker = Files.createTempFile(registryDir.toPath(), "kotlin-daemon-client-tsmarker", null).toFile()
|
||||||
val aliveWithMetadata = try {
|
val aliveWithMetadata = try {
|
||||||
walkDaemons(registryDir, compilerId, timestampMarker, report = report).toList()
|
walkDaemons(registryDir, compilerId, timestampMarker, report = report).toList()
|
||||||
}
|
} finally {
|
||||||
finally {
|
|
||||||
timestampMarker.delete()
|
timestampMarker.delete()
|
||||||
}
|
}
|
||||||
val comparator = compareBy<DaemonWithMetadata, DaemonJVMOptions>(DaemonJVMOptionsMemoryComparator(), { it.jvmOptions })
|
val comparator =
|
||||||
|
compareBy<DaemonWithMetadata, DaemonJVMOptions>(DaemonJVMOptionsMemoryComparator()) { it.jvmOptions }
|
||||||
.thenBy(FileAgeComparator()) { it.runFile }
|
.thenBy(FileAgeComparator()) { it.runFile }
|
||||||
val optsCopy = daemonJVMOptions.copy()
|
val optsCopy = daemonJVMOptions.copy()
|
||||||
// if required options fit into fattest running daemon - return the daemon and required options with memory params set to actual ones in the daemon
|
// if required options fit into fattest running daemon - return the daemon and required options with memory params set to actual ones in the daemon
|
||||||
@Suppress("DEPRECATION") // TODO: replace with maxWithOrNull as soon as minimal version of Gradle that we support has Kotlin 1.4+.
|
@Suppress("DEPRECATION") // TODO: replace with maxWithOrNull as soon as minimal version of Gradle that we support has Kotlin 1.4+.
|
||||||
return aliveWithMetadata.maxWith(comparator)?.takeIf { daemonJVMOptions memorywiseFitsInto it.jvmOptions }?.let {
|
return aliveWithMetadata.maxWith(comparator)?.takeIf { daemonJVMOptions memorywiseFitsInto it.jvmOptions }?.let {
|
||||||
Pair(it.daemon, optsCopy.updateMemoryUpperBounds(it.jvmOptions))
|
Pair(it.daemon, optsCopy.updateMemoryUpperBounds(it.jvmOptions))
|
||||||
}
|
}
|
||||||
// else combine all options from running daemon to get fattest option for a new daemon to run
|
// else combine all options from running daemon to get fattest option for a new daemon to run
|
||||||
?: Pair(null, aliveWithMetadata.fold(optsCopy, { opts, d -> opts.updateMemoryUpperBounds(d.jvmOptions) }))
|
?: Pair(null, aliveWithMetadata.fold(optsCopy) { opts, d -> opts.updateMemoryUpperBounds(d.jvmOptions) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun startDaemon(compilerId: CompilerId, daemonJVMOptions: DaemonJVMOptions, daemonOptions: DaemonOptions, reportingTargets: DaemonReportingTargets): Boolean {
|
private fun startDaemon(
|
||||||
|
compilerId: CompilerId,
|
||||||
|
daemonJVMOptions: DaemonJVMOptions,
|
||||||
|
daemonOptions: DaemonOptions,
|
||||||
|
reportingTargets: DaemonReportingTargets,
|
||||||
|
): Boolean {
|
||||||
val javaExecutable = File(File(CompilerSystemProperties.JAVA_HOME.safeValue, "bin"), "java")
|
val javaExecutable = File(File(CompilerSystemProperties.JAVA_HOME.safeValue, "bin"), "java")
|
||||||
val serverHostname = CompilerSystemProperties.JAVA_RMI_SERVER_HOSTNAME.value ?: error("${CompilerSystemProperties.JAVA_RMI_SERVER_HOSTNAME.property} is not set!")
|
val serverHostname = CompilerSystemProperties.JAVA_RMI_SERVER_HOSTNAME.value
|
||||||
|
?: error("${CompilerSystemProperties.JAVA_RMI_SERVER_HOSTNAME.property} is not set!")
|
||||||
val platformSpecificOptions = listOf(
|
val platformSpecificOptions = listOf(
|
||||||
// hide daemon window
|
// hide daemon window
|
||||||
"-Djava.awt.headless=true",
|
"-Djava.awt.headless=true",
|
||||||
"-D$${CompilerSystemProperties.JAVA_RMI_SERVER_HOSTNAME.property}=$serverHostname")
|
"-D$${CompilerSystemProperties.JAVA_RMI_SERVER_HOSTNAME.property}=$serverHostname"
|
||||||
|
)
|
||||||
val javaVersion = CompilerSystemProperties.JAVA_VERSION.value?.toIntOrNull()
|
val javaVersion = CompilerSystemProperties.JAVA_VERSION.value?.toIntOrNull()
|
||||||
val javaIllegalAccessWorkaround =
|
val javaIllegalAccessWorkaround =
|
||||||
if (javaVersion != null && javaVersion >= 16)
|
if (javaVersion != null && javaVersion >= 16)
|
||||||
listOf("--add-exports", "java.base/sun.nio.ch=ALL-UNNAMED")
|
listOf("--add-exports", "java.base/sun.nio.ch=ALL-UNNAMED")
|
||||||
else emptyList()
|
else emptyList()
|
||||||
val args = listOf(
|
val args = listOf(
|
||||||
javaExecutable.absolutePath, "-cp", compilerId.compilerClasspath.joinToString(File.pathSeparator)) +
|
javaExecutable.absolutePath, "-cp", compilerId.compilerClasspath.joinToString(File.pathSeparator)
|
||||||
platformSpecificOptions +
|
) +
|
||||||
daemonJVMOptions.mappers.flatMap { it.toArgs("-") } +
|
platformSpecificOptions +
|
||||||
javaIllegalAccessWorkaround +
|
daemonJVMOptions.mappers.flatMap { it.toArgs("-") } +
|
||||||
COMPILER_DAEMON_CLASS_FQN +
|
javaIllegalAccessWorkaround +
|
||||||
daemonOptions.mappers.flatMap { it.toArgs(COMPILE_DAEMON_CMDLINE_OPTIONS_PREFIX) } +
|
COMPILER_DAEMON_CLASS_FQN +
|
||||||
compilerId.mappers.flatMap { it.toArgs(COMPILE_DAEMON_CMDLINE_OPTIONS_PREFIX) }
|
daemonOptions.mappers.flatMap { it.toArgs(COMPILE_DAEMON_CMDLINE_OPTIONS_PREFIX) } +
|
||||||
|
compilerId.mappers.flatMap { it.toArgs(COMPILE_DAEMON_CMDLINE_OPTIONS_PREFIX) }
|
||||||
reportingTargets.report(DaemonReportCategory.DEBUG, "starting the daemon as: " + args.joinToString(" "))
|
reportingTargets.report(DaemonReportCategory.DEBUG, "starting the daemon as: " + args.joinToString(" "))
|
||||||
val processBuilder = ProcessBuilder(args)
|
val processBuilder = ProcessBuilder(args)
|
||||||
processBuilder.redirectErrorStream(true)
|
processBuilder.redirectErrorStream(true)
|
||||||
@@ -393,7 +458,10 @@ object KotlinCompilerClient {
|
|||||||
.forEachLine {
|
.forEachLine {
|
||||||
if (Thread.currentThread().isInterrupted) return@forEachLine
|
if (Thread.currentThread().isInterrupted) return@forEachLine
|
||||||
if (it == COMPILE_DAEMON_IS_READY_MESSAGE) {
|
if (it == COMPILE_DAEMON_IS_READY_MESSAGE) {
|
||||||
reportingTargets.report(DaemonReportCategory.DEBUG, "Received the message signalling that the daemon is ready")
|
reportingTargets.report(
|
||||||
|
DaemonReportCategory.DEBUG,
|
||||||
|
"Received the message signalling that the daemon is ready"
|
||||||
|
)
|
||||||
isEchoRead.release()
|
isEchoRead.release()
|
||||||
return@forEachLine
|
return@forEachLine
|
||||||
} else {
|
} else {
|
||||||
@@ -414,9 +482,11 @@ object KotlinCompilerClient {
|
|||||||
val daemonStartupTimeout = CompilerSystemProperties.COMPILE_DAEMON_STARTUP_TIMEOUT_PROPERTY.value?.let {
|
val daemonStartupTimeout = CompilerSystemProperties.COMPILE_DAEMON_STARTUP_TIMEOUT_PROPERTY.value?.let {
|
||||||
try {
|
try {
|
||||||
it.toLong()
|
it.toLong()
|
||||||
}
|
} catch (e: Exception) {
|
||||||
catch (e: Exception) {
|
reportingTargets.report(
|
||||||
reportingTargets.report(DaemonReportCategory.INFO, "unable to interpret ${CompilerSystemProperties.COMPILE_DAEMON_STARTUP_TIMEOUT_PROPERTY.property} property ('$it'); using default timeout $DAEMON_DEFAULT_STARTUP_TIMEOUT_MS ms")
|
DaemonReportCategory.INFO,
|
||||||
|
"unable to interpret ${CompilerSystemProperties.COMPILE_DAEMON_STARTUP_TIMEOUT_PROPERTY.property} property ('$it'); using default timeout $DAEMON_DEFAULT_STARTUP_TIMEOUT_MS ms"
|
||||||
|
)
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
} ?: DAEMON_DEFAULT_STARTUP_TIMEOUT_MS
|
} ?: DAEMON_DEFAULT_STARTUP_TIMEOUT_MS
|
||||||
@@ -424,7 +494,10 @@ object KotlinCompilerClient {
|
|||||||
val succeeded = isEchoRead.tryAcquire(daemonStartupTimeout, TimeUnit.MILLISECONDS)
|
val succeeded = isEchoRead.tryAcquire(daemonStartupTimeout, TimeUnit.MILLISECONDS)
|
||||||
return when {
|
return when {
|
||||||
!isProcessAlive(daemon) -> {
|
!isProcessAlive(daemon) -> {
|
||||||
reportingTargets.report(DaemonReportCategory.INFO, "Daemon terminated unexpectedly with error code: ${daemon.exitValue()}")
|
reportingTargets.report(
|
||||||
|
DaemonReportCategory.INFO,
|
||||||
|
"Daemon terminated unexpectedly with error code: ${daemon.exitValue()}"
|
||||||
|
)
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
!succeeded -> {
|
!succeeded -> {
|
||||||
@@ -433,13 +506,11 @@ object KotlinCompilerClient {
|
|||||||
}
|
}
|
||||||
else -> true
|
else -> true
|
||||||
}
|
}
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
// without startEcho defined waiting for max timeout
|
// without startEcho defined waiting for max timeout
|
||||||
Thread.sleep(daemonStartupTimeout)
|
Thread.sleep(daemonStartupTimeout)
|
||||||
return true
|
return true
|
||||||
}
|
} finally {
|
||||||
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 (stdoutThread.isAlive) {
|
if (stdoutThread.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
|
||||||
@@ -453,10 +524,12 @@ object KotlinCompilerClient {
|
|||||||
|
|
||||||
data class DaemonReportMessage(val category: DaemonReportCategory, val message: String)
|
data class DaemonReportMessage(val category: DaemonReportCategory, val message: String)
|
||||||
|
|
||||||
class DaemonReportingTargets(val out: PrintStream? = null,
|
class DaemonReportingTargets(
|
||||||
val messages: MutableCollection<DaemonReportMessage>? = null,
|
val out: PrintStream? = null,
|
||||||
val messageCollector: MessageCollector? = null,
|
val messages: MutableCollection<DaemonReportMessage>? = null,
|
||||||
val compilerServices: CompilerServicesFacadeBase? = null)
|
val messageCollector: MessageCollector? = null,
|
||||||
|
val compilerServices: CompilerServicesFacadeBase? = null,
|
||||||
|
)
|
||||||
|
|
||||||
internal fun DaemonReportingTargets.report(category: DaemonReportCategory, message: String, source: String? = null) {
|
internal fun DaemonReportingTargets.report(category: DaemonReportCategory, message: String, source: String? = null) {
|
||||||
val sourceMessage: String by lazy { source?.let { "[$it] $message" } ?: message }
|
val sourceMessage: String by lazy { source?.let { "[$it] $message" } ?: message }
|
||||||
@@ -479,10 +552,9 @@ internal fun DaemonReportingTargets.report(category: DaemonReportCategory, messa
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun isProcessAlive(process: Process) =
|
internal fun isProcessAlive(process: Process) =
|
||||||
try {
|
try {
|
||||||
process.exitValue()
|
process.exitValue()
|
||||||
false
|
false
|
||||||
}
|
} catch (e: IllegalThreadStateException) {
|
||||||
catch (e: IllegalThreadStateException) {
|
true
|
||||||
true
|
}
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user