Add proper message logging
diff --git a/compiler/incremental-compilation-facade/api/src/main/kotlin/org/jetbrains/kotlin/api/Callbacks.kt b/compiler/incremental-compilation-facade/api/src/main/kotlin/org/jetbrains/kotlin/api/Callbacks.kt index b57fcb2..15705dc 100644 --- a/compiler/incremental-compilation-facade/api/src/main/kotlin/org/jetbrains/kotlin/api/Callbacks.kt +++ b/compiler/incremental-compilation-facade/api/src/main/kotlin/org/jetbrains/kotlin/api/Callbacks.kt
@@ -10,5 +10,12 @@ ) interface MessageLogger { + fun report(level: FacadeLogLevel, message: String) +} +enum class FacadeLogLevel { + ERROR, + WARNING, + INFO, + DEBUG, } \ No newline at end of file
diff --git a/compiler/incremental-compilation-facade/impl/src/main/kotlin/org/jetbrains/kotlin/incremental/DefaultIncrementalCompilerFacade.kt b/compiler/incremental-compilation-facade/impl/src/main/kotlin/org/jetbrains/kotlin/incremental/DefaultIncrementalCompilerFacade.kt index 0d7201e..68d9e789 100644 --- a/compiler/incremental-compilation-facade/impl/src/main/kotlin/org/jetbrains/kotlin/incremental/DefaultIncrementalCompilerFacade.kt +++ b/compiler/incremental-compilation-facade/impl/src/main/kotlin/org/jetbrains/kotlin/incremental/DefaultIncrementalCompilerFacade.kt
@@ -7,10 +7,12 @@ import org.jetbrains.kotlin.api.* import org.jetbrains.kotlin.build.report.DoNothingBuildReporter +import org.jetbrains.kotlin.cli.common.ExitCode import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity +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 org.jetbrains.kotlin.compilerRunner.KotlinCompilerRunnerUtils @@ -40,19 +42,33 @@ } } -class MessageReporter(private val messageLogger: MessageLogger) : MessageCollector { - override fun clear() { - TODO("Not yet implemented") - } +class MessageReporter(private val messageLoggerCallback: MessageLogger) : MessageCollector { + override fun clear() {} override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageSourceLocation?) { - TODO("Not yet implemented") + val level = when { + severity.isError -> FacadeLogLevel.ERROR.also { hasErrors = true } + severity.isWarning -> FacadeLogLevel.WARNING + severity == INFO -> FacadeLogLevel.INFO + severity == LOGGING || severity == OUTPUT -> FacadeLogLevel.DEBUG + else -> error("Unknown message severity: $severity") + } + val formattedMessage = buildString { + location?.apply { + val fileUri = File(path).toPath().toUri() + append("$fileUri") + if (line > 0 && column > 0) { + append(":$line:$column ") + } + } + append(message) + } + messageLoggerCallback.report(level, formattedMessage) } - override fun hasErrors(): Boolean { - TODO("Not yet implemented") - } + private var hasErrors = false + override fun hasErrors() = hasErrors } class DefaultIncrementalCompilerFacade : IncrementalCompilerFacade { @@ -60,12 +76,12 @@ launchOptions: LaunchOptions.Daemon, arguments: List<String>, options: org.jetbrains.kotlin.api.CompilationOptions, - ) { + messageCollector: MessageCollector, + ): ExitCode { println("Compiling with daemon") val compilerId = CompilerId.makeCompilerId(launchOptions.classpath) val clientIsAliveFlagFile = File("1") val sessionIsAliveFlagFile = File("2") - val messageCollector = DumbMessageCollector val daemonOptions = configureDaemonJVMOptions( inheritMemoryLimits = true, @@ -118,30 +134,43 @@ kotlinScriptExtensions = options.kotlinScriptExtensions, ) } - daemon.compile( + val exitCode = daemon.compile( sessionId, arguments.toTypedArray(), daemonCompileOptions, BasicCompilerServicesWithResultsFacadeServer(messageCollector), DaemonCompilationResults() - ) + ).get() + return ExitCode.values().find { it.code == exitCode } ?: if (exitCode == 0) { + ExitCode.OK + } else { + ExitCode.COMPILATION_ERROR + } } - private fun compileInProcess(arguments: List<String>, options: org.jetbrains.kotlin.api.CompilationOptions) { + private fun compileInProcess( + arguments: List<String>, + options: org.jetbrains.kotlin.api.CompilationOptions, + messageCollector: MessageCollector, + ): ExitCode { println("Compiling in-process") val compiler = createCompiler(options.targetPlatform) val parsedArguments = prepareAndValidateCompilerArguments(compiler, arguments) - when (options) { - is org.jetbrains.kotlin.api.CompilationOptions.Incremental -> compileIncrementally(parsedArguments, options) + return when (options) { + is org.jetbrains.kotlin.api.CompilationOptions.Incremental -> compileIncrementally(parsedArguments, options, messageCollector) is org.jetbrains.kotlin.api.CompilationOptions.NonIncremental -> compiler.exec( - DumbMessageCollector, + messageCollector, Services.EMPTY, parsedArguments ) } } - private fun compileIncrementally(args: CommonCompilerArguments, options: org.jetbrains.kotlin.api.CompilationOptions.Incremental) { + private fun compileIncrementally( + args: CommonCompilerArguments, + options: org.jetbrains.kotlin.api.CompilationOptions.Incremental, + messageCollector: MessageCollector, + ): ExitCode { val incrementalCompilerRunner = when (options.targetPlatform) { TargetPlatform.JVM -> IncrementalCompilerRunnerWithArgs( args as K2JVMCompilerArguments, @@ -177,12 +206,12 @@ error("Unsupported platform") } } - execIncrementalCompilerRunner( + return execIncrementalCompilerRunner( incrementalCompilerRunner, options.kotlinScriptExtensions?.toList() ?: emptyList(), prepareFileChanges(options.areFileChangesKnown, options.modifiedFiles, options.deletedFiles), options.modulesInfo.projectRoot, - DumbMessageCollector + messageCollector ) } @@ -192,9 +221,13 @@ options: org.jetbrains.kotlin.api.CompilationOptions, callbacks: Callbacks, ) { - when (launchOptions) { - is LaunchOptions.Daemon -> compileWithDaemon(launchOptions, arguments, options) - is LaunchOptions.InProcess -> compileInProcess(arguments, options) + val messageCollector = callbacks.messageLogger?.let { MessageReporter(it) } ?: DumbMessageCollector + val exitCode = when (launchOptions) { + is LaunchOptions.Daemon -> compileWithDaemon(launchOptions, arguments, options, messageCollector) + is LaunchOptions.InProcess -> compileInProcess(arguments, options, messageCollector) + } + if (exitCode != ExitCode.OK) { + throw Exception("Compilation failed") } } } \ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/compilerRunner/GradleIncrementalCompilationFacadeRunner.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/compilerRunner/GradleIncrementalCompilationFacadeRunner.kt index ec18883..138d1d4 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/compilerRunner/GradleIncrementalCompilationFacadeRunner.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/compilerRunner/GradleIncrementalCompilationFacadeRunner.kt
@@ -16,17 +16,21 @@ import org.gradle.workers.WorkQueue import org.gradle.workers.WorkerExecutor import org.jetbrains.kotlin.api.* +import org.jetbrains.kotlin.api.FacadeLogLevel.* import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter import org.jetbrains.kotlin.build.report.metrics.BuildPerformanceMetric import org.jetbrains.kotlin.build.report.metrics.BuildTime import org.jetbrains.kotlin.build.report.metrics.measure -import org.jetbrains.kotlin.daemon.common.CompilerMode +import org.jetbrains.kotlin.gradle.logging.GradleKotlinLogger +import org.jetbrains.kotlin.gradle.logging.SL4JKotlinLogger +import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskLoggers import org.jetbrains.kotlin.gradle.tasks.* import org.jetbrains.kotlin.gradle.tasks.CompilationErrorException import org.jetbrains.kotlin.gradle.tasks.FailedCompilationException import org.jetbrains.kotlin.gradle.tasks.OOMErrorException import org.jetbrains.kotlin.gradle.tasks.TaskOutputsBackup import org.jetbrains.kotlin.incremental.* +import org.slf4j.LoggerFactory import java.io.File import java.net.URLClassLoader import java.util.* @@ -119,6 +123,21 @@ } } + private val taskPath + get() = workArguments.taskPath + private val log: KotlinLogger = + TaskLoggers.get(taskPath)?.let { GradleKotlinLogger(it).apply { debug("Using '$taskPath' logger") } } + ?: run { + val logger = LoggerFactory.getLogger("GradleKotlinCompilerWork") + val kotlinLogger = if (logger is org.gradle.api.logging.Logger) { + GradleKotlinLogger(logger) + } else SL4JKotlinLogger(logger) + + kotlinLogger.apply { + debug("Could not get logger for '$taskPath'. Falling back to sl4j logger") + } + } + override fun execute() { val taskOutputsBackup = if (parameters.snapshotsDir.isPresent) { TaskOutputsBackup( @@ -144,7 +163,13 @@ val classloader = URLClassLoader(classpath.toList().map { it.toURI().toURL() }.toTypedArray(), parentClassloader) val facade = ServiceLoader.load(IncrementalCompilerFacade::class.java, classloader).singleOrNull() ?: error("Compiler classpath should contain one and only one implementation of ${IncrementalCompilerFacade::class.java.name}") - facade.compile(prepareLaunchOptions(), workArguments.compilerArgs.toList(), prepareKotlinCompilerOptions(), Callbacks(null)) + val messageLogger = GradleFacadeMessageLogger(log, workArguments.allWarningsAsErrors) + facade.compile( + prepareLaunchOptions(), + workArguments.compilerArgs.toList(), + prepareKotlinCompilerOptions(), + Callbacks(messageLogger) + ) } catch (e: FailedCompilationException) { // Restore outputs only in cases where we expect that the user will make some changes to their project: // - For a compilation error, the user will need to fix their source code @@ -187,4 +212,17 @@ super.loadClass(name, resolve) } } +} + +private class GradleFacadeMessageLogger(private val log: KotlinLogger, private val warningsAsErrors: Boolean) : MessageLogger { + override fun report(level: FacadeLogLevel, message: String) { + when (level) { + INFO -> log.info("i: $message") + DEBUG -> log.debug("v: $message") + else -> when { + level == ERROR || warningsAsErrors -> log.error("e: $message") + else -> log.warn("w: $message") + } + } + } } \ No newline at end of file