mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-14 18:05:27 +07:00
[plugin model] process dependencies on modules in 'processAllNonOptionalDependencies' (IJPL-192427, IJPL-192738)
Before, only dependencies on plugins were processed. So if a plugin depends on a module from another plugin, such dependencies weren't handled in Settings | Plugins, for example. Now `processAllNonOptionalDependencies` processes dependencies on modules as well. To find a descriptor by the module ID (name), a corresponding mapping is built by `PluginSet::buildContentModuleIdMap` and propagated to `processAllNonOptionalDependencies` along with `pluginIdMap`. 'getNonOptionalDependenciesIds' is deprecated since it doesn't return dependencies on modules. It's now used only in the performance testing plugin, so this shouldn't cause problems. (cherry picked from commit 5ea349497169077cfe33cea4895ce853600fe856, IJ-CR-166457) GitOrigin-RevId: b8853da20b71a82fbdf1cc26abf2f019c06a4db7
This commit is contained in:
committed by
intellij-monorepo-bot
parent
1e83cd1933
commit
5b70765b8c
@@ -7,6 +7,7 @@ import com.intellij.diagnostic.CoroutineTracerShim
|
||||
import com.intellij.diagnostic.LoadingState
|
||||
import com.intellij.ide.plugins.DisabledPluginsState.Companion.invalidate
|
||||
import com.intellij.ide.plugins.PluginManagerCore.ULTIMATE_PLUGIN_ID
|
||||
import com.intellij.ide.plugins.PluginManagerCore.getPluginSet
|
||||
import com.intellij.ide.plugins.PluginManagerCore.isDisabled
|
||||
import com.intellij.ide.plugins.PluginManagerCore.loadedPlugins
|
||||
import com.intellij.ide.plugins.PluginManagerCore.processAllNonOptionalDependencies
|
||||
@@ -483,7 +484,13 @@ object PluginManagerCore {
|
||||
loadingResult.getIncompleteIdMap().flatMap { (_, value) ->
|
||||
value.pluginAliases.map { it to value }
|
||||
}.toMap()
|
||||
|
||||
val fullContentModuleIdMap = HashMap<String, ContentModuleDescriptor>()
|
||||
for (descriptor in loadingResult.getIncompleteIdMap().values) {
|
||||
descriptor.contentModules.associateByTo(fullContentModuleIdMap) { it.moduleName }
|
||||
}
|
||||
for (descriptor in idMap.values) {
|
||||
descriptor.contentModules.associateByTo(fullContentModuleIdMap) { it.moduleName }
|
||||
}
|
||||
|
||||
if (initContext.checkEssentialPlugins && !idMap.containsKey(CORE_ID)) {
|
||||
throw EssentialPluginMissingException(listOf("$CORE_ID (platform prefix: ${System.getProperty(PlatformUtils.PLATFORM_PREFIX_KEY)})"))
|
||||
@@ -513,7 +520,7 @@ object PluginManagerCore {
|
||||
incompletePlugins = loadingResult.getIncompleteIdMap().values,
|
||||
currentProductModeEvaluator = initContext::currentProductModeId,
|
||||
disabler = { descriptor, disabledModuleToProblematicPlugin ->
|
||||
val loadingError = pluginSetBuilder.initEnableState(descriptor, idMap, fullIdMap, initContext::isPluginDisabled, pluginErrorsById, disabledModuleToProblematicPlugin)
|
||||
val loadingError = pluginSetBuilder.initEnableState(descriptor, idMap, fullIdMap, fullContentModuleIdMap, initContext::isPluginDisabled, pluginErrorsById, disabledModuleToProblematicPlugin)
|
||||
if (loadingError != null) {
|
||||
registerLoadingError(loadingError)
|
||||
}
|
||||
@@ -560,7 +567,7 @@ object PluginManagerCore {
|
||||
}
|
||||
|
||||
private fun selectPluginsForLoading(
|
||||
descriptors: Collection<IdeaPluginDescriptorImpl>,
|
||||
descriptors: Collection<PluginMainDescriptor>,
|
||||
idMap: Map<PluginId, IdeaPluginDescriptorImpl>,
|
||||
errors: MutableMap<PluginId, PluginNonLoadReason>,
|
||||
initContext: PluginInitializationContext,
|
||||
@@ -568,10 +575,14 @@ object PluginManagerCore {
|
||||
if (initContext.explicitPluginSubsetToLoad != null) {
|
||||
val rootPluginsToLoad: Set<PluginId> = initContext.explicitPluginSubsetToLoad!!.toHashSet() + initContext.essentialPlugins
|
||||
val pluginsToLoad = LinkedHashSet<IdeaPluginDescriptorImpl>(rootPluginsToLoad.size)
|
||||
val contentModuleIdMap = HashMap<String, ContentModuleDescriptor>()
|
||||
for (descriptor in descriptors) {
|
||||
descriptor.contentModules.associateByTo(contentModuleIdMap) { it.moduleName }
|
||||
}
|
||||
for (id in rootPluginsToLoad) {
|
||||
val descriptor = idMap[id] ?: continue
|
||||
pluginsToLoad.add(descriptor)
|
||||
processAllNonOptionalDependencies(descriptor, idMap) { dependency ->
|
||||
processAllNonOptionalDependencies(descriptor, idMap, contentModuleIdMap) { dependency ->
|
||||
pluginsToLoad.add(dependency)
|
||||
FileVisitResult.CONTINUE
|
||||
}
|
||||
@@ -758,8 +769,12 @@ object PluginManagerCore {
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
fun processAllNonOptionalDependencyIds(rootDescriptor: IdeaPluginDescriptorImpl, pluginIdMap: Map<PluginId, IdeaPluginDescriptorImpl>, consumer: (PluginId) -> FileVisitResult) {
|
||||
processAllNonOptionalDependencies(rootDescriptor, depProcessed = HashSet(), pluginIdMap, consumer = { pluginId, _ -> consumer(pluginId) })
|
||||
fun processAllNonOptionalDependencyIds(rootDescriptor: IdeaPluginDescriptorImpl, pluginIdMap: Map<PluginId, IdeaPluginDescriptorImpl>,
|
||||
contentModuleIdMap: Map<String, ContentModuleDescriptor>,
|
||||
consumer: (PluginId) -> FileVisitResult) {
|
||||
processAllNonOptionalDependencies(rootDescriptor, depProcessed = HashSet(), pluginIdMap, contentModuleIdMap) { pluginId, _ ->
|
||||
if (pluginId == null) FileVisitResult.CONTINUE else consumer(pluginId)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -770,8 +785,9 @@ object PluginManagerCore {
|
||||
fun processAllNonOptionalDependencies(
|
||||
rootDescriptor: IdeaPluginDescriptorImpl,
|
||||
pluginIdMap: Map<PluginId, IdeaPluginDescriptorImpl>,
|
||||
contentModuleIdMap: Map<String, ContentModuleDescriptor>,
|
||||
consumer: (IdeaPluginDescriptorImpl) -> FileVisitResult,
|
||||
): Boolean = processAllNonOptionalDependencies(rootDescriptor, depProcessed = HashSet(), pluginIdMap, consumer = { _, descriptor ->
|
||||
): Boolean = processAllNonOptionalDependencies(rootDescriptor, depProcessed = HashSet(), pluginIdMap, contentModuleIdMap, consumer = { _, descriptor ->
|
||||
if (descriptor == null) FileVisitResult.CONTINUE else consumer(descriptor)
|
||||
})
|
||||
|
||||
@@ -779,25 +795,53 @@ object PluginManagerCore {
|
||||
rootDescriptor: IdeaPluginDescriptorImpl,
|
||||
depProcessed: MutableSet<in IdeaPluginDescriptorImpl>,
|
||||
pluginIdMap: Map<PluginId, IdeaPluginDescriptorImpl>,
|
||||
consumer: (PluginId, IdeaPluginDescriptorImpl?) -> FileVisitResult,
|
||||
contentModuleIdMap: Map<String, ContentModuleDescriptor>,
|
||||
consumer: (PluginId?, IdeaPluginDescriptorImpl?) -> FileVisitResult,
|
||||
): Boolean {
|
||||
for (dependencyId in getNonOptionalDependenciesIds(rootDescriptor)) {
|
||||
val descriptor = pluginIdMap[dependencyId]
|
||||
val pluginId = descriptor?.getPluginId() ?: dependencyId
|
||||
fun processDependency(pluginId: PluginId?, moduleId: String?): Boolean {
|
||||
val descriptor = if (pluginId != null) pluginIdMap[pluginId] else contentModuleIdMap[moduleId]
|
||||
val pluginId = descriptor?.getPluginId() ?: pluginId
|
||||
when (consumer(pluginId, descriptor)) {
|
||||
FileVisitResult.TERMINATE -> return false
|
||||
FileVisitResult.CONTINUE -> {
|
||||
if (descriptor != null && depProcessed.add(descriptor)) {
|
||||
if (!processAllNonOptionalDependencies(descriptor, depProcessed, pluginIdMap, consumer)) return false
|
||||
if (!processAllNonOptionalDependencies(descriptor, depProcessed, pluginIdMap, contentModuleIdMap, consumer)) return false
|
||||
}
|
||||
}
|
||||
FileVisitResult.SKIP_SUBTREE -> {}
|
||||
FileVisitResult.SKIP_SIBLINGS -> throw UnsupportedOperationException("FileVisitResult.SKIP_SIBLINGS is not supported")
|
||||
}
|
||||
return true
|
||||
}
|
||||
fun processModuleDependencies(moduleDependencies: ModuleDependencies): Boolean {
|
||||
for (plugin in moduleDependencies.plugins) {
|
||||
if (!processDependency(plugin.id, null)) return false
|
||||
}
|
||||
for (module in moduleDependencies.modules) {
|
||||
if (!processDependency(null, module.name)) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
for (dependency in rootDescriptor.dependencies) {
|
||||
if (!dependency.isOptional) {
|
||||
if (!processDependency(dependency.pluginId, null)) return false
|
||||
}
|
||||
}
|
||||
|
||||
if (!processModuleDependencies(rootDescriptor.moduleDependencies)) return false
|
||||
|
||||
if (rootDescriptor is PluginMainDescriptor) {
|
||||
for (contentModule in rootDescriptor.contentModules) {
|
||||
if (contentModule.moduleLoadingRule.required && !processModuleDependencies(contentModule.moduleDependencies)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@Deprecated("Use [processAllNonOptionalDependencyIds] instead, this function doesn't process dependencies on modules")
|
||||
@ApiStatus.Internal
|
||||
fun getNonOptionalDependenciesIds(descriptor: IdeaPluginDescriptorImpl): Set<PluginId> {
|
||||
val dependencies = LinkedHashSet<PluginId>()
|
||||
@@ -857,9 +901,10 @@ object PluginManagerCore {
|
||||
@ApiStatus.Internal
|
||||
fun dependsOnUltimateOptionally(pluginDescriptor: IdeaPluginDescriptor?): Boolean {
|
||||
if (pluginDescriptor == null || pluginDescriptor !is IdeaPluginDescriptorImpl || !isDisabled(ULTIMATE_PLUGIN_ID)) return false
|
||||
val idMap = buildPluginIdMap()
|
||||
val pluginIdMap = buildPluginIdMap()
|
||||
val contentModuleIdMap = getPluginSet().buildContentModuleIdMap()
|
||||
return pluginDescriptor.contentModules.any { contentModule ->
|
||||
!contentModule.moduleLoadingRule.required && !processAllNonOptionalDependencies(contentModule, idMap) { descriptorImpl ->
|
||||
!contentModule.moduleLoadingRule.required && !processAllNonOptionalDependencies(contentModule, pluginIdMap, contentModuleIdMap) { descriptorImpl ->
|
||||
when (descriptorImpl.pluginId) {
|
||||
ULTIMATE_PLUGIN_ID -> FileVisitResult.TERMINATE
|
||||
else -> FileVisitResult.CONTINUE
|
||||
@@ -928,20 +973,25 @@ fun getPluginDistDirByClass(aClass: Class<*>): Path? {
|
||||
@ApiStatus.Internal
|
||||
fun pluginRequiresUltimatePluginButItsDisabled(plugin: PluginId): Boolean {
|
||||
val idMap = PluginManagerCore.buildPluginIdMap()
|
||||
return pluginRequiresUltimatePluginButItsDisabled(plugin, idMap)
|
||||
val contentModuleIdMap = getPluginSet().buildContentModuleIdMap()
|
||||
return pluginRequiresUltimatePluginButItsDisabled(plugin, idMap, contentModuleIdMap)
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
fun pluginRequiresUltimatePluginButItsDisabled(plugin: PluginId, pluginMap: Map<PluginId, IdeaPluginDescriptorImpl>): Boolean {
|
||||
fun pluginRequiresUltimatePluginButItsDisabled(plugin: PluginId, pluginMap: Map<PluginId, IdeaPluginDescriptorImpl>,
|
||||
contentModuleIdMap: Map<String, ContentModuleDescriptor>): Boolean {
|
||||
if (!isDisabled(ULTIMATE_PLUGIN_ID)) return false
|
||||
return pluginRequiresUltimatePlugin(plugin, pluginMap)
|
||||
return pluginRequiresUltimatePlugin(plugin, pluginMap, contentModuleIdMap)
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
fun pluginRequiresUltimatePlugin(plugin: PluginId, pluginMap: Map<PluginId, IdeaPluginDescriptorImpl> = PluginManagerCore.buildPluginIdMap()): Boolean {
|
||||
fun pluginRequiresUltimatePlugin(plugin: PluginId,
|
||||
pluginMap: Map<PluginId, IdeaPluginDescriptorImpl>,
|
||||
contentModuleMap: Map<String, ContentModuleDescriptor>,
|
||||
): Boolean {
|
||||
val rootDescriptor = pluginMap[plugin]
|
||||
if (rootDescriptor == null) return false
|
||||
return !processAllNonOptionalDependencies(rootDescriptor, pluginMap) { descriptorImpl ->
|
||||
return !processAllNonOptionalDependencies(rootDescriptor, pluginMap, contentModuleMap) { descriptorImpl ->
|
||||
when (descriptorImpl.pluginId) {
|
||||
ULTIMATE_PLUGIN_ID -> FileVisitResult.TERMINATE
|
||||
else -> FileVisitResult.CONTINUE
|
||||
|
||||
@@ -80,4 +80,21 @@ class PluginSet internal constructor(
|
||||
// FIXME this is a bad way to treat ambiguous plugin ids
|
||||
return pluginIdResolutionMap.asSequence().filter { it.value.size == 1 }.associateTo(HashMap()) { it.key to it.value[0] }
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a map from content module ID (name) to the corresponding descriptor from all plugins, not only enabled.
|
||||
*/
|
||||
fun buildContentModuleIdMap(): Map<String, ContentModuleDescriptor> {
|
||||
val result = HashMap<String, ContentModuleDescriptor>()
|
||||
val enabledPluginIds = enabledPlugins.mapTo(HashSet()) { it.pluginId }
|
||||
for (plugin in allPlugins) {
|
||||
if (plugin.pluginId !in enabledPluginIds) {
|
||||
plugin.contentModules.associateByTo(result, ContentModuleDescriptor::moduleName)
|
||||
}
|
||||
}
|
||||
for (plugin in enabledPlugins) {
|
||||
plugin.contentModules.associateByTo(result, ContentModuleDescriptor::moduleName)
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -286,11 +286,12 @@ class PluginSetBuilder(@JvmField val unsortedPlugins: Set<PluginMainDescriptor>)
|
||||
descriptor: IdeaPluginDescriptorImpl,
|
||||
idMap: Map<PluginId, IdeaPluginDescriptorImpl>,
|
||||
fullIdMap: Map<PluginId, IdeaPluginDescriptorImpl>,
|
||||
fullContentModuleIdMap: Map<String, ContentModuleDescriptor>,
|
||||
isPluginDisabled: (PluginId) -> Boolean,
|
||||
errors: MutableMap<PluginId, PluginNonLoadReason>,
|
||||
disabledModuleToProblematicPlugin: Map<String, PluginId>,
|
||||
): PluginNonLoadReason? {
|
||||
val isNotifyUser = !descriptor.isImplementationDetail && !pluginRequiresUltimatePluginButItsDisabled(descriptor.pluginId, fullIdMap)
|
||||
val isNotifyUser = !descriptor.isImplementationDetail && !pluginRequiresUltimatePluginButItsDisabled(descriptor.pluginId, fullIdMap, fullContentModuleIdMap)
|
||||
for (incompatibleId in descriptor.incompatiblePlugins) {
|
||||
if (!enabledPluginIds.containsKey(incompatibleId) || isPluginDisabled(incompatibleId)) {
|
||||
continue
|
||||
|
||||
@@ -67,11 +67,13 @@ internal object DisablePluginsDialog {
|
||||
@JvmStatic
|
||||
private fun morePluginsAffected(pluginIdsToDisable: Set<PluginId>): Boolean {
|
||||
val pluginIdMap = PluginManagerCore.buildPluginIdMap()
|
||||
val contentModuleIdMap = PluginManagerCore.getPluginSet().buildContentModuleIdMap()
|
||||
|
||||
for (rootDescriptor in PluginManagerCore.plugins) {
|
||||
if (!rootDescriptor.isEnabled || pluginIdsToDisable.contains(rootDescriptor.pluginId)) {
|
||||
continue
|
||||
}
|
||||
if (!PluginManagerCore.processAllNonOptionalDependencies((rootDescriptor as IdeaPluginDescriptorImpl), pluginIdMap) { descriptor ->
|
||||
if (!PluginManagerCore.processAllNonOptionalDependencies((rootDescriptor as IdeaPluginDescriptorImpl), pluginIdMap, contentModuleIdMap) { descriptor ->
|
||||
when {
|
||||
descriptor.isEnabled -> if (pluginIdsToDisable.contains(descriptor.pluginId)) FileVisitResult.TERMINATE
|
||||
else FileVisitResult.CONTINUE
|
||||
|
||||
@@ -75,13 +75,14 @@ class DynamicPaidPluginsService(private val cs: CoroutineScope) {
|
||||
val disabledPlugins = DisabledPluginsState.getDisabledIds()
|
||||
val pluginSet = PluginManagerCore.getPluginSet()
|
||||
val pluginIdMap = PluginManagerCore.buildPluginIdMap()
|
||||
val contentModuleIdMap = pluginSet.buildContentModuleIdMap()
|
||||
val loadedPlugins = pluginSet.enabledPlugins.toSet()
|
||||
|
||||
val pluginsToEnable = pluginSet.allPlugins.filter {
|
||||
!disabledPlugins.contains(it.pluginId) &&
|
||||
!loadedPlugins.contains(it) &&
|
||||
pluginRequiresUltimatePlugin(it.pluginId, pluginIdMap) &&
|
||||
!pluginRequiresDisabledPlugin(it.pluginId, pluginIdMap, disabledPlugins)
|
||||
pluginRequiresUltimatePlugin(it.pluginId, pluginIdMap, contentModuleIdMap) &&
|
||||
!pluginRequiresDisabledPlugin(it.pluginId, pluginIdMap, contentModuleIdMap, disabledPlugins)
|
||||
}
|
||||
|
||||
if (pluginsToEnable.isEmpty()) {
|
||||
@@ -177,10 +178,11 @@ class DynamicPaidPluginsService(private val cs: CoroutineScope) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun pluginRequiresDisabledPlugin(plugin: PluginId, pluginMap: Map<PluginId, IdeaPluginDescriptorImpl>, disabledPluginIds: Set<PluginId>): Boolean {
|
||||
private fun pluginRequiresDisabledPlugin(plugin: PluginId, pluginMap: Map<PluginId, IdeaPluginDescriptorImpl>,
|
||||
contentModuleIdMap: Map<String, ContentModuleDescriptor>, disabledPluginIds: Set<PluginId>): Boolean {
|
||||
if (disabledPluginIds.isEmpty()) return false
|
||||
val rootDescriptor = pluginMap[plugin] ?: return false
|
||||
return !processAllNonOptionalDependencies(rootDescriptor, pluginMap) { descriptorImpl ->
|
||||
return !processAllNonOptionalDependencies(rootDescriptor, pluginMap, contentModuleIdMap) { descriptorImpl ->
|
||||
if (disabledPluginIds.contains(descriptorImpl.pluginId)) FileVisitResult.TERMINATE
|
||||
else FileVisitResult.CONTINUE
|
||||
}
|
||||
|
||||
@@ -125,7 +125,8 @@ object DefaultUiPluginManagerController : UiPluginManagerController {
|
||||
needRestart = true
|
||||
}
|
||||
val pluginIdMap = buildPluginIdMap()
|
||||
val pluginsToEnable = updatePluginDependencies(session, pluginIdMap)
|
||||
val contentModuleIdMap = getPluginSet().buildContentModuleIdMap()
|
||||
val pluginsToEnable = updatePluginDependencies(session, pluginIdMap, contentModuleIdMap)
|
||||
assertCanApply(session, pluginIdMap)
|
||||
|
||||
val pluginEnabler = PluginEnabler.getInstance()
|
||||
@@ -342,7 +343,8 @@ object DefaultUiPluginManagerController : UiPluginManagerController {
|
||||
override fun prepareToUninstall(pluginsToUninstall: List<PluginId>): PrepareToUninstallResult {
|
||||
val applicationInfo = ApplicationInfoEx.getInstanceEx()
|
||||
val idMap = buildPluginIdMap()
|
||||
val dependentsMap = pluginsToUninstall.associateWith { getDependents(it, applicationInfo, idMap).map { it.name } }
|
||||
val contentModuleIdMap = getPluginSet().buildContentModuleIdMap()
|
||||
val dependentsMap = pluginsToUninstall.associateWith { getDependents(it, applicationInfo, idMap, contentModuleIdMap).map { it.name } }
|
||||
val bundledPlugins = pluginsToUninstall
|
||||
.mapNotNull { idMap[it] }
|
||||
.filter { isBundledUpdate(it) }
|
||||
@@ -369,10 +371,11 @@ object DefaultUiPluginManagerController : UiPluginManagerController {
|
||||
setNewEnabled(descriptors, tempEnabled, action)
|
||||
|
||||
val pluginIdMap: Map<PluginId, IdeaPluginDescriptorImpl> = buildPluginIdMap()
|
||||
val contentModuleIdMap = getPluginSet().buildContentModuleIdMap()
|
||||
val descriptorsToUpdate = if (action.isEnable) {
|
||||
getDependenciesToEnable(descriptors, tempEnabled, pluginIdMap)
|
||||
getDependenciesToEnable(descriptors, tempEnabled, pluginIdMap, contentModuleIdMap)
|
||||
}
|
||||
else getDependentsToDisable(descriptorIds, tempEnabled, pluginIdMap)
|
||||
else getDependentsToDisable(descriptorIds, tempEnabled, pluginIdMap, contentModuleIdMap)
|
||||
|
||||
val pluginNamesToUpdate = descriptorsToUpdate
|
||||
.filter { !InstalledPluginsTableModel.isHiddenImplementationDetail(it) }
|
||||
@@ -384,7 +387,7 @@ object DefaultUiPluginManagerController : UiPluginManagerController {
|
||||
return SetEnabledStateResult(pluginNamesToUpdate, allDescriptorsToUpdate.map { it.pluginId }.toSet())
|
||||
}
|
||||
else {
|
||||
return enableDependencies(session, allDescriptorsToUpdate, action, pluginIdMap)
|
||||
return enableDependencies(session, allDescriptorsToUpdate, action, pluginIdMap, contentModuleIdMap)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -396,7 +399,7 @@ object DefaultUiPluginManagerController : UiPluginManagerController {
|
||||
val session = findSession(sessionId) ?: return SetEnabledStateResult()
|
||||
val descriptors = descriptorIds.toPluginDescriptors()
|
||||
val action = if (enable) PluginEnableDisableAction.ENABLE_GLOBALLY else PluginEnableDisableAction.DISABLE_GLOBALLY
|
||||
return enableDependencies(session, descriptors, action, buildPluginIdMap())
|
||||
return enableDependencies(session, descriptors, action, buildPluginIdMap(), getPluginSet().buildContentModuleIdMap())
|
||||
}
|
||||
|
||||
override fun enableRequiredPlugins(sessionId: String, pluginId: PluginId): Set<PluginId> {
|
||||
@@ -441,22 +444,26 @@ object DefaultUiPluginManagerController : UiPluginManagerController {
|
||||
|
||||
override fun hasPluginsAvailableForEnableDisable(pluginIds: List<PluginId>): Boolean {
|
||||
val idMap = buildPluginIdMap()
|
||||
return pluginIds.any { !pluginRequiresUltimatePluginButItsDisabled(it, idMap) }
|
||||
val contentModuleIdMap = getPluginSet().buildContentModuleIdMap()
|
||||
return pluginIds.any { !pluginRequiresUltimatePluginButItsDisabled(it, idMap, contentModuleIdMap) }
|
||||
}
|
||||
|
||||
override fun isPluginRequiresUltimateButItIsDisabled(pluginId: PluginId): Boolean {
|
||||
val idMap = buildPluginIdMap()
|
||||
return pluginRequiresUltimatePluginButItsDisabled(pluginId, idMap)
|
||||
val contentModuleIdMap = getPluginSet().buildContentModuleIdMap()
|
||||
return pluginRequiresUltimatePluginButItsDisabled(pluginId, idMap, contentModuleIdMap)
|
||||
}
|
||||
|
||||
override fun hasPluginRequiresUltimateButItsDisabled(pluginIds: List<PluginId>): Boolean {
|
||||
val idMap = buildPluginIdMap()
|
||||
return pluginIds.any { pluginRequiresUltimatePluginButItsDisabled(it, idMap) }
|
||||
val contentModuleIdMap = getPluginSet().buildContentModuleIdMap()
|
||||
return pluginIds.any { pluginRequiresUltimatePluginButItsDisabled(it, idMap, contentModuleIdMap) }
|
||||
}
|
||||
|
||||
override fun filterPluginsRequiringUltimateButItsDisabled(pluginIds: List<PluginId>): List<PluginId> {
|
||||
val idMap = buildPluginIdMap()
|
||||
return pluginIds.filter { pluginRequiresUltimatePluginButItsDisabled(it, idMap) }
|
||||
val contentModuleIdMap = getPluginSet().buildContentModuleIdMap()
|
||||
return pluginIds.filter { pluginRequiresUltimatePluginButItsDisabled(it, idMap, contentModuleIdMap) }
|
||||
}
|
||||
|
||||
override fun allowLoadUnloadWithoutRestart(pluginId: PluginId): Boolean {
|
||||
@@ -471,7 +478,7 @@ object DefaultUiPluginManagerController : UiPluginManagerController {
|
||||
|
||||
override fun updatePluginDependencies(sessionId: String): Set<PluginId> {
|
||||
val session = findSession(sessionId) ?: return emptySet()
|
||||
return updatePluginDependencies(session, null)
|
||||
return updatePluginDependencies(session, null, null)
|
||||
}
|
||||
|
||||
override fun executePluginsSearch(query: String, count: Int, includeIncompatible: Boolean): PluginSearchResult {
|
||||
@@ -604,10 +611,11 @@ object DefaultUiPluginManagerController : UiPluginManagerController {
|
||||
allDescriptorsToUpdate: List<IdeaPluginDescriptor>,
|
||||
action: PluginEnableDisableAction,
|
||||
pluginIdMap: Map<PluginId, IdeaPluginDescriptorImpl>,
|
||||
contentModuleIdMap: Map<String, ContentModuleDescriptor>,
|
||||
): SetEnabledStateResult {
|
||||
val changedStates = setNewEnabled(allDescriptorsToUpdate, session.pluginStates, action,
|
||||
{ descriptor, pair -> handleBeforeChangeEnableState(session, descriptor, pair) })
|
||||
val pluginsToEnable = updatePluginDependencies(session, pluginIdMap)
|
||||
val pluginsToEnable = updatePluginDependencies(session, pluginIdMap, contentModuleIdMap)
|
||||
pluginsToEnable.forEach { changedStates[it] = true }
|
||||
return SetEnabledStateResult(changedStates = changedStates)
|
||||
}
|
||||
@@ -792,10 +800,11 @@ object DefaultUiPluginManagerController : UiPluginManagerController {
|
||||
descriptors: List<IdeaPluginDescriptorImpl>,
|
||||
enabledMap: Map<PluginId, PluginEnabledState>,
|
||||
pluginIdMap: Map<PluginId, IdeaPluginDescriptorImpl>,
|
||||
contentModuleIdMap: Map<String, ContentModuleDescriptor>,
|
||||
): List<IdeaPluginDescriptor> {
|
||||
val result = mutableListOf<IdeaPluginDescriptor>()
|
||||
for (descriptor in descriptors) {
|
||||
PluginManagerCore.processAllNonOptionalDependencies(descriptor, pluginIdMap) { dependency ->
|
||||
PluginManagerCore.processAllNonOptionalDependencies(descriptor, pluginIdMap, contentModuleIdMap) { dependency ->
|
||||
val dependencyId = dependency.pluginId
|
||||
val state = enabledMap[dependencyId]
|
||||
|
||||
@@ -812,9 +821,11 @@ object DefaultUiPluginManagerController : UiPluginManagerController {
|
||||
private fun updatePluginDependencies(
|
||||
session: PluginManagerSession,
|
||||
pluginIdMap: Map<PluginId, IdeaPluginDescriptorImpl>?,
|
||||
contentModuleIdMap: Map<String, ContentModuleDescriptor>?,
|
||||
): Set<PluginId> {
|
||||
val pluginsToEnable = mutableSetOf<PluginId>()
|
||||
var pluginIdMap = pluginIdMap
|
||||
var contentModuleIdMap = contentModuleIdMap
|
||||
session.dependentToRequiredListMap.clear()
|
||||
|
||||
val pluginsState = InstalledPluginsState.getInstance()
|
||||
@@ -828,10 +839,13 @@ object DefaultUiPluginManagerController : UiPluginManagerController {
|
||||
if (pluginIdMap == null) {
|
||||
pluginIdMap = buildPluginIdMap()
|
||||
}
|
||||
if (contentModuleIdMap == null) {
|
||||
contentModuleIdMap = getPluginSet().buildContentModuleIdMap()
|
||||
}
|
||||
|
||||
val loaded: Boolean = session.pluginStates.contains(pluginId)
|
||||
if (rootDescriptor is IdeaPluginDescriptorImpl) {
|
||||
PluginManagerCore.processAllNonOptionalDependencyIds(rootDescriptor, pluginIdMap) { depId: PluginId ->
|
||||
PluginManagerCore.processAllNonOptionalDependencyIds(rootDescriptor, pluginIdMap, contentModuleIdMap) { depId: PluginId ->
|
||||
if (depId == pluginId) {
|
||||
return@processAllNonOptionalDependencyIds FileVisitResult.CONTINUE
|
||||
}
|
||||
@@ -877,6 +891,7 @@ object DefaultUiPluginManagerController : UiPluginManagerController {
|
||||
pluginIds: List<PluginId>,
|
||||
enabledMap: MutableMap<PluginId, PluginEnabledState>,
|
||||
pluginIdMap: Map<PluginId, IdeaPluginDescriptorImpl>,
|
||||
contentModuleIdMap: Map<String, ContentModuleDescriptor>,
|
||||
): List<IdeaPluginDescriptor> {
|
||||
val result = mutableListOf<IdeaPluginDescriptor>()
|
||||
|
||||
@@ -887,7 +902,7 @@ object DefaultUiPluginManagerController : UiPluginManagerController {
|
||||
continue
|
||||
}
|
||||
|
||||
PluginManagerCore.processAllNonOptionalDependencies(descriptor, pluginIdMap) { dependency: IdeaPluginDescriptorImpl? ->
|
||||
PluginManagerCore.processAllNonOptionalDependencies(descriptor, pluginIdMap, contentModuleIdMap) { dependency: IdeaPluginDescriptorImpl? ->
|
||||
val dependencyId = dependency!!.getPluginId()
|
||||
if (!enabledMap.contains(dependencyId)) {
|
||||
return@processAllNonOptionalDependencies FileVisitResult.TERMINATE
|
||||
@@ -908,6 +923,7 @@ object DefaultUiPluginManagerController : UiPluginManagerController {
|
||||
rootId: PluginId,
|
||||
applicationInfo: ApplicationInfoEx,
|
||||
pluginIdMap: Map<PluginId, IdeaPluginDescriptorImpl>,
|
||||
contentModuleIdMap: Map<String, ContentModuleDescriptor>,
|
||||
): List<IdeaPluginDescriptorImpl> {
|
||||
val result = mutableListOf<IdeaPluginDescriptorImpl>()
|
||||
for (entry in pluginIdMap.entries) {
|
||||
@@ -920,7 +936,7 @@ object DefaultUiPluginManagerController : UiPluginManagerController {
|
||||
continue
|
||||
}
|
||||
|
||||
PluginManagerCore.processAllNonOptionalDependencies(descriptor, pluginIdMap) {
|
||||
PluginManagerCore.processAllNonOptionalDependencies(descriptor, pluginIdMap, contentModuleIdMap) {
|
||||
if (it.pluginId == rootId) {
|
||||
result.add(descriptor)
|
||||
return@processAllNonOptionalDependencies FileVisitResult.TERMINATE
|
||||
|
||||
@@ -63,9 +63,10 @@ public final class PluginBooleanOptionDescriptor extends BooleanOptionDescriptio
|
||||
}
|
||||
|
||||
Map<PluginId, IdeaPluginDescriptorImpl> pluginIdMap = PluginManagerCore.INSTANCE.buildPluginIdMap();
|
||||
Map<@NotNull String, @NotNull ContentModuleDescriptor> contentModuleIdMap = PluginManagerCore.getPluginSet().buildContentModuleIdMap();
|
||||
Collection<? extends IdeaPluginDescriptor> autoSwitchedDescriptors = enable ?
|
||||
getDependenciesToEnable(descriptors, pluginIdMap) :
|
||||
getDependentsToDisable(descriptors, pluginIdMap);
|
||||
getDependenciesToEnable(descriptors, pluginIdMap, contentModuleIdMap) :
|
||||
getDependentsToDisable(descriptors, pluginIdMap, contentModuleIdMap);
|
||||
|
||||
PluginEnabler pluginEnabler = PluginEnabler.getInstance();
|
||||
boolean appliedWithoutRestart = enable ?
|
||||
@@ -131,7 +132,8 @@ public final class PluginBooleanOptionDescriptor extends BooleanOptionDescriptio
|
||||
}
|
||||
|
||||
private static @NotNull Collection<? extends IdeaPluginDescriptor> getDependenciesToEnable(@NotNull Collection<? extends IdeaPluginDescriptor> descriptors,
|
||||
@NotNull Map<PluginId, IdeaPluginDescriptorImpl> pluginIdMap) {
|
||||
@NotNull Map<PluginId, IdeaPluginDescriptorImpl> pluginIdMap,
|
||||
@NotNull Map<String, ContentModuleDescriptor> contentModuleIdMap) {
|
||||
Set<IdeaPluginDescriptor> result = new LinkedHashSet<>();
|
||||
|
||||
for (IdeaPluginDescriptor descriptor : descriptors) {
|
||||
@@ -141,7 +143,7 @@ public final class PluginBooleanOptionDescriptor extends BooleanOptionDescriptio
|
||||
continue;
|
||||
}
|
||||
|
||||
PluginManagerCore.INSTANCE.processAllNonOptionalDependencies((IdeaPluginDescriptorImpl)descriptor, pluginIdMap, dependency ->
|
||||
PluginManagerCore.INSTANCE.processAllNonOptionalDependencies((IdeaPluginDescriptorImpl)descriptor, pluginIdMap, contentModuleIdMap, dependency ->
|
||||
PluginManagerCore.CORE_ID.equals(dependency.getPluginId()) ||
|
||||
(PluginManagerCore.ULTIMATE_PLUGIN_ID.equals(dependency.getPluginId()) &&
|
||||
PluginManagerCore.isDisabled(PluginManagerCore.ULTIMATE_PLUGIN_ID)) ||
|
||||
@@ -155,14 +157,15 @@ public final class PluginBooleanOptionDescriptor extends BooleanOptionDescriptio
|
||||
}
|
||||
|
||||
private static @NotNull Collection<? extends IdeaPluginDescriptor> getDependentsToDisable(@NotNull Collection<? extends IdeaPluginDescriptor> descriptors,
|
||||
@NotNull Map<PluginId, IdeaPluginDescriptorImpl> pluginIdMap) {
|
||||
@NotNull Map<PluginId, IdeaPluginDescriptorImpl> pluginIdMap,
|
||||
@NotNull Map<String, ContentModuleDescriptor> contentModuleIdMap) {
|
||||
Set<IdeaPluginDescriptor> result = new LinkedHashSet<>();
|
||||
ApplicationInfoEx applicationInfo = ApplicationInfoEx.getInstanceEx();
|
||||
|
||||
for (IdeaPluginDescriptor descriptor : descriptors) {
|
||||
result.add(descriptor);
|
||||
|
||||
result.addAll(DefaultUiPluginManagerController.INSTANCE.getDependents(descriptor.getPluginId(), applicationInfo, pluginIdMap));
|
||||
result.addAll(DefaultUiPluginManagerController.INSTANCE.getDependents(descriptor.getPluginId(), applicationInfo, pluginIdMap, contentModuleIdMap));
|
||||
}
|
||||
|
||||
return Collections.unmodifiableSet(result);
|
||||
|
||||
@@ -172,10 +172,31 @@ internal class PluginDependenciesTest {
|
||||
assertFirstErrorContains("sample.plugin", "requires plugin", "bar")
|
||||
assertNonOptionalDependenciesIds(result, "sample.plugin", "bar")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `plugin is not loaded if required module depends on a module from disabled plugin`() {
|
||||
`bar-plugin with module bar`()
|
||||
plugin("sample.plugin") {
|
||||
content {
|
||||
module("required.module", ModuleLoadingRule.REQUIRED) {
|
||||
packagePrefix = "required"
|
||||
dependencies {
|
||||
module("bar")
|
||||
}
|
||||
}
|
||||
}
|
||||
}.buildDir(pluginDirPath.resolve("sample-plugin"))
|
||||
val result = buildPluginSet(disabledPluginIds = arrayOf("bar-plugin"))
|
||||
assertThat(result).doesNotHaveEnabledPlugins()
|
||||
assertFirstErrorContains("sample.plugin", "requires plugin", "bar-plugin"/*, "to be enabled"*/) //todo fix not loading reason
|
||||
assertNonOptionalDependenciesIds(result, "sample.plugin", "bar-plugin")
|
||||
}
|
||||
|
||||
private fun assertNonOptionalDependenciesIds(result: PluginSet, pluginId: String, vararg dependencyPluginId: String) {
|
||||
val actualDependencies = HashSet<String>()
|
||||
PluginManagerCore.processAllNonOptionalDependencyIds(result.getPlugin(pluginId), result.buildPluginIdMap()) {
|
||||
val actualDependencies = HashSet<String>()
|
||||
val pluginIdMap = result.buildPluginIdMap()
|
||||
val contentModuleIdMap = result.buildContentModuleIdMap()
|
||||
PluginManagerCore.processAllNonOptionalDependencyIds(result.getPlugin(pluginId), pluginIdMap, contentModuleIdMap) {
|
||||
actualDependencies.add(it.idString)
|
||||
FileVisitResult.CONTINUE
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.intellij.settingsSync.core.plugins
|
||||
|
||||
import com.intellij.ide.plugins.ContentModuleDescriptor
|
||||
import com.intellij.ide.plugins.IdeaPluginDescriptor
|
||||
import com.intellij.ide.plugins.IdeaPluginDescriptorImpl
|
||||
import com.intellij.ide.plugins.PluginEnableStateChangedListener
|
||||
@@ -88,7 +89,8 @@ internal class SettingsSyncPluginManager(private val cs: CoroutineScope) : Dispo
|
||||
}
|
||||
|
||||
val pluginIdMap = PluginManagerCore.buildPluginIdMap()
|
||||
|
||||
val contentModuleIdMap = PluginManagerCore.getPluginSet().buildContentModuleIdMap()
|
||||
|
||||
for (plugin in currentIdePlugins) {
|
||||
val id = plugin.pluginId
|
||||
if (!isPluginSynceable(id) || PluginManagerProxy.getInstance().isIncompatible(plugin)) {
|
||||
@@ -102,7 +104,7 @@ internal class SettingsSyncPluginManager(private val cs: CoroutineScope) : Dispo
|
||||
}
|
||||
else if (
|
||||
PluginManagerCore.isDisabled(PluginManagerCore.ULTIMATE_PLUGIN_ID) &&
|
||||
isUltimate(plugin, pluginIdMap)
|
||||
isUltimate(plugin, pluginIdMap, contentModuleIdMap)
|
||||
) {
|
||||
if (LOG.isDebugEnabled) {
|
||||
LOG.debug("Skipped syncing ultimate plugin ${plugin.pluginId}")
|
||||
@@ -125,9 +127,10 @@ internal class SettingsSyncPluginManager(private val cs: CoroutineScope) : Dispo
|
||||
private fun isUltimate(
|
||||
plugin: IdeaPluginDescriptor,
|
||||
pluginIdMap: Map<PluginId, IdeaPluginDescriptorImpl>,
|
||||
contentModuleIdMap: Map<String, ContentModuleDescriptor>,
|
||||
): Boolean {
|
||||
var isUltimate = false
|
||||
PluginManagerCore.processAllNonOptionalDependencyIds(plugin as IdeaPluginDescriptorImpl, pluginIdMap) {
|
||||
PluginManagerCore.processAllNonOptionalDependencyIds(plugin as IdeaPluginDescriptorImpl, pluginIdMap, contentModuleIdMap) {
|
||||
if (it == PluginManagerCore.ULTIMATE_PLUGIN_ID) {
|
||||
isUltimate = true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user