From f7e94c6bbc79533a75d0b630f2da15335fc9314a Mon Sep 17 00:00:00 2001 From: "Denis.Zhdanov" Date: Sat, 8 Jun 2013 12:57:43 +0400 Subject: [PATCH] IDEA-108633 Gradle: Provide 'auto-import' feature 'Auto-import' api and infrastructure is provided --- .../ExternalSystemAutoImportAware.java | 50 +++ .../util/ExternalSystemApiUtil.java | 4 + .../util/ExternalSystemConstants.java | 8 +- .../ExternalSystemStartupActivity.java | 2 + .../ExternalProjectRefreshCallback.java | 6 +- .../ExternalSystemAutoImporter.java | 344 ++++++++++++++++++ .../manage/LibraryDependencyDataService.java | 19 +- .../manage/ModuleDependencyDataService.java | 15 + 8 files changed, 441 insertions(+), 7 deletions(-) create mode 100644 platform/external-system-api/src/com/intellij/openapi/externalSystem/ExternalSystemAutoImportAware.java create mode 100644 platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/autoimport/ExternalSystemAutoImporter.java diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/ExternalSystemAutoImportAware.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/ExternalSystemAutoImportAware.java new file mode 100644 index 000000000000..80a96b843439 --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/ExternalSystemAutoImportAware.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.externalSystem; + +import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings; +import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * External system integration provides 'auto-import' feature, i.e. it listens for external system config files changes + * and automatically runs external project refresh and sync. + *

+ * Only {@link AbstractExternalSystemSettings#getLinkedProjectsSettings() registered project's} + * {@link ExternalProjectSettings#getExternalProjectPath() config files} are processed by default. However, there is a possible case + * that there are other auxiliary config files/directories which modification should trigger external project refresh. This interface + * is supposed to handle that situation, i.e. any {@link ExternalSystemManager external system implementation} which requires + * the functionality described above should implement this interface. + * + * @author Denis Zhdanov + * @since 6/7/13 6:44 PM + */ +public interface ExternalSystemAutoImportAware { + + /** + * This method serves to check if particular file/dir change should trigger external project refresh. + *

+ * Note: there is no need to handle here {@link ExternalProjectSettings#getExternalProjectPath() external project config files} + * known to the ide as that functionality is built-in. Only auxiliary files should be processed. + * + * @param changedFileOrDirPath changed file/dir path + * @return null if target change should not trigger external project refresh; + * path to config file of an external project which should be refreshed + */ + @Nullable + String getAffectedExternalProjectPath(@NotNull String changedFileOrDirPath); +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java index a548c795710b..c3b2ca44d0ed 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java @@ -186,6 +186,10 @@ public class ExternalSystemApiUtil { return MANAGERS.getValue().get(externalSystemId); } + public static Collection> getAllManagers() { + return MANAGERS.getValue().values(); + } + @NotNull public static Map, List>> group(@NotNull Collection> nodes) { if (nodes.isEmpty()) { diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemConstants.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemConstants.java index 8894c83229b5..30a28511e238 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemConstants.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemConstants.java @@ -34,9 +34,11 @@ public class ExternalSystemConstants { @NonNls @NotNull public static final String TOOL_WINDOW_PLACE = "ExternalSystem.ToolWindow"; @NonNls @NotNull public static final String TREE_PLACE = "ExternalSystem.Tree"; - public static final boolean VERBOSE_PROCESSING = SystemProperties.getBooleanProperty("external.system.verbose.processing", false); - public static final int RECENT_TASKS_NUMBER = SystemProperties.getIntProperty("external.system.recent.tasks.number", 5); - public static final char PATH_SEPARATOR = '/'; + public static final boolean VERBOSE_PROCESSING = SystemProperties.getBooleanProperty("external.system.verbose.processing", false); + public static final int RECENT_TASKS_NUMBER = SystemProperties.getIntProperty("external.system.recent.tasks.number", 5); + public static final int AUTO_IMPORT_DELAY_MILLIS = SystemProperties.getIntProperty("external.system.auto.import.delay.ms", 3000); + + public static final char PATH_SEPARATOR = '/'; // Order. public static final int BUILTIN_SERVICE_ORDER = 42; diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ExternalSystemStartupActivity.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ExternalSystemStartupActivity.java index 3cd313df770d..14e9a5165e08 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ExternalSystemStartupActivity.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ExternalSystemStartupActivity.java @@ -16,6 +16,7 @@ package com.intellij.openapi.externalSystem.service; import com.intellij.openapi.externalSystem.ExternalSystemManager; +import com.intellij.openapi.externalSystem.service.project.autoimport.ExternalSystemAutoImporter; import com.intellij.openapi.externalSystem.util.ExternalSystemConstants; import com.intellij.openapi.externalSystem.util.ExternalSystemUtil; import com.intellij.openapi.project.Project; @@ -43,6 +44,7 @@ public class ExternalSystemStartupActivity implements StartupActivity { ExternalSystemUtil.refreshProjects(project, manager.getSystemId()); } } + ExternalSystemAutoImporter.letTheMagicBegin(project); } }; diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/ExternalProjectRefreshCallback.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/ExternalProjectRefreshCallback.java index 760d1c190e75..5155c106b249 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/ExternalProjectRefreshCallback.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/ExternalProjectRefreshCallback.java @@ -19,7 +19,7 @@ import com.intellij.openapi.externalSystem.model.DataNode; import com.intellij.openapi.externalSystem.model.project.ProjectData; import com.intellij.openapi.externalSystem.model.settings.ExternalSystemExecutionSettings; import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId; -import com.intellij.openapi.externalSystem.service.project.ExternalSystemProjectResolver; +import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -31,9 +31,9 @@ public interface ExternalProjectRefreshCallback { /** * Is expected to be called when - * {@link ExternalSystemProjectResolver#resolveProjectInfo(ExternalSystemTaskId, String, boolean, ExternalSystemExecutionSettings)} + * {@link ExternalSystemProjectResolver#resolveProjectInfo(ExternalSystemTaskId, String, boolean, ExternalSystemExecutionSettings, ExternalSystemTaskNotificationListener)} * returns without exception. - * + * * @param externalProject target external project (if available) */ void onSuccess(@Nullable DataNode externalProject); diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/autoimport/ExternalSystemAutoImporter.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/autoimport/ExternalSystemAutoImporter.java new file mode 100644 index 000000000000..2ea5f5b27ea6 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/autoimport/ExternalSystemAutoImporter.java @@ -0,0 +1,344 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.externalSystem.service.project.autoimport; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.EditorFactory; +import com.intellij.openapi.editor.event.DocumentEvent; +import com.intellij.openapi.editor.event.DocumentListener; +import com.intellij.openapi.externalSystem.ExternalSystemAutoImportAware; +import com.intellij.openapi.externalSystem.ExternalSystemManager; +import com.intellij.openapi.externalSystem.model.DataNode; +import com.intellij.openapi.externalSystem.model.ProjectSystemId; +import com.intellij.openapi.externalSystem.model.project.ProjectData; +import com.intellij.openapi.externalSystem.service.project.ExternalProjectRefreshCallback; +import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; +import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings; +import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings; +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; +import com.intellij.openapi.externalSystem.util.ExternalSystemConstants; +import com.intellij.openapi.externalSystem.util.ExternalSystemUtil; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileManager; +import com.intellij.openapi.vfs.newvfs.BulkFileListener; +import com.intellij.openapi.vfs.newvfs.events.VFileEvent; +import com.intellij.util.Alarm; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.ContainerUtilRt; +import com.intellij.util.messages.MessageBus; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * @author Denis Zhdanov + * @since 6/7/13 6:38 PM + */ +public class ExternalSystemAutoImporter implements BulkFileListener, DocumentListener { + + @NotNull private final ConcurrentMap> myFilesToRefresh + = ContainerUtil.newConcurrentMap(); + + @NotNull private final Alarm myVfsAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD); + @NotNull private final ReadWriteLock myVfsLock = new ReentrantReadWriteLock(); + + @NotNull private final Set myDocumentsToSave = ContainerUtilRt.newHashSet(); + @NotNull private final Alarm myDocumentAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD); + @NotNull private final ReadWriteLock myDocumentLock = new ReentrantReadWriteLock(); + + @NotNull private final Runnable myFilesRequest = new Runnable() { + @Override + public void run() { + refreshFilesIfNecessary(); + } + }; + @NotNull private final Runnable myDocumentsSaveRequest = new Runnable() { + @Override + public void run() { + saveDocumentsIfNecessary(); + } + }; + @NotNull private final ExternalProjectRefreshCallback myRefreshCallback = new ExternalProjectRefreshCallback() { + @Override + public void onSuccess(@Nullable DataNode externalProject) { + if (externalProject != null) { + myProjectDataManager.importData(externalProject.getKey(), Collections.singleton(externalProject), myProject, false); + } + } + + @Override + public void onFailure(@NotNull String errorMessage, @Nullable String errorDetails) { + // Do nothing. + } + }; + + @NotNull private final Project myProject; + @NotNull private final ProjectDataManager myProjectDataManager; + + @NotNull private final MyEntry[] myAutoImportAware; + + public ExternalSystemAutoImporter(@NotNull Project project, + @NotNull ProjectDataManager projectDataManager, + @NotNull MyEntry[] autoImportAware) + { + myProject = project; + myProjectDataManager = projectDataManager; + myAutoImportAware = autoImportAware; + } + + @SuppressWarnings("unchecked") + public static void letTheMagicBegin(@NotNull Project project) { + List autoImportAware = ContainerUtilRt.newArrayList(); + Collection> managers = ExternalSystemApiUtil.getAllManagers(); + for (ExternalSystemManager manager : managers) { + AbstractExternalSystemSettings systemSettings = manager.getSettingsProvider().fun(project); + ExternalSystemAutoImportAware defaultImportAware = createDefault(systemSettings); + final ExternalSystemAutoImportAware aware; + if (manager instanceof ExternalSystemAutoImportAware) { + aware = combine(defaultImportAware, (ExternalSystemAutoImportAware)manager); + } + else { + aware = defaultImportAware; + } + autoImportAware.add(new MyEntry(manager.getSystemId(), systemSettings, aware)); + } + + MyEntry[] entries = autoImportAware.toArray(new MyEntry[autoImportAware.size()]); + ExternalSystemAutoImporter autoImporter = new ExternalSystemAutoImporter( + project, + ServiceManager.getService(ProjectDataManager.class), + entries + ); + final MessageBus messageBus = project.getMessageBus(); + messageBus.connect().subscribe(VirtualFileManager.VFS_CHANGES, autoImporter); + + EditorFactory.getInstance().getEventMulticaster().addDocumentListener(autoImporter, project); + } + + @NotNull + private static ExternalSystemAutoImportAware combine(@NotNull final ExternalSystemAutoImportAware aware1, + @NotNull final ExternalSystemAutoImportAware aware2) + { + return new ExternalSystemAutoImportAware() { + @Nullable + @Override + public String getAffectedExternalProjectPath(@NotNull String changedFileOrDirPath) { + String projectPath = aware1.getAffectedExternalProjectPath(changedFileOrDirPath); + return projectPath == null ? aware2.getAffectedExternalProjectPath(changedFileOrDirPath) : projectPath; + } + }; + } + + @NotNull + private static ExternalSystemAutoImportAware createDefault(@NotNull final AbstractExternalSystemSettings systemSettings) { + return new ExternalSystemAutoImportAware() { + @Nullable + @Override + public String getAffectedExternalProjectPath(@NotNull String changedFileOrDirPath) { + return systemSettings.getLinkedProjectSettings(changedFileOrDirPath) == null ? null : changedFileOrDirPath; + } + }; + } + + @Override + public void beforeDocumentChange(DocumentEvent event) { + } + + @Override + public void documentChanged(DocumentEvent event) { + Document document = event.getDocument(); + FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance(); + VirtualFile file = fileDocumentManager.getFile(document); + if (file == null) { + return; + } + + String path = ExternalSystemApiUtil.getLocalFileSystemPath(file); + for (MyEntry entry : myAutoImportAware) { + if (entry.aware.getAffectedExternalProjectPath(path) != null) { + // Document save triggers VFS event but FileDocumentManager might be registered after the current listener, that's why + // call to 'saveDocument()' might not produce the desired effect. That's why we reschedule document save if necessary. + scheduleDocumentSave(document); + return; + } + } + } + + private void scheduleDocumentSave(@NotNull Document document) { + Lock lock = myDocumentLock.readLock(); + lock.lock(); + try { + myDocumentsToSave.add(document); + if (myDocumentAlarm.getActiveRequestCount() <= 0) { + myDocumentAlarm.addRequest(myDocumentsSaveRequest, 100); + } + } + finally { + lock.unlock(); + } + } + + private void saveDocumentsIfNecessary() { + final FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance(); + Lock lock = myDocumentLock.writeLock(); + Set toKeep = ContainerUtilRt.newHashSet(); + final Set toSave = ContainerUtilRt.newHashSet(); + lock.lock(); + try { + myDocumentAlarm.cancelAllRequests(); + for (Document document : myDocumentsToSave) { + if (fileDocumentManager.isDocumentUnsaved(document)) { + toSave.add(document); + } + else { + toKeep.add(document); + } + } + myDocumentsToSave.clear(); + if (!toSave.isEmpty()) { + UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override + public void run() { + for (Document document : toSave) { + fileDocumentManager.saveDocument(document); + } + } + }); + } + if (!toKeep.isEmpty()) { + myDocumentsToSave.addAll(toKeep); + myDocumentAlarm.addRequest(myDocumentsSaveRequest, 100); + } + } + finally { + lock.unlock(); + } + } + + @Override + public void before(@NotNull List events) { + } + + @Override + public void after(@NotNull List events) { + boolean scheduleRefresh = false; + for (VFileEvent event : events) { + String changedPath = event.getPath(); + for (MyEntry entry : myAutoImportAware) { + String projectPath = entry.aware.getAffectedExternalProjectPath(changedPath); + if (projectPath == null) { + continue; + } + ExternalProjectSettings projectSettings = entry.systemSettings.getLinkedProjectSettings(projectPath); + if (projectSettings != null && projectSettings.isUseAutoImport()) { + addPath(entry.externalSystemId, projectPath); + scheduleRefresh = true; + break; + } + } + } + if (scheduleRefresh) { + myVfsAlarm.cancelAllRequests(); + myVfsAlarm.addRequest(myFilesRequest, ExternalSystemConstants.AUTO_IMPORT_DELAY_MILLIS); + } + } + + private void addPath(@NotNull ProjectSystemId externalSystemId, @NotNull String path) { + Lock lock = myVfsLock.readLock(); + lock.lock(); + try { + Set paths = myFilesToRefresh.get(externalSystemId); + while (paths == null) { + myFilesToRefresh.putIfAbsent(externalSystemId, ContainerUtilRt.newHashSet()); + paths = myFilesToRefresh.get(externalSystemId); + } + paths.add(path); + } + finally { + lock.unlock(); + } + } + + private void refreshFilesIfNecessary() { + if (myFilesToRefresh.isEmpty()) { + return; + } + + Map> copy = ContainerUtilRt.newHashMap(); + Lock fileLock = myVfsLock.writeLock(); + fileLock.lock(); + try { + copy.putAll(myFilesToRefresh); + myFilesToRefresh.clear(); + } + finally { + fileLock.unlock(); + } + + FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance(); + LocalFileSystem fileSystem = LocalFileSystem.getInstance(); + Lock documentLock = myDocumentLock.writeLock(); + documentLock.lock(); + try { + for (Set paths : copy.values()) { + for (String path : paths) { + VirtualFile file = fileSystem.findFileByPath(path); + if (file != null) { + Document document = fileDocumentManager.getCachedDocument(file); + if (document != null) { + myDocumentsToSave.remove(document); + } + } + } + } + } + finally { + documentLock.unlock(); + } + + for (Map.Entry> entry : copy.entrySet()) { + for (String path : entry.getValue()) { + ExternalSystemUtil.refreshProject(myProject, entry.getKey(), path, myRefreshCallback, true, false); + } + } + } + + private static class MyEntry { + + @NotNull public final ProjectSystemId externalSystemId; + @NotNull public final AbstractExternalSystemSettings systemSettings; + @NotNull public final ExternalSystemAutoImportAware aware; + + MyEntry(@NotNull ProjectSystemId externalSystemId, + @NotNull AbstractExternalSystemSettings systemSettings, + @NotNull ExternalSystemAutoImportAware aware) + { + this.externalSystemId = externalSystemId; + this.systemSettings = systemSettings; + this.aware = aware; + } + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDependencyDataService.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDependencyDataService.java index 896d7fb61870..d85b7ee160d0 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDependencyDataService.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDependencyDataService.java @@ -33,6 +33,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.LibraryOrderEntry; import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.OrderEntry; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.roots.libraries.LibraryTable; import com.intellij.util.BooleanFunction; @@ -133,12 +134,24 @@ public class LibraryDependencyDataService extends AbstractDependencyDataService< myLibraryManager.importData(librariesToImport, module.getProject(), synchronous); } + ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module); + Map toRemove = ContainerUtilRt.newHashMap(); + for (OrderEntry entry : moduleRootManager.getOrderEntries()) { + if (entry instanceof LibraryOrderEntry) { + LibraryOrderEntry e = (LibraryOrderEntry)entry; + String libraryName = e.getLibraryName(); + if (libraryName != null) { + toRemove.put(libraryName, e); + } + } + } + for (DataNode dependencyNode : nodesToImport) { - ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module); final ModifiableRootModel moduleRootModel = moduleRootManager.getModifiableModel(); try { libraryTable = myPlatformFacade.getProjectLibraryTable(module.getProject()); final LibraryDependencyData dependencyData = dependencyNode.getData(); + toRemove.remove(dependencyData.getName()); final Library library = libraryTable.getLibraryByName(dependencyData.getName()); if (library == null) { assert false; @@ -161,6 +174,10 @@ public class LibraryDependencyDataService extends AbstractDependencyDataService< moduleRootModel.commit(); } } + + if (!toRemove.isEmpty()) { + removeData(toRemove.values(), module, synchronous); + } } }); } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ModuleDependencyDataService.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ModuleDependencyDataService.java index e6134463a655..34130a2ed289 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ModuleDependencyDataService.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ModuleDependencyDataService.java @@ -31,7 +31,9 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.openapi.roots.ModuleOrderEntry; import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.OrderEntry; import com.intellij.util.BooleanFunction; +import com.intellij.util.containers.ContainerUtilRt; import org.jetbrains.annotations.NotNull; import java.util.Collection; @@ -92,10 +94,19 @@ public class ModuleDependencyDataService extends AbstractDependencyDataService toRemove = ContainerUtilRt.newHashMap(); + for (OrderEntry entry : moduleRootManager.getOrderEntries()) { + if (entry instanceof ModuleOrderEntry) { + ModuleOrderEntry e = (ModuleOrderEntry)entry; + toRemove.put(e.getModuleName(), e); + } + } + final ModifiableRootModel moduleRootModel = moduleRootManager.getModifiableModel(); try { for (DataNode dependencyNode : toImport) { final ModuleDependencyData dependencyData = dependencyNode.getData(); + toRemove.remove(dependencyData.getName()); final String moduleName = dependencyData.getName(); Module ideDependencyModule = myProjectStructureHelper.findIdeModule(moduleName, module.getProject()); if (ideDependencyModule == null) { @@ -135,6 +146,10 @@ public class ModuleDependencyDataService extends AbstractDependencyDataService