diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/vcs/UnloadedModulesCompilationCheckinHandler.kt b/java/compiler/impl/src/com/intellij/compiler/impl/vcs/UnloadedModulesCompilationCheckinHandler.kt index 05af2becec1e..14c1f899a7da 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/vcs/UnloadedModulesCompilationCheckinHandler.kt +++ b/java/compiler/impl/src/com/intellij/compiler/impl/vcs/UnloadedModulesCompilationCheckinHandler.kt @@ -1,33 +1,33 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.compiler.impl.vcs -import com.intellij.CommonBundle +import com.intellij.build.BuildContentManager import com.intellij.compiler.CompilerWorkspaceConfiguration import com.intellij.compiler.impl.ModuleCompileScope import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.EDT import com.intellij.openapi.application.ModalityState +import com.intellij.openapi.application.readAction import com.intellij.openapi.compiler.CompilerManager import com.intellij.openapi.compiler.JavaCompilerBundle import com.intellij.openapi.module.ModuleManager import com.intellij.openapi.project.Project import com.intellij.openapi.roots.ProjectFileIndex import com.intellij.openapi.roots.impl.DirectoryIndex -import com.intellij.openapi.ui.Messages import com.intellij.openapi.vcs.CheckinProjectPanel import com.intellij.openapi.vcs.changes.CommitContext -import com.intellij.openapi.vcs.changes.CommitExecutor import com.intellij.openapi.vcs.changes.ui.BooleanCommitOption.Companion.create -import com.intellij.openapi.vcs.checkin.CheckinHandler -import com.intellij.openapi.vcs.checkin.CheckinHandlerFactory +import com.intellij.openapi.vcs.checkin.* import com.intellij.openapi.vcs.ui.RefreshableOnComponent -import com.intellij.openapi.wm.ToolWindowId import com.intellij.openapi.wm.ToolWindowManager -import com.intellij.util.PairConsumer -import com.intellij.xml.util.XmlStringUtil -import java.util.concurrent.atomic.AtomicReference +import com.intellij.util.io.await +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import java.util.concurrent.CompletableFuture class UnloadedModulesCompilationCheckinHandler(private val project: Project, - private val checkinPanel: CheckinProjectPanel) : CheckinHandler() { + private val checkinPanel: CheckinProjectPanel) : CheckinHandler(), CommitCheck { + override fun getBeforeCheckinConfigurationPanel(): RefreshableOnComponent? { return if (ModuleManager.getInstance(project).unloadedModuleDescriptions.isNotEmpty()) create(checkinPanel.getProject(), this, false, @@ -40,61 +40,69 @@ class UnloadedModulesCompilationCheckinHandler(private val project: Project, } } - override fun beforeCheckin(executor: CommitExecutor?, additionalDataConsumer: PairConsumer): ReturnResult { - if (!settings.COMPILE_AFFECTED_UNLOADED_MODULES_BEFORE_COMMIT || - ModuleManager.getInstance(project).unloadedModuleDescriptions.isEmpty()) { - return ReturnResult.COMMIT + override suspend fun runCheck(commitInfo: CommitInfo): CommitProblem? = withContext(Dispatchers.Default) { + val unloadedModulesCompileScope = readAction { + if (ModuleManager.getInstance(project).unloadedModuleDescriptions.isEmpty()) { + return@readAction null + } + val fileIndex = ProjectFileIndex.getInstance(project) + val compilerManager = CompilerManager.getInstance(project) + val affectedModules = checkinPanel.getVirtualFiles() + .filter { compilerManager.isCompilableFileType(it.fileType) } + .mapNotNullTo(LinkedHashSet()) { fileIndex.getModuleForFile(it) } + val affectedUnloadedModules = affectedModules.flatMapTo(LinkedHashSet()) { + DirectoryIndex.getInstance(project).getDependentUnloadedModules(it) + } + if (affectedUnloadedModules.isEmpty()) { + return@readAction null + } + ModuleCompileScope(project, affectedModules, affectedUnloadedModules, true, false) } - val fileIndex = ProjectFileIndex.getInstance(project) - val compilerManager = CompilerManager.getInstance(project) - val affectedModules = checkinPanel.getVirtualFiles() - .filter { compilerManager.isCompilableFileType(it.fileType) } - .mapNotNullTo(LinkedHashSet()) { fileIndex.getModuleForFile(it) } - val affectedUnloadedModules = affectedModules.flatMapTo(LinkedHashSet()) { - DirectoryIndex.getInstance(project).getDependentUnloadedModules(it) + if (unloadedModulesCompileScope == null) { + return@withContext null } - if (affectedUnloadedModules.isEmpty()) { - return ReturnResult.COMMIT - } - val result = AtomicReference() - compilerManager.makeWithModalProgress(ModuleCompileScope(project, affectedModules, affectedUnloadedModules, true, false)) { aborted, errors, _, _ -> - result.set(when { - aborted -> BuildResult.CANCELED - errors > 0 -> BuildResult.FAILED - else -> BuildResult.SUCCESSFUL - }) - } - if (result.get() == BuildResult.SUCCESSFUL) { - return ReturnResult.COMMIT - } - val message = JavaCompilerBundle.message("dialog.message.compilation.of.unloaded.modules.failed") - val answer = Messages.showYesNoCancelDialog(project, XmlStringUtil.wrapInHtml(message), JavaCompilerBundle - .message("dialog.title.compilation.failed"), - JavaCompilerBundle.message("button.text.checkin.handler.commit"), - JavaCompilerBundle.message("button.text.checkin.handler.show.errors"), - CommonBundle.getCancelButtonText(), null) - return when (answer) { - Messages.CANCEL -> ReturnResult.CANCEL - Messages.YES -> ReturnResult.COMMIT - else -> { - ApplicationManager.getApplication().invokeLater({ - val toolWindow = ToolWindowManager.getInstance(project).getToolWindow(ToolWindowId.MESSAGES_WINDOW) - toolWindow?.activate(null, false) - }, ModalityState.nonModal()) - ReturnResult.CLOSE_WINDOW + + val compiledSuccessfully = CompletableFuture() + withContext(Dispatchers.EDT) { + CompilerManager.getInstance(project).make(unloadedModulesCompileScope) { aborted, errors, _, _ -> + if (aborted) { + compiledSuccessfully.cancel(true) + } + else { + compiledSuccessfully.complete(errors == 0) + } } } + + if (compiledSuccessfully.await()) { + return@withContext null + } + return@withContext CompilationFailedProblem() } + override fun getExecutionOrder(): CommitCheck.ExecutionOrder = CommitCheck.ExecutionOrder.LATE + + override fun isEnabled(): Boolean = settings.COMPILE_AFFECTED_UNLOADED_MODULES_BEFORE_COMMIT + private val settings: CompilerWorkspaceConfiguration get() = CompilerWorkspaceConfiguration.getInstance(project) - private enum class BuildResult { - SUCCESSFUL, - FAILED, - CANCELED - } + class CompilationFailedProblem : CommitProblemWithDetails { + override val text: String + get() = JavaCompilerBundle.message("dialog.message.compilation.of.unloaded.modules.failed") + override val showDetailsAction: String + get() = JavaCompilerBundle.message("button.text.checkin.handler.show.errors") + override val showDetailsLink: String + get() = JavaCompilerBundle.message("link.label.checkin.handler.show.errors") + override fun showDetails(project: Project) { + ApplicationManager.getApplication().invokeLater({ + val toolWindow = ToolWindowManager.getInstance(project).getToolWindow(BuildContentManager.TOOL_WINDOW_ID) + toolWindow?.activate(null, false) + }, ModalityState.nonModal()) + } + } + class Factory : CheckinHandlerFactory() { override fun createHandler(panel: CheckinProjectPanel, commitContext: CommitContext): CheckinHandler { return UnloadedModulesCompilationCheckinHandler(panel.getProject(), panel) diff --git a/java/compiler/openapi/resources/messages/JavaCompilerBundle.properties b/java/compiler/openapi/resources/messages/JavaCompilerBundle.properties index 88a6da41fb26..34e6c799210e 100644 --- a/java/compiler/openapi/resources/messages/JavaCompilerBundle.properties +++ b/java/compiler/openapi/resources/messages/JavaCompilerBundle.properties @@ -97,11 +97,10 @@ mesage.text.deployment.descriptor.file.not.exist=Deployment descriptor file ''{0 message.text.deployment.description.invalid.file=Invalid file warning.text.file.has.been.changed=File has been changed during compilation, inspection validation skipped -dialog.message.compilation.of.unloaded.modules.failed=There are unloaded modules in the project which depend on changed files.
\ +dialog.message.compilation.of.unloaded.modules.failed=There are unloaded modules in the project which depend on changed files.\n\ Compilation of these modules finished with errors. -dialog.title.compilation.failed=Compilation Failed -button.text.checkin.handler.commit=&Commit button.text.checkin.handler.show.errors=&Show Errors +link.label.checkin.handler.show.errors=Show errors checkbox.text.compile.affected.unloaded.modules=Compile affected &unloaded modules #artifacts