[maven] IDEA-343042 collect problems at the end of the sync

GitOrigin-RevId: d90487822fd2fae62bbf6293d3308993c956ebab
This commit is contained in:
Dmitry Kichinsky
2025-11-14 16:04:28 +00:00
committed by intellij-monorepo-bot
parent 8b5336d9bd
commit ddc88ddd86
5 changed files with 33 additions and 32 deletions
@@ -28,12 +28,12 @@ import org.jetbrains.idea.maven.plugins.api.MavenModelPropertiesPatcher
import org.jetbrains.idea.maven.server.MavenGoalExecutionResult
import org.jetbrains.idea.maven.utils.MavenArtifactUtil.hasArtifactFile
import org.jetbrains.idea.maven.utils.MavenLog
import org.jetbrains.idea.maven.utils.MavenPathWrapper
import org.jetbrains.idea.maven.utils.MavenUtil
import java.io.*
import java.nio.file.Path
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.CopyOnWriteArrayList
import java.util.function.Predicate
import kotlin.io.path.isDirectory
@@ -50,6 +50,7 @@ class MavenProject(val file: VirtualFile) {
private val cache = ConcurrentHashMap<Key<*>, Any>()
private val stateCache = ConcurrentHashMap<Key<*>, Any>()
private val problemsCache = CopyOnWriteArrayList<MavenProjectProblem>()
enum class ProcMode {
BOTH, ONLY, NONE
@@ -434,17 +435,13 @@ class MavenProject(val file: VirtualFile) {
val problems: List<MavenProjectProblem>
get() {
return collectProblems(null)
return problemsCache
}
@Internal
fun collectProblems(fileExistsPredicate: Predicate<File>?): List<MavenProjectProblem> {
var problemsCache = getStateCachedValue(PROBLEMS_CACHE_KEY)
if (problemsCache == null) {
problemsCache = doCollectProblems(file, fileExistsPredicate)
putStateCachedValue(PROBLEMS_CACHE_KEY, problemsCache)
}
return problemsCache
internal fun collectProblems(fileExistsPredicate: Predicate<File>?) {
val collectedProblems = doCollectProblems(file, fileExistsPredicate)
problemsCache.clear()
problemsCache.addAll(collectedProblems)
}
private fun doCollectProblems(file: VirtualFile, fileExistsPredicate: Predicate<File>?): List<MavenProjectProblem> {
@@ -803,7 +800,6 @@ class MavenProject(val file: VirtualFile) {
companion object {
private val DEPENDENCIES_CACHE_KEY: Key<MavenArtifactIndex?> = Key.create("MavenProject.DEPENDENCIES_CACHE_KEY")
private val FILTERS_CACHE_KEY: Key<List<String>> = Key.create("MavenProject.FILTERS_CACHE_KEY")
private val PROBLEMS_CACHE_KEY: Key<List<MavenProjectProblem>> = Key.create("MavenProject.PROBLEMS_CACHE_KEY")
private val UNRESOLVED_DEPENDENCIES_CACHE_KEY: Key<List<MavenArtifact>> = Key.create("MavenProject.UNRESOLVED_DEPENDENCIES_CACHE_KEY")
private val UNRESOLVED_PLUGINS_CACHE_KEY: Key<List<MavenPlugin>> = Key.create("MavenProject.UNRESOLVED_PLUGINS_CACHE_KEY")
private val UNRESOLVED_EXTENSIONS_CACHE_KEY: Key<List<MavenArtifact>> = Key.create("MavenProject.UNRESOLVED_EXTENSIONS_CACHE_KEY")
@@ -58,8 +58,6 @@ import org.jetbrains.idea.maven.telemetry.tracer
import org.jetbrains.idea.maven.utils.MavenActivityKey
import org.jetbrains.idea.maven.utils.MavenLog
import org.jetbrains.idea.maven.utils.MavenUtil
import java.io.File
import java.nio.file.Files
@ApiStatus.Experimental
interface MavenAsyncProjectsManager {
@@ -113,10 +111,6 @@ interface MavenAsyncProjectsManager {
syncProject: Boolean,
): List<Module>
fun projectFileExists(file: File): Boolean {
return Files.exists(file.toPath())
}
suspend fun onProjectStartup()
}
@@ -468,6 +462,10 @@ open class MavenProjectsManagerEx(project: Project, private val cs: CoroutineSco
importModules(syncActivity, resolutionResult, modelsProvider, mavenEmbedderWrappers)
}
tracer.spanBuilder("collectMavenProblems").useWithScope {
projectsTree.collectProblems()
}
tracer.spanBuilder("notifyMavenProblems").useWithScope {
MavenResolveResultProblemProcessor.notifyMavenProblems(myProject)
}
@@ -25,6 +25,7 @@ import com.intellij.util.containers.DisposableWrapperList
import com.intellij.util.containers.FileCollectionFactory
import it.unimi.dsi.fastutil.Hash
import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet
import kotlinx.coroutines.*
import org.jdom.output.Format
import org.jdom.output.XMLOutputter
import org.jetbrains.annotations.ApiStatus
@@ -36,12 +37,15 @@ import org.jetbrains.idea.maven.server.NativeMavenProjectHolder
import org.jetbrains.idea.maven.telemetry.tracer
import org.jetbrains.idea.maven.utils.*
import java.io.*
import java.lang.Runnable
import java.nio.file.Files
import java.nio.file.Path
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.locks.Lock
import java.util.concurrent.locks.ReentrantReadWriteLock
import java.util.function.Consumer
import java.util.function.Predicate
import java.util.regex.Pattern
import java.util.zip.CRC32
@@ -1104,6 +1108,23 @@ class MavenProjectsTree(val project: Project) {
}
internal suspend fun collectProblems() {
val existingFiles = ConcurrentHashMap<File, Boolean>()
val fileExistsPredicate = Predicate { f: File -> existingFiles.computeIfAbsent(f) { file: File -> Files.exists(file.toPath()) } }
coroutineScope {
withContext(Dispatchers.IO) {
projects.forEach { project ->
launch(CoroutineName("collecting problems in ${project.name}")) {
tracer.spanBuilder("collectProblems").useWithScope {
project.collectProblems(fileExistsPredicate) // fill problem cache
}
}
}
}
}
}
@ApiStatus.Internal
fun read(path: Path) {
if (!Files.exists(path)) return
@@ -4,12 +4,9 @@ package org.jetbrains.idea.maven.project;
import com.intellij.openapi.util.Pair;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.maven.utils.ParallelRunner;
import java.io.File;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
@ApiStatus.Internal
class MavenProjectsTreeUpdateContext {
@@ -45,18 +42,6 @@ class MavenProjectsTreeUpdateContext {
}
private @NotNull List<Pair<MavenProject, MavenProjectChanges>> mapToListWithPairs() {
var existingFiles = new ConcurrentHashMap<File, Boolean>();
Predicate<File> fileExistsPredicate = f -> {
return existingFiles.computeIfAbsent(f, file -> {
return MavenProjectsManagerEx.getInstance(myTree.getProject()).projectFileExists(file);
});
};
ParallelRunner.getInstance(myTree.getProject()).runInParallelBlocking(updatedProjectsWithChanges.keySet(), mavenProject -> {
mavenProject.collectProblems(fileExistsPredicate); // need for fill problem cache
return null;
});
ArrayList<Pair<MavenProject, MavenProjectChanges>> result = new ArrayList<>(updatedProjectsWithChanges.size());
for (Map.Entry<MavenProject, MavenProjectChanges> entry : updatedProjectsWithChanges.entrySet()) {
result.add(Pair.create(entry.getKey(), entry.getValue()));
@@ -608,6 +608,7 @@ class MavenProjectsTreeReadingTest : MavenProjectsTreeTestCase() {
val mavenProject = tree.findProject(projectPom)!!
resolve(project, mavenProject, mavenGeneralSettings)
assertEquals(log().add("resolved", "project"), listener.log)
updateAllProjects()
assertFalse(mavenProject.problems.isEmpty())
}