Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Batch import dependencies in data services #2985

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ protected Map<OrderEntry, OrderAware> importData(@NotNull Collection<? extends D

Map<OrderEntry, OrderAware> orderEntryDataMap = new LinkedHashMap<>();
ModifiableRootModel modifiableRootModel = modelsProvider.getModifiableRootModel(module);
final ArrayList<ModifiableRootModel.Dependency> dependencies = new ArrayList<>(nodesToImport.size());
final ArrayList<LibraryDependencyData> orderedDependencies = new ArrayList<>(nodesToImport.size());

for (OrderEntry entry : modifiableRootModel.getOrderEntries()) {
LibraryDependencyData processingResult = null;
Expand All @@ -89,9 +91,18 @@ else if (entry instanceof LibraryOrderEntry libraryOrderEntry) {

// Import missing library dependencies.
for (LibraryDependencyData dependencyData : toImport.projectLibraries.values()) {
OrderEntry entry = importMissingLibraryOrderEntry(dependencyData, modifiableRootModel, modelsProvider, module);
orderEntryDataMap.put(entry, dependencyData);
ModifiableRootModel.LibraryDependency dependency =
importMissingLibraryOrderEntry(dependencyData, modifiableRootModel, modelsProvider, module);
if (dependency != null) {
dependencies.add(dependency);
orderedDependencies.add(dependencyData);
}
}
List<OrderEntry> entries = modifiableRootModel.addEntries(dependencies);
for (int i=0; i < entries.size(); i++) {
orderEntryDataMap.put(entries.get(i), orderedDependencies.get(i));
}

for (LibraryDependencyData dependencyData : toImport.moduleLibraries.values()) {
OrderEntry entry = importMissingModuleLibraryOrderEntry(dependencyData, modifiableRootModel, modelsProvider,
module);
Expand Down Expand Up @@ -166,7 +177,7 @@ else if (LibraryLevel.PROJECT == dependencyDataLevel) {
return new DataToImport(moduleLibrariesToImport, projectLibrariesToImport, hasUnresolved);
}

private static @NotNull OrderEntry importMissingModuleLibraryOrderEntry(@NotNull LibraryDependencyData dependencyData,
private static @Nullable OrderEntry importMissingModuleLibraryOrderEntry(@NotNull LibraryDependencyData dependencyData,
@NotNull ModifiableRootModel moduleRootModel,
@NotNull IdeModifiableModelsProvider modelsProvider,
@NotNull Module module
Expand All @@ -181,10 +192,11 @@ else if (LibraryLevel.PROJECT == dependencyDataLevel) {
else {
moduleLib = moduleLibraryTable.createLibrary(libraryName);
}
return syncExistingLibraryDependency(modelsProvider, dependencyData, moduleLib, moduleRootModel, module, null);
syncExistingLibraryDependency(modelsProvider, dependencyData, moduleLib, moduleRootModel, module, null);
return null; // not adding a new library
}

private static @NotNull OrderEntry importMissingLibraryOrderEntry(@NotNull LibraryDependencyData dependencyData,
private static @Nullable ModifiableRootModel.LibraryDependency importMissingLibraryOrderEntry(@NotNull LibraryDependencyData dependencyData,
@NotNull ModifiableRootModel moduleRootModel,
@NotNull IdeModifiableModelsProvider modelsProvider,
@NotNull Module module
Expand All @@ -194,12 +206,11 @@ else if (LibraryLevel.PROJECT == dependencyDataLevel) {
final Library projectLib = modelsProvider.getLibraryByName(libraryName);
if (projectLib == null) {
LibraryTable moduleLibraryTable = moduleRootModel.getModuleLibraryTable();
return syncExistingLibraryDependency(modelsProvider, dependencyData, moduleLibraryTable.createLibrary(libraryName), moduleRootModel,
syncExistingLibraryDependency(modelsProvider, dependencyData, moduleLibraryTable.createLibrary(libraryName), moduleRootModel,
module, null);
return null; // not adding a new library
}
LibraryOrderEntry orderEntry = moduleRootModel.addLibraryEntry(projectLib);
setLibraryScope(orderEntry, projectLib, module, dependencyData);
return orderEntry;
return new ModifiableRootModel.LibraryDependency(projectLib, dependencyData.getScope(), dependencyData.isExported());
}

private static void setLibraryScope(@NotNull LibraryOrderEntry orderEntry,
Expand All @@ -216,7 +227,7 @@ private static void setLibraryScope(@NotNull LibraryOrderEntry orderEntry,
}
}

private static @NotNull LibraryOrderEntry syncExistingLibraryDependency(@NotNull IdeModifiableModelsProvider modelsProvider,
private static void syncExistingLibraryDependency(@NotNull IdeModifiableModelsProvider modelsProvider,
final @NotNull LibraryDependencyData libraryDependencyData,
final @NotNull Library library,
final @NotNull ModifiableRootModel moduleRootModel,
Expand All @@ -235,7 +246,6 @@ private static void setLibraryScope(@NotNull LibraryOrderEntry orderEntry,

assert orderEntry != null;
setLibraryScope(orderEntry, library, module, libraryDependencyData);
return orderEntry;
}

private static @Nullable LibraryOrderEntry findLibraryOrderEntry(@NotNull ModifiableRootModel moduleRootModel,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.externalSystem.service.project.manage;

import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.externalSystem.model.DataNode;
import com.intellij.openapi.externalSystem.model.Key;
Expand Down Expand Up @@ -69,7 +68,8 @@ protected Map<OrderEntry, OrderAware> importData(final @NotNull Collection<? ext
}
}
final Set<ModuleDependencyData> processed = new HashSet<>();
final ModifiableRootModel modifiableRootModel = modelsProvider.getModifiableRootModel(module);
final ArrayList<ModifiableRootModel.Dependency> dependencyToBeAdded = new ArrayList<>(toImport.size());
final ArrayList<ModuleDependencyData> dependencyDataToBeAdded = new ArrayList<>(toImport.size());
for (DataNode<ModuleDependencyData> dependencyNode : toImport) {
final ModuleDependencyData dependencyData = dependencyNode.getData();

Expand All @@ -79,39 +79,47 @@ protected Map<OrderEntry, OrderAware> importData(final @NotNull Collection<? ext
final ModuleData moduleData = dependencyData.getTarget();
Module ideDependencyModule = modelsProvider.findIdeModule(moduleData);

if (ideDependencyModule != null) {
final String targetModuleName = ideDependencyModule.getName();
toRemove.remove(Pair.create(targetModuleName, dependencyData.getScope()));
dependencyData.setInternalName(targetModuleName);
}

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 = modelsProvider.findIdeModuleDependency(dependencyData, module);
if (orderEntry == null) {
orderEntry = ReadAction.compute(() ->
ideDependencyModule == null
? modifiableRootModel.addInvalidModuleEntry(moduleData.getInternalName())
: modifiableRootModel.addModuleOrderEntry(ideDependencyModule));
}
}

orderEntry.setScope(dependencyData.getScope());
orderEntry.setExported(dependencyData.isExported());
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
));
dependencyToBeAdded.add(new ModifiableRootModel.InvalidModuleDependency(
moduleData.getInternalName(),
dependencyData.getScope(),
dependencyData.isExported(),
dependencyData.isProductionOnTestDependency()
));
dependencyDataToBeAdded.add(dependencyData);
continue;
}
final String targetModuleName = ideDependencyModule.getName();
ModuleOrderEntry existingOrderEntry = toRemove.remove(Pair.create(targetModuleName, dependencyData.getScope()));
dependencyData.setInternalName(targetModuleName);

orderEntry.setProductionOnTestDependency(dependencyData.isProductionOnTestDependency());
if (existingOrderEntry != null) {
// Already existing module, continue to next one
orderEntryDataMap.put(existingOrderEntry, dependencyData);
continue;
}
dependencyToBeAdded.add(new ModifiableRootModel.ValidModuleDependency(
ideDependencyModule,
dependencyData.getScope(),
dependencyData.isExported(),
dependencyData.isProductionOnTestDependency()
));
dependencyDataToBeAdded.add(dependencyData);

orderEntryDataMap.put(orderEntry, dependencyData);
}
final ModifiableRootModel modifiableRootModel = modelsProvider.getModifiableRootModel(module);
List<OrderEntry> entries = modifiableRootModel.addEntries(dependencyToBeAdded);
for (int i=0; i < dependencyToBeAdded.size(); i++) {
orderEntryDataMap.put(entries.get(i), dependencyDataToBeAdded.get(i));
}

if (!toRemove.isEmpty() || !duplicatesToRemove.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,16 @@ public interface ModifiableRootModel extends ModuleRootModel {
@NotNull
ModuleOrderEntry addInvalidModuleEntry(@NotNull String name);

sealed interface Dependency {}
record ValidModuleDependency(Module module, DependencyScope scope, boolean exported, boolean productionOnTest) implements Dependency {}
record InvalidModuleDependency(String moduleName, DependencyScope scope, boolean exported, boolean productionOnTest) implements Dependency {}
record LibraryDependency(Library library, DependencyScope scope, boolean exported) implements Dependency {}

/**
* Adds dependencies on several {@code modules} and sets the specified {@code scope} and {@code exported} flag for them. This works
* faster than adding these dependencies one-by-one via {@link #addModuleOrderEntry}.
*/
void addModuleEntries(@NotNull List<Module> modules, @NotNull DependencyScope scope, boolean exported);
List<OrderEntry> addEntries(@NotNull List<Dependency> dependencies);

@Nullable
ModuleOrderEntry findModuleOrderEntry(@NotNull Module module);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.roots.*
import com.intellij.openapi.roots.ModifiableRootModel.Dependency
import com.intellij.openapi.roots.ModifiableRootModel.InvalidModuleDependency
import com.intellij.openapi.roots.ModifiableRootModel.ValidModuleDependency
import com.intellij.openapi.roots.impl.ModuleOrderEnumerator
import com.intellij.openapi.roots.impl.RootConfigurationAccessor
import com.intellij.openapi.roots.impl.RootModelBase.CollectDependentModules
Expand Down Expand Up @@ -315,6 +318,17 @@ internal class ModifiableRootModelBridgeImpl(
return (mutableOrderEntries.lastOrNull() as? LibraryOrderEntry ?: error("Unable to find library orderEntry after adding"))
}

override fun addEntries(dependencies: List<Dependency>): List<OrderEntry> {
appendDependencies(dependencies.map {
when(it) {
is ValidModuleDependency -> ModuleDependency((it.module as ModuleBridge).moduleEntityId, it.exported, it.scope.toEntityDependencyScope(), productionOnTest = it.productionOnTest)
is InvalidModuleDependency -> ModuleDependency(ModuleId(it.moduleName), it.exported, it.scope.toEntityDependencyScope(), productionOnTest = it.productionOnTest)
is ModifiableRootModel.LibraryDependency -> LibraryDependency(it.library.libraryId, it.exported, it.scope.toEntityDependencyScope())
}
})
return mutableOrderEntries.takeLast(dependencies.size)
}

override fun addModuleOrderEntry(module: Module): ModuleOrderEntry {
val moduleDependency = ModuleDependency(
module = (module as ModuleBridge).moduleEntityId,
Expand All @@ -328,13 +342,6 @@ internal class ModifiableRootModelBridgeImpl(
return mutableOrderEntries.lastOrNull() as? ModuleOrderEntry ?: error("Unable to find module orderEntry after adding")
}

override fun addModuleEntries(modules: MutableList<Module>, scope: DependencyScope, exported: Boolean) {
val dependencyScope = scope.toEntityDependencyScope()
appendDependencies(modules.map {
ModuleDependency((it as ModuleBridge).moduleEntityId, exported, dependencyScope, productionOnTest = false)
})
}

override fun addInvalidModuleEntry(name: String): ModuleOrderEntry {
val moduleDependency = ModuleDependency(
module = ModuleId(name),
Expand Down