use gradle execOperation and set args in file

This commit is contained in:
nataliya.valtman
2020-03-06 09:23:56 +03:00
parent cfdcbe5b71
commit ce2ae58ffb
4 changed files with 93 additions and 18 deletions
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.gradle.report.BuildReportMode
import org.jetbrains.kotlin.gradle.report.TaskExecutionResult import org.jetbrains.kotlin.gradle.report.TaskExecutionResult
import org.jetbrains.kotlin.gradle.tasks.clearLocalState import org.jetbrains.kotlin.gradle.tasks.clearLocalState
import org.jetbrains.kotlin.gradle.tasks.throwGradleExceptionIfError import org.jetbrains.kotlin.gradle.tasks.throwGradleExceptionIfError
import org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast
import org.jetbrains.kotlin.gradle.utils.stackTraceAsString import org.jetbrains.kotlin.gradle.utils.stackTraceAsString
import org.jetbrains.kotlin.incremental.ChangedFiles import org.jetbrains.kotlin.incremental.ChangedFiles
import org.jetbrains.kotlin.incremental.IncrementalModuleInfo import org.jetbrains.kotlin.incremental.IncrementalModuleInfo
@@ -32,12 +33,14 @@ import javax.inject.Inject
internal class ProjectFilesForCompilation( internal class ProjectFilesForCompilation(
val projectRootFile: File, val projectRootFile: File,
val clientIsAliveFlagFile: File, val clientIsAliveFlagFile: File,
val sessionFlagFile: File val sessionFlagFile: File,
val project: Project
) : Serializable { ) : Serializable {
constructor(project: Project) : this( constructor(project: Project) : this(
projectRootFile = project.rootProject.projectDir, projectRootFile = project.rootProject.projectDir,
clientIsAliveFlagFile = GradleCompilerRunner.getOrCreateClientFlagFile(project), clientIsAliveFlagFile = GradleCompilerRunner.getOrCreateClientFlagFile(project),
sessionFlagFile = GradleCompilerRunner.getOrCreateSessionFlagFile(project) sessionFlagFile = GradleCompilerRunner.getOrCreateSessionFlagFile(project),
project = project
) )
companion object { companion object {
@@ -97,6 +100,7 @@ internal class GradleKotlinCompilerWork @Inject constructor(
private val buildReportMode = config.buildReportMode private val buildReportMode = config.buildReportMode
private val kotlinScriptExtensions = config.kotlinScriptExtensions private val kotlinScriptExtensions = config.kotlinScriptExtensions
private val allWarningsAsErrors = config.allWarningsAsErrors private val allWarningsAsErrors = config.allWarningsAsErrors
private val project = config.projectFiles.project
private val log: KotlinLogger = private val log: KotlinLogger =
TaskLoggers.get(taskPath)?.let { GradleKotlinLogger(it).apply { debug("Using '$taskPath' logger") } } TaskLoggers.get(taskPath)?.let { GradleKotlinLogger(it).apply { debug("Using '$taskPath' logger") } }
@@ -297,7 +301,13 @@ internal class GradleKotlinCompilerWork @Inject constructor(
clearLocalState(outputFiles, log, reason = "out-of-process execution strategy is non-incremental") clearLocalState(outputFiles, log, reason = "out-of-process execution strategy is non-incremental")
return try { return try {
runToolInSeparateProcess(compilerArgs, compilerClassName, compilerFullClasspath, log) if (isGradleVersionAtLeast(6, 0)) {
val execResult =
runToolInSeparateProcessForGradle6AndMore(compilerArgs, compilerClassName, compilerFullClasspath, project)
exitCodeFromProcessExitCode(log, execResult.exitValue)
} else {
runToolInSeparateProcess(compilerArgs, compilerClassName, compilerFullClasspath, log, project.buildDir)
}
} finally { } finally {
reportExecutionResultIfNeeded { reportExecutionResultIfNeeded {
TaskExecutionResult( TaskExecutionResult(
@@ -16,6 +16,8 @@
package org.jetbrains.kotlin.compilerRunner package org.jetbrains.kotlin.compilerRunner
import org.gradle.api.Project
import org.gradle.process.ExecResult
import org.jetbrains.kotlin.cli.common.ExitCode import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
@@ -25,11 +27,14 @@ import org.jetbrains.kotlin.config.KotlinCompilerVersion
import org.jetbrains.kotlin.daemon.client.DaemonReportingTargets import org.jetbrains.kotlin.daemon.client.DaemonReportingTargets
import org.jetbrains.kotlin.daemon.client.launchProcessWithFallback import org.jetbrains.kotlin.daemon.client.launchProcessWithFallback
import org.jetbrains.kotlin.gradle.logging.GradleKotlinLogger import org.jetbrains.kotlin.gradle.logging.GradleKotlinLogger
import org.jetbrains.kotlin.gradle.tasks.internal.GradleExecOperationsHolder
import org.jetbrains.org.objectweb.asm.ClassReader import org.jetbrains.org.objectweb.asm.ClassReader
import org.jetbrains.org.objectweb.asm.ClassVisitor import org.jetbrains.org.objectweb.asm.ClassVisitor
import org.jetbrains.org.objectweb.asm.FieldVisitor import org.jetbrains.org.objectweb.asm.FieldVisitor
import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Opcodes
import java.io.File import java.io.File
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.zip.ZipFile import java.util.zip.ZipFile
import kotlin.concurrent.thread import kotlin.concurrent.thread
@@ -37,14 +42,17 @@ internal fun loadCompilerVersion(compilerClasspath: List<File>): String {
var result: String? = null var result: String? = null
fun checkVersion(bytes: ByteArray) { fun checkVersion(bytes: ByteArray) {
ClassReader(bytes).accept(object : ClassVisitor(Opcodes.API_VERSION) { ClassReader(bytes).accept(
override fun visitField(access: Int, name: String, desc: String, signature: String?, value: Any?): FieldVisitor { object : ClassVisitor(Opcodes.API_VERSION) {
if (name == KotlinCompilerVersion::VERSION.name && value is String) { override fun visitField(access: Int, name: String, desc: String, signature: String?, value: Any?): FieldVisitor {
result = value if (name == KotlinCompilerVersion::VERSION.name && value is String) {
result = value
}
return super.visitField(access, name, desc, signature, value)
} }
return super.visitField(access, name, desc, signature, value) },
} ClassReader.SKIP_CODE or ClassReader.SKIP_FRAMES or ClassReader.SKIP_DEBUG
}, ClassReader.SKIP_CODE or ClassReader.SKIP_FRAMES or ClassReader.SKIP_DEBUG) )
} }
try { try {
@@ -78,15 +86,34 @@ internal fun loadCompilerVersion(compilerClasspath: List<File>): String {
return result ?: "<unknown>" return result ?: "<unknown>"
} }
internal fun runToolInSeparateProcessForGradle6AndMore(
argsArray: Array<String>,
compilerClassName: String,
classpath: List<File>,
project: Project
): ExecResult {
val gradleExecutionOperation = project.objects.newInstance(GradleExecOperationsHolder::class.java)
val compilationArguments = writeArgumentsToFile(project.buildDir, argsArray)
return gradleExecutionOperation.execOperation.javaexec {
it.classpath = project.files(classpath)
it.args = listOf("@${compilationArguments.absolutePath}")
it.main = compilerClassName
}
}
internal fun runToolInSeparateProcess( internal fun runToolInSeparateProcess(
argsArray: Array<String>, argsArray: Array<String>,
compilerClassName: String, compilerClassName: String,
classpath: List<File>, classpath: List<File>,
logger: KotlinLogger logger: KotlinLogger,
buildDir: File
): ExitCode { ): ExitCode {
val javaBin = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java" val javaBin = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java"
val classpathString = classpath.map { it.absolutePath }.joinToString(separator = File.pathSeparator) val classpathString = classpath.map { it.absolutePath }.joinToString(separator = File.pathSeparator)
val builder = ProcessBuilder(javaBin, "-cp", classpathString, compilerClassName, *argsArray)
val compilerOptions = writeArgumentsToFile(buildDir, argsArray)
val builder = ProcessBuilder(javaBin, "-cp", classpathString, compilerClassName, "@${compilerOptions.absolutePath}")
val messageCollector = createLoggingMessageCollector(logger) val messageCollector = createLoggingMessageCollector(logger)
val process = launchProcessWithFallback(builder, DaemonReportingTargets(messageCollector = messageCollector)) val process = launchProcessWithFallback(builder, DaemonReportingTargets(messageCollector = messageCollector))
@@ -114,6 +141,13 @@ internal fun runToolInSeparateProcess(
return exitCodeFromProcessExitCode(logger, exitCode) return exitCodeFromProcessExitCode(logger, exitCode)
} }
private fun writeArgumentsToFile(directory: File, argsArray: Array<String>): File {
val compilerOptions = File.createTempFile(LocalDateTime.now().format(DateTimeFormatter.BASIC_ISO_DATE) + "_", ".compiler.options", directory)
compilerOptions.deleteOnExit()
compilerOptions.writeText(argsArray.joinToString(" "))
return compilerOptions
}
private fun createLoggingMessageCollector(log: KotlinLogger): MessageCollector = object : MessageCollector { private fun createLoggingMessageCollector(log: KotlinLogger): MessageCollector = object : MessageCollector {
private var hasErrors = false private var hasErrors = false
private val messageRenderer = MessageRenderer.PLAIN_FULL_PATHS private val messageRenderer = MessageRenderer.PLAIN_FULL_PATHS
@@ -131,7 +165,8 @@ private fun createLoggingMessageCollector(log: KotlinLogger): MessageCollector =
CompilerMessageSeverity.ERROR, CompilerMessageSeverity.ERROR,
CompilerMessageSeverity.STRONG_WARNING, CompilerMessageSeverity.STRONG_WARNING,
CompilerMessageSeverity.WARNING, CompilerMessageSeverity.WARNING,
CompilerMessageSeverity.INFO -> log.info(locMessage) CompilerMessageSeverity.INFO
-> log.info(locMessage)
CompilerMessageSeverity.LOGGING -> log.debug(locMessage) CompilerMessageSeverity.LOGGING -> log.debug(locMessage)
CompilerMessageSeverity.OUTPUT -> { CompilerMessageSeverity.OUTPUT -> {
} }
@@ -26,11 +26,13 @@ import org.gradle.api.tasks.TaskAction
import org.jetbrains.kotlin.cli.common.arguments.K2JSDceArguments import org.jetbrains.kotlin.cli.common.arguments.K2JSDceArguments
import org.jetbrains.kotlin.cli.js.dce.K2JSDce import org.jetbrains.kotlin.cli.js.dce.K2JSDce
import org.jetbrains.kotlin.compilerRunner.runToolInSeparateProcess import org.jetbrains.kotlin.compilerRunner.runToolInSeparateProcess
import org.jetbrains.kotlin.compilerRunner.runToolInSeparateProcessForGradle6AndMore
import org.jetbrains.kotlin.gradle.dsl.KotlinJsDce import org.jetbrains.kotlin.gradle.dsl.KotlinJsDce
import org.jetbrains.kotlin.gradle.dsl.KotlinJsDceOptions import org.jetbrains.kotlin.gradle.dsl.KotlinJsDceOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinJsDceOptionsImpl import org.jetbrains.kotlin.gradle.dsl.KotlinJsDceOptionsImpl
import org.jetbrains.kotlin.gradle.logging.GradleKotlinLogger import org.jetbrains.kotlin.gradle.logging.GradleKotlinLogger
import org.jetbrains.kotlin.gradle.utils.canonicalPathWithoutExtension import org.jetbrains.kotlin.gradle.utils.canonicalPathWithoutExtension
import org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast
import java.io.File import java.io.File
@CacheableTask @CacheableTask
@@ -82,11 +84,24 @@ open class KotlinJsDce : AbstractKotlinCompileTool<K2JSDceArguments>(), KotlinJs
val log = GradleKotlinLogger(logger) val log = GradleKotlinLogger(logger)
val allArgs = argsArray + outputDirArgs + inputFiles val allArgs = argsArray + outputDirArgs + inputFiles
val exitCode = runToolInSeparateProcess(
allArgs, K2JSDce::class.java.name, computedCompilerClasspath, if (isGradleVersionAtLeast(6,0)) {
log runToolInSeparateProcessForGradle6AndMore(
) allArgs,
throwGradleExceptionIfError(exitCode) K2JSDce::class.java.name,
computedCompilerClasspath,
project
).rethrowFailure()
} else {
val exitCode = runToolInSeparateProcess(
allArgs,
K2JSDce::class.java.name,
computedCompilerClasspath,
log,
project.buildDir
)
throwGradleExceptionIfError(exitCode)
}
} }
private fun isDceCandidate(file: File): Boolean { private fun isDceCandidate(file: File): Boolean {
@@ -0,0 +1,15 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.tasks.internal
import javax.inject.Inject
import org.gradle.process.ExecOperations
/**
* Available since Gradle 6.0
*/
open class GradleExecOperationsHolder @Inject constructor(val execOperation: ExecOperations) {
}