Run JS DCE gradle task in a separate process

This commit is contained in:
Alexey Andreev
2017-06-06 19:53:42 +03:00
parent cfbb9209a7
commit 479148f7e0
4 changed files with 92 additions and 33 deletions
@@ -147,12 +147,16 @@ abstract class KotlinCompilerRunner<in Env : CompilerEnvironment> {
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
}
}
}
@@ -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)
@@ -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 = "<unknown>"
@@ -45,3 +53,65 @@ internal fun loadCompilerVersion(compilerJar: File): String {
return result
}
internal fun runToolInSeparateProcess(
argsArray: Array<String>, compilerClassName: String, classpath: List<File>,
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
}
@@ -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<K2JSDceArguments>(), 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)
}
}