[platform] merging component storage utils

GitOrigin-RevId: 40144952ae1cb624a55f4b7e4e3527f24f323028
This commit is contained in:
Roman Shevchenko
2024-02-06 15:12:15 +01:00
committed by intellij-monorepo-bot
parent e1aa19b5eb
commit dfb0692f2f
16 changed files with 199 additions and 258 deletions

View File

@@ -1,8 +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-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.compiler.impl.javaCompiler.javac;
import com.intellij.openapi.application.PathMacroFilter;
import com.intellij.openapi.components.impl.stores.FileStorageCoreUtil;
import com.intellij.openapi.components.impl.stores.ComponentStorageUtil;
import com.intellij.util.xmlb.Constants;
import org.jdom.Attribute;
import org.jdom.Element;
@@ -15,7 +15,7 @@ final class JavacConfigurationMacroFilter extends PathMacroFilter {
Element parent = attribute.getParent();
if (parent != null && Constants.OPTION.equals(parent.getName()) && "ADDITIONAL_OPTIONS_STRING".equals(parent.getAttributeValue(Constants.NAME))) {
Element grandParent = parent.getParentElement();
return grandParent != null && grandParent.getName().equals(FileStorageCoreUtil.COMPONENT)
return grandParent != null && grandParent.getName().equals(ComponentStorageUtil.COMPONENT)
&& "JavacSettings".equals(grandParent.getAttributeValue(Constants.NAME));
}
}

View File

@@ -1,10 +1,11 @@
// 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.find.impl;
import com.intellij.openapi.application.PathMacroFilter;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.impl.stores.FileStorageCoreUtil;
import com.intellij.openapi.components.impl.stores.ComponentStorageUtil;
import com.intellij.openapi.util.NlsSafe;
import com.intellij.openapi.util.text.Strings;
import com.intellij.util.ArrayUtilRt;
import com.intellij.util.xmlb.XmlSerializerUtil;
import com.intellij.util.xmlb.annotations.XCollection;
@@ -106,10 +107,20 @@ public class FindInProjectSettingsBase implements PersistentStateComponent<FindI
String tag = element.getName();
// dirStrings must be replaced, so, we must not skip it
if (tag.equals("findStrings") || tag.equals("replaceStrings")) {
String component = FileStorageCoreUtil.findComponentName(element);
String component = findComponentName(element);
return component != null && (component.equals("FindSettings") || component.equals("FindInProjectRecents"));
}
return false;
}
private static @Nullable String findComponentName(Element element) {
var componentElement = element;
while (true) {
var parent = componentElement.getParent();
if (!(parent instanceof Element)) break;
componentElement = (Element)parent;
}
return Strings.nullize(componentElement.getAttributeValue(ComponentStorageUtil.NAME));
}
}
}

View File

@@ -5,8 +5,7 @@ import com.intellij.configurationStore.schemeManager.createDir
import com.intellij.configurationStore.schemeManager.getOrCreateChild
import com.intellij.openapi.components.PathMacroSubstitutor
import com.intellij.openapi.components.StateSplitterEx
import com.intellij.openapi.components.impl.stores.DirectoryStorageUtil
import com.intellij.openapi.components.impl.stores.FileStorageCoreUtil
import com.intellij.openapi.components.impl.stores.ComponentStorageUtil
import com.intellij.openapi.util.JDOMUtil
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VirtualFile
@@ -24,7 +23,7 @@ open class DirectoryBasedStorage(
protected var componentName: String? = null
public override fun loadData(): StateMap =
StateMap.fromMap(DirectoryStorageUtil.loadFrom(dir, pathMacroSubstitutor))
StateMap.fromMap(ComponentStorageUtil.load(dir, pathMacroSubstitutor))
override fun analyzeExternalChangesAndUpdateIfNeeded(componentNames: MutableSet<in String>) {
// todo reload only changed file, compute diff
@@ -44,7 +43,7 @@ open class DirectoryBasedStorage(
// on load, `FileStorageCoreUtil` checks both component and name attributes
// (critically important for the external store case, where we have only in-project artifacts, but not external)
val state = Element(FileStorageCoreUtil.COMPONENT).setAttribute(FileStorageCoreUtil.NAME, componentName)
val state = Element(ComponentStorageUtil.COMPONENT).setAttribute(ComponentStorageUtil.NAME, componentName)
if (splitter is StateSplitterEx) {
for (fileName in storageData.keys()) {
val subState = storageData.getState(fileName, archive) ?: return null
@@ -201,7 +200,7 @@ open class DirectoryBasedStorage(
val file = dir.getOrCreateChild(fileName, this)
// we don't write xml prolog due to historical reasons (and should not in any case)
val macroManager = if (storage.pathMacroSubstitutor == null) null else (storage.pathMacroSubstitutor as TrackingPathMacroSubstitutorImpl).macroManager
val xmlDataWriter = XmlDataWriter(FileStorageCoreUtil.COMPONENT, listOf(element), mapOf(FileStorageCoreUtil.NAME to storage.componentName!!), macroManager, dir.path)
val xmlDataWriter = XmlDataWriter(ComponentStorageUtil.COMPONENT, listOf(element), mapOf(ComponentStorageUtil.NAME to storage.componentName!!), macroManager, dir.path)
writeFile(null, this, file, xmlDataWriter, getOrDetectLineSeparator(file) ?: LineSeparator.getSystemLineSeparator(), false)
}
catch (e: IOException) {
@@ -226,7 +225,7 @@ open class DirectoryBasedStorage(
val copiedStorageData = copiedStorageData!!
for (file in dir.children) {
val fileName = file.name
if (fileName.endsWith(FileStorageCoreUtil.DEFAULT_EXT) && !copiedStorageData.containsKey(fileName)) {
if (fileName.endsWith(ComponentStorageUtil.DEFAULT_EXT) && !copiedStorageData.containsKey(fileName)) {
if (file.isWritable) {
file.delete(this)
}

View File

@@ -9,7 +9,7 @@ import com.intellij.ide.impl.isTrusted
import com.intellij.openapi.components.*
import com.intellij.openapi.components.impl.ModulePathMacroManager
import com.intellij.openapi.components.impl.ProjectPathMacroManager
import com.intellij.openapi.components.impl.stores.FileStorageCoreUtil
import com.intellij.openapi.components.impl.stores.ComponentStorageUtil
import com.intellij.openapi.components.impl.stores.IComponentStore
import com.intellij.openapi.components.impl.stores.IProjectStore
import com.intellij.openapi.module.ModuleManager
@@ -195,7 +195,7 @@ internal class StorageJpsConfigurationReader(private val project: Project,
val component = if (storage is DirectoryBasedStorage) {
val elementContent = stateMap.getElement(PathUtilRt.getFileName(filePath))
if (elementContent != null) {
Element(FileStorageCoreUtil.COMPONENT).setAttribute(FileStorageCoreUtil.NAME, componentName).addContent(elementContent)
Element(ComponentStorageUtil.COMPONENT).setAttribute(ComponentStorageUtil.NAME, componentName).addContent(elementContent)
}
else {
null

View File

@@ -1,7 +1,7 @@
// 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.components.impl.stores.FileStorageCoreUtil
import com.intellij.openapi.components.impl.stores.ComponentStorageUtil
import com.intellij.openapi.util.WriteExternalException
import com.intellij.openapi.vfs.LargeFileWriteRequestor
import com.intellij.openapi.vfs.SafeWriteRequestor
@@ -38,7 +38,7 @@ internal fun serializeState(state: Any): Element? {
return when (state) {
is Element -> state
is com.intellij.openapi.util.JDOMExternalizable -> {
val element = Element(FileStorageCoreUtil.COMPONENT)
val element = Element(ComponentStorageUtil.COMPONENT)
state.writeExternal(element)
element
}

View File

@@ -1,11 +1,11 @@
// 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.
@file:Suppress("ReplacePutWithAssignment", "ReplaceGetOrSet")
package com.intellij.configurationStore
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.StateStorage
import com.intellij.openapi.components.impl.stores.FileStorageCoreUtil
import com.intellij.openapi.components.impl.stores.ComponentStorageUtil
import com.intellij.openapi.components.impl.stores.IComponentStore
import com.intellij.openapi.components.stateStore
import com.intellij.openapi.module.Module
@@ -71,7 +71,7 @@ internal class StorageVirtualFileTracker {
// So, we don't check if some of the registered storages located inside changed directory.
// but if we have DirectoryBasedStorage, we check - if file located inside it
if (storage == null && hasDirectoryBasedStorages && path.endsWith(FileStorageCoreUtil.DEFAULT_EXT, ignoreCase = true)) {
if (storage == null && hasDirectoryBasedStorages && path.endsWith(ComponentStorageUtil.DEFAULT_EXT, ignoreCase = true)) {
storage = filePathToStorage.get(VfsUtil.getParentDir(path))
}
}
@@ -129,4 +129,4 @@ internal class StorageVirtualFileTracker {
StoreReloadManager.getInstance(project).storageFilesBatchProcessing(batchStorageEvents)
}
}
}
}

View File

@@ -5,7 +5,7 @@ import com.intellij.openapi.components.PathMacroManager
import com.intellij.openapi.components.PathMacroSubstitutor
import com.intellij.openapi.components.RoamingType
import com.intellij.openapi.components.StateStorage
import com.intellij.openapi.components.impl.stores.FileStorageCoreUtil
import com.intellij.openapi.components.impl.stores.ComponentStorageUtil
import com.intellij.openapi.diagnostic.debug
import com.intellij.openapi.util.JDOMUtil
import com.intellij.openapi.util.SystemInfo
@@ -88,7 +88,7 @@ abstract class XmlElementStorage protected constructor(val fileSpec: String,
private fun loadState(element: Element): StateMap {
beforeElementLoaded(element)
return StateMap.fromMap(FileStorageCoreUtil.load(element, pathMacroSubstitutor))
return StateMap.fromMap(ComponentStorageUtil.load(element, pathMacroSubstitutor))
}
final override fun createSaveSessionProducer(): SaveSessionProducer? {
@@ -305,13 +305,13 @@ private fun save(states: StateMap, newLiveStates: Map<String, Element>): Mutable
// name attribute should be first
val elementAttributes = element.attributes
var nameAttribute = element.getAttribute(FileStorageCoreUtil.NAME)
var nameAttribute = element.getAttribute(ComponentStorageUtil.NAME)
if (nameAttribute != null && nameAttribute === elementAttributes[0] && componentName == nameAttribute.value) {
// all is OK
}
else {
if (nameAttribute == null) {
nameAttribute = Attribute(FileStorageCoreUtil.NAME, componentName)
nameAttribute = Attribute(ComponentStorageUtil.NAME, componentName)
elementAttributes.add(0, nameAttribute)
}
else {
@@ -334,12 +334,12 @@ private fun save(states: StateMap, newLiveStates: Map<String, Element>): Mutable
internal fun Element.normalizeRootName(): Element {
if (org.jdom.JDOMInterner.isInterned(this)) {
if (name == FileStorageCoreUtil.COMPONENT) {
if (name == ComponentStorageUtil.COMPONENT) {
return this
}
else {
val clone = clone()
clone.name = FileStorageCoreUtil.COMPONENT
clone.name = ComponentStorageUtil.COMPONENT
return clone
}
}
@@ -348,7 +348,7 @@ internal fun Element.normalizeRootName(): Element {
LOG.warn("State element must not have a parent: ${JDOMUtil.writeElement(this)}")
detach()
}
name = FileStorageCoreUtil.COMPONENT
name = ComponentStorageUtil.COMPONENT
return this
}
}

View File

@@ -11,7 +11,7 @@ import com.intellij.ide.ui.laf.TempUIThemeLookAndFeelInfo
import com.intellij.openapi.application.runWriteAction
import com.intellij.openapi.components.RoamingType
import com.intellij.openapi.components.SettingsCategory
import com.intellij.openapi.components.impl.stores.FileStorageCoreUtil
import com.intellij.openapi.components.impl.stores.ComponentStorageUtil
import com.intellij.openapi.diagnostic.debug
import com.intellij.openapi.diagnostic.getOrLogException
import com.intellij.openapi.extensions.PluginDescriptor
@@ -80,7 +80,7 @@ class SchemeManagerImpl<T : Scheme, MUTABLE_SCHEME : T>(
updateExtension = true
}
else {
schemeExtension = FileStorageCoreUtil.DEFAULT_EXT
schemeExtension = ComponentStorageUtil.DEFAULT_EXT
updateExtension = false
}
@@ -123,7 +123,7 @@ class SchemeManagerImpl<T : Scheme, MUTABLE_SCHEME : T>(
val fileNameWithoutExtension = schemeNameToFileName(schemeKey)
val externalInfo = ExternalInfo(fileNameWithoutExtension = fileNameWithoutExtension,
fileExtension = fileNameWithoutExtension + FileStorageCoreUtil.DEFAULT_EXT)
fileExtension = fileNameWithoutExtension + ComponentStorageUtil.DEFAULT_EXT)
externalInfo.schemeKey = schemeKey
@@ -246,7 +246,7 @@ class SchemeManagerImpl<T : Scheme, MUTABLE_SCHEME : T>(
internal fun getFileExtension(fileName: CharSequence, isAllowAny: Boolean): String {
return when {
fileName.endsWith(schemeExtension, ignoreCase = true) -> schemeExtension
fileName.endsWith(FileStorageCoreUtil.DEFAULT_EXT, ignoreCase = true) -> FileStorageCoreUtil.DEFAULT_EXT
fileName.endsWith(ComponentStorageUtil.DEFAULT_EXT, ignoreCase = true) -> ComponentStorageUtil.DEFAULT_EXT
isAllowAny -> PathUtilRt.getFileExtension(fileName.toString())!!
else -> throw IllegalStateException("Scheme file extension $fileName is unknown, must be filtered out")
}
@@ -348,7 +348,7 @@ class SchemeManagerImpl<T : Scheme, MUTABLE_SCHEME : T>(
internal fun getFileName(scheme: T) = schemeListManager.getExternalInfo(scheme)?.fileNameWithoutExtension
fun canRead(name: CharSequence): Boolean {
return (updateExtension && name.endsWith(FileStorageCoreUtil.DEFAULT_EXT, true) || name.endsWith(schemeExtension, ignoreCase = true)) &&
return (updateExtension && name.endsWith(ComponentStorageUtil.DEFAULT_EXT, true) || name.endsWith(schemeExtension, ignoreCase = true)) &&
(processor !is LazySchemeProcessor || processor.isSchemeFile(name))
}

View File

@@ -1,9 +1,9 @@
// 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.application.writeAction
import com.intellij.openapi.components.MainConfigurationStateSplitter
import com.intellij.openapi.components.impl.stores.DirectoryStorageUtil
import com.intellij.openapi.components.impl.stores.ComponentStorageUtil
import com.intellij.openapi.util.JDOMUtil
import com.intellij.testFramework.ProjectRule
import com.intellij.testFramework.RuleChain
@@ -30,7 +30,7 @@ class DirectoryBasedStorageTest {
val dir = tempDirManager.newPath(refreshVfs = true)
Files.createDirectories(dir)
Files.write(dir.resolve("empty.xml"), ByteArray(0))
DirectoryStorageUtil.loadFrom(dir, null)
ComponentStorageUtil.load(dir, null)
}
@Test

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.codeInsight.template.impl;
import com.intellij.DynamicBundle;
@@ -11,7 +11,7 @@ import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.SettingsCategory;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.openapi.components.impl.stores.FileStorageCoreUtil;
import com.intellij.openapi.components.impl.stores.ComponentStorageUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.extensions.PluginId;
@@ -593,7 +593,7 @@ public final class TemplateSettings implements PersistentStateComponent<Template
}
private static String appendExt(@NotNull String head) {
return head.endsWith(FileStorageCoreUtil.DEFAULT_EXT) ? head : head + FileStorageCoreUtil.DEFAULT_EXT;
return head.endsWith(ComponentStorageUtil.DEFAULT_EXT) ? head : head + ComponentStorageUtil.DEFAULT_EXT;
}
@Nullable

View File

@@ -1,11 +1,11 @@
// 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.workspaceModel.ide.impl.jps.serialization
import com.intellij.openapi.components.ExpandMacroToPathMap
import com.intellij.openapi.components.PathMacroManager
import com.intellij.openapi.components.impl.ModulePathMacroManager
import com.intellij.openapi.components.impl.ProjectPathMacroManager
import com.intellij.openapi.components.impl.stores.FileStorageCoreUtil
import com.intellij.openapi.components.impl.stores.ComponentStorageUtil
import com.intellij.openapi.util.JDOMUtil
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.util.text.Strings
@@ -69,6 +69,6 @@ class CachingJpsFileContentReader(private val configLocation: JpsProjectConfigLo
}
rootElement.addContent(optionElement)
}
return FileStorageCoreUtil.load(rootElement, pathMacroManager)
return ComponentStorageUtil.load(rootElement, pathMacroManager)
}
}
}

View File

@@ -1,11 +1,11 @@
// 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.application.options.ReplacePathToMacroMap
import com.intellij.openapi.application.PathMacroFilter
import com.intellij.openapi.components.ComponentManager
import com.intellij.openapi.components.PathMacroManager
import com.intellij.openapi.components.impl.stores.FileStorageCoreUtil
import com.intellij.openapi.components.impl.stores.ComponentStorageUtil
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.util.JDOMUtil
import com.intellij.openapi.util.SystemInfoRt
@@ -483,8 +483,8 @@ open class JbXmlOutputter @JvmOverloads constructor(lineSeparator: String = "\n"
var parent = parentElement
while (parent != null) {
var parentId = parent.name
if (parentId == FileStorageCoreUtil.COMPONENT) {
val componentName = parent.getAttributeValue(FileStorageCoreUtil.NAME)
if (parentId == ComponentStorageUtil.COMPONENT) {
val componentName = parent.getAttributeValue(ComponentStorageUtil.NAME)
if (componentName != null) {
parentId += "@$componentName"
}
@@ -579,4 +579,4 @@ private fun printQualifiedName(out: Writer, a: Attribute) {
out.write(':'.code)
}
out.write(a.name)
}
}

View File

@@ -0,0 +1,139 @@
// 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.components.impl.stores;
import com.intellij.application.options.PathMacrosCollector;
import com.intellij.application.options.PathMacrosImpl;
import com.intellij.openapi.components.CompositePathMacroFilter;
import com.intellij.openapi.components.PathMacroSubstitutor;
import com.intellij.openapi.components.TrackingPathMacroSubstitutor;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.text.Strings;
import com.intellij.util.SmartList;
import org.jdom.Element;
import org.jdom.Text;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.nio.file.*;
import java.util.*;
@ApiStatus.Internal
public final class ComponentStorageUtil {
private static final Logger LOG = Logger.getInstance(ComponentStorageUtil.class);
public static final String COMPONENT = "component";
public static final String NAME = "name";
public static final String DEFAULT_EXT = ".xml";
public static @NotNull Map<String, Element> load(@NotNull Element rootElement, @Nullable PathMacroSubstitutor pathMacroSubstitutor) {
if (pathMacroSubstitutor != null) {
pathMacroSubstitutor.expandPaths(rootElement);
}
var children = rootElement.getChildren(COMPONENT);
if (children.isEmpty() && rootElement.getName().equals(COMPONENT) && rootElement.getAttributeValue(NAME) != null) {
children = new SmartList<>(rootElement); // must be modifiable
}
var map = new TreeMap<String, Element>();
CompositePathMacroFilter filter = null;
for (var iterator = children.iterator(); iterator.hasNext(); ) {
var element = iterator.next();
var name = getComponentNameIfValid(element);
if (name == null || (element.getAttributes().size() <= 1 && element.getContent().isEmpty())) {
continue;
}
// so, PathMacroFilter can easily find component name (null parent)
iterator.remove();
if (pathMacroSubstitutor instanceof TrackingPathMacroSubstitutor ts && !isKotlinSerializable(element)) {
if (filter == null) {
filter = new CompositePathMacroFilter(PathMacrosCollector.MACRO_FILTER_EXTENSION_POINT_NAME.getExtensionList());
}
ts.addUnknownMacros(name, PathMacrosCollector.getMacroNames(element, filter, PathMacrosImpl.getInstanceEx()));
}
// remove only after "getMacroNames" - some PathMacroFilter requires element name attribute
element.removeAttribute(NAME);
map.put(name, element);
}
return map;
}
public static @NotNull Map<String, Element> load(@NotNull Path dir, @Nullable PathMacroSubstitutor pathMacroSubstitutor) throws IOException {
try (var files = Files.newDirectoryStream(dir)) {
var fileToState = new HashMap<String, Element>();
for (var file : files) {
// ignore system files like .DS_Store on Mac
if (!Strings.endsWithIgnoreCase(file.toString(), DEFAULT_EXT)) {
continue;
}
try {
var element = JDOMUtil.load(file);
var componentName = getComponentNameIfValid(element);
if (componentName == null) continue;
if (!element.getName().equals(COMPONENT)) {
LOG.error("Incorrect root tag name (" + element.getName() + ") in " + file);
continue;
}
var elementChildren = element.getChildren();
if (elementChildren.isEmpty()) continue;
var state = elementChildren.get(0).detach();
if (JDOMUtil.isEmpty(state)) {
continue;
}
if (pathMacroSubstitutor != null) {
pathMacroSubstitutor.expandPaths(state);
if (pathMacroSubstitutor instanceof TrackingPathMacroSubstitutor ts) {
ts.addUnknownMacros(componentName, PathMacrosCollector.getMacroNames(state));
}
}
fileToState.put(file.getFileName().toString(), state);
}
catch (Throwable e) {
if (e.getMessage().startsWith("Unexpected End-of-input in prolog")) {
LOG.warn("Ignore empty file " + file);
}
else {
LOG.warn("Unable to load state from " + file, e);
}
}
}
return fileToState;
}
catch (DirectoryIteratorException e) {
throw e.getCause();
}
catch (NoSuchFileException | NotDirectoryException ignore) {
return Map.of();
}
}
private static boolean isKotlinSerializable(Element element) {
if (element.hasAttributes()) return false;
var content = element.getContent();
return content.size() == 1 && content.get(0) instanceof Text;
}
private static @Nullable String getComponentNameIfValid(Element element) {
var name = element.getAttributeValue(NAME);
if (!Strings.isEmpty(name)) return name;
LOG.warn("No name attribute for component in " + JDOMUtil.writeElement(element));
return null;
}
}

View File

@@ -1,101 +0,0 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.components.impl.stores;
import com.intellij.application.options.PathMacrosCollector;
import com.intellij.openapi.components.PathMacroSubstitutor;
import com.intellij.openapi.components.StateSplitterEx;
import com.intellij.openapi.components.TrackingPathMacroSubstitutor;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.text.Strings;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.nio.file.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public final class DirectoryStorageUtil {
private static final Logger LOG = Logger.getInstance(DirectoryStorageUtil.class);
public static @NotNull Map<String, Element> loadFrom(@NotNull Path dir, @Nullable PathMacroSubstitutor pathMacroSubstitutor)
throws IOException {
try (DirectoryStream<Path> files = Files.newDirectoryStream(dir)) {
Map<String, Element> fileToState = new HashMap<>();
for (Path file : files) {
// ignore system files like .DS_Store on Mac
if (!Strings.endsWithIgnoreCase(file.toString(), FileStorageCoreUtil.DEFAULT_EXT)) {
continue;
}
try {
Element element = JDOMUtil.load(file);
String componentName = FileStorageCoreUtil.getComponentNameIfValid(element);
if (componentName == null) {
continue;
}
if (!element.getName().equals(FileStorageCoreUtil.COMPONENT)) {
LOG.error("Incorrect root tag name (" + element.getName() + ") in " + file);
continue;
}
List<Element> elementChildren = element.getChildren();
if (elementChildren.isEmpty()) {
continue;
}
Element state = elementChildren.get(0).detach();
if (JDOMUtil.isEmpty(state)) {
continue;
}
if (pathMacroSubstitutor != null) {
pathMacroSubstitutor.expandPaths(state);
if (pathMacroSubstitutor instanceof TrackingPathMacroSubstitutor) {
((TrackingPathMacroSubstitutor)pathMacroSubstitutor).addUnknownMacros(componentName, PathMacrosCollector.getMacroNames(state));
}
}
fileToState.put(file.getFileName().toString(), state);
}
catch (Throwable e) {
if (e.getMessage().startsWith("Unexpected End-of-input in prolog")) {
LOG.warn("Ignore empty file " + file);
}
else {
LOG.warn("Unable to load state from " + file, e);
}
}
}
return fileToState;
}
catch (DirectoryIteratorException e) {
throw e.getCause();
}
catch (NoSuchFileException | NotDirectoryException ignore) {
return Collections.emptyMap();
}
}
public static @Nullable Element getCompositeState(@NotNull Map<String, Element> fileToState, @NotNull StateSplitterEx splitter) {
Element state = new Element(FileStorageCoreUtil.COMPONENT);
if (fileToState.isEmpty()) {
return state;
}
for (String fileName : fileToState.keySet()) {
Element subState = fileToState.get(fileName);
if (subState == null) {
return null;
}
splitter.mergeStateInto(state, subState);
}
return state;
}
}

View File

@@ -1,107 +0,0 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.components.impl.stores;
import com.intellij.application.options.PathMacrosCollector;
import com.intellij.application.options.PathMacrosImpl;
import com.intellij.openapi.components.CompositePathMacroFilter;
import com.intellij.openapi.components.PathMacroSubstitutor;
import com.intellij.openapi.components.TrackingPathMacroSubstitutor;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.text.Strings;
import com.intellij.util.SmartList;
import org.jdom.Content;
import org.jdom.Element;
import org.jdom.Parent;
import org.jdom.Text;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
@ApiStatus.Internal
public final class FileStorageCoreUtil {
private static final Logger LOG = Logger.getInstance(FileStorageCoreUtil.class);
public static final String COMPONENT = "component";
public static final String NAME = "name";
public static final String DEFAULT_EXT = ".xml";
public static @NotNull Map<String, Element> load(@NotNull Element rootElement, @Nullable PathMacroSubstitutor pathMacroSubstitutor) {
if (pathMacroSubstitutor != null) {
pathMacroSubstitutor.expandPaths(rootElement);
}
List<Element> children = rootElement.getChildren(COMPONENT);
if (children.isEmpty() && rootElement.getName().equals(COMPONENT) && rootElement.getAttributeValue(NAME) != null) {
// exclusive component data
// singleton must be not used here - later we modify list
children = new SmartList<>(rootElement);
}
CompositePathMacroFilter filter = null;
Map<String, Element> map = new TreeMap<>();
for (Iterator<Element> iterator = children.iterator(); iterator.hasNext(); ) {
Element element = iterator.next();
String name = getComponentNameIfValid(element);
if (name == null || (element.getAttributes().size() <= 1 && element.getContent().isEmpty())) {
continue;
}
// so, PathMacroFilter can easily find component name (null parent)
iterator.remove();
if (pathMacroSubstitutor instanceof TrackingPathMacroSubstitutor && !isKotlinSerializable(element)) {
if (filter == null) {
filter = new CompositePathMacroFilter(PathMacrosCollector.MACRO_FILTER_EXTENSION_POINT_NAME.getExtensionList());
}
((TrackingPathMacroSubstitutor)pathMacroSubstitutor)
.addUnknownMacros(name, PathMacrosCollector.getMacroNames(element, filter, PathMacrosImpl.getInstanceEx()));
}
// remove only after "getMacroNames" - some PathMacroFilter requires element name attribute
element.removeAttribute(NAME);
map.put(name, element);
}
return map;
}
private static boolean isKotlinSerializable(Element element) {
if (element.hasAttributes()) {
return false;
}
List<Content> content = element.getContent();
return content.size() == 1 && content.get(0) instanceof Text;
}
static @Nullable String getComponentNameIfValid(@NotNull Element element) {
String name = element.getAttributeValue(NAME);
if (Strings.isEmpty(name)) {
LOG.warn("No name attribute for component in " + JDOMUtil.writeElement(element));
return null;
}
return name;
}
public static @Nullable String findComponentName(@NotNull Element element) {
Element componentElement = element;
while (true) {
Parent parent = componentElement.getParent();
if (!(parent instanceof Element)) {
break;
}
componentElement = (Element)parent;
}
return Strings.nullize(componentElement.getAttributeValue(NAME));
}
}

View File

@@ -9,7 +9,7 @@ import com.intellij.configurationStore.SaveSessionProducer
import com.intellij.configurationStore.__platformSerializer
import com.intellij.configurationStore.jdomSerializer
import com.intellij.openapi.components.StateStorage
import com.intellij.openapi.components.impl.stores.FileStorageCoreUtil
import com.intellij.openapi.components.impl.stores.ComponentStorageUtil
import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.openapi.extensions.PluginId
import com.intellij.openapi.util.IntellijInternalApi
@@ -172,7 +172,7 @@ private class ControllerBackedSaveSessionProducer(
when (state) {
is Element -> putJdomElement(settingDescriptor, state)
is com.intellij.openapi.util.JDOMExternalizable -> {
val element = Element(FileStorageCoreUtil.COMPONENT)
val element = Element(ComponentStorageUtil.COMPONENT)
state.writeExternal(element)
putJdomElement(settingDescriptor, element)
}