From ce2ae58ffb1e9a4e54c4b4aa8ec29298a1113be1 Mon Sep 17 00:00:00 2001 From: "nataliya.valtman" Date: Fri, 6 Mar 2020 09:23:56 +0300 Subject: [PATCH] use gradle execOperation and set args in file --- .../GradleKotlinCompilerWork.kt | 16 +++++- .../kotlin/compilerRunner/reportUtils.kt | 55 +++++++++++++++---- .../kotlin/gradle/tasks/KotlinJsDce.kt | 25 +++++++-- .../internal/GradleExecOperationsHolder.kt | 15 +++++ 4 files changed, 93 insertions(+), 18 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/internal/GradleExecOperationsHolder.kt diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerWork.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerWork.kt index c8b1f7539b1..acbbe859894 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerWork.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerWork.kt @@ -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( diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/reportUtils.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/reportUtils.kt index 7de9fbea8c0..0a3710237ce 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/reportUtils.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/reportUtils.kt @@ -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): 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): String { return result ?: "" } +internal fun runToolInSeparateProcessForGradle6AndMore( + argsArray: Array, + compilerClassName: String, + classpath: List, + 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, compilerClassName: String, classpath: List, - 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): 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 -> { } 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 09496b5dd60..adf1379ef73 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 @@ -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(), 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 { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/internal/GradleExecOperationsHolder.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/internal/GradleExecOperationsHolder.kt new file mode 100644 index 00000000000..bb065cc0293 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/internal/GradleExecOperationsHolder.kt @@ -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) { +} \ No newline at end of file