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.tasks.clearLocalState
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.incremental.ChangedFiles
import org.jetbrains.kotlin.incremental.IncrementalModuleInfo
@@ -32,12 +33,14 @@ import javax.inject.Inject
internal class ProjectFilesForCompilation(
val projectRootFile: File,
val clientIsAliveFlagFile: File,
val sessionFlagFile: File
val sessionFlagFile: File,
val project: Project
) : Serializable {
constructor(project: Project) : this(
projectRootFile = project.rootProject.projectDir,
clientIsAliveFlagFile = GradleCompilerRunner.getOrCreateClientFlagFile(project),
sessionFlagFile = GradleCompilerRunner.getOrCreateSessionFlagFile(project)
sessionFlagFile = GradleCompilerRunner.getOrCreateSessionFlagFile(project),
project = project
)
companion object {
@@ -97,6 +100,7 @@ internal class GradleKotlinCompilerWork @Inject constructor(
private val buildReportMode = config.buildReportMode
private val kotlinScriptExtensions = config.kotlinScriptExtensions
private val allWarningsAsErrors = config.allWarningsAsErrors
private val project = config.projectFiles.project
private val log: KotlinLogger =
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")
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 {
reportExecutionResultIfNeeded {
TaskExecutionResult(
@@ -16,6 +16,8 @@
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.messages.CompilerMessageLocation
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.launchProcessWithFallback
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.ClassVisitor
import org.jetbrains.org.objectweb.asm.FieldVisitor
import org.jetbrains.org.objectweb.asm.Opcodes
import java.io.File
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.zip.ZipFile
import kotlin.concurrent.thread
@@ -37,14 +42,17 @@ internal fun loadCompilerVersion(compilerClasspath: List<File>): String {
var result: String? = null
fun checkVersion(bytes: ByteArray) {
ClassReader(bytes).accept(object : ClassVisitor(Opcodes.API_VERSION) {
override fun visitField(access: Int, name: String, desc: String, signature: String?, value: Any?): FieldVisitor {
if (name == KotlinCompilerVersion::VERSION.name && value is String) {
result = value
ClassReader(bytes).accept(
object : ClassVisitor(Opcodes.API_VERSION) {
override fun visitField(access: Int, name: String, desc: String, signature: String?, value: Any?): FieldVisitor {
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 {
@@ -78,15 +86,34 @@ internal fun loadCompilerVersion(compilerClasspath: List<File>): String {
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(
argsArray: Array<String>,
compilerClassName: String,
classpath: List<File>,
logger: KotlinLogger
logger: KotlinLogger,
buildDir: File
): 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 compilerOptions = writeArgumentsToFile(buildDir, argsArray)
val builder = ProcessBuilder(javaBin, "-cp", classpathString, compilerClassName, "@${compilerOptions.absolutePath}")
val messageCollector = createLoggingMessageCollector(logger)
val process = launchProcessWithFallback(builder, DaemonReportingTargets(messageCollector = messageCollector))
@@ -114,6 +141,13 @@ internal fun runToolInSeparateProcess(
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 var hasErrors = false
private val messageRenderer = MessageRenderer.PLAIN_FULL_PATHS
@@ -131,7 +165,8 @@ private fun createLoggingMessageCollector(log: KotlinLogger): MessageCollector =
CompilerMessageSeverity.ERROR,
CompilerMessageSeverity.STRONG_WARNING,
CompilerMessageSeverity.WARNING,
CompilerMessageSeverity.INFO -> log.info(locMessage)
CompilerMessageSeverity.INFO
-> log.info(locMessage)
CompilerMessageSeverity.LOGGING -> log.debug(locMessage)
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.js.dce.K2JSDce
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.KotlinJsDceOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinJsDceOptionsImpl
import org.jetbrains.kotlin.gradle.logging.GradleKotlinLogger
import org.jetbrains.kotlin.gradle.utils.canonicalPathWithoutExtension
import org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast
import java.io.File
@CacheableTask
@@ -82,11 +84,24 @@ open class KotlinJsDce : AbstractKotlinCompileTool<K2JSDceArguments>(), KotlinJs
val log = GradleKotlinLogger(logger)
val allArgs = argsArray + outputDirArgs + inputFiles
val exitCode = runToolInSeparateProcess(
allArgs, K2JSDce::class.java.name, computedCompilerClasspath,
log
)
throwGradleExceptionIfError(exitCode)
if (isGradleVersionAtLeast(6,0)) {
runToolInSeparateProcessForGradle6AndMore(
allArgs,
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 {
@@ -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) {
}