From cc6023df7263cbf9beaa753dede9d2108cfe9c65 Mon Sep 17 00:00:00 2001 From: "Vladislav.Soroka" Date: Thu, 9 Sep 2021 12:44:25 +0300 Subject: [PATCH] [Gradle] wait for import finish during project preparation for opening in headless or automated environments IDEA-277743 GitOrigin-RevId: ffd7cc30804fe18dd593ca15647dc2b692a5b4fc --- .../GradleCommandLineProjectConfigurator.kt | 51 ++++++++++++------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/GradleCommandLineProjectConfigurator.kt b/plugins/gradle/src/org/jetbrains/plugins/gradle/GradleCommandLineProjectConfigurator.kt index b090350521ce..afc4a607eca3 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/GradleCommandLineProjectConfigurator.kt +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/GradleCommandLineProjectConfigurator.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.gradle import com.intellij.ide.CommandLineInspectionProjectConfigurator @@ -8,7 +8,9 @@ import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.externalSystem.autoimport.AutoImportProjectTracker import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListenerAdapter +import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskType import com.intellij.openapi.externalSystem.service.notification.ExternalSystemProgressNotificationManager +import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataImportListener import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil import com.intellij.openapi.project.Project import com.intellij.openapi.util.io.FileUtil @@ -54,12 +56,13 @@ class GradleCommandLineProjectConfigurator : CommandLineInspectionProjectConfigu linkProjects(basePath, project) } val progressManager = ExternalSystemProgressNotificationManager.getInstance() - val notificationListener = StateNotificationListener() + val notificationListener = StateNotificationListener(project) try { progressManager.addNotificationListener(notificationListener) importProjects(project) notificationListener.waitForImportEnd() - } finally { + } + finally { progressManager.removeNotificationListener(notificationListener) } } @@ -114,42 +117,54 @@ class GradleCommandLineProjectConfigurator : CommandLineInspectionProjectConfigu } - class StateNotificationListener : ExternalSystemTaskNotificationListenerAdapter() { + class StateNotificationListener(private val project: Project) : ExternalSystemTaskNotificationListenerAdapter() { private val externalSystemState = ConcurrentHashMap>() override fun onSuccess(id: ExternalSystemTaskId) { - LOG.info("Gradle import success: ${id.ideProjectId}") - val future = externalSystemState[id] ?: return - future.complete(id) + if (!id.isGradleProjectResolveTask()) return + LOG.info("Gradle resolve success: ${id.ideProjectId}") + val connection = project.messageBus.simpleConnect() + connection.subscribe(ProjectDataImportListener.TOPIC, object : ProjectDataImportListener { + override fun onImportFinished(projectPath: String?) { + LOG.info("Gradle import success: ${id.ideProjectId}") + val future = externalSystemState[id] ?: return + future.complete(id) + } + + override fun onImportFailed(projectPath: String?) { + LOG.info("Gradle import failure: ${id.ideProjectId}") + val future = externalSystemState[id] ?: return + future.completeExceptionally(IllegalStateException("Gradle project ${id.ideProjectId} import failed.")) + } + }) } override fun onFailure(id: ExternalSystemTaskId, e: Exception) { - LOG.error("Gradle import failure ${id.ideProjectId}", e) + if (!id.isGradleProjectResolveTask()) return + LOG.error("Gradle resolve failure ${id.ideProjectId}", e) val future = externalSystemState[id] ?: return - future.completeExceptionally(IllegalStateException("Gradle project ${id.ideProjectId} import failed.", e)) + future.completeExceptionally(IllegalStateException("Gradle project ${id.ideProjectId} resolve failed.", e)) } override fun onCancel(id: ExternalSystemTaskId) { - LOG.error("Gradle import canceled ${id.ideProjectId}") + if (!id.isGradleProjectResolveTask()) return + LOG.error("Gradle resolve canceled ${id.ideProjectId}") val future = externalSystemState[id] ?: return - future.completeExceptionally(IllegalStateException("Import of ${id.ideProjectId} was canceled")) + future.completeExceptionally(IllegalStateException("Resolve of ${id.ideProjectId} was canceled")) } override fun onStart(id: ExternalSystemTaskId) { + if (!id.isGradleProjectResolveTask()) return externalSystemState[id] = CompletableFuture() - LOG.info("Gradle import started ${id.ideProjectId}") + LOG.info("Gradle project resolve started ${id.ideProjectId}") } fun waitForImportEnd() { externalSystemState.values.forEach { it.get() } } - override fun onEnd(id: ExternalSystemTaskId) { - val future = externalSystemState[id] ?: return - if (future.isDone) return - LOG.error("Gradle import finished ${id.ideProjectId} without success event") - future.completeExceptionally(IllegalStateException("Import of ${id.ideProjectId} was finished without success event")) - } + private fun ExternalSystemTaskId.isGradleProjectResolveTask() = this.projectSystemId == GradleConstants.SYSTEM_ID && + this.type == ExternalSystemTaskType.RESOLVE_PROJECT } class LoggingNotificationListener : ExternalSystemTaskNotificationListenerAdapter() {