IJPL-136 pass plugin id to PSC proxy

GitOrigin-RevId: ceacd58fb3bf6c8a76e68e1328814de5814d2826
This commit is contained in:
Vladimir Krivosheev
2024-02-18 12:25:57 +01:00
committed by intellij-monorepo-bot
parent 26ec54adf8
commit 353d2e563f
15 changed files with 218 additions and 130 deletions

View File

@@ -1,6 +1,7 @@
// 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.configurationStore
import com.intellij.ide.plugins.PluginManagerCore
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.PathManager
import com.intellij.openapi.components.*
@@ -51,36 +52,45 @@ internal class AppStorageContentReader : JpsFileContentReader {
}
internal class AppStorageContentWriter(private val session: SaveSessionProducerManager) : JpsAppFileContentWriter {
override fun saveComponent(fileUrl: String, componentName: String, componentTag: Element?): Unit = saveComponentTimeMs.addMeasuredTime {
val filePath = JpsPathUtil.urlToPath(fileUrl)
if (isApplicationLevelFile(filePath)) {
val storageSpec = FileStorageAnnotation(PathUtil.getFileName(filePath), false, StateSplitterEx::class.java)
@Suppress("UNCHECKED_CAST")
val storage = ApplicationManager.getApplication().stateStore.storageManager.getStateStorage(storageSpec) as StateStorageBase<StateMap>
session.getProducer(storage)?.setState(null, componentName, componentTag)
}
}
override fun getReplacePathMacroMap(fileUrl: String): PathMacroMap =
PathMacroManager.getInstance(ApplicationManager.getApplication()).replacePathMap
override suspend fun saveSession() {
session.save(SaveResult())
}
private fun isApplicationLevelFile(filePath: String): Boolean =
Path.of(filePath).startsWith(Path.of(PathManager.getOptionsPath()))
companion object {
private val saveComponentTimeMs = MillisecondsMeasurer()
init {
setupOpenTelemetryReporting(jpsMetrics.meter)
}
private fun setupOpenTelemetryReporting(meter: Meter) {
val saveComponentTimeCounter = meter.counterBuilder("jps.app.storage.content.writer.save.component.ms").buildObserver()
meter.batchCallback({ saveComponentTimeCounter.record(saveComponentTimeMs.asMilliseconds()) }, saveComponentTimeCounter)
}
}
init {
setupOpenTelemetryReporting(jpsMetrics.meter)
override fun saveComponent(fileUrl: String, componentName: String, componentTag: Element?) {
saveComponentTimeMs.addMeasuredTime {
val filePath = JpsPathUtil.urlToPath(fileUrl)
if (isApplicationLevelFile(filePath)) {
val storageSpec = FileStorageAnnotation(PathUtil.getFileName(filePath), false, StateSplitterEx::class.java)
@Suppress("UNCHECKED_CAST")
val storage = ApplicationManager.getApplication().stateStore.storageManager.getStateStorage(storageSpec) as StateStorageBase<StateMap>
session.getProducer(storage)?.setState(
component = null,
componentName = componentName,
// doesn't matter for now
pluginId = PluginManagerCore.CORE_ID,
state = componentTag,
)
}
}
}
override fun getReplacePathMacroMap(fileUrl: String): PathMacroMap {
return PathMacroManager.getInstance(ApplicationManager.getApplication()).replacePathMap
}
override suspend fun saveSession() {
session.save(SaveResult())
}
private fun isApplicationLevelFile(filePath: String): Boolean = Path.of(filePath).startsWith(Path.of(PathManager.getOptionsPath()))
}

View File

@@ -321,16 +321,19 @@ abstract class ComponentStoreImpl : IComponentStore {
val stateSpec = getStateSpec(component)
LOG.debug { "saveComponent is called for ${stateSpec.name}" }
val saveManager = createSaveSessionProducerManager()
val storages = getStorageSpecs(component, stateSpec, StateStorageOperation.WRITE)
val storages = getStorageSpecs(component = component, stateSpec = stateSpec, operation = StateStorageOperation.WRITE)
val storage = storages.firstOrNull { !it.deprecated } ?: throw AssertionError("All storages are deprecated")
val absolutePath = storageManager.expandMacro(storage.path).toString()
val componentInfo = components.get(stateSpec.name)
Disposer.newDisposable().use {
VfsRootAccess.allowRootAccess(it, absolutePath)
@Suppress("DEPRECATION")
runUnderModalProgressIfIsEdt {
commitComponent(
sessionManager = saveManager,
info = ComponentInfoImpl(
info = componentInfo ?: ComponentInfoImpl(
pluginId = PluginManager.getPluginByClass(component::class.java)?.pluginId ?: PluginManagerCore.CORE_ID,
component = component,
stateSpec = stateSpec,
@@ -371,7 +374,12 @@ abstract class ComponentStoreImpl : IComponentStore {
if (component is com.intellij.openapi.util.JDOMExternalizable) {
val effectiveComponentName = componentName ?: getComponentName(component)
storageManager.getOldStorage(component, effectiveComponentName, StateStorageOperation.WRITE)?.let {
sessionManager.getProducer(it)?.setState(component = component, componentName = effectiveComponentName, state = component)
sessionManager.getProducer(it)?.setState(
component = component,
componentName = effectiveComponentName,
pluginId = info.pluginId,
state = component,
)
}
return
}
@@ -385,7 +393,11 @@ abstract class ComponentStoreImpl : IComponentStore {
val stateStorageChooser = component as? StateStorageChooserEx
@Suppress("UNCHECKED_CAST")
val storageSpecs = getStorageSpecs(component as PersistentStateComponent<Any>, stateSpec, StateStorageOperation.WRITE)
val storageSpecs = getStorageSpecs(
component = component as PersistentStateComponent<Any>,
stateSpec = stateSpec,
operation = StateStorageOperation.WRITE,
)
for (storageSpec in storageSpecs) {
var resolution = stateStorageChooser?.getResolution(storageSpec, StateStorageOperation.WRITE) ?: Resolution.DO
if (resolution == Resolution.SKIP) {
@@ -404,7 +416,7 @@ abstract class ComponentStoreImpl : IComponentStore {
val sessionProducer = sessionManager.getProducer(storage) ?: continue
if (resolution == Resolution.CLEAR ||
(storageSpec.deprecated && storageSpecs.none { !it.deprecated && it.value == storageSpec.value })) {
sessionProducer.setState(component = component, componentName = effectiveComponentName, state = null)
sessionProducer.setState(component = component, componentName = effectiveComponentName, pluginId = info.pluginId, state = null)
}
else {
if (!stateRequested) {
@@ -428,11 +440,13 @@ abstract class ComponentStoreImpl : IComponentStore {
// method is not called if storage is deprecated or clear was requested
// (state in these cases is null), but called if state is null if returned so from a component
protected open fun setStateToSaveSessionProducer(state: Any?,
info: ComponentInfo,
effectiveComponentName: String,
sessionProducer: SaveSessionProducer) {
sessionProducer.setState(component = info.component, componentName = effectiveComponentName, state = state)
protected open fun setStateToSaveSessionProducer(
state: Any?,
info: ComponentInfo,
effectiveComponentName: String,
sessionProducer: SaveSessionProducer,
) {
sessionProducer.setState(component = info.component, componentName = effectiveComponentName, pluginId = info.pluginId, state = state)
}
private fun registerComponent(name: String, info: ComponentInfo): ComponentInfo {

View File

@@ -96,16 +96,21 @@ abstract class ComponentStoreWithExtraComponents : ComponentStoreImpl() {
}
internal open fun commitObsoleteComponents(session: SaveSessionProducerManager, isProjectLevel: Boolean) {
for (bean in ObsoleteStorageBean.EP_NAME.lazySequence()) {
val storageManager = storageManager as? StateStorageManagerImpl ?: return
for (item in ObsoleteStorageBean.EP_NAME.filterableLazySequence()) {
val bean = item.instance ?: continue
if (bean.isProjectLevel != isProjectLevel) {
continue
}
val storage = (storageManager as? StateStorageManagerImpl)?.getOrCreateStorage(bean.file ?: continue, RoamingType.DISABLED)
if (storage != null) {
for (componentName in bean.components) {
session.getProducer(storage)?.setState(component = null, componentName = componentName, state = null)
}
val storage = storageManager.getOrCreateStorage(collapsedPath = bean.file ?: continue, roamingType = RoamingType.DISABLED)
for (componentName in bean.components) {
session.getProducer(storage)?.setState(
component = null,
componentName = componentName,
pluginId = item.pluginDescriptor.pluginId,
state = null,
)
}
}
}

View File

@@ -1,11 +1,12 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@file:Suppress("ReplaceGetOrSet")
@file:Suppress("ReplaceGetOrSet", "ReplacePutWithAssignment")
package com.intellij.configurationStore
import com.intellij.concurrency.ConcurrentCollectionFactory
import com.intellij.ide.impl.ProjectUtil
import com.intellij.ide.impl.isTrusted
import com.intellij.ide.plugins.PluginManagerCore
import com.intellij.openapi.components.*
import com.intellij.openapi.components.impl.ModulePathMacroManager
import com.intellij.openapi.components.impl.ProjectPathMacroManager
@@ -75,26 +76,35 @@ open class ProjectWithModuleStoreImpl(project: Project) : ProjectStoreImpl(proje
StorageJpsConfigurationReader(project, getJpsProjectConfigLocation(project)!!)
}
private class JpsStorageContentWriter(private val session: ProjectWithModulesSaveSessionProducerManager,
private val store: IProjectStore,
private val project: Project) : JpsFileContentWriter {
private class JpsStorageContentWriter(
private val session: ProjectWithModulesSaveSessionProducerManager,
private val store: IProjectStore,
private val project: Project,
) : JpsFileContentWriter {
override fun saveComponent(fileUrl: String, componentName: String, componentTag: Element?) {
val filePath = JpsPathUtil.urlToPath(fileUrl)
if (FileUtilRt.extensionEquals(filePath, "iml")) {
session.setModuleComponentState(filePath, componentName, componentTag)
session.setModuleComponentState(imlFilePath = filePath, componentName = componentName, componentTag = componentTag)
}
else if (isExternalModuleFile(filePath)) {
session.setExternalModuleComponentState(FileUtilRt.getNameWithoutExtension(PathUtilRt.getFileName(filePath)), componentName,
componentTag)
session.setExternalModuleComponentState(
moduleFileName = FileUtilRt.getNameWithoutExtension(PathUtilRt.getFileName(filePath)),
componentName = componentName,
componentTag = componentTag,
)
}
else {
val stateStorage = getProjectStateStorage(filePath, store, project)
val stateStorage = getProjectStateStorage(filePath = filePath, store = store, project = project)
val producer = session.getProducer(stateStorage)
if (producer is DirectoryBasedSaveSessionProducer) {
producer.setFileState(PathUtilRt.getFileName(filePath), componentName, componentTag?.children?.first())
producer.setFileState(
fileName = PathUtilRt.getFileName(filePath),
componentName = componentName,
element = componentTag?.children?.first(),
)
}
else {
producer?.setState(null, componentName, componentTag)
producer?.setState(component = null, componentName = componentName, pluginId = PluginManagerCore.CORE_ID, state = componentTag)
}
}
}
@@ -117,18 +127,22 @@ private class ProjectWithModulesSaveSessionProducerManager(project: Project, isU
: ProjectSaveSessionProducerManager(project, isUseVfsForWrite)
{
private val internalModuleComponents: ConcurrentMap<String, ConcurrentHashMap<String, Element>> =
if (!SystemInfoRt.isFileSystemCaseSensitive) ConcurrentCollectionFactory.createConcurrentMap(HashingStrategy.caseInsensitive())
else ConcurrentCollectionFactory.createConcurrentMap()
if (SystemInfoRt.isFileSystemCaseSensitive) {
ConcurrentCollectionFactory.createConcurrentMap()
}
else {
ConcurrentCollectionFactory.createConcurrentMap(HashingStrategy.caseInsensitive())
}
private val externalModuleComponents = ConcurrentHashMap<String, ConcurrentHashMap<String, Element>>()
fun setModuleComponentState(imlFilePath: String, componentName: String, componentTag: Element?) {
val componentToElement = internalModuleComponents.computeIfAbsent(imlFilePath) { ConcurrentHashMap() }
componentToElement[componentName] = componentTag ?: NULL_ELEMENT
componentToElement.put(componentName, componentTag ?: NULL_ELEMENT)
}
fun setExternalModuleComponentState(moduleFileName: String, componentName: String, componentTag: Element?) {
val componentToElement = externalModuleComponents.computeIfAbsent(moduleFileName) { ConcurrentHashMap() }
componentToElement[componentName] = componentTag ?: NULL_ELEMENT
componentToElement.put(componentName, componentTag ?: NULL_ELEMENT)
}
fun commitComponents(moduleStore: ComponentStoreImpl, moduleSaveSessionManager: SaveSessionProducerManager) {
@@ -137,9 +151,12 @@ private class ProjectWithModulesSaveSessionProducerManager(project: Project, isU
val producer = moduleSaveSessionManager.getProducer(storage)
if (producer != null) {
for ((componentName, componentTag) in componentToElement) {
producer.setState(component = null,
componentName = componentName,
state = if (componentTag === NULL_ELEMENT) null else componentTag)
producer.setState(
component = null,
componentName = componentName,
pluginId = PluginManagerCore.CORE_ID,
state = if (componentTag === NULL_ELEMENT) null else componentTag,
)
}
}
}

View File

@@ -2,6 +2,7 @@
package com.intellij.configurationStore
import com.intellij.openapi.components.impl.stores.ComponentStorageUtil
import com.intellij.openapi.extensions.PluginId
import com.intellij.openapi.util.WriteExternalException
import com.intellij.openapi.vfs.LargeFileWriteRequestor
import com.intellij.openapi.vfs.SafeWriteRequestor
@@ -11,7 +12,7 @@ import com.intellij.util.xmlb.XmlSerializationException
import org.jdom.Element
abstract class SaveSessionProducerBase : SaveSessionProducer, SafeWriteRequestor, LargeFileWriteRequestor {
final override fun setState(component: Any?, componentName: String, state: Any?) {
final override fun setState(component: Any?, componentName: String, pluginId: PluginId, state: Any?) {
if (state == null) {
setSerializedState(componentName = componentName, element = null)
return

View File

@@ -93,28 +93,34 @@ open class StateStorageManagerImpl(
}
// storageCustomizer - to ensure that other threads will use fully constructed and configured storage (invoked under the same lock as created)
fun getOrCreateStorage(collapsedPath: String,
roamingType: RoamingType,
storageClass: Class<out StateStorage> = StateStorage::class.java,
@Suppress("DEPRECATION", "removal") stateSplitter: Class<out StateSplitter> = StateSplitterEx::class.java,
exclusive: Boolean = false,
storageCustomizer: (StateStorage.() -> Unit)? = null,
storageCreator: StorageCreator? = null,
usePathMacroManager: Boolean = true): StateStorage {
fun getOrCreateStorage(
collapsedPath: String,
roamingType: RoamingType,
storageClass: Class<out StateStorage> = StateStorage::class.java,
@Suppress("DEPRECATION", "removal") stateSplitter: Class<out StateSplitter> = StateSplitterEx::class.java,
exclusive: Boolean = false,
storageCustomizer: (StateStorage.() -> Unit)? = null,
storageCreator: StorageCreator? = null,
usePathMacroManager: Boolean = true,
): StateStorage {
val normalizedCollapsedPath = normalizeFileSpec(collapsedPath)
val key = computeStorageKey(storageClass = storageClass,
normalizedCollapsedPath = normalizedCollapsedPath,
collapsedPath = collapsedPath,
storageCreator = storageCreator)
val key = computeStorageKey(
storageClass = storageClass,
normalizedCollapsedPath = normalizedCollapsedPath,
collapsedPath = collapsedPath,
storageCreator = storageCreator,
)
val storage = storageLock.read { storages.get(key) } ?: return storageLock.write {
storages.getOrPut(key) {
val storage = when (storageCreator) {
null -> createStateStorage(storageClass = storageClass,
collapsedPath = normalizedCollapsedPath,
roamingType = roamingType,
stateSplitter = stateSplitter,
usePathMacroManager = usePathMacroManager,
exclusive = exclusive)
null -> createStateStorage(
storageClass = storageClass,
collapsedPath = normalizedCollapsedPath,
roamingType = roamingType,
stateSplitter = stateSplitter,
usePathMacroManager = usePathMacroManager,
exclusive = exclusive,
)
else -> storageCreator.create(this)
}
storageCustomizer?.let { storage.it() }

View File

@@ -104,7 +104,7 @@ internal fun <T : Any> deserializeStateWithController(
componentName = componentName,
pluginId = pluginId,
stateElement = stateElement,
)
) as T? ?: mergeInto
}
else if (com.intellij.openapi.util.JDOMExternalizable::class.java.isAssignableFrom(stateClass)) {
if (stateElement == null) {
@@ -175,25 +175,23 @@ internal fun <T : Any> deserializeStateWithController(
}
}
private fun <T : Any> deserializeAsJdomElement(
private fun deserializeAsJdomElement(
controller: SettingsController?,
componentName: String,
pluginId: PluginId,
stateElement: Element?,
): T? {
): Element? {
try {
val item = controller?.doGetItem(createSettingDescriptor(key = componentName, pluginId = pluginId)) ?: GetResult.inapplicable()
if (item.isResolved) {
val xmlData = item.get() ?: return null
@Suppress("UNCHECKED_CAST")
return buildNsUnawareJdom(xmlData) as T
return buildNsUnawareJdom(xmlData)
}
}
catch (e: Throwable) {
LOG.error("Cannot deserialize value for $componentName", e)
}
@Suppress("UNCHECKED_CAST")
return stateElement as T?
return stateElement
}
private fun <T : Any> getXmlSerializationState(

View File

@@ -149,10 +149,9 @@ abstract class XmlElementStorage protected constructor(
abstract class XmlElementStorageSaveSessionProducer<T : XmlElementStorage>(
private val originalStates: StateMap,
protected val storage: T
@JvmField protected val storage: T
) : SaveSessionProducerBase() {
private var copiedStates: MutableMap<String, Any>? = null
private var newLiveStates: MutableMap<String, Element>? = HashMap()
protected open fun isSaveAllowed(): Boolean = !storage.checkIsSavingDisabled()
@@ -269,19 +268,26 @@ abstract class XmlElementStorage protected constructor(
val normalized = element?.normalizeRootName()
if (copiedStates == null) {
copiedStates = setStateAndCloneIfNeeded(componentName, normalized, originalStates, newLiveStates)
copiedStates = setStateAndCloneIfNeeded(
key = componentName,
newState = normalized,
oldStates = originalStates,
newLiveStates = newLiveStates,
)
}
else {
updateState(copiedStates!!, componentName, normalized, newLiveStates)
updateState(states = copiedStates!!, key = componentName, newState = normalized, newLiveStates = newLiveStates)
}
}
protected abstract fun saveLocally(dataWriter: DataWriter?)
}
protected open fun beforeElementLoaded(element: Element) { }
protected open fun beforeElementLoaded(element: Element) {
}
protected open fun beforeElementSaved(elements: MutableList<Element>, rootAttributes: MutableMap<String, String>) { }
protected open fun beforeElementSaved(elements: MutableList<Element>, rootAttributes: MutableMap<String, String>) {
}
fun updatedFromStreamProvider(changedComponentNames: MutableSet<String>, deleted: Boolean) {
val newElement = if (deleted) null else loadElement()

View File

@@ -1,6 +1,7 @@
// 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.configurationStore
import com.intellij.ide.plugins.PluginManagerCore
import com.intellij.openapi.application.writeAction
import com.intellij.openapi.components.MainConfigurationStateSplitter
import com.intellij.openapi.util.JDOMUtil
@@ -53,14 +54,22 @@ class DirectoryBasedStorageTest {
assertThat(dir).doesNotExist()
}
private fun generateData(name: String): String = """
<component name="test">
<${if (name == "test") "component" else "sub"} name="$name" />
</component>""".trimIndent()
private fun generateData(name: String): String {
return """
<component name="test">
<${if (name == "test") "component" else "sub"} name="$name" />
</component>
""".trimIndent()
}
private suspend fun setStateAndSave(storage: StateStorageBase<*>, componentName: String, state: String?) {
val saveSessionProducer = storage.createSaveSessionProducer()!!
saveSessionProducer.setState(null, componentName, if (state == null) Element("state") else JDOMUtil.load(state))
saveSessionProducer.setState(
component = null,
componentName = componentName,
pluginId = PluginManagerCore.CORE_ID,
state = if (state == null) Element("state") else JDOMUtil.load(state),
)
writeAction {
saveSessionProducer.createSaveSession()!!.saveBlocking()
}

View File

@@ -49,7 +49,7 @@ class XmlElementStorageTest {
val storage = MyXmlElementStorage(Element("root").addContent(Element("component").setAttribute("name", "test").addContent(Element("foo"))))
val newState = Element("component").setAttribute("name", "test").addContent(Element("bar"))
val externalizationSession = storage.createSaveSessionProducer()!!
externalizationSession.setState(null, "test", newState)
externalizationSession.setState(component = null, componentName = "test", pluginId = PluginManagerCore.CORE_ID, state = newState)
externalizationSession.createSaveSession()!!.saveBlocking()
assertThat(storage.savedElement).isNotNull
assertThat(storage.savedElement!!.getChild("component").getChild("bar")).isNotNull

View File

@@ -1,6 +1,8 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// 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.configurationStore
import com.intellij.openapi.extensions.PluginId
interface SaveSession : StorageManagerFileWriteRequestor {
suspend fun save() {
saveBlocking()
@@ -10,7 +12,7 @@ interface SaveSession : StorageManagerFileWriteRequestor {
}
interface SaveSessionProducer : StorageManagerFileWriteRequestor {
fun setState(component: Any?, componentName: String, state: Any?)
fun setState(component: Any?, componentName: String, pluginId: PluginId, state: Any?)
/**
* Returns `null` if nothing to save.

View File

@@ -31,8 +31,6 @@ import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.concurrent.read
import kotlin.concurrent.write
private val shimPluginId = PluginId.getId("__controller_shim__")
internal class StateStorageBackedByController(
@JvmField val controller: SettingsControllerMediator,
private val tags: List<SettingTag>,
@@ -51,28 +49,33 @@ internal class StateStorageBackedByController(
@Suppress("DEPRECATION", "UNCHECKED_CAST")
when {
stateClass === Element::class.java -> {
getXmlData(createSettingDescriptor(componentName)).takeIf { it.isResolved }?.let {
getXmlData(createSettingDescriptor(componentName, pluginId)).takeIf { it.isResolved }?.let {
return it.get() as T?
}
return mergeInto
}
com.intellij.openapi.util.JDOMExternalizable::class.java.isAssignableFrom(stateClass) -> {
return readDataForDeprecatedJdomExternalizable(componentName = componentName, mergeInto = mergeInto, stateClass = stateClass)
return readDataForDeprecatedJdomExternalizable(
componentName = componentName,
mergeInto = mergeInto,
stateClass = stateClass,
pluginId = pluginId,
)
}
else -> {
try {
val beanBinding = bindingProducer.getRootBinding(stateClass) as NotNullDeserializeBinding
if (beanBinding is KotlinxSerializationBinding) {
val data = controller.getItem(createSettingDescriptor(componentName))
if (data != null) {
return cborFormat.decodeFromByteArray(beanBinding.serializer, data) as T
}
else {
return null
}
val data = controller.getItem(createSettingDescriptor(componentName, pluginId)) ?: return null
return cborFormat.decodeFromByteArray(beanBinding.serializer, data) as T
}
else {
return getXmlSerializationState(mergeInto = mergeInto, beanBinding = beanBinding, componentName = componentName)
return getXmlSerializationState(
mergeInto = mergeInto,
beanBinding = beanBinding,
componentName = componentName,
pluginId = pluginId,
)
}
}
catch (e: SerializationException) {
@@ -85,9 +88,14 @@ internal class StateStorageBackedByController(
}
}
private fun <T : Any> readDataForDeprecatedJdomExternalizable(componentName: String, mergeInto: T?, stateClass: Class<T>): T? {
private fun <T : Any> readDataForDeprecatedJdomExternalizable(
componentName: String,
pluginId: PluginId,
mergeInto: T?,
stateClass: Class<T>,
): T? {
// we don't care about data from the old storage for deprecated JDOMExternalizable
val data = getXmlData(createSettingDescriptor(componentName)).get() ?: return mergeInto
val data = getXmlData(createSettingDescriptor(componentName, pluginId)).get() ?: return mergeInto
if (mergeInto != null) {
thisLogger().error("State is ${stateClass.name}, merge into is $mergeInto, state element text is $data")
}
@@ -101,12 +109,17 @@ internal class StateStorageBackedByController(
return t as T
}
private fun <T : Any> getXmlSerializationState(mergeInto: T?, beanBinding: NotNullDeserializeBinding, componentName: String): T? {
private fun <T : Any> getXmlSerializationState(
mergeInto: T?,
beanBinding: NotNullDeserializeBinding,
componentName: String,
pluginId: PluginId,
): T? {
var result = mergeInto
val bindings = (beanBinding as BeanBinding).bindings!!
for ((index, binding) in bindings.withIndex()) {
val data = getXmlData(createSettingDescriptor("$componentName.${binding.accessor.name}"))
val data = getXmlData(createSettingDescriptor("$componentName.${binding.accessor.name}", pluginId))
if (!data.isResolved) {
continue
}
@@ -153,10 +166,10 @@ internal class StateStorageBackedByController(
// external change is not expected and not supported
}
internal fun createSettingDescriptor(key: String): SettingDescriptor<ByteArray> {
internal fun createSettingDescriptor(key: String, pluginId: PluginId): SettingDescriptor<ByteArray> {
return SettingDescriptor(
key = key,
pluginId = shimPluginId,
pluginId = pluginId,
tags = tags,
serializer = RawSettingSerializerDescriptor,
)
@@ -171,8 +184,8 @@ private class ControllerBackedSaveSessionProducer(
storageController.controller.setItem(key, value)
}
override fun setState(component: Any?, componentName: String, state: Any?) {
val settingDescriptor = storageController.createSettingDescriptor(componentName)
override fun setState(component: Any?, componentName: String, pluginId: PluginId, state: Any?) {
val settingDescriptor = storageController.createSettingDescriptor(componentName, pluginId)
if (state == null) {
put(key = settingDescriptor, value = null)
return
@@ -200,11 +213,13 @@ private class ControllerBackedSaveSessionProducer(
continue
}
val element = beanBinding.serializePropertyInto(/* binding = */ binding,
/* o = */ state,
/* element = */ null,
/* filter = */ filter,
/* isFilterPropertyItself = */ true)
val element = beanBinding.serializePropertyInto(
binding = binding,
o = state,
preCreatedElement = null,
filter = filter,
isFilterPropertyItself = true,
)
putJdomElement(settingDescriptor.withSubName(binding.accessor.name), element)
}
}
@@ -230,7 +245,7 @@ private class ControllerBackedSaveSessionProducer(
}
private class BindingProducer : XmlSerializerImpl.XmlSerializerBase() {
private val cache: MutableMap<Class<*>, Binding> = HashMap()
private val cache = HashMap<Class<*>, Binding>()
private val cacheLock = ReentrantReadWriteLock()
override fun getRootBinding(aClass: Class<*>): Binding {

View File

@@ -910,7 +910,7 @@ class JpsProjectSerializersImpl(directorySerializersFactories: List<JpsDirectory
unloadedEntityStorage: EntityStorage,
writer: JpsFileContentWriter) {
LOG.trace("saving modules list")
it.saveEntitiesList(storage.entities(ModuleEntity::class.java) + unloadedEntityStorage.entities(ModuleEntity::class.java), writer)
it.saveEntityList(storage.entities(ModuleEntity::class.java) + unloadedEntityStorage.entities(ModuleEntity::class.java), writer)
}
companion object {

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// 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.platform.workspace.jps.serialization.impl
import com.intellij.java.workspace.entities.*
@@ -1031,7 +1031,7 @@ internal open class ModuleListSerializerImpl(override val fileUrl: String,
}
}
override fun saveEntitiesList(entities: Sequence<ModuleEntity>, writer: JpsFileContentWriter) {
override fun saveEntityList(entities: Sequence<ModuleEntity>, writer: JpsFileContentWriter) {
val entitiesToSave = entities
.filter { moduleEntity ->
entitySourceFilter(moduleEntity.entitySource)

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// 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.platform.workspace.jps.serialization.impl
import com.intellij.openapi.components.ExpandMacroToPathMap
@@ -29,6 +29,7 @@ interface JpsFileContentReader {
interface JpsFileContentWriter {
fun saveComponent(fileUrl: String, componentName: String, componentTag: Element?)
fun getReplacePathMacroMap(fileUrl: String): PathMacroMap
}
@@ -48,7 +49,7 @@ interface JpsFileEntitiesSerializer<E : WorkspaceEntity> {
* This method reads configuration files and creates entities that are not added to any builder.
*
* These entities can be just added to builder, but it's suggested to do it using [checkAndAddToBuilder] because this method
* implements additional actions on adding (e.g. reports error when trying to add a library that already exists).
* implements additional actions on adding (e.g., reports error when trying to add a library that already exists).
*/
fun loadEntities(reader: JpsFileContentReader,
errorReporter: ErrorReporter,
@@ -65,7 +66,7 @@ interface JpsFileEntitiesSerializer<E : WorkspaceEntity> {
}
/**
* Represents a serializer which is responsible for serializing all entities of the given type (e.g. libraries in *.ipr file).
* Represents a serializer which is responsible for serializing all entities of the given type (e.g., libraries in *.ipr file).
*/
interface JpsFileEntityTypeSerializer<E : WorkspaceEntity> : JpsFileEntitiesSerializer<E> {
val isExternalStorage: Boolean
@@ -75,7 +76,7 @@ interface JpsFileEntityTypeSerializer<E : WorkspaceEntity> : JpsFileEntitiesSeri
}
/**
* Represents a directory containing configuration files (e.g. .idea/libraries).
* Represents a directory containing configuration files (e.g. `.idea/libraries`).
*/
interface JpsDirectoryEntitiesSerializerFactory<E : WorkspaceEntity> {
val directoryUrl: String
@@ -103,14 +104,18 @@ interface JpsModuleListSerializer {
get() = { true }
fun loadFileList(reader: JpsFileContentReader, virtualFileManager: VirtualFileUrlManager): List<Pair<VirtualFileUrl, String?>>
fun createSerializer(internalSource: JpsFileEntitySource, fileUrl: VirtualFileUrl, moduleGroup: String?): JpsFileEntitiesSerializer<ModuleEntity>
fun saveEntitiesList(entities: Sequence<ModuleEntity>, writer: JpsFileContentWriter)
fun saveEntityList(entities: Sequence<ModuleEntity>, writer: JpsFileContentWriter)
fun getFileName(entity: ModuleEntity): String
fun deleteObsoleteFile(fileUrl: String, writer: JpsFileContentWriter)
}
/**
* Represents set of serializers for some project.
* Represents a set of serializers for some project.
*/
interface JpsProjectSerializers {
companion object {