IJPL-136 PluginFeatureService - use new settings controller API

GitOrigin-RevId: aaae8b1afcb1531e35c484add8f02faeaecf114f
This commit is contained in:
Vladimir Krivosheev
2023-12-08 22:51:51 +01:00
committed by intellij-monorepo-bot
parent 1108f853a1
commit e99d04d836
11 changed files with 80 additions and 88 deletions

View File

@@ -1,16 +1,16 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.packaging.impl.artifacts
import com.intellij.ide.plugins.PluginFeatureService
import com.intellij.openapi.components.serviceAsync
import com.intellij.openapi.project.Project
import com.intellij.openapi.startup.ProjectActivity
import com.intellij.packaging.artifacts.ArtifactManager
import com.intellij.packaging.artifacts.ArtifactType
private class ArtifactTypeFeatureCollector : ProjectActivity {
override suspend fun execute(project: Project) {
PluginFeatureService.instance.collectFeatureMapping(
serviceAsync<PluginFeatureService>().collectFeatureMapping(
ArtifactManager.FEATURE_TYPE,
ArtifactType.EP_NAME,
ArtifactType::getId,

View File

@@ -4,7 +4,6 @@
package com.intellij.configurationStore.xml
import com.intellij.configurationStore.deserialize
import com.intellij.ide.plugins.PluginFeatureService
import com.intellij.ide.plugins.advertiser.FeaturePluginData
import com.intellij.ide.plugins.advertiser.PluginData
import com.intellij.ide.plugins.advertiser.PluginDataSet
@@ -356,25 +355,6 @@ internal class XmlSerializerMapTest {
)
}
@Test
fun `pluginFeatureService serialization`() {
val state = PluginFeatureService.State(
mapOf("foo" to PluginFeatureService.FeaturePluginList())
)
testSerializer(
"""
<state><![CDATA[{
"features": {
"foo": {
}
}
}]]></state>
""".trimIndent(),
state,
)
}
@Test
fun fastUtilObjectIntMap() {
@Tag("bean")

View File

@@ -5,6 +5,7 @@ import com.intellij.execution.RunManager
import com.intellij.execution.configurations.ConfigurationType
import com.intellij.ide.plugins.PluginFeatureService
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.serviceAsync
import com.intellij.openapi.extensions.ExtensionNotApplicableException
import com.intellij.openapi.project.Project
import com.intellij.openapi.startup.ProjectActivity
@@ -23,7 +24,7 @@ private class RunConfigurationFeatureCollector : ProjectActivity {
// no hurry to update current feature mapping of all run configurations types
delay(10.minutes)
PluginFeatureService.instance.collectFeatureMapping(
serviceAsync<PluginFeatureService>().collectFeatureMapping(
featureType = RunManager.CONFIGURATION_TYPE_FEATURE_ID,
ep = ConfigurationType.CONFIGURATION_TYPE_EP,
idMapping = ConfigurationType::getId,

View File

@@ -105,17 +105,17 @@ public final class UnknownRunConfiguration implements RunConfiguration, WithoutO
@Override
public void checkConfiguration() throws RuntimeConfigurationException {
String typeId = getConfigurationTypeId();
if (typeId != null) {
FeaturePluginData plugin = PluginFeatureService.getInstance().getPluginForFeature(RunManager.CONFIGURATION_TYPE_FEATURE_ID,
typeId);
if (plugin != null) {
RuntimeConfigurationError err = new RuntimeConfigurationError(
ExecutionBundle.message("dialog.message.broken.configuration.missing.plugin", plugin.displayName));
err.setQuickFix(() -> {
PluginManagerConfigurableService.getInstance().showPluginConfigurableAndEnable(null, plugin.pluginData.pluginIdString);
});
throw err;
}
if (typeId == null) {
return;
}
FeaturePluginData plugin = PluginFeatureService.Companion.__getPluginForFeature(RunManager.CONFIGURATION_TYPE_FEATURE_ID, typeId);
if (plugin != null) {
RuntimeConfigurationError err = new RuntimeConfigurationError(
ExecutionBundle.message("dialog.message.broken.configuration.missing.plugin", plugin.displayName));
err.setQuickFix(() -> {
PluginManagerConfigurableService.getInstance().showPluginConfigurableAndEnable(null, plugin.pluginData.pluginIdString);
});
throw err;
}
throw new RuntimeConfigurationException(ExecutionBundle.message("dialog.message.broken.configuration"));
}

View File

@@ -45,5 +45,6 @@
<orderEntry type="library" name="kotlinx-serialization-json" level="project" />
<orderEntry type="library" name="kotlinx-coroutines-core" level="project" />
<orderEntry type="module" module-name="intellij.platform.diagnostic" />
<orderEntry type="module" module-name="intellij.platform.settings" />
</component>
</module>

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@file:Suppress("ReplaceGetOrSet", "ReplacePutWithAssignment")
package com.intellij.ide.plugins
@@ -6,8 +6,15 @@ package com.intellij.ide.plugins
import com.intellij.ide.plugins.advertiser.FeaturePluginData
import com.intellij.ide.plugins.advertiser.PluginData
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.*
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.serviceAsync
import com.intellij.openapi.extensions.ExtensionPointName
import com.intellij.openapi.extensions.PluginId
import com.intellij.openapi.progress.runBlockingCancellable
import com.intellij.platform.settings.CacheStateTag
import com.intellij.platform.settings.objectSettingValueSerializer
import com.intellij.platform.settings.settingDescriptorFactoryFactory
import com.intellij.util.concurrency.annotations.RequiresBlockingContext
import kotlinx.serialization.Serializable
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.annotations.Nls
@@ -15,63 +22,61 @@ import org.jetbrains.annotations.NonNls
@ApiStatus.Internal
@Service(Service.Level.APP)
@State(name = "PluginFeatureService", storages = [Storage(StoragePathMacros.CACHE_FILE)])
class PluginFeatureService : SerializablePersistentStateComponent<PluginFeatureService.State>(State()) {
class PluginFeatureService {
companion object {
@JvmStatic
val instance: PluginFeatureService
get() = ApplicationManager.getApplication().getService(PluginFeatureService::class.java)
fun getInstance(): PluginFeatureService {
return ApplicationManager.getApplication().getService(PluginFeatureService::class.java)
}
@Suppress("FunctionName")
@RequiresBlockingContext
fun __getPluginForFeature(featureType: @NonNls String, implementationName: @NonNls String): FeaturePluginData? {
return runBlockingCancellable {
serviceAsync<PluginFeatureService>().getPluginForFeature(featureType, implementationName)
}
}
}
@Serializable
data class FeaturePluginList(
val featureMap: Map<@NonNls String, FeaturePluginData> = emptyMap(),
@JvmField val featureMap: Map<@NonNls String, FeaturePluginData> = emptyMap(),
)
@Serializable
data class State(
val features: Map<@NonNls String, FeaturePluginList> = emptyMap(),
)
private val serializer = objectSettingValueSerializer<FeaturePluginList>()
private val settingGroup = settingDescriptorFactoryFactory(PluginId.getId("com.intellij")).group(key = "pluginFeature") {
tags = listOf(CacheStateTag)
}
fun <T : Any> collectFeatureMapping(
suspend fun <T : Any> collectFeatureMapping(
featureType: @NonNls String,
ep: ExtensionPointName<T>,
idMapping: (T) -> @NonNls String,
displayNameMapping: (T) -> @Nls String,
) {
val featureMap = LinkedHashMap<@NonNls String, FeaturePluginData>()
// fold
ep.processWithPluginDescriptor { ext, descriptor ->
val pluginData = FeaturePluginData(
displayNameMapping(ext),
PluginData(descriptor),
)
featureMap.put(idMapping(ext), pluginData)
featureMap.put(idMapping(ext), FeaturePluginData(displayName = displayNameMapping(ext), pluginData = PluginData(descriptor)))
}
updateFeatureMapping(featureType, featureMap)
}
@ApiStatus.Experimental
fun updateFeatureMapping(
featureType: @NonNls String,
featureMap: Map<@NonNls String, FeaturePluginData>,
) {
updateState { oldState ->
val oldFeatures = oldState.features
val newFeatureMap = LinkedHashMap(oldFeatures.getFeatureMap(featureType) ?: emptyMap()) + featureMap
State(oldFeatures + (featureType to FeaturePluginList(newFeatureMap)))
private suspend fun updateFeatureMapping(featureType: @NonNls String, featureMap: Map<@NonNls String, FeaturePluginData>) {
val setting = settingGroup.setting(featureType, serializer)
val existingMap = setting.get()
if (existingMap == null) {
setting.set(FeaturePluginList(featureMap))
}
else {
val newMap = LinkedHashMap<@NonNls String, FeaturePluginData>()
newMap.putAll(existingMap.featureMap)
newMap.putAll(featureMap)
setting.set(FeaturePluginList(newMap))
}
}
fun getPluginForFeature(
featureType: @NonNls String,
implementationName: @NonNls String,
): FeaturePluginData? = state.features.getFeatureMap(featureType)?.get(implementationName)
private fun Map<@NonNls String, FeaturePluginList>.getFeatureMap(featureType: @NonNls String) =
get(featureType)?.featureMap
suspend fun getPluginForFeature(featureType: @NonNls String, implementationName: @NonNls String): FeaturePluginData? {
return settingGroup.setting(featureType, serializer).get()?.featureMap?.get(implementationName)
}
}

View File

@@ -1,13 +1,14 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.facet
import com.intellij.ide.plugins.PluginFeatureService
import com.intellij.openapi.components.serviceAsync
import com.intellij.openapi.project.Project
import com.intellij.openapi.startup.ProjectActivity
internal class FacetTypeFeatureCollector : ProjectActivity {
private class FacetTypeFeatureCollector : ProjectActivity {
override suspend fun execute(project: Project) {
PluginFeatureService.instance.collectFeatureMapping(
serviceAsync<PluginFeatureService>().collectFeatureMapping(
FacetManagerBase.FEATURE_TYPE,
FacetType.EP_NAME,
FacetType<*, *>::getStringId,

View File

@@ -1,7 +1,8 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.ide.plugins
import com.intellij.diagnostic.PluginException
import com.intellij.openapi.components.serviceAsync
import com.intellij.openapi.extensions.ExtensionPointName
import com.intellij.openapi.extensions.PluginAware
import com.intellij.openapi.extensions.PluginDescriptor
@@ -26,7 +27,7 @@ internal class DependencyCollectorBean : BaseKeyedLazyInstance<DependencyCollect
var implementation: String = ""
companion object {
val EP_NAME: ExtensionPointName<DependencyCollectorBean> = ExtensionPointName.create("com.intellij.dependencyCollector")
val EP_NAME: ExtensionPointName<DependencyCollectorBean> = ExtensionPointName("com.intellij.dependencyCollector")
}
override fun getImplementationClassName(): String = implementation
@@ -108,14 +109,13 @@ internal val DependencySupportBean.id: @NlsSafe String
internal val DependencySupportBean.displayNameOrId: @NlsSafe String
get() = displayName.ifEmpty { id }
internal class DependencyFeatureCollector : ProjectActivity {
private class DependencyFeatureCollector : ProjectActivity {
override suspend fun execute(project: Project) {
PluginFeatureService.instance.collectFeatureMapping(
DEPENDENCY_SUPPORT_FEATURE,
DependencySupportBean.EP_NAME,
{ it.id },
{ it.displayNameOrId },
serviceAsync<PluginFeatureService>().collectFeatureMapping(
featureType = DEPENDENCY_SUPPORT_FEATURE,
ep = DependencySupportBean.EP_NAME,
idMapping = { it.id },
displayNameMapping = { it.displayNameOrId },
)
}
}

View File

@@ -24,7 +24,6 @@ class PluginFeatureCacheService {
}
private val serializer = objectSettingValueSerializer<PluginFeatureMap>()
private val settingGroup = settingDescriptorFactoryFactory(PluginManagerCore.CORE_ID).group(key = "pluginFeatureCache") {
tags = listOf(CacheStateTag)
}

View File

@@ -207,12 +207,13 @@ open class PluginAdvertiserServiceImpl(
val plugins = mutableSetOf<PluginData>()
val dependencies = serviceAsync<PluginFeatureCacheService>().dependencies.get()
val ignoredPluginSuggestionState = GlobalIgnoredPluginSuggestionState.getInstance()
val ignoredPluginSuggestionState = serviceAsync<GlobalIgnoredPluginSuggestionState>()
val pluginFeatureService = serviceAsync<PluginFeatureService>()
for (feature in features) {
coroutineContext.ensureActive()
val featureType = feature.featureType
val implementationName = feature.implementationName
val featurePluginData = PluginFeatureService.instance.getPluginForFeature(featureType, implementationName)
val featurePluginData = pluginFeatureService.getPluginForFeature(featureType, implementationName)
val installedPluginData = featurePluginData?.pluginData
@@ -223,7 +224,7 @@ open class PluginAdvertiserServiceImpl(
return
}
plugins += data
plugins.add(data)
featuresMap.putValue(pluginId, featurePluginData?.displayName?.let { feature.withImplementationDisplayName(it) } ?: feature)
}

View File

@@ -1328,6 +1328,10 @@
<obsoleteStorage file="$CACHE_FILE$">
<components>
<component>KnownExtensionsService</component>
<component>PluginFeatureCacheService</component>
<component>ErrorReportConfigurable</component>
<component>PluginAdvertiserExtensions</component>
<component>PluginFeatureService</component>
</components>
</obsoleteStorage>