Store errors into separate files

This commit is contained in:
nataliya.valtman
2022-09-13 12:39:22 +02:00
parent 4cbee3cde7
commit 4863e5d47b
14 changed files with 150 additions and 20 deletions
@@ -6,7 +6,10 @@
package org.jetbrains.kotlin.build.report package org.jetbrains.kotlin.build.report
import org.jetbrains.kotlin.cli.common.ExitCode import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import java.io.File import java.io.File
import kotlin.reflect.KFunction1
interface ICReporter { interface ICReporter {
@@ -24,6 +27,7 @@ interface ICReporter {
fun reportMarkDirty(affectedFiles: Iterable<File>, reason: String) fun reportMarkDirty(affectedFiles: Iterable<File>, reason: String)
} }
//TODO check and remove?
fun ICReporter.warn(message: () -> String) = report(message, severity = ICReporter.ReportSeverity.WARNING) fun ICReporter.warn(message: () -> String) = report(message, severity = ICReporter.ReportSeverity.WARNING)
fun ICReporter.info(message: () -> String) = report(message, severity = ICReporter.ReportSeverity.INFO) fun ICReporter.info(message: () -> String) = report(message, severity = ICReporter.ReportSeverity.INFO)
fun ICReporter.debug(message: () -> String) = report(message, severity = ICReporter.ReportSeverity.DEBUG) fun ICReporter.debug(message: () -> String) = report(message, severity = ICReporter.ReportSeverity.DEBUG)
@@ -35,3 +39,4 @@ object DoNothingICReporter : ICReporter {
override fun reportMarkDirtyMember(affectedFiles: Iterable<File>, scope: String, name: String) {} override fun reportMarkDirtyMember(affectedFiles: Iterable<File>, scope: String, name: String) {}
override fun reportMarkDirty(affectedFiles: Iterable<File>, reason: String) {} override fun reportMarkDirty(affectedFiles: Iterable<File>, reason: String) {}
} }
@@ -18,6 +18,8 @@ enum class BuildAttributeKind : Serializable {
enum class BuildAttribute(val kind: BuildAttributeKind, val readableString: String) : Serializable { enum class BuildAttribute(val kind: BuildAttributeKind, val readableString: String) : Serializable {
NO_BUILD_HISTORY(BuildAttributeKind.REBUILD_REASON, "Build history file not found"), NO_BUILD_HISTORY(BuildAttributeKind.REBUILD_REASON, "Build history file not found"),
NO_ABI_SNAPSHOT(BuildAttributeKind.REBUILD_REASON, "ABI snapshot not found"), NO_ABI_SNAPSHOT(BuildAttributeKind.REBUILD_REASON, "ABI snapshot not found"),
NO_LAST_BUILD_INFO(BuildAttributeKind.REBUILD_REASON, "Last build info not found"),
INVALID_LAST_BUILD_INFO(BuildAttributeKind.REBUILD_REASON, "Last build info corrupted"),
CLASSPATH_SNAPSHOT_NOT_FOUND(BuildAttributeKind.REBUILD_REASON, "Classpath snapshot not found"), CLASSPATH_SNAPSHOT_NOT_FOUND(BuildAttributeKind.REBUILD_REASON, "Classpath snapshot not found"),
IC_FAILED_TO_GET_CHANGED_FILES(BuildAttributeKind.REBUILD_REASON, "Failed to get changed files"), IC_FAILED_TO_GET_CHANGED_FILES(BuildAttributeKind.REBUILD_REASON, "Failed to get changed files"),
IC_FAILED_TO_COMPUTE_FILES_TO_RECOMPILE(BuildAttributeKind.REBUILD_REASON, "Failed to compute files to recompile"), IC_FAILED_TO_COMPUTE_FILES_TO_RECOMPILE(BuildAttributeKind.REBUILD_REASON, "Failed to compute files to recompile"),
@@ -16,8 +16,10 @@
package org.jetbrains.kotlin.incremental package org.jetbrains.kotlin.incremental
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.incremental.AbiSnapshotImpl.Companion.readAbiSnapshot import org.jetbrains.kotlin.incremental.AbiSnapshotImpl.Companion.readAbiSnapshot
import org.jetbrains.kotlin.incremental.AbiSnapshotImpl.Companion.writeAbiSnapshot import org.jetbrains.kotlin.incremental.AbiSnapshotImpl.Companion.writeAbiSnapshot
import org.jetbrains.kotlin.incremental.util.reportException
import java.io.* import java.io.*
data class BuildInfo(val startTS: Long, val dependencyToAbiSnapshot: Map<String, AbiSnapshot> = mapOf()) : Serializable { data class BuildInfo(val startTS: Long, val dependencyToAbiSnapshot: Map<String, AbiSnapshot> = mapOf()) : Serializable {
@@ -43,10 +45,16 @@ data class BuildInfo(val startTS: Long, val dependencyToAbiSnapshot: Map<String,
} }
} }
fun read(file: File): BuildInfo = fun read(file: File, messageCollector: MessageCollector): BuildInfo? {
ObjectInputStream(FileInputStream(file)).use { return try {
it.readBuildInfo() ObjectInputStream(FileInputStream(file)).use {
it.readBuildInfo()
}
} catch (e: Exception) {
messageCollector.reportException(e)
null
} }
}
fun write(buildInfo: BuildInfo, file: File) { fun write(buildInfo: BuildInfo, file: File) {
ObjectOutputStream(FileOutputStream(file)).use { ObjectOutputStream(FileOutputStream(file)).use {
@@ -18,15 +18,12 @@ package org.jetbrains.kotlin.incremental
import org.jetbrains.kotlin.build.DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS import org.jetbrains.kotlin.build.DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS
import org.jetbrains.kotlin.build.GeneratedFile import org.jetbrains.kotlin.build.GeneratedFile
import org.jetbrains.kotlin.build.report.BuildReporter import org.jetbrains.kotlin.build.report.*
import org.jetbrains.kotlin.build.report.debug
import org.jetbrains.kotlin.build.report.info
import org.jetbrains.kotlin.build.report.metrics.BuildAttribute import org.jetbrains.kotlin.build.report.metrics.BuildAttribute
import org.jetbrains.kotlin.build.report.metrics.BuildAttribute.* import org.jetbrains.kotlin.build.report.metrics.BuildAttribute.*
import org.jetbrains.kotlin.build.report.metrics.BuildPerformanceMetric import org.jetbrains.kotlin.build.report.metrics.BuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.BuildTime import org.jetbrains.kotlin.build.report.metrics.BuildTime
import org.jetbrains.kotlin.build.report.metrics.measure import org.jetbrains.kotlin.build.report.metrics.measure
import org.jetbrains.kotlin.build.report.warn
import org.jetbrains.kotlin.cli.common.* import org.jetbrains.kotlin.cli.common.*
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.cli.common.messages.MessageCollector import org.jetbrains.kotlin.cli.common.messages.MessageCollector
@@ -39,6 +36,7 @@ import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.incremental.parsing.classesFqNames import org.jetbrains.kotlin.incremental.parsing.classesFqNames
import org.jetbrains.kotlin.incremental.util.BufferingMessageCollector import org.jetbrains.kotlin.incremental.util.BufferingMessageCollector
import org.jetbrains.kotlin.incremental.util.reportException
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.progress.CompilationCanceledStatus import org.jetbrains.kotlin.progress.CompilationCanceledStatus
import org.jetbrains.kotlin.util.removeSuffixIfPresent import org.jetbrains.kotlin.util.removeSuffixIfPresent
@@ -100,6 +98,7 @@ abstract class IncrementalCompilerRunner<
) )
} }
is ICResult.Failed -> { is ICResult.Failed -> {
messageCollector.reportException(result.cause)
reporter.warn { reporter.warn {
// The indentation after the first line is intentional (so that this message is distinct from next message) // The indentation after the first line is intentional (so that this message is distinct from next message)
""" """
@@ -126,7 +126,7 @@ class IncrementalJsCompilerRunner(
if (!withAbiSnapshot && !buildHistoryFile.isFile) { if (!withAbiSnapshot && !buildHistoryFile.isFile) {
return CompilationMode.Rebuild(BuildAttribute.NO_BUILD_HISTORY) return CompilationMode.Rebuild(BuildAttribute.NO_BUILD_HISTORY)
} }
val lastBuildInfo = BuildInfo.read(lastBuildInfoFile) val lastBuildInfo = BuildInfo.read(lastBuildInfoFile, messageCollector) ?: return CompilationMode.Rebuild(BuildAttribute.INVALID_LAST_BUILD_INFO)
val dirtyFiles = DirtyFilesContainer(caches, reporter, kotlinSourceFilesExtensions) val dirtyFiles = DirtyFilesContainer(caches, reporter, kotlinSourceFilesExtensions)
initDirtyFiles(dirtyFiles, changedFiles) initDirtyFiles(dirtyFiles, changedFiles)
@@ -195,7 +195,7 @@ open class IncrementalJvmCompilerRunner(
classpathAbiSnapshots: Map<String, AbiSnapshot> classpathAbiSnapshots: Map<String, AbiSnapshot>
): CompilationMode { ): CompilationMode {
return try { return try {
calculateSourcesToCompileImpl(caches, changedFiles, args, classpathAbiSnapshots, withAbiSnapshot) calculateSourcesToCompileImpl(caches, changedFiles, args, messageCollector, classpathAbiSnapshots, withAbiSnapshot)
} finally { } finally {
psiFileProvider.messageCollector.flush(messageCollector) psiFileProvider.messageCollector.flush(messageCollector)
psiFileProvider.messageCollector.clear() psiFileProvider.messageCollector.clear()
@@ -238,6 +238,7 @@ open class IncrementalJvmCompilerRunner(
caches: IncrementalJvmCachesManager, caches: IncrementalJvmCachesManager,
changedFiles: ChangedFiles.Known, changedFiles: ChangedFiles.Known,
args: K2JVMCompilerArguments, args: K2JVMCompilerArguments,
messageCollector: MessageCollector,
abiSnapshots: Map<String, AbiSnapshot>, abiSnapshots: Map<String, AbiSnapshot>,
withAbiSnapshot: Boolean withAbiSnapshot: Boolean
): CompilationMode { ): CompilationMode {
@@ -273,7 +274,10 @@ open class IncrementalJvmCompilerRunner(
// workingDir as workingDir is an @OutputDirectory, so the files must be present in an incremental build.) // workingDir as workingDir is an @OutputDirectory, so the files must be present in an incremental build.)
return CompilationMode.Rebuild(BuildAttribute.NO_BUILD_HISTORY) return CompilationMode.Rebuild(BuildAttribute.NO_BUILD_HISTORY)
} }
val lastBuildInfo = BuildInfo.read(lastBuildInfoFile) if (!lastBuildInfoFile.exists()) {
return CompilationMode.Rebuild(BuildAttribute.NO_LAST_BUILD_INFO)
}
val lastBuildInfo = BuildInfo.read(lastBuildInfoFile, messageCollector) ?: return CompilationMode.Rebuild(BuildAttribute.INVALID_LAST_BUILD_INFO)
reporter.debug { "Last Kotlin Build info -- $lastBuildInfo" } reporter.debug { "Last Kotlin Build info -- $lastBuildInfo" }
val scopes = caches.lookupCache.lookupSymbols.map { it.scope.ifBlank { it.name } }.distinct() val scopes = caches.lookupCache.lookupSymbols.map { it.scope.ifBlank { it.name } }.distinct()
@@ -0,0 +1,14 @@
/*
* Copyright 2010-2022 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.incremental.util
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
internal fun MessageCollector.reportException(e: Throwable) {
report(severity = CompilerMessageSeverity.EXCEPTION, message = "Incremental compilation failed:${e.message}\n${e.stackTraceToString()}")
}
@@ -12,6 +12,10 @@ import org.jetbrains.kotlin.gradle.report.BuildReportType
import org.jetbrains.kotlin.gradle.testbase.* import org.jetbrains.kotlin.gradle.testbase.*
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import java.io.ObjectInputStream import java.io.ObjectInputStream
import kotlin.io.path.exists
import kotlin.io.path.listDirectoryEntries
import kotlin.io.path.name
import kotlin.io.path.notExists
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertNotNull import kotlin.test.assertNotNull
import kotlin.test.assertTrue import kotlin.test.assertTrue
@@ -140,4 +144,22 @@ class BuildReportsIT : KGPBaseTest() {
} }
} }
} }
@DisplayName("Error file is created")
@GradleTest
fun testErrorsFileSmokeTest(gradleVersion: GradleVersion) {
project("simpleProject", gradleVersion) {
build("compileKotlin") {
assertTrue { projectPath.resolve(".gradle/build_errors").listDirectoryEntries().isEmpty() }
}
val kotlinFile = kotlinSourcesDir().resolve("helloWorld.kt")
kotlinFile.modify { it.replace("ArrayList","skjfghsjk") }
buildAndFail("compileKotlin") {
val buildErrorDir = projectPath.resolve(".gradle/build_errors").toFile()
val files = buildErrorDir.listFiles()
assertTrue { files?.first()?.exists() ?: false }
}
}
}
} }
@@ -6,13 +6,13 @@
package org.jetbrains.kotlin.compilerRunner package org.jetbrains.kotlin.compilerRunner
import org.jetbrains.kotlin.config.Services import org.jetbrains.kotlin.config.Services
import org.jetbrains.kotlin.gradle.logging.GradlePrintingMessageCollector import org.jetbrains.kotlin.gradle.logging.GradleErrorMessageCollector
import org.jetbrains.kotlin.gradle.report.ReportingSettings import org.jetbrains.kotlin.gradle.report.ReportingSettings
import java.io.File import java.io.File
internal class GradleCompilerEnvironment( internal class GradleCompilerEnvironment(
val compilerClasspath: Iterable<File>, val compilerClasspath: Iterable<File>,
messageCollector: GradlePrintingMessageCollector, messageCollector: GradleErrorMessageCollector,
outputItemsCollector: OutputItemsCollector, outputItemsCollector: OutputItemsCollector,
val outputFiles: List<File>, val outputFiles: List<File>,
val reportingSettings: ReportingSettings, val reportingSettings: ReportingSettings,
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.daemon.common.filterExtractProps
import org.jetbrains.kotlin.gradle.dsl.KotlinJsProjectExtension import org.jetbrains.kotlin.gradle.dsl.KotlinJsProjectExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull
import org.jetbrains.kotlin.gradle.logging.GradleErrorMessageCollector
import org.jetbrains.kotlin.gradle.logging.kotlinDebug import org.jetbrains.kotlin.gradle.logging.kotlinDebug
import org.jetbrains.kotlin.gradle.logging.kotlinInfo import org.jetbrains.kotlin.gradle.logging.kotlinInfo
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
@@ -67,6 +68,7 @@ internal open class GradleCompilerRunner(
internal val sessionDirProvider = taskProvider.sessionsDir.get() internal val sessionDirProvider = taskProvider.sessionsDir.get()
internal val projectNameProvider = taskProvider.projectName.get() internal val projectNameProvider = taskProvider.projectName.get()
internal val incrementalModuleInfoProvider = taskProvider.buildModulesInfo internal val incrementalModuleInfoProvider = taskProvider.buildModulesInfo
internal val errorsFile = taskProvider.errorsFile.get()
/** /**
* Compiler might be executed asynchronously. Do not do anything requiring end of compilation after this function is called. * Compiler might be executed asynchronously. Do not do anything requiring end of compilation after this function is called.
@@ -203,6 +205,7 @@ internal open class GradleCompilerRunner(
kotlinScriptExtensions = environment.kotlinScriptExtensions, kotlinScriptExtensions = environment.kotlinScriptExtensions,
allWarningsAsErrors = compilerArgs.allWarningsAsErrors, allWarningsAsErrors = compilerArgs.allWarningsAsErrors,
compilerExecutionSettings = compilerExecutionSettings, compilerExecutionSettings = compilerExecutionSettings,
errorsFile = errorsFile
) )
TaskLoggers.put(pathProvider, loggerProvider) TaskLoggers.put(pathProvider, loggerProvider)
return runCompilerAsync( return runCompilerAsync(
@@ -65,6 +65,7 @@ internal class GradleKotlinCompilerWorkArguments(
val kotlinScriptExtensions: Array<String>, val kotlinScriptExtensions: Array<String>,
val allWarningsAsErrors: Boolean, val allWarningsAsErrors: Boolean,
val compilerExecutionSettings: CompilerExecutionSettings, val compilerExecutionSettings: CompilerExecutionSettings,
val errorsFile: File?,
) : Serializable { ) : Serializable {
companion object { companion object {
const val serialVersionUID: Long = 1 const val serialVersionUID: Long = 1
@@ -100,6 +101,7 @@ internal class GradleKotlinCompilerWork @Inject constructor(
private val metrics = if (reportingSettings.buildReportOutputs.isNotEmpty()) BuildMetricsReporterImpl() else DoNothingBuildMetricsReporter private val metrics = if (reportingSettings.buildReportOutputs.isNotEmpty()) BuildMetricsReporterImpl() else DoNothingBuildMetricsReporter
private var icLogLines: List<String> = emptyList() private var icLogLines: List<String> = emptyList()
private val compilerExecutionSettings = config.compilerExecutionSettings private val compilerExecutionSettings = config.compilerExecutionSettings
private val errorsFile = config.errorsFile
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") } }
@@ -119,11 +121,13 @@ internal class GradleKotlinCompilerWork @Inject constructor(
override fun run() { override fun run() {
try { try {
val messageCollector = GradlePrintingMessageCollector(log, allWarningsAsErrors) val gradlePrintingMessageCollector = GradlePrintingMessageCollector(log, allWarningsAsErrors)
val (exitCode, executionStrategy) = compileWithDaemonOrFallbackImpl(messageCollector) val gradleMessageCollector = GradleErrorMessageCollector(gradlePrintingMessageCollector)
val (exitCode, executionStrategy) = compileWithDaemonOrFallbackImpl(gradleMessageCollector)
if (incrementalCompilationEnvironment?.disableMultiModuleIC == true) { if (incrementalCompilationEnvironment?.disableMultiModuleIC == true) {
incrementalCompilationEnvironment.multiModuleICSettings.buildHistoryFile.delete() incrementalCompilationEnvironment.multiModuleICSettings.buildHistoryFile.delete()
} }
errorsFile?.also { gradleMessageCollector.flush(it) }
throwExceptionIfCompilationFailed(exitCode, executionStrategy) throwExceptionIfCompilationFailed(exitCode, executionStrategy)
} finally { } finally {
@@ -0,0 +1,54 @@
/*
* Copyright 2010-2022 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.logging
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSourceLocation
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import java.io.File
import java.io.FileWriter
class GradleErrorMessageCollector(private val delegate: MessageCollector? = null) : MessageCollector {
private val errors = ArrayList<String>()
override fun clear() {
delegate?.clear()
errors.clear()
}
fun report(error: Throwable, location: CompilerMessageSourceLocation?) {
report(CompilerMessageSeverity.EXCEPTION, "${error.message}\n${error.stackTraceToString()}", location)
}
override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageSourceLocation?) {
delegate?.report(severity, message, location)
if (severity in listOf(CompilerMessageSeverity.ERROR, CompilerMessageSeverity.EXCEPTION)) {
synchronized(errors) {
errors.add(message)
}
}
}
override fun hasErrors(): Boolean {
return errors.isNotEmpty()
}
fun flush(file: File) {
if (!hasErrors()) {
return
}
file.createNewFile()
println("Errors were stored into ${file.absolutePath}")
FileWriter(file).use {
for (error in errors) {
it.append("error message: $error\n\n")
}
it.flush()
}
clear()
}
}
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.compilerRunner.GradleCompilerEnvironment
import org.jetbrains.kotlin.compilerRunner.OutputItemsCollectorImpl import org.jetbrains.kotlin.compilerRunner.OutputItemsCollectorImpl
import org.jetbrains.kotlin.gradle.dsl.* import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles
import org.jetbrains.kotlin.gradle.logging.GradleErrorMessageCollector
import org.jetbrains.kotlin.gradle.logging.GradlePrintingMessageCollector import org.jetbrains.kotlin.gradle.logging.GradlePrintingMessageCollector
import org.jetbrains.kotlin.gradle.tasks.internal.KotlinMultiplatformCommonOptionsCompat import org.jetbrains.kotlin.gradle.tasks.internal.KotlinMultiplatformCommonOptionsCompat
import java.io.File import java.io.File
@@ -109,11 +110,12 @@ abstract class KotlinCompileCommon @Inject constructor(
inputChanges: InputChanges, inputChanges: InputChanges,
taskOutputsBackup: TaskOutputsBackup? taskOutputsBackup: TaskOutputsBackup?
) { ) {
val messageCollector = GradlePrintingMessageCollector(logger, args.allWarningsAsErrors) val gradlePrintingMessageCollector = GradlePrintingMessageCollector(logger, args.allWarningsAsErrors)
val gradleMessageCollector = GradleErrorMessageCollector(gradlePrintingMessageCollector)
val outputItemCollector = OutputItemsCollectorImpl() val outputItemCollector = OutputItemsCollectorImpl()
val compilerRunner = compilerRunner.get() val compilerRunner = compilerRunner.get()
val environment = GradleCompilerEnvironment( val environment = GradleCompilerEnvironment(
defaultCompilerClasspath, messageCollector, outputItemCollector, defaultCompilerClasspath, gradleMessageCollector, outputItemCollector,
reportingSettings = reportingSettings(), reportingSettings = reportingSettings(),
outputFiles = allOutputFiles() outputFiles = allOutputFiles()
) )
@@ -123,5 +125,6 @@ abstract class KotlinCompileCommon @Inject constructor(
args, args,
environment environment
) )
compilerRunner.errorsFile?.also { gradleMessageCollector.flush(it) }
} }
} }
@@ -44,6 +44,7 @@ import org.jetbrains.kotlin.gradle.incremental.*
import org.jetbrains.kotlin.gradle.internal.* import org.jetbrains.kotlin.gradle.internal.*
import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState
import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles
import org.jetbrains.kotlin.gradle.logging.GradleErrorMessageCollector
import org.jetbrains.kotlin.gradle.logging.GradleKotlinLogger import org.jetbrains.kotlin.gradle.logging.GradleKotlinLogger
import org.jetbrains.kotlin.gradle.logging.GradlePrintingMessageCollector import org.jetbrains.kotlin.gradle.logging.GradlePrintingMessageCollector
import org.jetbrains.kotlin.gradle.logging.kotlinDebug import org.jetbrains.kotlin.gradle.logging.kotlinDebug
@@ -232,6 +233,12 @@ abstract class GradleCompileTaskProvider @Inject constructor(
} }
} }
) )
@get:Internal
val errorsFile: Provider<File?> = objectFactory
.property(
gradle.rootProject.rootDir.resolve(".gradle/build_errors/").also { it.mkdirs() }
.resolve("errors-${System.currentTimeMillis()}.log"))
} }
abstract class AbstractKotlinCompile<T : CommonCompilerArguments> @Inject constructor( abstract class AbstractKotlinCompile<T : CommonCompilerArguments> @Inject constructor(
@@ -723,7 +730,8 @@ abstract class KotlinCompile @Inject constructor(
validateKotlinAndJavaHasSameTargetCompatibility(args, kotlinSources) validateKotlinAndJavaHasSameTargetCompatibility(args, kotlinSources)
val scriptSources = scriptSources.asFileTree.files val scriptSources = scriptSources.asFileTree.files
val messageCollector = GradlePrintingMessageCollector(logger, args.allWarningsAsErrors) val gradlePrintingMessageCollector = GradlePrintingMessageCollector(logger, args.allWarningsAsErrors,)
val gradleMessageCollector = GradleErrorMessageCollector(gradlePrintingMessageCollector)
val outputItemCollector = OutputItemsCollectorImpl() val outputItemCollector = OutputItemsCollectorImpl()
val compilerRunner = compilerRunner.get() val compilerRunner = compilerRunner.get()
@@ -742,7 +750,7 @@ abstract class KotlinCompile @Inject constructor(
@Suppress("ConvertArgumentToSet", "DEPRECATION") @Suppress("ConvertArgumentToSet", "DEPRECATION")
val environment = GradleCompilerEnvironment( val environment = GradleCompilerEnvironment(
defaultCompilerClasspath, messageCollector, outputItemCollector, defaultCompilerClasspath, gradleMessageCollector, outputItemCollector,
// In the incremental compiler, outputFiles will be cleaned on rebuild. However, because classpathSnapshotDir is not included in // In the incremental compiler, outputFiles will be cleaned on rebuild. However, because classpathSnapshotDir is not included in
// TaskOutputsBackup, we don't want classpathSnapshotDir to be cleaned immediately on rebuild, and therefore we exclude it from // TaskOutputsBackup, we don't want classpathSnapshotDir to be cleaned immediately on rebuild, and therefore we exclude it from
// outputFiles here. (See TaskOutputsBackup's kdoc for more info.) // outputFiles here. (See TaskOutputsBackup's kdoc for more info.)
@@ -765,6 +773,7 @@ abstract class KotlinCompile @Inject constructor(
defaultKotlinJavaToolchain.get().providedJvm.get().javaHome, defaultKotlinJavaToolchain.get().providedJvm.get().javaHome,
taskOutputsBackup taskOutputsBackup
) )
compilerRunner.errorsFile?.also { gradleMessageCollector.flush(it) }
} }
private fun validateKotlinAndJavaHasSameTargetCompatibility( private fun validateKotlinAndJavaHasSameTargetCompatibility(
@@ -1152,7 +1161,8 @@ abstract class Kotlin2JsCompile @Inject constructor(
logger.kotlinDebug("compiling with args ${ArgumentUtils.convertArgumentsToStringList(args)}") logger.kotlinDebug("compiling with args ${ArgumentUtils.convertArgumentsToStringList(args)}")
val messageCollector = GradlePrintingMessageCollector(logger, args.allWarningsAsErrors) val gradlePrintingMessageCollector = GradlePrintingMessageCollector(logger, args.allWarningsAsErrors)
val gradleMessageCollector = GradleErrorMessageCollector(gradlePrintingMessageCollector)
val outputItemCollector = OutputItemsCollectorImpl() val outputItemCollector = OutputItemsCollectorImpl()
val compilerRunner = compilerRunner.get() val compilerRunner = compilerRunner.get()
@@ -1167,7 +1177,7 @@ abstract class Kotlin2JsCompile @Inject constructor(
} else null } else null
val environment = GradleCompilerEnvironment( val environment = GradleCompilerEnvironment(
defaultCompilerClasspath, messageCollector, outputItemCollector, defaultCompilerClasspath, gradleMessageCollector, outputItemCollector,
outputFiles = allOutputFiles(), outputFiles = allOutputFiles(),
reportingSettings = reportingSettings(), reportingSettings = reportingSettings(),
incrementalCompilationEnvironment = icEnv incrementalCompilationEnvironment = icEnv
@@ -1180,6 +1190,8 @@ abstract class Kotlin2JsCompile @Inject constructor(
environment, environment,
taskOutputsBackup taskOutputsBackup
) )
compilerRunner.errorsFile?.also { gradleMessageCollector.flush(it) }
} }
private val projectRootDir = project.rootDir private val projectRootDir = project.rootDir