diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/logging/gradleLoggingUtils.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/logging/gradleLoggingUtils.kt index f1b57de6f0a..9036cdffe26 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/logging/gradleLoggingUtils.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/logging/gradleLoggingUtils.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.gradle.logging +import org.gradle.api.Task import org.gradle.api.logging.Logger import org.jetbrains.kotlin.compilerRunner.KotlinLogger @@ -31,4 +32,17 @@ internal inline fun KotlinLogger.kotlinDebug(fn: () -> String) { val msg = fn() debug("[KOTLIN] $msg") } +} + +internal inline fun KotlinLogger.logTime(action: String, fn: () -> T): T { + val startNs = System.nanoTime() + val result = fn() + val endNs = System.nanoTime() + + val timeNs = endNs - startNs + val timeMs = timeNs.toDouble() / 1_000_000 + + debug(String.format("%s took %.2f ms", action, timeMs)) + + return result } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt index 36c6814160b..28486d52631 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt @@ -28,16 +28,13 @@ import org.jetbrains.kotlin.gradle.internal.CompilerArgumentAwareWithInput import org.jetbrains.kotlin.gradle.internal.prepareCompilerArguments import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles -import org.jetbrains.kotlin.gradle.logging.GradlePrintingMessageCollector -import org.jetbrains.kotlin.gradle.logging.kotlinDebug -import org.jetbrains.kotlin.gradle.logging.kotlinWarn +import org.jetbrains.kotlin.gradle.logging.* import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.utils.* import org.jetbrains.kotlin.incremental.ChangedFiles import org.jetbrains.kotlin.incremental.classpathAsList import org.jetbrains.kotlin.incremental.destinationAsFile import org.jetbrains.kotlin.utils.LibraryUtils -import org.jetbrains.kotlin.utils.keysToMap import java.io.File import java.util.* import javax.inject.Inject @@ -254,6 +251,8 @@ abstract class AbstractKotlinCompile() : AbstractKo } } + private val kotlinLogger by lazy { GradleKotlinLogger(logger) } + internal open fun compilerRunner(): GradleCompilerRunner = GradleCompilerRunner(this) @@ -266,18 +265,12 @@ abstract class AbstractKotlinCompile() : AbstractKo // If task throws exception, but its outputs are changed during execution, // then Gradle forces next build to be non-incremental (see Gradle's DefaultTaskArtifactStateRepository#persistNewOutputs) // To prevent this, we backup outputs before incremental build and restore when exception is thrown - val prevOutputs: Map? = if (incremental && inputs.isIncremental) { - val outputFiles = HashSet() - allOutputFiles().forEach { - if (it.isDirectory) { - it.walk().filterTo(outputFiles, File::isFile) - } else if (it.isFile) { - outputFiles.add(it) + val outputsBackup: TaskOutputsBackup? = + if (incremental && inputs.isIncremental) + kotlinLogger.logTime("Backing up outputs for incremental build") { + TaskOutputsBackup(allOutputFiles()) } - } - - outputFiles.keysToMap { it.readBytes() } - } else null + else null if (!incremental) { clearLocalState("IC is disabled") @@ -286,26 +279,11 @@ abstract class AbstractKotlinCompile() : AbstractKo try { executeImpl(inputs) } catch (t: Throwable) { - allOutputFiles().forEach { - if (it.isDirectory) { - it.deleteRecursively() - } else if (it.isFile) { - it.delete() + if (outputsBackup != null) { + kotlinLogger.logTime("Restoring previous outputs on error") { + outputsBackup.restoreOutputs() } } - - if (prevOutputs != null) { - val dirs = HashSet() - - for ((file, bytes) in prevOutputs) { - val dir = file.parentFile - if (dirs.add(dir)) { - dir.mkdirs() - } - file.writeBytes(bytes) - } - } - throw t } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/TasksOutputsBackup.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/TasksOutputsBackup.kt new file mode 100644 index 00000000000..8a448bca74e --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/TasksOutputsBackup.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. 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 + +import org.gradle.api.file.FileCollection +import org.jetbrains.kotlin.utils.keysToMap +import java.io.File +import java.util.HashSet + +internal class TaskOutputsBackup(private val outputs: FileCollection) { + private val previousOutputs: Map + + init { + val outputFiles = HashSet() + outputs.forEach { + if (it.isDirectory) { + it.walk().filterTo(outputFiles, File::isFile) + } else if (it.isFile) { + outputFiles.add(it) + } + } + + previousOutputs = outputFiles.keysToMap { it.readBytes() } + } + + fun restoreOutputs() { + outputs.forEach { + if (it.isDirectory) { + it.deleteRecursively() + } else if (it.isFile) { + it.delete() + } + } + + val dirs = HashSet() + + for ((file, bytes) in previousOutputs) { + val dir = file.parentFile + if (dirs.add(dir)) { + dir.mkdirs() + } + file.writeBytes(bytes) + } + } +}