diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/KotlinToolRunner.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/KotlinToolRunner.kt index daaae6ceaec..5662186d02f 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/KotlinToolRunner.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/KotlinToolRunner.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.compilerRunner +import com.intellij.openapi.util.text.StringUtil.escapeStringCharacters import org.gradle.api.Project import org.jetbrains.kotlin.konan.target.HostManager import java.io.File @@ -67,37 +68,58 @@ internal abstract class KotlinToolRunner( } fun run(args: List) { - project.logger.info("Run tool: \"$displayName\" with args: ${args.joinToString(separator = " ")}") checkClasspath() if (mustRunViaExec) runViaExec(args) else runInProcess(args) } private fun runViaExec(args: List) { + val transformedArgs = transformArgs(args) + val classpath = project.files(classpath) + val systemProperties = System.getProperties().asSequence() + .map { (k, v) -> k.toString() to v.toString() } + .filter { (k, _) -> k !in execSystemPropertiesBlacklist } + .escapeQuotesForWindows() + .toMap() + execSystemProperties + + project.logger.info( + """|Run "$displayName" tool in a separate JVM process + |Main class = $mainClass + |Arguments = ${transformedArgs.toPrettyString()} + |Classpath = ${classpath.files.map { it.absolutePath }.toPrettyString()} + |JVM options = ${jvmArgs.toPrettyString()} + |Java system properties = ${systemProperties.toPrettyString()} + |Suppressed ENV variables = ${execEnvironmentBlacklist.toPrettyString()} + |Custom ENV variables = ${execEnvironment.toPrettyString()} + """.trimMargin() + ) + project.javaexec { spec -> spec.main = mainClass - spec.classpath = project.files(classpath) + spec.classpath = classpath spec.jvmArgs(jvmArgs) - spec.systemProperties( - System.getProperties().asSequence() - .map { (k, v) -> k.toString() to v.toString() } - .filter { (k, _) -> k !in execSystemPropertiesBlacklist } - .escapeQuotesForWindows() - .toMap() - ) - spec.systemProperties(execSystemProperties) + spec.systemProperties(systemProperties) execEnvironmentBlacklist.forEach { spec.environment.remove(it) } spec.environment(execEnvironment) - spec.args(transformArgs(args)) + spec.args(transformedArgs) } } private fun runInProcess(args: List) { + val transformedArgs = transformArgs(args) + + project.logger.info( + """|Run in-process tool "$displayName" + |Entry point method = $mainClass.$daemonEntryPoint + |Arguments = ${transformedArgs.toPrettyString()} + """.trimMargin() + ) + try { val mainClass = getIsolatedClassLoader().loadClass(mainClass) val entryPoint = mainClass.methods.single { it.name == daemonEntryPoint } - entryPoint.invoke(null, transformArgs(args).toTypedArray()) + entryPoint.invoke(null, transformedArgs.toTypedArray()) } catch (t: InvocationTargetException) { throw t.targetException } @@ -110,5 +132,24 @@ internal abstract class KotlinToolRunner( if (HostManager.hostIsMingw) map { (key, value) -> key.escapeQuotes() to value.escapeQuotes() } else this private val isolatedClassLoadersMap = ConcurrentHashMap() + + private fun Map.toPrettyString(): String = buildString { + append('{') + if (this@toPrettyString.isNotEmpty()) append('\n') + this@toPrettyString.entries.forEach { (key, value) -> + append('\t').append(key).append(" = ").append(value.toPrettyString()).append('\n') + } + append('}') + } + + private fun Collection.toPrettyString(): String = buildString { + append('[') + if (this@toPrettyString.isNotEmpty()) append('\n') + this@toPrettyString.forEach { append('\t').append(it.toPrettyString()).append('\n') } + append(']') + } + + private fun String.toPrettyString(): String = + if (isEmpty()) "\"\"" else escapeStringCharacters(this).let { if (any(Char::isWhitespace)) "\"$it\"" else it } } }