Move after-compilation cleanup actions to GradleKotlinCompilerWork

Otherwise cleanup actions would run in-parallel or before
compilation when Gradle Workers are used
This commit is contained in:
Alexey Tsvetkov
2018-11-02 01:11:38 +03:00
parent ff81a46233
commit 21289722b7
8 changed files with 92 additions and 55 deletions
@@ -14,7 +14,7 @@ internal class GradleCompilerRunnerWithWorkers(
project: Project,
private val workersExecutor: WorkerExecutor
) : GradleCompilerRunner(project) {
override fun compileWithDaemonOrFallback(workArgs: GradleKotlinCompilerWorkArguments) {
override fun runCompilerAsync(workArgs: GradleKotlinCompilerWorkArguments) {
workersExecutor.submit(GradleKotlinCompilerWork::class.java) { config ->
config.isolationMode = IsolationMode.NONE
config.forkMode = ForkMode.NEVER
@@ -51,7 +51,11 @@ internal fun kotlinCompilerExecutionStrategy(): String =
System.getProperty(KOTLIN_COMPILER_EXECUTION_STRATEGY_PROPERTY) ?: DAEMON_EXECUTION_STRATEGY
internal open class GradleCompilerRunner(protected val project: Project) {
fun runJvmCompiler(
/**
* Compiler might be executed asynchronuosly. Do not do anything requiring end of compilation after this function is called.
* @see [GradleKotlinCompilerWork]
*/
fun runJvmCompilerAsync(
sourcesToCompile: List<File>,
commonSources: List<File>,
javaSourceRoots: Iterable<File>,
@@ -75,16 +79,14 @@ internal open class GradleCompilerRunner(protected val project: Project) {
args.destination = null
}
try {
runCompiler(KotlinCompilerClass.JVM, args, environment)
} finally {
if (System.getProperty(DELETE_MODULE_FILE_PROPERTY) != "false") {
buildFile.delete()
}
}
runCompilerAsync(KotlinCompilerClass.JVM, args, environment, buildFile = buildFile)
}
fun runJsCompiler(
/**
* Compiler might be executed asynchronuosly. Do not do anything requiring end of compilation after this function is called.
* @see [GradleKotlinCompilerWork]
*/
fun runJsCompilerAsync(
kotlinSources: List<File>,
kotlinCommonSources: List<File>,
args: K2JSCompilerArguments,
@@ -92,22 +94,27 @@ internal open class GradleCompilerRunner(protected val project: Project) {
) {
args.freeArgs += kotlinSources.map { it.absolutePath }
args.commonSources = kotlinCommonSources.map { it.absolutePath }.toTypedArray()
runCompiler(KotlinCompilerClass.JS, args, environment)
runCompilerAsync(KotlinCompilerClass.JS, args, environment)
}
fun runMetadataCompiler(
/**
* Compiler might be executed asynchronuosly. Do not do anything requiring end of compilation after this function is called.
* @see [GradleKotlinCompilerWork]
*/
fun runMetadataCompilerAsync(
kotlinSources: List<File>,
args: K2MetadataCompilerArguments,
environment: GradleCompilerEnvironment
) {
args.freeArgs += kotlinSources.map { it.absolutePath }
runCompiler(KotlinCompilerClass.METADATA, args, environment)
runCompilerAsync(KotlinCompilerClass.METADATA, args, environment)
}
private fun runCompiler(
private fun runCompilerAsync(
compilerClassName: String,
compilerArgs: CommonCompilerArguments,
environment: GradleCompilerEnvironment
environment: GradleCompilerEnvironment,
buildFile: File? = null
) {
if (compilerArgs.version) {
project.logger.lifecycle(
@@ -126,12 +133,13 @@ internal open class GradleCompilerRunner(protected val project: Project) {
compilerArgs = argsArray,
isVerbose = compilerArgs.verbose,
incrementalCompilationEnvironment = incrementalCompilationEnvironment,
incrementalModuleInfo = modulesInfo
incrementalModuleInfo = modulesInfo,
buildFile = buildFile
)
compileWithDaemonOrFallback(workArgs)
runCompilerAsync(workArgs)
}
protected open fun compileWithDaemonOrFallback(workArgs: GradleKotlinCompilerWorkArguments) {
protected open fun runCompilerAsync(workArgs: GradleKotlinCompilerWorkArguments) {
val kotlinCompilerRunnable = GradleKotlinCompilerWork(workArgs)
kotlinCompilerRunnable.run()
}
@@ -14,9 +14,11 @@ import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
import org.jetbrains.kotlin.config.Services
import org.jetbrains.kotlin.daemon.common.*
import org.jetbrains.kotlin.gradle.plugin.kotlinDebug
import org.jetbrains.kotlin.gradle.plugin.kotlinInfo
import org.jetbrains.kotlin.gradle.tasks.GradleMessageCollector
import org.jetbrains.kotlin.gradle.tasks.throwGradleExceptionIfError
import org.jetbrains.kotlin.incremental.ChangedFiles
import org.jetbrains.kotlin.incremental.DELETE_MODULE_FILE_PROPERTY
import org.slf4j.LoggerFactory
import java.io.ByteArrayOutputStream
import java.io.File
@@ -49,7 +51,8 @@ internal class GradleKotlinCompilerWorkArguments(
val compilerArgs: Array<String>,
val isVerbose: Boolean,
val incrementalCompilationEnvironment: IncrementalCompilationEnvironment?,
val incrementalModuleInfo: IncrementalModuleInfo?
val incrementalModuleInfo: IncrementalModuleInfo?,
val buildFile: File?
) : Serializable {
companion object {
const val serialVersionUID: Long = 0
@@ -75,6 +78,7 @@ internal class GradleKotlinCompilerWork @Inject constructor(
private val isVerbose = config.isVerbose
private val incrementalCompilationEnvironment = config.incrementalCompilationEnvironment
private val incrementalModuleInfo = config.incrementalModuleInfo
private val buildFile = config.buildFile
private val log: KotlinLogger =
SL4JKotlinLogger(LoggerFactory.getLogger("GradleKotlinCompilerWork"))
@@ -84,10 +88,42 @@ internal class GradleKotlinCompilerWork @Inject constructor(
get() = incrementalCompilationEnvironment != null
override fun run() {
val exitCode = compileWithDaemonOrFallbackImpl()
val exitCode = try {
compileWithDaemonOrFallbackImpl()
} finally {
if (buildFile != null && System.getProperty(DELETE_MODULE_FILE_PROPERTY) != "false") {
buildFile.delete()
}
}
if (incrementalCompilationEnvironment != null) {
if (incrementalCompilationEnvironment.disableMultiModuleIC) {
incrementalCompilationEnvironment.multiModuleICSettings.buildHistoryFile.delete()
}
if (exitCode != ExitCode.OK) {
// for non-incremental compilation cleanup is always performed before compiler is called
cleanupOnError(incrementalCompilationEnvironment)
}
}
throwGradleExceptionIfError(exitCode)
}
private fun cleanupOnError(incrementalCompilationEnvironment: IncrementalCompilationEnvironment) {
val localStateDirs = incrementalCompilationEnvironment.localStateDirs
log.info("Deleting output directories on error: ${localStateDirs.joinToString()}")
for (dir in localStateDirs) {
if (dir.exists()) {
if (dir.deleteRecursively()) {
log.debug("Deleted $dir")
} else {
log.debug("Could not delete $dir")
}
}
}
}
private fun compileWithDaemonOrFallbackImpl(): ExitCode {
with(log) {
kotlinDebug { "Kotlin compiler class: ${compilerClassName}" }
@@ -15,6 +15,7 @@ internal class IncrementalCompilationEnvironment(
val workingDir: File,
val usePreciseJavaTracking: Boolean = false,
val localStateDirs: List<File> = emptyList(),
val disableMultiModuleIC: Boolean = false,
val multiModuleICSettings: MultiModuleICSettings
) : Serializable {
companion object {
@@ -101,6 +101,6 @@ open class KaptGenerateStubsTask : KotlinCompile() {
sourceRoots.log(this.name, logger)
val args = prepareCompilerArguments()
callCompiler(args, sourceRoots, ChangedFiles(inputs))
callCompilerAsync(args, sourceRoots, ChangedFiles(inputs))
}
}
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.gradle.plugin.PLUGIN_CLASSPATH_CONFIGURATION_NAME
import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions
import org.jetbrains.kotlin.gradle.tasks.GradleMessageCollector
import org.jetbrains.kotlin.gradle.tasks.clearOutputDirectories
import org.jetbrains.kotlin.gradle.tasks.throwGradleExceptionIfError
import org.jetbrains.kotlin.gradle.utils.toSortedPathsArray
open class KaptWithKotlincTask : KaptTask(), CompilerArgumentAwareWithInput<K2JVMCompilerArguments> {
@@ -70,7 +69,7 @@ open class KaptWithKotlincTask : KaptTask(), CompilerArgumentAwareWithInput<K2JV
}
val compilerRunner = GradleCompilerRunner(project)
compilerRunner.runJvmCompiler(
compilerRunner.runJvmCompilerAsync(
sourcesToCompile = emptyList(),
commonSources = emptyList(),
javaSourceRoots = javaSourceRoots,
@@ -20,7 +20,6 @@ import org.gradle.api.Project
import org.gradle.api.tasks.CacheableTask
import org.jetbrains.kotlin.cli.common.arguments.K2MetadataCompilerArguments
import org.jetbrains.kotlin.compilerRunner.GradleCompilerEnvironment
import org.jetbrains.kotlin.compilerRunner.GradleCompilerRunner
import org.jetbrains.kotlin.compilerRunner.OutputItemsCollectorImpl
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonCompile
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformCommonOptions
@@ -64,11 +63,11 @@ internal open class KotlinCompileCommon : AbstractKotlinCompile<K2MetadataCompil
kotlinOptionsImpl.updateArguments(args)
}
override fun callCompiler(args: K2MetadataCompilerArguments, sourceRoots: SourceRoots, changedFiles: ChangedFiles) {
override fun callCompilerAsync(args: K2MetadataCompilerArguments, sourceRoots: SourceRoots, changedFiles: ChangedFiles) {
val messageCollector = GradleMessageCollector(logger)
val outputItemCollector = OutputItemsCollectorImpl()
val compilerRunner = compilerRunner()
val environment = GradleCompilerEnvironment(computedCompilerClasspath, messageCollector, outputItemCollector)
compilerRunner.runMetadataCompiler(sourceRoots.kotlinSourceFiles, args, environment)
compilerRunner.runMetadataCompilerAsync(sourceRoots.kotlinSourceFiles, args, environment)
}
}
@@ -17,7 +17,6 @@ import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.api.tasks.incremental.IncrementalTaskInputs
import org.gradle.workers.WorkerExecutor
import org.jetbrains.kotlin.build.DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.cli.common.arguments.CommonToolArguments
import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments
@@ -275,13 +274,17 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
sourceRoots.log(this.name, logger)
val args = prepareCompilerArguments()
taskBuildDirectory.mkdirs()
callCompiler(args, sourceRoots, ChangedFiles(inputs))
callCompilerAsync(args, sourceRoots, ChangedFiles(inputs))
}
@Internal
internal abstract fun getSourceRoots(): SourceRoots
internal abstract fun callCompiler(args: T, sourceRoots: SourceRoots, changedFiles: ChangedFiles)
/**
* Compiler might be executed asynchronuosly. Do not do anything requiring end of compilation after this function is called.
* @see [GradleKotlinCompilerWork]
*/
internal abstract fun callCompilerAsync(args: T, sourceRoots: SourceRoots, changedFiles: ChangedFiles)
override fun setupCompilerArgs(args: T, defaultsOnly: Boolean) {
args.coroutinesState = when (coroutines) {
@@ -381,7 +384,7 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
@Internal
override fun getSourceRoots() = SourceRoots.ForJvm.create(getSource(), sourceRootsContainer, sourceFilesExtensions)
override fun callCompiler(args: K2JVMCompilerArguments, sourceRoots: SourceRoots, changedFiles: ChangedFiles) {
override fun callCompilerAsync(args: K2JVMCompilerArguments, sourceRoots: SourceRoots, changedFiles: ChangedFiles) {
sourceRoots as SourceRoots.ForJvm
val messageCollector = GradleMessageCollector(logger)
@@ -395,6 +398,7 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
taskBuildDirectory,
usePreciseJavaTracking = usePreciseJavaTracking,
localStateDirs = outputDirectories,
disableMultiModuleIC = disableMultiModuleIC(),
multiModuleICSettings = multiModuleICSettings
)
} else {
@@ -402,26 +406,19 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
null
}
try {
val environment = GradleCompilerEnvironment(computedCompilerClasspath, messageCollector, outputItemCollector, icEnv)
compilerRunner.runJvmCompiler(
sourceRoots.kotlinSourceFiles,
commonSourceSet.toList(),
sourceRoots.javaSourceRoots,
javaPackagePrefix,
args,
environment
)
disableMultiModuleICIfNeeded()
} catch (e: Throwable) {
cleanupOnError()
throw e
}
val environment = GradleCompilerEnvironment(computedCompilerClasspath, messageCollector, outputItemCollector, icEnv)
compilerRunner.runJvmCompilerAsync(
sourceRoots.kotlinSourceFiles,
commonSourceSet.toList(),
sourceRoots.javaSourceRoots,
javaPackagePrefix,
args,
environment
)
}
private fun disableMultiModuleICIfNeeded() {
if (!incremental || javaOutputDir == null) return
private fun disableMultiModuleIC(): Boolean {
if (!incremental || javaOutputDir == null) return false
val illegalTask = project.tasks.matching {
it is AbstractCompile &&
@@ -436,13 +433,10 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
"unknown task '$illegalTask' destination dir ${illegalTask.destinationDir} " +
"intersects with java destination dir $javaOutputDir"
)
buildHistoryFile.delete()
return true
}
}
private fun cleanupOnError() {
logger.kotlinInfo("deleting $destinationDir on error")
destinationDir.deleteRecursively()
return false
}
// override setSource to track source directory sets and files (for generated android folders)
@@ -523,7 +517,7 @@ open class Kotlin2JsCompile() : AbstractKotlinCompile<K2JSCompilerArguments>(),
?.let { if (LibraryUtils.isKotlinJavascriptLibrary(it)) it else null }
?.absolutePath
override fun callCompiler(args: K2JSCompilerArguments, sourceRoots: SourceRoots, changedFiles: ChangedFiles) {
override fun callCompilerAsync(args: K2JSCompilerArguments, sourceRoots: SourceRoots, changedFiles: ChangedFiles) {
sourceRoots as SourceRoots.KotlinOnly
logger.debug("Calling compiler")
@@ -561,7 +555,7 @@ open class Kotlin2JsCompile() : AbstractKotlinCompile<K2JSCompilerArguments>(),
} else null
val environment = GradleCompilerEnvironment(computedCompilerClasspath, messageCollector, outputItemCollector, icEnv)
compilerRunner.runJsCompiler(sourceRoots.kotlinSourceFiles, commonSourceSet.toList(), args, environment)
compilerRunner.runJsCompilerAsync(sourceRoots.kotlinSourceFiles, commonSourceSet.toList(), args, environment)
}
}