mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
refactored external system services to reduce amount of write actions
This commit is contained in:
+1
-3
@@ -1,6 +1,5 @@
|
||||
package com.intellij.openapi.externalSystem.service.project;
|
||||
|
||||
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
|
||||
import com.intellij.openapi.externalSystem.model.project.*;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -60,8 +59,7 @@ public interface PlatformFacade {
|
||||
|
||||
/**
|
||||
* Creates a module of the specified type at the specified path and adds it to the project
|
||||
* to which the module manager is related. {@link #commit()} must be called to
|
||||
* bring the changes in effect.
|
||||
* to which the module manager is related.
|
||||
*
|
||||
*
|
||||
* @param project
|
||||
|
||||
+58
-4
@@ -26,6 +26,7 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.externalSystem.ExternalSystemAutoImportAware;
|
||||
import com.intellij.openapi.externalSystem.ExternalSystemManager;
|
||||
import com.intellij.openapi.externalSystem.model.*;
|
||||
import com.intellij.openapi.externalSystem.model.Key;
|
||||
import com.intellij.openapi.externalSystem.model.project.LibraryData;
|
||||
import com.intellij.openapi.externalSystem.model.project.ModuleData;
|
||||
import com.intellij.openapi.externalSystem.model.project.ProjectData;
|
||||
@@ -39,12 +40,10 @@ import com.intellij.openapi.externalSystem.settings.ExternalSystemSettingsListen
|
||||
import com.intellij.openapi.fileTypes.FileTypes;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ModifiableRootModel;
|
||||
import com.intellij.openapi.roots.OrderRootType;
|
||||
import com.intellij.openapi.roots.libraries.Library;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Conditions;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
@@ -446,6 +445,61 @@ public class ExternalSystemApiUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void commitChangedModels(boolean synchronous, Project project, List<Library.ModifiableModel> models) {
|
||||
final List<Library.ModifiableModel> changedModels = ContainerUtil.findAll(models, new Condition<Library.ModifiableModel>() {
|
||||
@Override
|
||||
public boolean value(Library.ModifiableModel model) {
|
||||
return model.isChanged();
|
||||
}
|
||||
});
|
||||
if (!changedModels.isEmpty()) {
|
||||
executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(project) {
|
||||
@Override
|
||||
public void execute() {
|
||||
for (Library.ModifiableModel modifiableModel : changedModels) {
|
||||
modifiableModel.commit();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void disposeModels(@NotNull Collection<ModifiableRootModel> models) {
|
||||
for (ModifiableRootModel model : models) {
|
||||
if (!model.isDisposed()) {
|
||||
model.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void commitModels(boolean synchronous, Project project, List<ModifiableRootModel> models) {
|
||||
final List<ModifiableRootModel> changedModels = ContainerUtilRt.newArrayList();
|
||||
for (ModifiableRootModel modifiableRootModel : models) {
|
||||
if (modifiableRootModel.isDisposed()) {
|
||||
continue;
|
||||
}
|
||||
if (modifiableRootModel.isChanged()) {
|
||||
changedModels.add(modifiableRootModel);
|
||||
} else {
|
||||
modifiableRootModel.dispose();
|
||||
}
|
||||
}
|
||||
// Commit only if there are changes. #executeProjectChangeAction acquires a write lock
|
||||
if (!changedModels.isEmpty()) {
|
||||
executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(project) {
|
||||
@Override
|
||||
public void execute() {
|
||||
for (ModifiableRootModel modifiableRootModel : changedModels) {
|
||||
// double check
|
||||
if (!modifiableRootModel.isDisposed()) {
|
||||
modifiableRootModel.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void executeProjectChangeAction(@NotNull final DisposeAwareProjectChange task) {
|
||||
executeProjectChangeAction(false, task);
|
||||
}
|
||||
|
||||
+39
-42
@@ -28,6 +28,7 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.*;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.ExceptionUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.ContainerUtilRt;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
@@ -133,15 +134,27 @@ public abstract class AbstractDependencyDataService<E extends AbstractDependency
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeData(@NotNull final Computable<Collection<I>> toRemoveComputable,
|
||||
@NotNull final Collection<DataNode<E>> toIgnore,
|
||||
@NotNull final ProjectData projectData,
|
||||
@NotNull final Project project,
|
||||
@NotNull final PlatformFacade platformFacade,
|
||||
final boolean synchronous) {
|
||||
Map<Module, Collection<ExportableOrderEntry>> byModule = groupByModule(toRemoveComputable.compute());
|
||||
for (Map.Entry<Module, Collection<ExportableOrderEntry>> entry : byModule.entrySet()) {
|
||||
removeData(entry.getValue(), entry.getKey(), platformFacade, synchronous);
|
||||
public void removeData(@NotNull Computable<Collection<I>> toRemoveComputable,
|
||||
@NotNull Collection<DataNode<E>> toIgnore,
|
||||
@NotNull ProjectData projectData,
|
||||
@NotNull Project project,
|
||||
@NotNull PlatformFacade platformFacade,
|
||||
boolean synchronous) {
|
||||
List<ModifiableRootModel> models = ContainerUtilRt.newArrayList();
|
||||
try {
|
||||
Map<Module, Collection<ExportableOrderEntry>> byModule = groupByModule(toRemoveComputable.compute());
|
||||
for (Map.Entry<Module, Collection<ExportableOrderEntry>> entry : byModule.entrySet()) {
|
||||
Module module = entry.getKey();
|
||||
Collection<ExportableOrderEntry> depsToRemove = entry.getValue();
|
||||
ModifiableRootModel model = platformFacade.getModuleModifiableModel(module);
|
||||
removeData(depsToRemove, model);
|
||||
models.add(model);
|
||||
}
|
||||
ExternalSystemApiUtil.commitModels(synchronous, project, models);
|
||||
}
|
||||
catch (Throwable t) {
|
||||
ExternalSystemApiUtil.disposeModels(models);
|
||||
ExceptionUtil.rethrowUnchecked(t);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,41 +172,25 @@ public abstract class AbstractDependencyDataService<E extends AbstractDependency
|
||||
}
|
||||
|
||||
protected void removeData(@NotNull Collection<? extends ExportableOrderEntry> toRemove,
|
||||
@NotNull final Module module,
|
||||
@NotNull final PlatformFacade platformFacade,
|
||||
boolean synchronous) {
|
||||
if (toRemove.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (final ExportableOrderEntry dependency : toRemove) {
|
||||
ExternalSystemApiUtil.executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(dependency.getOwnerModule()) {
|
||||
@Override
|
||||
public void execute() {
|
||||
final ModifiableRootModel moduleRootModel = platformFacade.getModuleModifiableModel(module);
|
||||
try {
|
||||
// The thing is that intellij created order entry objects every time new modifiable model is created,
|
||||
// that's why we can't use target dependency object as is but need to get a reference to the current
|
||||
// entry object from the model instead.
|
||||
for (OrderEntry entry : moduleRootModel.getOrderEntries()) {
|
||||
if (entry instanceof ExportableOrderEntry) {
|
||||
ExportableOrderEntry orderEntry = (ExportableOrderEntry)entry;
|
||||
if (orderEntry.getPresentableName().equals(dependency.getPresentableName()) &&
|
||||
orderEntry.getScope().equals(dependency.getScope())) {
|
||||
moduleRootModel.removeOrderEntry(entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (entry.getPresentableName().equals(dependency.getPresentableName())) {
|
||||
moduleRootModel.removeOrderEntry(entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
moduleRootModel.commit();
|
||||
@NotNull ModifiableRootModel moduleRootModel) {
|
||||
for (ExportableOrderEntry dependency : toRemove) {
|
||||
// The thing is that intellij created order entry objects every time new modifiable model is created,
|
||||
// that's why we can't use target dependency object as is but need to get a reference to the current
|
||||
// entry object from the model instead.
|
||||
for (OrderEntry entry : moduleRootModel.getOrderEntries()) {
|
||||
if (entry instanceof ExportableOrderEntry) {
|
||||
ExportableOrderEntry orderEntry = (ExportableOrderEntry)entry;
|
||||
if (orderEntry.getPresentableName().equals(dependency.getPresentableName()) &&
|
||||
orderEntry.getScope().equals(dependency.getScope())) {
|
||||
moduleRootModel.removeOrderEntry(entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
else if (entry.getPresentableName().equals(dependency.getPresentableName())) {
|
||||
moduleRootModel.removeOrderEntry(entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+78
-79
@@ -28,7 +28,6 @@ import com.intellij.openapi.externalSystem.model.project.ProjectData;
|
||||
import com.intellij.openapi.externalSystem.service.project.PlatformFacade;
|
||||
import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings;
|
||||
import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings;
|
||||
import com.intellij.openapi.externalSystem.util.DisposeAwareProjectChange;
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemConstants;
|
||||
import com.intellij.openapi.externalSystem.util.Order;
|
||||
@@ -36,7 +35,6 @@ import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ContentEntry;
|
||||
import com.intellij.openapi.roots.ModifiableRootModel;
|
||||
import com.intellij.openapi.roots.ModuleRootModificationUtil;
|
||||
import com.intellij.openapi.roots.SourceFolder;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
@@ -44,7 +42,7 @@ import com.intellij.openapi.vcs.changes.ChangeListManager;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.ExceptionUtil;
|
||||
import com.intellij.util.containers.ContainerUtilRt;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -78,94 +76,95 @@ public class ContentRootDataService extends AbstractProjectDataService<ContentRo
|
||||
}
|
||||
|
||||
@Override
|
||||
public void importData(@NotNull final Collection<DataNode<ContentRootData>> toImport,
|
||||
public void importData(@NotNull Collection<DataNode<ContentRootData>> toImport,
|
||||
@Nullable ProjectData projectData,
|
||||
@NotNull final Project project,
|
||||
@NotNull final PlatformFacade platformFacade,
|
||||
final boolean synchronous) {
|
||||
@NotNull Project project,
|
||||
@NotNull PlatformFacade platformFacade,
|
||||
boolean synchronous) {
|
||||
if (toImport.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MultiMap<DataNode<ModuleData>, DataNode<ContentRootData>> byModule = ExternalSystemApiUtil.groupBy(toImport, ProjectKeys.MODULE);
|
||||
for (Map.Entry<DataNode<ModuleData>, Collection<DataNode<ContentRootData>>> entry : byModule.entrySet()) {
|
||||
final Module module = platformFacade.findIdeModule(entry.getKey().getData(), project);
|
||||
if (module == null) {
|
||||
LOG.warn(String.format(
|
||||
"Can't import content roots. Reason: target module (%s) is not found at the ide. Content roots: %s",
|
||||
entry.getKey(), entry.getValue()
|
||||
));
|
||||
continue;
|
||||
List<ModifiableRootModel> models = ContainerUtilRt.newArrayList();
|
||||
try {
|
||||
MultiMap<DataNode<ModuleData>, DataNode<ContentRootData>> byModule = ExternalSystemApiUtil.groupBy(toImport, ProjectKeys.MODULE);
|
||||
for (Map.Entry<DataNode<ModuleData>, Collection<DataNode<ContentRootData>>> entry : byModule.entrySet()) {
|
||||
Module module = platformFacade.findIdeModule(entry.getKey().getData(), project);
|
||||
if (module == null) {
|
||||
LOG.warn(String.format(
|
||||
"Can't import content roots. Reason: target module (%s) is not found at the ide. Content roots: %s",
|
||||
entry.getKey(), entry.getValue()
|
||||
));
|
||||
continue;
|
||||
}
|
||||
models.add(importData(entry.getValue(), module, platformFacade));
|
||||
}
|
||||
importData(entry.getValue(), module, synchronous);
|
||||
ExternalSystemApiUtil.commitModels(synchronous, project, models);
|
||||
}
|
||||
catch (Throwable t) {
|
||||
ExternalSystemApiUtil.disposeModels(models);
|
||||
ExceptionUtil.rethrowUnchecked(t);
|
||||
}
|
||||
}
|
||||
|
||||
private static void importData(@NotNull final Collection<DataNode<ContentRootData>> data,
|
||||
@NotNull final Module module,
|
||||
boolean synchronous) {
|
||||
ExternalSystemApiUtil.executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(module) {
|
||||
@Override
|
||||
public void execute() {
|
||||
ModuleRootModificationUtil.updateModel(module, new Consumer<ModifiableRootModel>() {
|
||||
@Override
|
||||
public void consume(ModifiableRootModel model) {
|
||||
final ContentEntry[] contentEntries = model.getContentEntries();
|
||||
final Map<String, ContentEntry> contentEntriesMap = ContainerUtilRt.newHashMap();
|
||||
for(ContentEntry contentEntry : contentEntries) {
|
||||
contentEntriesMap.put(contentEntry.getUrl(), contentEntry);
|
||||
}
|
||||
@NotNull
|
||||
private static ModifiableRootModel importData(@NotNull Collection<DataNode<ContentRootData>> data,
|
||||
@NotNull Module module,
|
||||
@NotNull PlatformFacade platformFacade) {
|
||||
ModifiableRootModel model = platformFacade.getModuleModifiableModel(module);
|
||||
ContentEntry[] contentEntries = model.getContentEntries();
|
||||
Map<String, ContentEntry> contentEntriesMap = ContainerUtilRt.newHashMap();
|
||||
for(ContentEntry contentEntry : contentEntries) {
|
||||
contentEntriesMap.put(contentEntry.getUrl(), contentEntry);
|
||||
}
|
||||
|
||||
boolean createEmptyContentRootDirectories = false;
|
||||
if (!data.isEmpty()) {
|
||||
ProjectSystemId projectSystemId = data.iterator().next().getData().getOwner();
|
||||
AbstractExternalSystemSettings externalSystemSettings =
|
||||
ExternalSystemApiUtil.getSettings(module.getProject(), projectSystemId);
|
||||
boolean createEmptyContentRootDirectories = false;
|
||||
if (!data.isEmpty()) {
|
||||
ProjectSystemId projectSystemId = data.iterator().next().getData().getOwner();
|
||||
AbstractExternalSystemSettings externalSystemSettings =
|
||||
ExternalSystemApiUtil.getSettings(module.getProject(), projectSystemId);
|
||||
|
||||
String path = module.getOptionValue(ExternalSystemConstants.ROOT_PROJECT_PATH_KEY);
|
||||
if (path != null) {
|
||||
ExternalProjectSettings projectSettings = externalSystemSettings.getLinkedProjectSettings(path);
|
||||
createEmptyContentRootDirectories = projectSettings != null && projectSettings.isCreateEmptyContentRootDirectories();
|
||||
}
|
||||
}
|
||||
|
||||
for (final DataNode<ContentRootData> node : data) {
|
||||
final ContentRootData contentRoot = node.getData();
|
||||
|
||||
final ContentEntry contentEntry = findOrCreateContentRoot(model, contentRoot.getRootPath());
|
||||
contentEntry.clearExcludeFolders();
|
||||
contentEntry.clearSourceFolders();
|
||||
LOG.debug(String.format("Importing content root '%s' for module '%s'", contentRoot.getRootPath(), module.getName()));
|
||||
for (SourceRoot path : contentRoot.getPaths(ExternalSystemSourceType.SOURCE)) {
|
||||
createSourceRootIfAbsent(contentEntry, path, module.getName(), JavaSourceRootType.SOURCE, false, createEmptyContentRootDirectories);
|
||||
}
|
||||
for (SourceRoot path : contentRoot.getPaths(ExternalSystemSourceType.TEST)) {
|
||||
createSourceRootIfAbsent(contentEntry, path, module.getName(), JavaSourceRootType.TEST_SOURCE, false, createEmptyContentRootDirectories);
|
||||
}
|
||||
for (SourceRoot path : contentRoot.getPaths(ExternalSystemSourceType.RESOURCE)) {
|
||||
createSourceRootIfAbsent(contentEntry, path, module.getName(), JavaResourceRootType.RESOURCE, false, createEmptyContentRootDirectories);
|
||||
}
|
||||
for (SourceRoot path : contentRoot.getPaths(ExternalSystemSourceType.TEST_RESOURCE)) {
|
||||
createSourceRootIfAbsent(contentEntry, path, module.getName(), JavaResourceRootType.TEST_RESOURCE, false, createEmptyContentRootDirectories);
|
||||
}
|
||||
for (SourceRoot path : contentRoot.getPaths(ExternalSystemSourceType.SOURCE_GENERATED)) {
|
||||
createSourceRootIfAbsent(contentEntry, path, module.getName(), JavaSourceRootType.SOURCE, true, createEmptyContentRootDirectories);
|
||||
}
|
||||
for (SourceRoot path : contentRoot.getPaths(ExternalSystemSourceType.TEST_GENERATED)) {
|
||||
createSourceRootIfAbsent(contentEntry, path, module.getName(), JavaSourceRootType.TEST_SOURCE, true, createEmptyContentRootDirectories);
|
||||
}
|
||||
for (SourceRoot path : contentRoot.getPaths(ExternalSystemSourceType.EXCLUDED)) {
|
||||
createExcludedRootIfAbsent(contentEntry, path, module.getName(), module.getProject());
|
||||
}
|
||||
contentEntriesMap.remove(contentEntry.getUrl());
|
||||
}
|
||||
for(ContentEntry contentEntry : contentEntriesMap.values()) {
|
||||
model.removeContentEntry(contentEntry);
|
||||
}
|
||||
}
|
||||
});
|
||||
String path = module.getOptionValue(ExternalSystemConstants.ROOT_PROJECT_PATH_KEY);
|
||||
if (path != null) {
|
||||
ExternalProjectSettings projectSettings = externalSystemSettings.getLinkedProjectSettings(path);
|
||||
createEmptyContentRootDirectories = projectSettings != null && projectSettings.isCreateEmptyContentRootDirectories();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (DataNode<ContentRootData> node : data) {
|
||||
ContentRootData contentRoot = node.getData();
|
||||
|
||||
ContentEntry contentEntry = findOrCreateContentRoot(model, contentRoot.getRootPath());
|
||||
contentEntry.clearExcludeFolders();
|
||||
contentEntry.clearSourceFolders();
|
||||
LOG.debug(String.format("Importing content root '%s' for module '%s'", contentRoot.getRootPath(), module.getName()));
|
||||
for (SourceRoot path : contentRoot.getPaths(ExternalSystemSourceType.SOURCE)) {
|
||||
createSourceRootIfAbsent(contentEntry, path, module.getName(), JavaSourceRootType.SOURCE, false, createEmptyContentRootDirectories);
|
||||
}
|
||||
for (SourceRoot path : contentRoot.getPaths(ExternalSystemSourceType.TEST)) {
|
||||
createSourceRootIfAbsent(contentEntry, path, module.getName(), JavaSourceRootType.TEST_SOURCE, false, createEmptyContentRootDirectories);
|
||||
}
|
||||
for (SourceRoot path : contentRoot.getPaths(ExternalSystemSourceType.RESOURCE)) {
|
||||
createSourceRootIfAbsent(contentEntry, path, module.getName(), JavaResourceRootType.RESOURCE, false, createEmptyContentRootDirectories);
|
||||
}
|
||||
for (SourceRoot path : contentRoot.getPaths(ExternalSystemSourceType.TEST_RESOURCE)) {
|
||||
createSourceRootIfAbsent(contentEntry, path, module.getName(), JavaResourceRootType.TEST_RESOURCE, false, createEmptyContentRootDirectories);
|
||||
}
|
||||
for (SourceRoot path : contentRoot.getPaths(ExternalSystemSourceType.SOURCE_GENERATED)) {
|
||||
createSourceRootIfAbsent(contentEntry, path, module.getName(), JavaSourceRootType.SOURCE, true, createEmptyContentRootDirectories);
|
||||
}
|
||||
for (SourceRoot path : contentRoot.getPaths(ExternalSystemSourceType.TEST_GENERATED)) {
|
||||
createSourceRootIfAbsent(contentEntry, path, module.getName(), JavaSourceRootType.TEST_SOURCE, true, createEmptyContentRootDirectories);
|
||||
}
|
||||
for (SourceRoot path : contentRoot.getPaths(ExternalSystemSourceType.EXCLUDED)) {
|
||||
createExcludedRootIfAbsent(contentEntry, path, module.getName(), module.getProject());
|
||||
}
|
||||
contentEntriesMap.remove(contentEntry.getUrl());
|
||||
}
|
||||
for(ContentEntry contentEntry : contentEntriesMap.values()) {
|
||||
model.removeContentEntry(contentEntry);
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+57
-65
@@ -1,14 +1,12 @@
|
||||
package com.intellij.openapi.externalSystem.service.project.manage;
|
||||
|
||||
import com.intellij.ide.highlighter.ArchiveFileType;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.externalSystem.model.DataNode;
|
||||
import com.intellij.openapi.externalSystem.model.Key;
|
||||
import com.intellij.openapi.externalSystem.model.ProjectKeys;
|
||||
import com.intellij.openapi.externalSystem.model.project.LibraryData;
|
||||
import com.intellij.openapi.externalSystem.model.project.LibraryPathType;
|
||||
import com.intellij.openapi.externalSystem.model.project.ModuleData;
|
||||
import com.intellij.openapi.externalSystem.model.project.ProjectData;
|
||||
import com.intellij.openapi.externalSystem.service.project.ExternalLibraryPathTypeMapper;
|
||||
import com.intellij.openapi.externalSystem.service.project.PlatformFacade;
|
||||
@@ -68,18 +66,23 @@ public class LibraryDataService extends AbstractProjectDataService<LibraryData,
|
||||
|
||||
@Override
|
||||
public void importData(@NotNull final Collection<DataNode<LibraryData>> toImport,
|
||||
@Nullable final ProjectData projectData,
|
||||
@Nullable ProjectData projectData,
|
||||
@NotNull final Project project,
|
||||
@NotNull final PlatformFacade platformFacade,
|
||||
final boolean synchronous) {
|
||||
for (DataNode<LibraryData> dataNode : toImport) {
|
||||
importLibrary(dataNode.getData(), project, platformFacade, synchronous);
|
||||
}
|
||||
ExternalSystemApiUtil.executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(project) {
|
||||
@Override
|
||||
public void execute() {
|
||||
for (DataNode<LibraryData> dataNode : toImport) {
|
||||
importLibrary(dataNode.getData(), project, platformFacade, synchronous);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void importLibrary(@NotNull final LibraryData toImport,
|
||||
@NotNull final Project project,
|
||||
@NotNull final PlatformFacade platformFacade,
|
||||
private void importLibrary(@NotNull LibraryData toImport,
|
||||
@NotNull Project project,
|
||||
@NotNull PlatformFacade platformFacade,
|
||||
boolean synchronous) {
|
||||
Map<OrderRootType, Collection<File>> libraryFiles = prepareLibraryFiles(toImport);
|
||||
|
||||
@@ -88,14 +91,14 @@ public class LibraryDataService extends AbstractProjectDataService<LibraryData,
|
||||
syncPaths(toImport, library, project, synchronous);
|
||||
return;
|
||||
}
|
||||
importLibrary(toImport.getInternalName(), libraryFiles, project, platformFacade, synchronous);
|
||||
importLibrary(toImport.getInternalName(), libraryFiles, project, platformFacade);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Map<OrderRootType, Collection<File>> prepareLibraryFiles(@NotNull LibraryData data) {
|
||||
Map<OrderRootType, Collection<File>> result = ContainerUtilRt.newHashMap();
|
||||
for (LibraryPathType pathType : LibraryPathType.values()) {
|
||||
final Set<String> paths = data.getPaths(pathType);
|
||||
Set<String> paths = data.getPaths(pathType);
|
||||
if (paths.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
@@ -104,38 +107,32 @@ public class LibraryDataService extends AbstractProjectDataService<LibraryData,
|
||||
return result;
|
||||
}
|
||||
|
||||
private void importLibrary(@NotNull final String libraryName,
|
||||
@NotNull final Map<OrderRootType, Collection<File>> libraryFiles,
|
||||
@NotNull final Project project,
|
||||
@NotNull final PlatformFacade platformFacade,
|
||||
boolean synchronous)
|
||||
private void importLibrary(@NotNull String libraryName,
|
||||
@NotNull Map<OrderRootType, Collection<File>> libraryFiles,
|
||||
@NotNull Project project,
|
||||
@NotNull PlatformFacade platformFacade)
|
||||
{
|
||||
ExternalSystemApiUtil.executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(project) {
|
||||
@Override
|
||||
public void execute() {
|
||||
// Is assumed to be called from the EDT.
|
||||
final LibraryTable libraryTable = platformFacade.getProjectLibraryTable(project);
|
||||
final LibraryTable.ModifiableModel projectLibraryModel = libraryTable.getModifiableModel();
|
||||
final Library intellijLibrary;
|
||||
try {
|
||||
intellijLibrary = projectLibraryModel.createLibrary(libraryName);
|
||||
}
|
||||
finally {
|
||||
projectLibraryModel.commit();
|
||||
}
|
||||
final Library.ModifiableModel libraryModel = intellijLibrary.getModifiableModel();
|
||||
try {
|
||||
registerPaths(libraryFiles, libraryModel, libraryName);
|
||||
}
|
||||
finally {
|
||||
libraryModel.commit();
|
||||
}
|
||||
}
|
||||
});
|
||||
// Is assumed to be called from the EDT.
|
||||
LibraryTable libraryTable = platformFacade.getProjectLibraryTable(project);
|
||||
LibraryTable.ModifiableModel projectLibraryModel = libraryTable.getModifiableModel();
|
||||
Library intellijLibrary;
|
||||
try {
|
||||
intellijLibrary = projectLibraryModel.createLibrary(libraryName);
|
||||
}
|
||||
finally {
|
||||
projectLibraryModel.commit();
|
||||
}
|
||||
Library.ModifiableModel libraryModel = intellijLibrary.getModifiableModel();
|
||||
try {
|
||||
registerPaths(libraryFiles, libraryModel, libraryName);
|
||||
}
|
||||
finally {
|
||||
libraryModel.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("MethodMayBeStatic")
|
||||
public void registerPaths(@NotNull final Map<OrderRootType, Collection<File>> libraryFiles,
|
||||
public void registerPaths(@NotNull Map<OrderRootType, Collection<File>> libraryFiles,
|
||||
@NotNull Library.ModifiableModel model,
|
||||
@NotNull String libraryName)
|
||||
{
|
||||
@@ -150,14 +147,14 @@ public class LibraryDataService extends AbstractProjectDataService<LibraryData,
|
||||
}
|
||||
String url = VfsUtil.getUrlForLibraryRoot(file);
|
||||
|
||||
final String[] urls = model.getUrls(entry.getKey());
|
||||
String[] urls = model.getUrls(entry.getKey());
|
||||
if (!ArrayUtil.contains(url, urls)) {
|
||||
model.addRoot(url, entry.getKey());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (virtualFile.isDirectory()) {
|
||||
final VirtualFile[] files = model.getFiles(entry.getKey());
|
||||
VirtualFile[] files = model.getFiles(entry.getKey());
|
||||
if (!ArrayUtil.contains(virtualFile, files)) {
|
||||
model.addRoot(virtualFile, entry.getKey());
|
||||
}
|
||||
@@ -173,7 +170,7 @@ public class LibraryDataService extends AbstractProjectDataService<LibraryData,
|
||||
continue;
|
||||
}
|
||||
}
|
||||
final VirtualFile[] files = model.getFiles(entry.getKey());
|
||||
VirtualFile[] files = model.getFiles(entry.getKey());
|
||||
if (!ArrayUtil.contains(root, files)) {
|
||||
model.addRoot(root, entry.getKey());
|
||||
}
|
||||
@@ -216,12 +213,12 @@ public class LibraryDataService extends AbstractProjectDataService<LibraryData,
|
||||
});
|
||||
}
|
||||
|
||||
public void syncPaths(@NotNull final LibraryData externalLibrary, @NotNull final Library ideLibrary, @NotNull final Project project, boolean synchronous) {
|
||||
public void syncPaths(@NotNull LibraryData externalLibrary, @NotNull Library ideLibrary, @NotNull Project project, boolean synchronous) {
|
||||
if (externalLibrary.isUnresolved()) {
|
||||
return;
|
||||
}
|
||||
final Map<OrderRootType, Set<String>> toRemove = ContainerUtilRt.newHashMap();
|
||||
final Map<OrderRootType, Set<String>> toAdd = ContainerUtilRt.newHashMap();
|
||||
Map<OrderRootType, Set<String>> toRemove = ContainerUtilRt.newHashMap();
|
||||
Map<OrderRootType, Set<String>> toAdd = ContainerUtilRt.newHashMap();
|
||||
for (LibraryPathType pathType : LibraryPathType.values()) {
|
||||
OrderRootType ideType = myLibraryPathTypeMapper.map(pathType);
|
||||
HashSet<String> toAddPerType = ContainerUtilRt.newHashSet(externalLibrary.getPaths(pathType));
|
||||
@@ -240,27 +237,22 @@ public class LibraryDataService extends AbstractProjectDataService<LibraryData,
|
||||
if (toRemove.isEmpty() && toAdd.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ExternalSystemApiUtil.executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(project) {
|
||||
@Override
|
||||
public void execute() {
|
||||
Library.ModifiableModel model = ideLibrary.getModifiableModel();
|
||||
try {
|
||||
for (Map.Entry<OrderRootType, Set<String>> entry : toRemove.entrySet()) {
|
||||
for (String path : entry.getValue()) {
|
||||
model.removeRoot(path, entry.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<OrderRootType, Set<String>> entry : toAdd.entrySet()) {
|
||||
Map<OrderRootType, Collection<File>> roots = ContainerUtilRt.newHashMap();
|
||||
roots.put(entry.getKey(), ContainerUtil.map(entry.getValue(), PATH_TO_FILE));
|
||||
registerPaths(roots, model, externalLibrary.getInternalName());
|
||||
}
|
||||
}
|
||||
finally {
|
||||
model.commit();
|
||||
Library.ModifiableModel model = ideLibrary.getModifiableModel();
|
||||
try {
|
||||
for (Map.Entry<OrderRootType, Set<String>> entry : toRemove.entrySet()) {
|
||||
for (String path : entry.getValue()) {
|
||||
model.removeRoot(path, entry.getKey());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (Map.Entry<OrderRootType, Set<String>> entry : toAdd.entrySet()) {
|
||||
Map<OrderRootType, Collection<File>> roots = ContainerUtilRt.newHashMap();
|
||||
roots.put(entry.getKey(), ContainerUtil.map(entry.getValue(), PATH_TO_FILE));
|
||||
registerPaths(roots, model, externalLibrary.getInternalName());
|
||||
}
|
||||
}
|
||||
finally {
|
||||
model.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+160
-148
@@ -21,7 +21,6 @@ import com.intellij.openapi.externalSystem.model.Key;
|
||||
import com.intellij.openapi.externalSystem.model.ProjectKeys;
|
||||
import com.intellij.openapi.externalSystem.model.project.*;
|
||||
import com.intellij.openapi.externalSystem.service.project.PlatformFacade;
|
||||
import com.intellij.openapi.externalSystem.util.DisposeAwareProjectChange;
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemConstants;
|
||||
import com.intellij.openapi.externalSystem.util.Order;
|
||||
@@ -35,6 +34,8 @@ import com.intellij.openapi.roots.impl.ModuleLibraryOrderEntryImpl;
|
||||
import com.intellij.openapi.roots.libraries.Library;
|
||||
import com.intellij.openapi.roots.libraries.LibraryTable;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.ExceptionUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.ContainerUtilRt;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -42,6 +43,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -78,17 +80,28 @@ public class LibraryDependencyDataService extends AbstractDependencyDataService<
|
||||
return;
|
||||
}
|
||||
|
||||
MultiMap<DataNode<ModuleData>, DataNode<LibraryDependencyData>> byModule = ExternalSystemApiUtil.groupBy(toImport, MODULE);
|
||||
for (Map.Entry<DataNode<ModuleData>, Collection<DataNode<LibraryDependencyData>>> entry : byModule.entrySet()) {
|
||||
Module module = platformFacade.findIdeModule(entry.getKey().getData(), project);
|
||||
if (module == null) {
|
||||
LOG.warn(String.format(
|
||||
"Can't import library dependencies %s. Reason: target module (%s) is not found at the ide and can't be imported",
|
||||
entry.getValue(), entry.getKey()
|
||||
));
|
||||
continue;
|
||||
MyImporter importer = new MyImporter(platformFacade);
|
||||
try {
|
||||
MultiMap<DataNode<ModuleData>, DataNode<LibraryDependencyData>> byModule = ExternalSystemApiUtil.groupBy(toImport, MODULE);
|
||||
for (Map.Entry<DataNode<ModuleData>, Collection<DataNode<LibraryDependencyData>>> entry : byModule.entrySet()) {
|
||||
Module module = platformFacade.findIdeModule(entry.getKey().getData(), project);
|
||||
Collection<DataNode<LibraryDependencyData>> libraryDependency = entry.getValue();
|
||||
if (module == null) {
|
||||
LOG.warn(String.format(
|
||||
"Can't import library dependencies %s. Reason: target module (%s) is not found at the ide and can't be imported",
|
||||
libraryDependency, entry.getKey()
|
||||
));
|
||||
continue;
|
||||
}
|
||||
importer.importData(module, libraryDependency);
|
||||
}
|
||||
importData(entry.getValue(), module, platformFacade, synchronous);
|
||||
// change libraries first
|
||||
ExternalSystemApiUtil.commitChangedModels(synchronous, project, importer.getLibraryModels());
|
||||
ExternalSystemApiUtil.commitModels(synchronous, project, importer.getModels());
|
||||
}
|
||||
catch (Throwable t) {
|
||||
ExternalSystemApiUtil.disposeModels(importer.getModels());
|
||||
ExceptionUtil.rethrowUnchecked(t);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,158 +116,157 @@ public class LibraryDependencyDataService extends AbstractDependencyDataService<
|
||||
return orderEntry.getLibraryName();
|
||||
}
|
||||
|
||||
private void importData(@NotNull final Collection<DataNode<LibraryDependencyData>> nodesToImport,
|
||||
@NotNull final Module module,
|
||||
@NotNull final PlatformFacade platformFacade,
|
||||
final boolean synchronous) {
|
||||
ExternalSystemApiUtil.executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(module) {
|
||||
@Override
|
||||
public void execute() {
|
||||
// The general idea is to import all external project library dependencies and module libraries which don't present at the
|
||||
// ide side yet and remove all project library dependencies and module libraries which present at the ide but not at
|
||||
// the given collection.
|
||||
// The trick is that we should perform module settings modification inside try/finally block against target root model.
|
||||
// That means that we need to prepare all necessary data, obtain a model and modify it as necessary.
|
||||
Map<Set<String>/* library paths */, LibraryDependencyData> moduleLibrariesToImport = ContainerUtilRt.newHashMap();
|
||||
Map<String/* library name + scope */, LibraryDependencyData> projectLibrariesToImport = ContainerUtilRt.newHashMap();
|
||||
Set<LibraryDependencyData> toImport = ContainerUtilRt.newLinkedHashSet();
|
||||
private class MyImporter {
|
||||
private final PlatformFacade myPlatformFacade;
|
||||
private final List<ModifiableRootModel> myModels = ContainerUtilRt.newArrayList();
|
||||
private final List<Library.ModifiableModel> myLibraryModels = ContainerUtilRt.newArrayList();
|
||||
|
||||
boolean hasUnresolved = false;
|
||||
for (DataNode<LibraryDependencyData> dependencyNode : nodesToImport) {
|
||||
LibraryDependencyData dependencyData = dependencyNode.getData();
|
||||
LibraryData libraryData = dependencyData.getTarget();
|
||||
hasUnresolved |= libraryData.isUnresolved();
|
||||
switch (dependencyData.getLevel()) {
|
||||
case MODULE:
|
||||
if (!libraryData.isUnresolved()) {
|
||||
Set<String> paths = ContainerUtilRt.newHashSet();
|
||||
for (String path : libraryData.getPaths(LibraryPathType.BINARY)) {
|
||||
paths.add(ExternalSystemApiUtil.toCanonicalPath(path) + dependencyData.getScope().name());
|
||||
}
|
||||
moduleLibrariesToImport.put(paths, dependencyData);
|
||||
toImport.add(dependencyData);
|
||||
private MyImporter(PlatformFacade platformFacade) {
|
||||
myPlatformFacade = platformFacade;
|
||||
}
|
||||
|
||||
public List<ModifiableRootModel> getModels() {
|
||||
return ContainerUtil.newUnmodifiableList(myModels);
|
||||
}
|
||||
|
||||
public List<Library.ModifiableModel> getLibraryModels() {
|
||||
return ContainerUtil.newUnmodifiableList(myLibraryModels);
|
||||
}
|
||||
|
||||
public void importData(@NotNull Module module, @NotNull Collection<DataNode<LibraryDependencyData>> nodesToImport) {
|
||||
// The general idea is to import all external project library dependencies and module libraries which don't present at the
|
||||
// ide side yet and remove all project library dependencies and module libraries which present at the ide but not at
|
||||
// the given collection.
|
||||
// The trick is that we should perform module settings modification inside try/finally block against target root model.
|
||||
// That means that we need to prepare all necessary data, obtain a model and modify it as necessary.
|
||||
Map<Set<String>/* library paths */, LibraryDependencyData> moduleLibrariesToImport = ContainerUtilRt.newHashMap();
|
||||
Map<String/* library name + scope */, LibraryDependencyData> projectLibrariesToImport = ContainerUtilRt.newHashMap();
|
||||
Set<LibraryDependencyData> toImport = ContainerUtilRt.newLinkedHashSet();
|
||||
|
||||
boolean hasUnresolved = false;
|
||||
for (DataNode<LibraryDependencyData> dependencyNode : nodesToImport) {
|
||||
LibraryDependencyData dependencyData = dependencyNode.getData();
|
||||
LibraryData libraryData = dependencyData.getTarget();
|
||||
hasUnresolved |= libraryData.isUnresolved();
|
||||
switch (dependencyData.getLevel()) {
|
||||
case MODULE:
|
||||
if (!libraryData.isUnresolved()) {
|
||||
Set<String> paths = ContainerUtilRt.newHashSet();
|
||||
for (String path : libraryData.getPaths(LibraryPathType.BINARY)) {
|
||||
paths.add(ExternalSystemApiUtil.toCanonicalPath(path) + dependencyData.getScope().name());
|
||||
}
|
||||
break;
|
||||
case PROJECT:
|
||||
projectLibrariesToImport.put(libraryData.getInternalName() + dependencyData.getScope().name(), dependencyData);
|
||||
moduleLibrariesToImport.put(paths, dependencyData);
|
||||
toImport.add(dependencyData);
|
||||
}
|
||||
}
|
||||
|
||||
final ModifiableRootModel moduleRootModel = platformFacade.getModuleModifiableModel(module);
|
||||
LibraryTable moduleLibraryTable = moduleRootModel.getModuleLibraryTable();
|
||||
LibraryTable libraryTable = platformFacade.getProjectLibraryTable(module.getProject());
|
||||
try {
|
||||
syncExistingAndRemoveObsolete(moduleLibrariesToImport, projectLibrariesToImport, toImport, moduleRootModel, hasUnresolved);
|
||||
|
||||
// Import missing library dependencies.
|
||||
if (!toImport.isEmpty()) {
|
||||
importMissing(toImport, moduleRootModel, moduleLibraryTable, libraryTable, module);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
moduleRootModel.commit();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void importMissing(@NotNull Set<LibraryDependencyData> toImport,
|
||||
@NotNull ModifiableRootModel moduleRootModel,
|
||||
@NotNull LibraryTable moduleLibraryTable,
|
||||
@NotNull LibraryTable libraryTable,
|
||||
@NotNull Module module) {
|
||||
for (final LibraryDependencyData dependencyData : toImport) {
|
||||
final LibraryData libraryData = dependencyData.getTarget();
|
||||
final String libraryName = libraryData.getInternalName();
|
||||
switch (dependencyData.getLevel()) {
|
||||
case MODULE:
|
||||
final Library moduleLib = moduleLibraryTable.createLibrary(libraryName);
|
||||
syncExistingLibraryDependency(dependencyData, moduleLib, moduleRootModel, module);
|
||||
break;
|
||||
case PROJECT:
|
||||
final Library projectLib = libraryTable.getLibraryByName(libraryName);
|
||||
if (projectLib == null) {
|
||||
syncExistingLibraryDependency(dependencyData, moduleLibraryTable.createLibrary(libraryName), moduleRootModel, module);
|
||||
}
|
||||
break;
|
||||
case PROJECT:
|
||||
projectLibrariesToImport.put(libraryData.getInternalName() + dependencyData.getScope().name(), dependencyData);
|
||||
toImport.add(dependencyData);
|
||||
}
|
||||
}
|
||||
|
||||
ModifiableRootModel moduleRootModel = myPlatformFacade.getModuleModifiableModel(module);
|
||||
LibraryTable moduleLibraryTable = moduleRootModel.getModuleLibraryTable();
|
||||
LibraryTable libraryTable = myPlatformFacade.getProjectLibraryTable(module.getProject());
|
||||
syncExistingAndRemoveObsolete(moduleLibrariesToImport, projectLibrariesToImport, toImport, moduleRootModel, hasUnresolved);
|
||||
|
||||
// Import missing library dependencies.
|
||||
if (!toImport.isEmpty()) {
|
||||
importMissing(toImport, moduleRootModel, moduleLibraryTable, libraryTable, module);
|
||||
}
|
||||
myModels.add(moduleRootModel);
|
||||
}
|
||||
|
||||
private void importMissing(@NotNull Set<LibraryDependencyData> toImport,
|
||||
@NotNull ModifiableRootModel moduleRootModel,
|
||||
@NotNull LibraryTable moduleLibraryTable,
|
||||
@NotNull LibraryTable libraryTable,
|
||||
@NotNull Module module) {
|
||||
for (LibraryDependencyData dependencyData : toImport) {
|
||||
LibraryData libraryData = dependencyData.getTarget();
|
||||
String libraryName = libraryData.getInternalName();
|
||||
switch (dependencyData.getLevel()) {
|
||||
case MODULE:
|
||||
Library moduleLib = moduleLibraryTable.createLibrary(libraryName);
|
||||
syncExistingLibraryDependency(dependencyData, moduleLib, moduleRootModel, module);
|
||||
break;
|
||||
case PROJECT:
|
||||
Library projectLib = libraryTable.getLibraryByName(libraryName);
|
||||
if (projectLib == null) {
|
||||
syncExistingLibraryDependency(dependencyData, moduleLibraryTable.createLibrary(libraryName), moduleRootModel, module);
|
||||
break;
|
||||
}
|
||||
LibraryOrderEntry orderEntry = moduleRootModel.addLibraryEntry(projectLib);
|
||||
setLibraryScope(orderEntry, projectLib, module, dependencyData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setLibraryScope(@NotNull LibraryOrderEntry orderEntry,
|
||||
@NotNull Library lib,
|
||||
@NotNull Module module,
|
||||
@NotNull LibraryDependencyData dependencyData) {
|
||||
LOG.debug(String.format("Adding library dependency '%s' to module '%s'", lib.getName(), module.getName()));
|
||||
orderEntry.setExported(dependencyData.isExported());
|
||||
orderEntry.setScope(dependencyData.getScope());
|
||||
LOG.debug(String.format("Configuring library dependency '%s' of module '%s' to be%s exported and have scope %s", lib.getName(), module.getName(), dependencyData.isExported() ? " not" : "", dependencyData.getScope()));
|
||||
}
|
||||
|
||||
private void syncExistingAndRemoveObsolete(@NotNull Map<Set<String>, LibraryDependencyData> moduleLibrariesToImport,
|
||||
@NotNull Map<String, LibraryDependencyData> projectLibrariesToImport,
|
||||
@NotNull Set<LibraryDependencyData> toImport,
|
||||
@NotNull ModifiableRootModel moduleRootModel,
|
||||
boolean hasUnresolvedLibraries) {
|
||||
Set<String> moduleLibraryKey = ContainerUtilRt.newHashSet();
|
||||
for (OrderEntry entry : moduleRootModel.getOrderEntries()) {
|
||||
if (entry instanceof ModuleLibraryOrderEntryImpl) {
|
||||
ModuleLibraryOrderEntryImpl moduleLibraryOrderEntry = (ModuleLibraryOrderEntryImpl)entry;
|
||||
Library library = moduleLibraryOrderEntry.getLibrary();
|
||||
if (library == null) {
|
||||
LOG.warn("Skipping module-level library entry because it doesn't have backing Library object. Entry: " + entry);
|
||||
continue;
|
||||
}
|
||||
moduleLibraryKey.clear();
|
||||
for (VirtualFile file : library.getFiles(OrderRootType.CLASSES)) {
|
||||
moduleLibraryKey.add(ExternalSystemApiUtil.getLocalFileSystemPath(file) + moduleLibraryOrderEntry.getScope().name());
|
||||
}
|
||||
LibraryDependencyData existing = moduleLibrariesToImport.remove(moduleLibraryKey);
|
||||
if (existing == null) {
|
||||
moduleRootModel.removeOrderEntry(entry);
|
||||
}
|
||||
else {
|
||||
syncExistingLibraryDependency(existing, library, moduleRootModel, moduleLibraryOrderEntry.getOwnerModule());
|
||||
toImport.remove(existing);
|
||||
}
|
||||
LibraryOrderEntry orderEntry = moduleRootModel.addLibraryEntry(projectLib);
|
||||
setLibraryScope(orderEntry, projectLib, module, dependencyData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void setLibraryScope(@NotNull LibraryOrderEntry orderEntry,
|
||||
@NotNull Library lib,
|
||||
@NotNull Module module,
|
||||
@NotNull LibraryDependencyData dependencyData) {
|
||||
LOG.debug(String.format("Adding library dependency '%s' to module '%s'", lib.getName(), module.getName()));
|
||||
orderEntry.setExported(dependencyData.isExported());
|
||||
orderEntry.setScope(dependencyData.getScope());
|
||||
LOG.debug(String.format(
|
||||
"Configuring library dependency '%s' of module '%s' to be%s exported and have scope %s",
|
||||
lib.getName(), module.getName(), dependencyData.isExported() ? " not" : "", dependencyData.getScope()
|
||||
));
|
||||
}
|
||||
|
||||
private void syncExistingAndRemoveObsolete(@NotNull Map<Set<String>, LibraryDependencyData> moduleLibrariesToImport,
|
||||
@NotNull Map<String, LibraryDependencyData> projectLibrariesToImport,
|
||||
@NotNull Set<LibraryDependencyData> toImport,
|
||||
@NotNull ModifiableRootModel moduleRootModel,
|
||||
boolean hasUnresolvedLibraries) {
|
||||
Set<String> moduleLibraryKey = ContainerUtilRt.newHashSet();
|
||||
for (OrderEntry entry : moduleRootModel.getOrderEntries()) {
|
||||
if (entry instanceof ModuleLibraryOrderEntryImpl) {
|
||||
ModuleLibraryOrderEntryImpl moduleLibraryOrderEntry = (ModuleLibraryOrderEntryImpl)entry;
|
||||
Library library = moduleLibraryOrderEntry.getLibrary();
|
||||
if (library == null) {
|
||||
LOG.warn("Skipping module-level library entry because it doesn't have backing Library object. Entry: " + entry);
|
||||
continue;
|
||||
}
|
||||
moduleLibraryKey.clear();
|
||||
for (VirtualFile file : library.getFiles(OrderRootType.CLASSES)) {
|
||||
moduleLibraryKey.add(ExternalSystemApiUtil.getLocalFileSystemPath(file) + moduleLibraryOrderEntry.getScope().name());
|
||||
}
|
||||
LibraryDependencyData existing = moduleLibrariesToImport.remove(moduleLibraryKey);
|
||||
if (existing == null) {
|
||||
moduleRootModel.removeOrderEntry(entry);
|
||||
}
|
||||
else {
|
||||
syncExistingLibraryDependency(existing, library, moduleRootModel, moduleLibraryOrderEntry.getOwnerModule());
|
||||
toImport.remove(existing);
|
||||
}
|
||||
}
|
||||
else if (entry instanceof LibraryOrderEntry) {
|
||||
final LibraryOrderEntry libraryOrderEntry = (LibraryOrderEntry)entry;
|
||||
final String libraryName = libraryOrderEntry.getLibraryName();
|
||||
final LibraryDependencyData existing = projectLibrariesToImport.remove(libraryName + libraryOrderEntry.getScope().name());
|
||||
if (existing != null) {
|
||||
toImport.remove(existing);
|
||||
}
|
||||
else if (!hasUnresolvedLibraries) {
|
||||
// There is a possible case that a project has been successfully imported from external model and after
|
||||
// that network/repo goes down. We don't want to drop existing binary mappings then.
|
||||
moduleRootModel.removeOrderEntry(entry);
|
||||
else if (entry instanceof LibraryOrderEntry) {
|
||||
LibraryOrderEntry libraryOrderEntry = (LibraryOrderEntry)entry;
|
||||
String libraryName = libraryOrderEntry.getLibraryName();
|
||||
LibraryDependencyData existing = projectLibrariesToImport.remove(libraryName + libraryOrderEntry.getScope().name());
|
||||
if (existing != null) {
|
||||
toImport.remove(existing);
|
||||
}
|
||||
else if (!hasUnresolvedLibraries) {
|
||||
// There is a possible case that a project has been successfully imported from external model and after
|
||||
// that network/repo goes down. We don't want to drop existing binary mappings then.
|
||||
moduleRootModel.removeOrderEntry(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void syncExistingLibraryDependency(@NotNull LibraryDependencyData libraryDependencyData,
|
||||
@NotNull Library library,
|
||||
@NotNull ModifiableRootModel moduleRootModel,
|
||||
@NotNull Module module) {
|
||||
final Library.ModifiableModel libModel = library.getModifiableModel();
|
||||
try {
|
||||
final String libraryName = libraryDependencyData.getInternalName();
|
||||
private void syncExistingLibraryDependency(@NotNull LibraryDependencyData libraryDependencyData,
|
||||
@NotNull Library library,
|
||||
@NotNull ModifiableRootModel moduleRootModel,
|
||||
@NotNull Module module) {
|
||||
Library.ModifiableModel libModel = library.getModifiableModel();
|
||||
String libraryName = libraryDependencyData.getInternalName();
|
||||
Map<OrderRootType, Collection<File>> files = myLibraryManager.prepareLibraryFiles(libraryDependencyData.getTarget());
|
||||
myLibraryManager.registerPaths(files, libModel, libraryName);
|
||||
LibraryOrderEntry orderEntry = moduleRootModel.findLibraryOrderEntry(library);
|
||||
assert orderEntry != null;
|
||||
setLibraryScope(orderEntry, library, module, libraryDependencyData);
|
||||
}
|
||||
finally {
|
||||
libModel.commit();
|
||||
myLibraryModels.add(libModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+89
-84
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package com.intellij.openapi.externalSystem.service.project.manage;
|
||||
|
||||
import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.externalSystem.model.DataNode;
|
||||
@@ -39,6 +38,7 @@ import com.intellij.ui.CheckBoxList;
|
||||
import com.intellij.ui.IdeBorderFactory;
|
||||
import com.intellij.ui.components.JBScrollPane;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.ExceptionUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
@@ -52,11 +52,10 @@ import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Encapsulates functionality of importing external system module to the intellij project.
|
||||
*
|
||||
*
|
||||
* @author Denis Zhdanov
|
||||
* @since 2/7/12 2:49 PM
|
||||
*/
|
||||
@@ -74,82 +73,72 @@ public class ModuleDataService extends AbstractProjectDataService<ModuleData, Mo
|
||||
}
|
||||
|
||||
@Override
|
||||
public void importData(@NotNull final Collection<DataNode<ModuleData>> toImport,
|
||||
public void importData(@NotNull Collection<DataNode<ModuleData>> toImport,
|
||||
@Nullable ProjectData projectData,
|
||||
@NotNull final Project project,
|
||||
@NotNull final PlatformFacade platformFacade,
|
||||
final boolean synchronous) {
|
||||
@NotNull Project project,
|
||||
@NotNull PlatformFacade platformFacade,
|
||||
boolean synchronous) {
|
||||
if (toImport.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ExternalSystemApiUtil.executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(project) {
|
||||
@Override
|
||||
public void execute() {
|
||||
final Collection<DataNode<ModuleData>> toCreate = filterExistingModules(toImport, project, platformFacade);
|
||||
if (!toCreate.isEmpty()) {
|
||||
createModules(toCreate, project, platformFacade);
|
||||
}
|
||||
for (DataNode<ModuleData> node : toImport) {
|
||||
Module module = platformFacade.findIdeModule(node.getData(), project);
|
||||
if (module != null) {
|
||||
syncPaths(module, platformFacade, node.getData());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
Collection<DataNode<ModuleData>> toCreate = filterExistingModules(toImport, project, platformFacade);
|
||||
if (!toCreate.isEmpty()) {
|
||||
ExternalSystemApiUtil.commitModels(synchronous, project, createModules(project, platformFacade, toCreate));
|
||||
}
|
||||
ExternalSystemApiUtil.commitModels(synchronous, project, syncModulesPaths(project, platformFacade, toImport));
|
||||
}
|
||||
|
||||
private static void createModules(@NotNull final Collection<DataNode<ModuleData>> toCreate,
|
||||
@NotNull final Project project,
|
||||
@NotNull final PlatformFacade platformFacade) {
|
||||
Application application = ApplicationManager.getApplication();
|
||||
final Map<DataNode<ModuleData>, Module> moduleMappings = ContainerUtilRt.newHashMap();
|
||||
application.runWriteAction(new Runnable() {
|
||||
@NotNull
|
||||
private static List<ModifiableRootModel> createModules(@NotNull Project project,
|
||||
@NotNull PlatformFacade platformFacade,
|
||||
Collection<DataNode<ModuleData>> toCreate) {
|
||||
List<ModifiableRootModel> models = ContainerUtilRt.newArrayList();
|
||||
try {
|
||||
for (DataNode<ModuleData> moduleData : toCreate) {
|
||||
models.add(createModule(project, platformFacade, moduleData));
|
||||
}
|
||||
}
|
||||
catch (Throwable t) {
|
||||
ExternalSystemApiUtil.disposeModels(models);
|
||||
ExceptionUtil.rethrowUnchecked(t);
|
||||
}
|
||||
return models;
|
||||
}
|
||||
|
||||
private static ModifiableRootModel createModule(@NotNull Project project,
|
||||
@NotNull PlatformFacade platformFacade,
|
||||
@NotNull DataNode<ModuleData> module) {
|
||||
ModuleData data = module.getData();
|
||||
Module created = platformFacade.newModule(project, data.getModuleFilePath(), data.getModuleTypeId());
|
||||
|
||||
// Ensure that the dependencies are clear (used to be not clear when manually removing the module and importing it via gradle)
|
||||
final ModifiableRootModel moduleRootModel = platformFacade.getModuleModifiableModel(created);
|
||||
moduleRootModel.inheritSdk();
|
||||
setModuleOptions(created, module);
|
||||
|
||||
RootPolicy<Object> visitor = new RootPolicy<Object>() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (DataNode<ModuleData> module : toCreate) {
|
||||
importModule(module);
|
||||
}
|
||||
public Object visitLibraryOrderEntry(LibraryOrderEntry libraryOrderEntry, Object value) {
|
||||
moduleRootModel.removeOrderEntry(libraryOrderEntry);
|
||||
return value;
|
||||
}
|
||||
|
||||
private void importModule(@NotNull DataNode<ModuleData> module) {
|
||||
ModuleData data = module.getData();
|
||||
final Module created = platformFacade.newModule(project, data.getModuleFilePath(), data.getModuleTypeId());
|
||||
|
||||
// Ensure that the dependencies are clear (used to be not clear when manually removing the module and importing it via gradle)
|
||||
final ModifiableRootModel moduleRootModel = platformFacade.getModuleModifiableModel(created);
|
||||
moduleRootModel.inheritSdk();
|
||||
setModuleOptions(created, module);
|
||||
|
||||
RootPolicy<Object> visitor = new RootPolicy<Object>() {
|
||||
@Override
|
||||
public Object visitLibraryOrderEntry(LibraryOrderEntry libraryOrderEntry, Object value) {
|
||||
moduleRootModel.removeOrderEntry(libraryOrderEntry);
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitModuleOrderEntry(ModuleOrderEntry moduleOrderEntry, Object value) {
|
||||
moduleRootModel.removeOrderEntry(moduleOrderEntry);
|
||||
return value;
|
||||
}
|
||||
};
|
||||
try {
|
||||
for (OrderEntry orderEntry : moduleRootModel.getOrderEntries()) {
|
||||
orderEntry.accept(visitor, null);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
moduleRootModel.commit();
|
||||
}
|
||||
moduleMappings.put(module, created);
|
||||
@Override
|
||||
public Object visitModuleOrderEntry(ModuleOrderEntry moduleOrderEntry, Object value) {
|
||||
moduleRootModel.removeOrderEntry(moduleOrderEntry);
|
||||
return value;
|
||||
}
|
||||
});
|
||||
};
|
||||
for (OrderEntry orderEntry : moduleRootModel.getOrderEntries()) {
|
||||
orderEntry.accept(visitor, null);
|
||||
}
|
||||
return moduleRootModel;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Collection<DataNode<ModuleData>> filterExistingModules(@NotNull Collection<DataNode<ModuleData>> modules,
|
||||
@NotNull Project project, @NotNull PlatformFacade platformFacade)
|
||||
@NotNull Project project,
|
||||
@NotNull PlatformFacade platformFacade)
|
||||
{
|
||||
Collection<DataNode<ModuleData>> result = ContainerUtilRt.newArrayList();
|
||||
for (DataNode<ModuleData> node : modules) {
|
||||
@@ -165,30 +154,46 @@ public class ModuleDataService extends AbstractProjectDataService<ModuleData, Mo
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void syncPaths(@NotNull Module module, @NotNull PlatformFacade platformFacade, @NotNull ModuleData data) {
|
||||
@NotNull
|
||||
private List<ModifiableRootModel> syncModulesPaths(@NotNull Project project,
|
||||
@NotNull PlatformFacade platformFacade,
|
||||
Collection<DataNode<ModuleData>> toCreate) {
|
||||
List<ModifiableRootModel> models = ContainerUtilRt.newArrayList();
|
||||
try {
|
||||
for (DataNode<ModuleData> moduleData : toCreate) {
|
||||
Module module = platformFacade.findIdeModule(moduleData.getData(), project);
|
||||
if (module != null) {
|
||||
models.add(syncPaths(module, platformFacade, moduleData.getData()));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable t) {
|
||||
ExternalSystemApiUtil.disposeModels(models);
|
||||
ExceptionUtil.rethrowUnchecked(t);
|
||||
}
|
||||
return models;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static ModifiableRootModel syncPaths(@NotNull Module module, @NotNull PlatformFacade platformFacade, @NotNull ModuleData data) {
|
||||
ModifiableRootModel modifiableModel = platformFacade.getModuleModifiableModel(module);
|
||||
CompilerModuleExtension extension = modifiableModel.getModuleExtension(CompilerModuleExtension.class);
|
||||
if (extension == null) {
|
||||
modifiableModel.dispose();
|
||||
LOG.warn(String.format("Can't sync paths for module '%s'. Reason: no compiler extension is found for it", module.getName()));
|
||||
return;
|
||||
return modifiableModel;
|
||||
}
|
||||
String compileOutputPath = data.getCompileOutputPath(ExternalSystemSourceType.SOURCE);
|
||||
if (compileOutputPath != null) {
|
||||
extension.setCompilerOutputPath(VfsUtilCore.pathToUrl(compileOutputPath));
|
||||
}
|
||||
try {
|
||||
String compileOutputPath = data.getCompileOutputPath(ExternalSystemSourceType.SOURCE);
|
||||
if (compileOutputPath != null) {
|
||||
extension.setCompilerOutputPath(VfsUtilCore.pathToUrl(compileOutputPath));
|
||||
}
|
||||
|
||||
String testCompileOutputPath = data.getCompileOutputPath(ExternalSystemSourceType.TEST);
|
||||
if (testCompileOutputPath != null) {
|
||||
extension.setCompilerOutputPathForTests(VfsUtilCore.pathToUrl(testCompileOutputPath));
|
||||
}
|
||||
String testCompileOutputPath = data.getCompileOutputPath(ExternalSystemSourceType.TEST);
|
||||
if (testCompileOutputPath != null) {
|
||||
extension.setCompilerOutputPathForTests(VfsUtilCore.pathToUrl(testCompileOutputPath));
|
||||
}
|
||||
|
||||
extension.inheritCompilerOutputPath(data.isInheritProjectCompileOutputPath());
|
||||
}
|
||||
finally {
|
||||
modifiableModel.commit();
|
||||
}
|
||||
extension.inheritCompilerOutputPath(data.isInheritProjectCompileOutputPath());
|
||||
return modifiableModel;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -340,7 +345,7 @@ public class ModuleDataService extends AbstractProjectDataService<ModuleData, Mo
|
||||
protected JComponent createCenterPanel() {
|
||||
return new JBScrollPane(content);
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
protected Action[] createActions() {
|
||||
return new Action[]{getOKAction()};
|
||||
@@ -377,7 +382,7 @@ public class ModuleDataService extends AbstractProjectDataService<ModuleData, Mo
|
||||
module.setOption(ExternalSystemConstants.EXTERNAL_SYSTEM_ID_KEY, moduleData.getOwner().toString());
|
||||
module.setOption(ExternalSystemConstants.LINKED_PROJECT_ID_KEY, moduleData.getId());
|
||||
module.setOption(ExternalSystemConstants.LINKED_PROJECT_PATH_KEY, moduleData.getLinkedExternalProjectPath());
|
||||
final ProjectData projectData = moduleDataNode.getData(ProjectKeys.PROJECT);
|
||||
ProjectData projectData = moduleDataNode.getData(ProjectKeys.PROJECT);
|
||||
module.setOption(ExternalSystemConstants.ROOT_PROJECT_PATH_KEY, projectData != null ? projectData.getLinkedExternalProjectPath() : "");
|
||||
|
||||
if (moduleData.getGroup() != null) {
|
||||
|
||||
+64
-69
@@ -19,23 +19,18 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.externalSystem.model.DataNode;
|
||||
import com.intellij.openapi.externalSystem.model.Key;
|
||||
import com.intellij.openapi.externalSystem.model.ProjectKeys;
|
||||
import com.intellij.openapi.externalSystem.model.project.LibraryDependencyData;
|
||||
import com.intellij.openapi.externalSystem.model.project.ModuleData;
|
||||
import com.intellij.openapi.externalSystem.model.project.ModuleDependencyData;
|
||||
import com.intellij.openapi.externalSystem.model.project.ProjectData;
|
||||
import com.intellij.openapi.externalSystem.service.project.PlatformFacade;
|
||||
import com.intellij.openapi.externalSystem.util.DisposeAwareProjectChange;
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemConstants;
|
||||
import com.intellij.openapi.externalSystem.util.Order;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.*;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.ExceptionUtil;
|
||||
import com.intellij.util.containers.ContainerUtilRt;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -68,17 +63,25 @@ public class ModuleDependencyDataService extends AbstractDependencyDataService<M
|
||||
@NotNull Project project,
|
||||
@NotNull PlatformFacade platformFacade,
|
||||
boolean synchronous) {
|
||||
MultiMap<DataNode<ModuleData>, DataNode<ModuleDependencyData>> byModule = ExternalSystemApiUtil.groupBy(toImport, MODULE);
|
||||
for (Map.Entry<DataNode<ModuleData>, Collection<DataNode<ModuleDependencyData>>> entry : byModule.entrySet()) {
|
||||
Module ideModule = platformFacade.findIdeModule(entry.getKey().getData(), project);
|
||||
if (ideModule == null) {
|
||||
LOG.warn(String.format(
|
||||
"Can't import module dependencies %s. Reason: target module (%s) is not found at the ide and can't be imported",
|
||||
entry.getValue(), entry.getKey()
|
||||
));
|
||||
continue;
|
||||
List<ModifiableRootModel> models = ContainerUtilRt.newArrayList();
|
||||
try {
|
||||
MultiMap<DataNode<ModuleData>, DataNode<ModuleDependencyData>> byModule = ExternalSystemApiUtil.groupBy(toImport, MODULE);
|
||||
for (Map.Entry<DataNode<ModuleData>, Collection<DataNode<ModuleDependencyData>>> entry : byModule.entrySet()) {
|
||||
Module ideModule = platformFacade.findIdeModule(entry.getKey().getData(), project);
|
||||
if (ideModule == null) {
|
||||
LOG.warn(String.format(
|
||||
"Can't import module dependencies %s. Reason: target module (%s) is not found at the ide and can't be imported",
|
||||
entry.getValue(), entry.getKey()
|
||||
));
|
||||
continue;
|
||||
}
|
||||
models.add(importData(entry.getValue(), ideModule, platformFacade));
|
||||
}
|
||||
importData(entry.getValue(), ideModule, platformFacade, synchronous);
|
||||
ExternalSystemApiUtil.commitModels(synchronous, project, models);
|
||||
}
|
||||
catch (Throwable t) {
|
||||
ExternalSystemApiUtil.disposeModels(models);
|
||||
ExceptionUtil.rethrowUnchecked(t);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,62 +96,54 @@ public class ModuleDependencyDataService extends AbstractDependencyDataService<M
|
||||
return orderEntry.getModuleName();
|
||||
}
|
||||
|
||||
private void importData(@NotNull final Collection<DataNode<ModuleDependencyData>> toImport,
|
||||
@NotNull final Module module,
|
||||
@NotNull final PlatformFacade platformFacade,
|
||||
final boolean synchronous)
|
||||
@NotNull
|
||||
private ModifiableRootModel importData(@NotNull Collection<DataNode<ModuleDependencyData>> toImport,
|
||||
@NotNull Module module,
|
||||
@NotNull PlatformFacade platformFacade)
|
||||
{
|
||||
ExternalSystemApiUtil.executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(module) {
|
||||
@Override
|
||||
public void execute() {
|
||||
ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module);
|
||||
Map<Pair<String /* dependency module internal name */, /* dependency module scope */DependencyScope> , ModuleOrderEntry> toRemove = ContainerUtilRt.newHashMap();
|
||||
for (OrderEntry entry : moduleRootManager.getOrderEntries()) {
|
||||
if (entry instanceof ModuleOrderEntry) {
|
||||
ModuleOrderEntry e = (ModuleOrderEntry)entry;
|
||||
toRemove.put(Pair.create(e.getModuleName(), e.getScope()), e);
|
||||
}
|
||||
ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module);
|
||||
Map<Pair<String /* dependency module internal name */, /* dependency module scope */DependencyScope>, ModuleOrderEntry> toRemove =
|
||||
ContainerUtilRt.newHashMap();
|
||||
for (OrderEntry entry : moduleRootManager.getOrderEntries()) {
|
||||
if (entry instanceof ModuleOrderEntry) {
|
||||
ModuleOrderEntry e = (ModuleOrderEntry)entry;
|
||||
toRemove.put(Pair.create(e.getModuleName(), e.getScope()), e);
|
||||
}
|
||||
}
|
||||
|
||||
ModifiableRootModel moduleRootModel = platformFacade.getModuleModifiableModel(module);
|
||||
for (DataNode<ModuleDependencyData> dependencyNode : toImport) {
|
||||
ModuleDependencyData dependencyData = dependencyNode.getData();
|
||||
toRemove.remove(Pair.create(dependencyData.getInternalName(), dependencyData.getScope()));
|
||||
String moduleName = dependencyData.getInternalName();
|
||||
Module ideDependencyModule = platformFacade.findIdeModule(moduleName, module.getProject());
|
||||
|
||||
ModuleOrderEntry orderEntry;
|
||||
if (module.equals(ideDependencyModule)) {
|
||||
// skip recursive module dependency check
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
if (ideDependencyModule == null) {
|
||||
LOG.warn(String.format("Can't import module dependency for '%s' module. Reason: target module (%s) is not found at the ide",
|
||||
module.getName(), dependencyData));
|
||||
}
|
||||
|
||||
final ModifiableRootModel moduleRootModel = platformFacade.getModuleModifiableModel(module);
|
||||
try {
|
||||
for (DataNode<ModuleDependencyData> dependencyNode : toImport) {
|
||||
final ModuleDependencyData dependencyData = dependencyNode.getData();
|
||||
toRemove.remove(Pair.create(dependencyData.getInternalName(), dependencyData.getScope()));
|
||||
final String moduleName = dependencyData.getInternalName();
|
||||
Module ideDependencyModule = platformFacade.findIdeModule(moduleName, module.getProject());
|
||||
|
||||
ModuleOrderEntry orderEntry;
|
||||
if (module.equals(ideDependencyModule)) {
|
||||
// skip recursive module dependency check
|
||||
continue;
|
||||
} else {
|
||||
if(ideDependencyModule == null) {
|
||||
LOG.warn(String.format(
|
||||
"Can't import module dependency for '%s' module. Reason: target module (%s) is not found at the ide",
|
||||
module.getName(), dependencyData
|
||||
));
|
||||
}
|
||||
orderEntry = platformFacade.findIdeModuleDependency(dependencyData, moduleRootModel);
|
||||
if (orderEntry == null) {
|
||||
orderEntry = ideDependencyModule == null
|
||||
? moduleRootModel.addInvalidModuleEntry(moduleName)
|
||||
: moduleRootModel.addModuleOrderEntry(ideDependencyModule);
|
||||
}
|
||||
}
|
||||
|
||||
orderEntry.setScope(dependencyData.getScope());
|
||||
orderEntry.setExported(dependencyData.isExported());
|
||||
}
|
||||
}
|
||||
finally {
|
||||
moduleRootModel.commit();
|
||||
}
|
||||
|
||||
if (!toRemove.isEmpty()) {
|
||||
removeData(toRemove.values(), module, platformFacade, synchronous);
|
||||
orderEntry = platformFacade.findIdeModuleDependency(dependencyData, moduleRootModel);
|
||||
if (orderEntry == null) {
|
||||
orderEntry = ideDependencyModule == null
|
||||
? moduleRootModel.addInvalidModuleEntry(moduleName)
|
||||
: moduleRootModel.addModuleOrderEntry(ideDependencyModule);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
orderEntry.setScope(dependencyData.getScope());
|
||||
orderEntry.setExported(dependencyData.isExported());
|
||||
}
|
||||
|
||||
if (!toRemove.isEmpty()) {
|
||||
removeData(toRemove.values(), moduleRootModel);
|
||||
}
|
||||
|
||||
return moduleRootModel;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -127,7 +127,7 @@ public class ModuleRootManagerImpl extends ModuleRootManager implements ModuleCo
|
||||
}
|
||||
|
||||
for (OrderEntry entry : ModuleRootManagerImpl.this.getOrderEntries()) {
|
||||
assert !((RootModelComponentBase)entry).isDisposed();
|
||||
assert !((RootModelComponentBase)entry).isDisposed() : String.format("%s is not disposed!", entry.getPresentableName());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
+3
-1
@@ -589,7 +589,9 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
|
||||
public void commit() {
|
||||
checkDisposed();
|
||||
|
||||
mySource.commit(this);
|
||||
if (isChanged()) {
|
||||
mySource.commit(this);
|
||||
}
|
||||
Disposer.dispose(this);
|
||||
}
|
||||
|
||||
|
||||
+4
@@ -167,6 +167,10 @@ public abstract class LibraryTableBase implements PersistentStateComponent<Eleme
|
||||
private void commit(LibraryModel model) {
|
||||
myFirstLoad = false;
|
||||
ApplicationManager.getApplication().assertWriteAccessAllowed();
|
||||
if (!model.isChanged()) {
|
||||
myModel = model;
|
||||
return;
|
||||
}
|
||||
//todo[nik] remove LibraryImpl#equals method instead of using identity sets
|
||||
Set<Library> addedLibraries = ContainerUtil.newIdentityTroveSet(model.myLibraries);
|
||||
addedLibraries.removeAll(myModel.myLibraries);
|
||||
|
||||
Reference in New Issue
Block a user