mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[workspace model] refactoring: extract JpsFileContentWriter::getReplacePathMacroMap method
We need to access PathMacroMap to properly generate *.eml files for projects imported from Eclipse (IDEA-246236). This change also extracts additional constructors in (Module/Project)PathMacroManager classes to get rid of corresponding *Bridge implementations. (We cannot use (Module/Project)PathMacroManager directly while loading the workspace model because Module/Project instance aren't available at that time.) It simplifies code and allows to use these classes from ProjectStoreBridge.kt where *Bridge classes weren't accessible from. GitOrigin-RevId: 39126ba8efe1da98650c2819ebd4354327ed61ac
This commit is contained in:
committed by
intellij-monorepo-bot
parent
477410cd20
commit
b80fd5473c
@@ -2,6 +2,8 @@
|
||||
package com.intellij.configurationStore
|
||||
|
||||
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.IProjectStore
|
||||
import com.intellij.openapi.project.Project
|
||||
@@ -16,6 +18,7 @@ import com.intellij.workspaceModel.ide.impl.jps.serialization.*
|
||||
import org.jdom.Element
|
||||
import org.jetbrains.jps.util.JpsPathUtil
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.function.Supplier
|
||||
|
||||
class ProjectStoreBridge(private val project: Project) : ModuleSavingCustomizer {
|
||||
override fun createSaveSessionProducerManager(): ProjectSaveSessionProducerManager {
|
||||
@@ -56,6 +59,16 @@ private class JpsStorageContentWriter(private val session: ProjectWithModulesSav
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getReplacePathMacroMap(fileUrl: String): PathMacroMap {
|
||||
val filePath = JpsPathUtil.urlToPath(fileUrl)
|
||||
return if (FileUtil.extensionEquals(filePath, "iml") || isExternalModuleFile(filePath)) {
|
||||
ModulePathMacroManager.createInstance(Supplier { filePath }).replacePathMap
|
||||
}
|
||||
else {
|
||||
ProjectPathMacroManager.getInstance(project).replacePathMap
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val MODULE_FILE_STORAGE_ANNOTATION = FileStorageAnnotation(StoragePathMacros.MODULE_FILE, false)
|
||||
|
||||
+18
-5
@@ -6,29 +6,42 @@ import com.intellij.openapi.application.PathMacros;
|
||||
import com.intellij.openapi.components.ExpandMacroToPathMap;
|
||||
import com.intellij.openapi.components.PathMacroManager;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.serviceContainer.NonInjectable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.SystemIndependent;
|
||||
import org.jetbrains.jps.model.serialization.PathMacroUtil;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public final class ModulePathMacroManager extends PathMacroManager {
|
||||
private final Module myModule;
|
||||
private final Supplier<@SystemIndependent String> myModuleDirPointer;
|
||||
|
||||
public ModulePathMacroManager(@NotNull Module module) {
|
||||
super(PathMacros.getInstance());
|
||||
myModule = module;
|
||||
myModuleDirPointer = module::getModuleFilePath;
|
||||
}
|
||||
|
||||
@NonInjectable
|
||||
private ModulePathMacroManager(Supplier<@SystemIndependent String> moduleDirPointer) {
|
||||
super(PathMacros.getInstance());
|
||||
myModuleDirPointer = moduleDirPointer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ExpandMacroToPathMap getExpandMacroMap() {
|
||||
ExpandMacroToPathMap result = super.getExpandMacroMap();
|
||||
addFileHierarchyReplacements(result, PathMacroUtil.MODULE_DIR_MACRO_NAME, PathMacroUtil.getModuleDir(myModule.getModuleFilePath()));
|
||||
addFileHierarchyReplacements(result, PathMacroUtil.MODULE_DIR_MACRO_NAME, PathMacroUtil.getModuleDir(myModuleDirPointer.get()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ReplacePathToMacroMap computeReplacePathMap() {
|
||||
ReplacePathToMacroMap result = super.computeReplacePathMap();
|
||||
String modulePath = PathMacroUtil.getModuleDir(myModule.getModuleFilePath());
|
||||
addFileHierarchyReplacements(result, PathMacroUtil.MODULE_DIR_MACRO_NAME, modulePath, PathMacroUtil.getUserHomePath());
|
||||
addFileHierarchyReplacements(result, PathMacroUtil.MODULE_DIR_MACRO_NAME, PathMacroUtil.getModuleDir(myModuleDirPointer.get()), PathMacroUtil.getUserHomePath());
|
||||
return result;
|
||||
}
|
||||
|
||||
public static ModulePathMacroManager createInstance(Supplier<@SystemIndependent String> moduleDirPointer) {
|
||||
return new ModulePathMacroManager(moduleDirPointer);
|
||||
}
|
||||
}
|
||||
+25
-6
@@ -6,25 +6,39 @@ import com.intellij.openapi.application.PathMacros;
|
||||
import com.intellij.openapi.components.ExpandMacroToPathMap;
|
||||
import com.intellij.openapi.components.PathMacroManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.serviceContainer.NonInjectable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.SystemIndependent;
|
||||
import org.jetbrains.jps.model.serialization.PathMacroUtil;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ProjectPathMacroManager extends PathMacroManager {
|
||||
private final Project myProject;
|
||||
private final Supplier<@SystemIndependent String> myBasePathPointer;
|
||||
private final @Nullable Supplier<@SystemIndependent String> myNamePointer;
|
||||
|
||||
public ProjectPathMacroManager(@NotNull Project project) {
|
||||
super(PathMacros.getInstance());
|
||||
myBasePathPointer = project::getBasePath;
|
||||
myNamePointer = !project.isDefault() ? project::getName : null;
|
||||
}
|
||||
|
||||
myProject = project;
|
||||
@NonInjectable
|
||||
private ProjectPathMacroManager(Supplier<@SystemIndependent String> basePathPointer,
|
||||
@Nullable Supplier<@SystemIndependent String> namePointer) {
|
||||
super(PathMacros.getInstance());
|
||||
myBasePathPointer = basePathPointer;
|
||||
myNamePointer = namePointer;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ExpandMacroToPathMap getExpandMacroMap() {
|
||||
ExpandMacroToPathMap result = super.getExpandMacroMap();
|
||||
addFileHierarchyReplacements(result, PathMacroUtil.PROJECT_DIR_MACRO_NAME, myProject.getBasePath());
|
||||
if (!myProject.isDefault()) {
|
||||
result.addMacroExpand(PathMacroUtil.PROJECT_NAME_MACRO_NAME, myProject.getName());
|
||||
addFileHierarchyReplacements(result, PathMacroUtil.PROJECT_DIR_MACRO_NAME, myBasePathPointer.get());
|
||||
if (myNamePointer != null) {
|
||||
result.addMacroExpand(PathMacroUtil.PROJECT_NAME_MACRO_NAME, myNamePointer.get());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -33,7 +47,12 @@ public class ProjectPathMacroManager extends PathMacroManager {
|
||||
@Override
|
||||
protected ReplacePathToMacroMap computeReplacePathMap() {
|
||||
ReplacePathToMacroMap result = super.computeReplacePathMap();
|
||||
addFileHierarchyReplacements(result, PathMacroUtil.PROJECT_DIR_MACRO_NAME, myProject.getBasePath(), null);
|
||||
addFileHierarchyReplacements(result, PathMacroUtil.PROJECT_DIR_MACRO_NAME, myBasePathPointer.get(), null);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static ProjectPathMacroManager createInstance(Supplier<@SystemIndependent String> basePathPointer,
|
||||
@Nullable Supplier<@SystemIndependent String> namePointer) {
|
||||
return new ProjectPathMacroManager(basePathPointer, namePointer);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-39
@@ -1,10 +1,10 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.workspaceModel.ide.impl.jps.serialization
|
||||
|
||||
import com.intellij.application.options.ReplacePathToMacroMap
|
||||
import com.intellij.openapi.application.PathMacros
|
||||
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.module.impl.ModulePath
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vfs.VfsUtilCore
|
||||
@@ -25,7 +25,6 @@ import com.intellij.workspaceModel.storage.bridgeEntities.ModuleEntity
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
|
||||
import org.jdom.Element
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.jps.model.serialization.PathMacroUtil
|
||||
import org.jetbrains.jps.util.JpsPathUtil
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
@@ -457,7 +456,7 @@ class JpsProjectSerializersImpl(directorySerializersFactories: List<JpsDirectory
|
||||
}
|
||||
|
||||
class CachingJpsFileContentReader(projectBaseDirUrl: String) : JpsFileContentReader {
|
||||
private val projectPathMacroManager = ProjectPathMacroManagerBridge(JpsPathUtil.urlToPath(projectBaseDirUrl))
|
||||
private val projectPathMacroManager = ProjectPathMacroManager.createInstance({ JpsPathUtil.urlToPath(projectBaseDirUrl) }, null)
|
||||
private val fileContentCache = ConcurrentHashMap<String, Map<String, Element>>()
|
||||
|
||||
override fun loadComponent(fileUrl: String, componentName: String, customModuleFilePath: String?): Element? {
|
||||
@@ -482,46 +481,12 @@ class CachingJpsFileContentReader(projectBaseDirUrl: String) : JpsFileContentRea
|
||||
customModuleFilePath: String?): PathMacroManager {
|
||||
val path = JpsPathUtil.urlToPath(fileUrl)
|
||||
return if (FileUtil.extensionEquals(fileUrl, "iml") || isExternalModuleFile(path)) {
|
||||
ModulePathMacroManagerBridge(PathMacros.getInstance(), customModuleFilePath ?: path)
|
||||
ModulePathMacroManager.createInstance { customModuleFilePath ?: path }
|
||||
}
|
||||
else {
|
||||
projectPathMacroManager
|
||||
}
|
||||
}
|
||||
|
||||
internal class ModulePathMacroManagerBridge(pathMacros: PathMacros, private val moduleFilePath: String) : PathMacroManager(
|
||||
pathMacros) {
|
||||
override fun getExpandMacroMap(): ExpandMacroToPathMap {
|
||||
val result = super.getExpandMacroMap()
|
||||
addFileHierarchyReplacements(
|
||||
result, PathMacroUtil.MODULE_DIR_MACRO_NAME,
|
||||
PathMacroUtil.getModuleDir(moduleFilePath))
|
||||
return result
|
||||
}
|
||||
|
||||
public override fun computeReplacePathMap(): ReplacePathToMacroMap {
|
||||
val result = super.computeReplacePathMap()
|
||||
val modulePath = PathMacroUtil.getModuleDir(moduleFilePath)
|
||||
addFileHierarchyReplacements(
|
||||
result, PathMacroUtil.MODULE_DIR_MACRO_NAME, modulePath,
|
||||
PathMacroUtil.getUserHomePath())
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
internal class ProjectPathMacroManagerBridge(private val projectDirPath: String) : PathMacroManager(PathMacros.getInstance()) {
|
||||
override fun getExpandMacroMap(): ExpandMacroToPathMap {
|
||||
val result = super.getExpandMacroMap()
|
||||
addFileHierarchyReplacements(result, PathMacroUtil.PROJECT_DIR_MACRO_NAME, projectDirPath)
|
||||
return result
|
||||
}
|
||||
|
||||
override fun computeReplacePathMap(): ReplacePathToMacroMap {
|
||||
val result = super.computeReplacePathMap()
|
||||
addFileHierarchyReplacements(result, PathMacroUtil.PROJECT_DIR_MACRO_NAME, projectDirPath, null)
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Add more diagnostics: file path, line etc
|
||||
|
||||
+2
@@ -2,6 +2,7 @@
|
||||
package com.intellij.workspaceModel.ide.impl.jps.serialization
|
||||
|
||||
import com.intellij.openapi.components.ExpandMacroToPathMap
|
||||
import com.intellij.openapi.components.PathMacroMap
|
||||
import com.intellij.openapi.module.impl.ModulePath
|
||||
import com.intellij.workspaceModel.storage.bridgeEntities.ModuleEntity
|
||||
import com.intellij.workspaceModel.ide.JpsFileEntitySource
|
||||
@@ -21,6 +22,7 @@ interface JpsFileContentReader {
|
||||
|
||||
interface JpsFileContentWriter {
|
||||
fun saveComponent(fileUrl: String, componentName: String, componentTag: Element?)
|
||||
fun getReplacePathMacroMap(fileUrl: String): PathMacroMap
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-2
@@ -157,9 +157,9 @@ class JpsProjectSaveAfterChangesTest {
|
||||
is EntityChange.Replaced -> listOf(change.oldEntity, change.newEntity)
|
||||
}
|
||||
}.map { it.entitySource }}
|
||||
val writer = JpsFileContentWriterImpl()
|
||||
val writer = JpsFileContentWriterImpl(projectData.projectDir)
|
||||
projectData.serializers.saveEntities(builder.toStorage(), changedSources, writer)
|
||||
writer.writeFiles(projectData.projectDir)
|
||||
writer.writeFiles()
|
||||
projectData.serializers.checkConsistency(projectData.projectDirUrl, builder.toStorage(), virtualFileManager)
|
||||
|
||||
val expectedDir = FileUtil.createTempDirectory("jpsProjectTest", "expected")
|
||||
|
||||
+73
-68
@@ -3,6 +3,9 @@ package com.intellij.workspaceModel.ide.impl.jps.serialization
|
||||
|
||||
import com.intellij.openapi.application.PathMacros
|
||||
import com.intellij.openapi.application.ex.PathManagerEx
|
||||
import com.intellij.openapi.components.PathMacroMap
|
||||
import com.intellij.openapi.components.impl.ModulePathMacroManager
|
||||
import com.intellij.openapi.components.impl.ProjectPathMacroManager
|
||||
import com.intellij.openapi.util.JDOMUtil
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.util.io.systemIndependentPath
|
||||
@@ -62,74 +65,9 @@ internal fun loadProject(configLocation: JpsProjectConfigLocation, originalBui
|
||||
}
|
||||
|
||||
internal fun JpsProjectSerializersImpl.saveAllEntities(storage: WorkspaceEntityStorage, projectDir: File) {
|
||||
val writer = JpsFileContentWriterImpl()
|
||||
val writer = JpsFileContentWriterImpl(projectDir)
|
||||
saveAllEntities(storage, writer)
|
||||
writer.writeFiles(projectDir)
|
||||
}
|
||||
|
||||
internal fun JpsFileContentWriterImpl.writeFiles(baseProjectDir: File) {
|
||||
urlToComponents.forEach { (url, newComponents) ->
|
||||
val components = HashMap(newComponents)
|
||||
val file = JpsPathUtil.urlToFile(url)
|
||||
|
||||
val isModuleFile = FileUtil.extensionEquals(file.absolutePath, "iml")
|
||||
|| file.parentFile.name == "modules" && file.parentFile.parentFile.name != ".idea"
|
||||
val replaceMacroMap = if (isModuleFile)
|
||||
CachingJpsFileContentReader.ModulePathMacroManagerBridge(PathMacros.getInstance(), JpsPathUtil.urlToOsPath(url)).replacePathMap
|
||||
else
|
||||
CachingJpsFileContentReader.ProjectPathMacroManagerBridge(baseProjectDir.systemIndependentPath).replacePathMap
|
||||
|
||||
|
||||
val newRootElement = when {
|
||||
isModuleFile -> Element("module")
|
||||
FileUtil.filesEqual(File(baseProjectDir, ".idea"), file.parentFile.parentFile) -> null
|
||||
else -> Element("project")
|
||||
}
|
||||
|
||||
fun isEmptyComponentTag(componentTag: Element) = componentTag.contentSize == 0 && componentTag.attributes.all { it.name == "name" }
|
||||
|
||||
val rootElement: Element?
|
||||
if (newRootElement != null) {
|
||||
if (file.exists()) {
|
||||
val oldElement = JDOMUtil.load(file)
|
||||
oldElement.getChildren("component")
|
||||
.filterNot { it.getAttributeValue("name") in components }
|
||||
.map { it.clone() }
|
||||
.associateByTo(components) { it.getAttributeValue("name") }
|
||||
}
|
||||
components.entries.sortedBy { it.key }.forEach { (name, element) ->
|
||||
if (element != null && !isEmptyComponentTag(element)) {
|
||||
if (name == "DeprecatedModuleOptionManager") {
|
||||
element.getChildren("option").forEach {
|
||||
newRootElement.setAttribute(it.getAttributeValue("key")!!, it.getAttributeValue("value")!!)
|
||||
}
|
||||
}
|
||||
else {
|
||||
newRootElement.addContent(element)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!JDOMUtil.isEmpty(newRootElement)) {
|
||||
newRootElement.setAttribute("version", "4")
|
||||
rootElement = newRootElement
|
||||
}
|
||||
else {
|
||||
rootElement = null
|
||||
}
|
||||
}
|
||||
else {
|
||||
val singleComponent = components.values.single()
|
||||
rootElement = if (singleComponent != null && !isEmptyComponentTag(singleComponent)) singleComponent else null
|
||||
}
|
||||
if (rootElement != null) {
|
||||
replaceMacroMap.substitute(rootElement, true, true)
|
||||
FileUtil.createParentDirs(file)
|
||||
JDOMUtil.write(rootElement, file)
|
||||
}
|
||||
else {
|
||||
FileUtil.delete(file)
|
||||
}
|
||||
}
|
||||
writer.writeFiles()
|
||||
}
|
||||
|
||||
internal fun assertDirectoryMatches(actualDir: File, expectedDir: File, filesToIgnore: Set<String>, componentsToIgnore: List<String>) {
|
||||
@@ -228,12 +166,79 @@ internal fun toConfigLocation(file: Path, virtualFileManager: VirtualFileUrlMana
|
||||
}
|
||||
}
|
||||
|
||||
internal class JpsFileContentWriterImpl : JpsFileContentWriter {
|
||||
internal class JpsFileContentWriterImpl(private val baseProjectDir: File) : JpsFileContentWriter {
|
||||
val urlToComponents = LinkedHashMap<String, LinkedHashMap<String, Element?>>()
|
||||
|
||||
override fun saveComponent(fileUrl: String, componentName: String, componentTag: Element?) {
|
||||
urlToComponents.computeIfAbsent(fileUrl) { LinkedHashMap() }[componentName] = componentTag
|
||||
}
|
||||
|
||||
override fun getReplacePathMacroMap(fileUrl: String): PathMacroMap {
|
||||
return if (isModuleFile(JpsPathUtil.urlToFile(fileUrl)))
|
||||
ModulePathMacroManager.createInstance { JpsPathUtil.urlToOsPath(fileUrl) }.replacePathMap
|
||||
else
|
||||
ProjectPathMacroManager.createInstance({ baseProjectDir.systemIndependentPath }, null).replacePathMap
|
||||
}
|
||||
|
||||
internal fun writeFiles() {
|
||||
urlToComponents.forEach { (url, newComponents) ->
|
||||
val components = HashMap(newComponents)
|
||||
val file = JpsPathUtil.urlToFile(url)
|
||||
val replaceMacroMap = getReplacePathMacroMap(url)
|
||||
val newRootElement = when {
|
||||
isModuleFile(file) -> Element("module")
|
||||
FileUtil.filesEqual(File(baseProjectDir, ".idea"), file.parentFile.parentFile) -> null
|
||||
else -> Element("project")
|
||||
}
|
||||
|
||||
fun isEmptyComponentTag(componentTag: Element) = componentTag.contentSize == 0 && componentTag.attributes.all { it.name == "name" }
|
||||
|
||||
val rootElement: Element?
|
||||
if (newRootElement != null) {
|
||||
if (file.exists()) {
|
||||
val oldElement = JDOMUtil.load(file)
|
||||
oldElement.getChildren("component")
|
||||
.filterNot { it.getAttributeValue("name") in components }
|
||||
.map { it.clone() }
|
||||
.associateByTo(components) { it.getAttributeValue("name") }
|
||||
}
|
||||
components.entries.sortedBy { it.key }.forEach { (name, element) ->
|
||||
if (element != null && !isEmptyComponentTag(element)) {
|
||||
if (name == "DeprecatedModuleOptionManager") {
|
||||
element.getChildren("option").forEach {
|
||||
newRootElement.setAttribute(it.getAttributeValue("key")!!, it.getAttributeValue("value")!!)
|
||||
}
|
||||
}
|
||||
else {
|
||||
newRootElement.addContent(element)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!JDOMUtil.isEmpty(newRootElement)) {
|
||||
newRootElement.setAttribute("version", "4")
|
||||
rootElement = newRootElement
|
||||
}
|
||||
else {
|
||||
rootElement = null
|
||||
}
|
||||
}
|
||||
else {
|
||||
val singleComponent = components.values.single()
|
||||
rootElement = if (singleComponent != null && !isEmptyComponentTag(singleComponent)) singleComponent else null
|
||||
}
|
||||
if (rootElement != null) {
|
||||
replaceMacroMap.substitute(rootElement, true, true)
|
||||
FileUtil.createParentDirs(file)
|
||||
JDOMUtil.write(rootElement, file)
|
||||
}
|
||||
else {
|
||||
FileUtil.delete(file)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isModuleFile(file: File) = (FileUtil.extensionEquals(file.absolutePath, "iml")
|
||||
|| file.parentFile.name == "modules" && file.parentFile.parentFile.name != ".idea")
|
||||
}
|
||||
|
||||
internal object TestErrorReporter : ErrorReporter {
|
||||
|
||||
Reference in New Issue
Block a user