From 479148f7e0a6b093c680f06ddfd49114d9f6f953 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Tue, 6 Jun 2017 19:53:42 +0300 Subject: [PATCH] Run JS DCE gradle task in a separate process --- .../compilerRunner/KotlinCompilerRunner.kt | 14 ++-- .../GradleKotlinCompilerRunner.kt | 31 ++------ .../jetbrains/kotlin/compilerRunner/utils.kt | 70 +++++++++++++++++++ .../kotlin/gradle/tasks/KotlinJsDce.kt | 10 ++- 4 files changed, 92 insertions(+), 33 deletions(-) diff --git a/compiler/compiler-runner/src/org/jetbrains/kotlin/compilerRunner/KotlinCompilerRunner.kt b/compiler/compiler-runner/src/org/jetbrains/kotlin/compilerRunner/KotlinCompilerRunner.kt index b2ae2267fc7..ca4b7936496 100644 --- a/compiler/compiler-runner/src/org/jetbrains/kotlin/compilerRunner/KotlinCompilerRunner.kt +++ b/compiler/compiler-runner/src/org/jetbrains/kotlin/compilerRunner/KotlinCompilerRunner.kt @@ -147,12 +147,16 @@ abstract class KotlinCompilerRunner { environment: Env ): ExitCode? - protected fun exitCodeFromProcessExitCode(code: Int): ExitCode { - val exitCode = ExitCode.values().find { it.code == code } - if (exitCode != null) return exitCode + protected fun exitCodeFromProcessExitCode(code: Int): ExitCode = Companion.exitCodeFromProcessExitCode(log, code) - log.debug("Could not find exit code by value: $code") - return if (code == 0) ExitCode.OK else ExitCode.COMPILATION_ERROR + companion object { + fun exitCodeFromProcessExitCode(log: KotlinLogger, code: Int): ExitCode { + val exitCode = ExitCode.values().find { it.code == code } + if (exitCode != null) return exitCode + + log.debug("Could not find exit code by value: $code") + return if (code == 0) ExitCode.OK else ExitCode.COMPILATION_ERROR + } } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt index 69b112a3465..44a2381cf1b 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt @@ -16,8 +16,6 @@ package org.jetbrains.kotlin.compilerRunner -import net.rubygrapefruit.platform.Native -import net.rubygrapefruit.platform.ProcessLauncher import org.gradle.api.Project import org.jetbrains.kotlin.cli.common.ExitCode import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments @@ -37,8 +35,9 @@ import org.jetbrains.kotlin.daemon.common.* import org.jetbrains.kotlin.gradle.plugin.ParentLastURLClassLoader import org.jetbrains.kotlin.gradle.plugin.kotlinDebug import org.jetbrains.kotlin.incremental.* - -import java.io.* +import java.io.ByteArrayOutputStream +import java.io.File +import java.io.PrintStream import kotlin.concurrent.thread internal const val KOTLIN_COMPILER_EXECUTION_STRATEGY_PROPERTY = "kotlin.compiler.execution.strategy" @@ -286,25 +285,7 @@ internal class GradleCompilerRunner(private val project: Project) : KotlinCompil compilerClassName: String, environment: GradleCompilerEnvironment ): ExitCode { - val javaBin = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java" - val classpathString = environment.compilerClasspath.map {it.absolutePath}.joinToString(separator = File.pathSeparator) - val builder = ProcessBuilder(javaBin, "-cp", classpathString, compilerClassName, *argsArray) - val process = launchProcessWithFallback(builder, DaemonReportingTargets(messageCollector = loggingMessageCollector)) - - // important to read inputStream, otherwise the process may hang on some systems - val readErrThread = thread { - process.errorStream!!.bufferedReader().forEachLine { - System.err.println(it) - } - } - process.inputStream!!.bufferedReader().forEachLine { - System.out.println(it) - } - readErrThread.join() - - val exitCode = process.waitFor() - logFinish(OUT_OF_PROCESS_EXECUTION_STRATEGY) - return exitCodeFromProcessExitCode(exitCode) + return runToolInSeparateProcess(argsArray, compilerClassName, environment.compilerClasspath, log, loggingMessageCollector) } private fun compileInProcess( @@ -334,9 +315,7 @@ internal class GradleCompilerRunner(private val project: Project) : KotlinCompil return exitCode } - private fun logFinish(strategy: String) { - log.debug("Finished executing kotlin compiler using $strategy strategy") - } + private fun logFinish(strategy: String) = log.logFinish(strategy) override fun getDaemonConnection(environment: GradleCompilerEnvironment): CompileServiceSession? { val compilerId = CompilerId.makeCompilerId(environment.compilerClasspath) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/utils.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/utils.kt index 7a70c03e392..e15510413a2 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/utils.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/utils.kt @@ -16,13 +16,21 @@ package org.jetbrains.kotlin.compilerRunner +import org.jetbrains.kotlin.cli.common.ExitCode +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity +import org.jetbrains.kotlin.cli.common.messages.MessageCollector +import org.jetbrains.kotlin.cli.common.messages.MessageRenderer import org.jetbrains.kotlin.config.KotlinCompilerVersion +import org.jetbrains.kotlin.daemon.client.DaemonReportingTargets +import org.jetbrains.kotlin.daemon.client.launchProcessWithFallback import org.jetbrains.org.objectweb.asm.ClassReader import org.jetbrains.org.objectweb.asm.ClassVisitor import org.jetbrains.org.objectweb.asm.FieldVisitor import org.jetbrains.org.objectweb.asm.Opcodes import java.io.File import java.util.zip.ZipFile +import kotlin.concurrent.thread internal fun loadCompilerVersion(compilerJar: File): String { var result = "" @@ -45,3 +53,65 @@ internal fun loadCompilerVersion(compilerJar: File): String { return result } + +internal fun runToolInSeparateProcess( + argsArray: Array, compilerClassName: String, classpath: List, + logger: KotlinLogger, messageCollector: MessageCollector +): ExitCode { + val javaBin = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java" + val classpathString = classpath.map {it.absolutePath}.joinToString(separator = File.pathSeparator) + val builder = ProcessBuilder(javaBin, "-cp", classpathString, compilerClassName, *argsArray) + val process = launchProcessWithFallback(builder, DaemonReportingTargets(messageCollector = messageCollector)) + + // important to read inputStream, otherwise the process may hang on some systems + val readErrThread = thread { + process.errorStream!!.bufferedReader().forEachLine { + System.err.println(it) + } + } + process.inputStream!!.bufferedReader().forEachLine { + System.out.println(it) + } + readErrThread.join() + + val exitCode = process.waitFor() + logger.logFinish(OUT_OF_PROCESS_EXECUTION_STRATEGY) + return exitCodeFromProcessExitCode(logger, exitCode) +} + +internal fun createLoggingMessageCollector(log: KotlinLogger): MessageCollector = object : MessageCollector { + private var hasErrors = false + private val messageRenderer = MessageRenderer.PLAIN_FULL_PATHS + + override fun clear() { + hasErrors = false + } + + override fun hasErrors(): Boolean = hasErrors + + override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation?) { + val locMessage = messageRenderer.render(severity, message, location) + when (severity) { + CompilerMessageSeverity.EXCEPTION -> log.error(locMessage) + CompilerMessageSeverity.ERROR, + CompilerMessageSeverity.STRONG_WARNING, + CompilerMessageSeverity.WARNING, + CompilerMessageSeverity.INFO -> log.info(locMessage) + CompilerMessageSeverity.LOGGING -> log.debug(locMessage) + CompilerMessageSeverity.OUTPUT -> { + } + } + } +} + +internal fun KotlinLogger.logFinish(strategy: String) { + debug("Finished executing kotlin compiler using $strategy strategy") +} + +internal fun exitCodeFromProcessExitCode(log: KotlinLogger, code: Int): ExitCode { + val exitCode = ExitCode.values().find { it.code == code } + if (exitCode != null) return exitCode + + log.debug("Could not find exit code by value: $code") + return if (code == 0) ExitCode.OK else ExitCode.COMPILATION_ERROR +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinJsDce.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinJsDce.kt index 00af2432d04..de1c1012e8e 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinJsDce.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinJsDce.kt @@ -18,10 +18,12 @@ package org.jetbrains.kotlin.gradle.tasks import org.gradle.api.Project import org.gradle.api.tasks.TaskAction -import org.jetbrains.kotlin.cli.common.CLITool import org.jetbrains.kotlin.cli.common.arguments.K2JSDceArguments import org.jetbrains.kotlin.cli.js.dce.K2JSDce import org.jetbrains.kotlin.compilerRunner.ArgumentUtils +import org.jetbrains.kotlin.compilerRunner.GradleKotlinLogger +import org.jetbrains.kotlin.compilerRunner.createLoggingMessageCollector +import org.jetbrains.kotlin.compilerRunner.runToolInSeparateProcess import org.jetbrains.kotlin.gradle.dsl.KotlinJsDce import org.jetbrains.kotlin.gradle.dsl.KotlinJsDceOptions import org.jetbrains.kotlin.gradle.dsl.KotlinJsDceOptionsImpl @@ -53,7 +55,11 @@ open class KotlinJsDce : AbstractKotlinCompileTool(), KotlinJs dceOptionsImpl.updateArguments(args) args.declarationsToKeep = keep.toTypedArray() val argsArray = ArgumentUtils.convertArgumentsToStringList(args).toTypedArray() - val exitCode = CLITool.doMainNoExit(K2JSDce(), argsArray + outputDirArgs + inputFiles) + + val log = GradleKotlinLogger(project.logger) + val allArgs = argsArray + outputDirArgs + inputFiles + val exitCode = runToolInSeparateProcess(allArgs, K2JSDce::class.java.name, listOf(compilerJar), + log, createLoggingMessageCollector(log)) throwGradleExceptionIfError(exitCode) } } \ No newline at end of file