mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 15:19:59 +07:00
[workspace model] properly handle cases when iml file of a module is moved to another directory (IJPL-8707)
The common logic which updates VirtualFileUrl instances doesn't work here because the entity source for a module points to the parent directory of its iml file (see IJPL-158284). So we need to manually check this case, and also ensure that the path in ModuleStore is updated. GitOrigin-RevId: cc518f86a9f22c4d9d57932edcb0479982907adb
This commit is contained in:
committed by
intellij-monorepo-bot
parent
02196cd0f5
commit
61312dc086
@@ -31,6 +31,7 @@ import org.junit.Test
|
||||
import org.junit.rules.ExternalResource
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.invariantSeparatorsPathString
|
||||
import kotlin.io.path.isRegularFile
|
||||
import kotlin.io.path.readText
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
@@ -178,6 +179,21 @@ class ChangeModuleStorePathTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `move iml file`() = runBlocking {
|
||||
saveProjectState()
|
||||
val imlFile = module.storage.getVirtualFile()!!
|
||||
val oldFile = imlFile.toNioPath()
|
||||
val moduleName = module.name
|
||||
writeAction {
|
||||
imlFile.move(null, tempDirManager.newVirtualDirectory("newParent"))
|
||||
}
|
||||
val newFile = imlFile.toNioPath()
|
||||
assertThat(newFile.isRegularFile())
|
||||
assertModuleFileRenamed(moduleName, oldFile)
|
||||
assertThat(oldModuleNames).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `rename module source root`() = runBlocking<Unit>(Dispatchers.EDT) {
|
||||
saveProjectState()
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.intellij.openapi.roots.impl.storage.ClasspathStorage
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vfs.AsyncFileListener
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.isFile
|
||||
import com.intellij.openapi.vfs.newvfs.events.VFileEvent
|
||||
import com.intellij.openapi.vfs.newvfs.events.VFileMoveEvent
|
||||
import com.intellij.openapi.vfs.newvfs.events.VFilePropertyChangeEvent
|
||||
@@ -24,6 +25,7 @@ import com.intellij.workspaceModel.core.fileIndex.impl.getOldAndNewUrls
|
||||
import com.intellij.workspaceModel.ide.impl.legacyBridge.watcher.VirtualFileUrlWatcher
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
import kotlin.io.path.Path
|
||||
|
||||
/**
|
||||
* This class is used to update entities in [WorkspaceModel] when files referenced from them are moved or renamed.
|
||||
@@ -39,6 +41,9 @@ internal class FileReferenceInWorkspaceEntityUpdater(private val project: Projec
|
||||
if (event is VFilePropertyChangeEvent) {
|
||||
collectChangedModuleStorePathsAfterDirectoryRename(event, changedModuleStorePaths)
|
||||
}
|
||||
if (event is VFileMoveEvent) {
|
||||
addChangedModuleStorePathAfterImlFileMove(event, changedModuleStorePaths)
|
||||
}
|
||||
val (oldUrl, newUrl) = getOldAndNewUrls(event)
|
||||
if (oldUrl != newUrl) {
|
||||
changedUrlsList.add(Pair(oldUrl, newUrl))
|
||||
@@ -108,5 +113,14 @@ internal class FileReferenceInWorkspaceEntityUpdater(private val project: Projec
|
||||
}
|
||||
}
|
||||
|
||||
private fun addChangedModuleStorePathAfterImlFileMove(event: VFileMoveEvent, changedModuleStorePaths: MutableList<Pair<Module, Path>>) {
|
||||
if (!event.file.isFile || event.requestor is StateStorage || event.file.extension != ModuleFileType.DEFAULT_EXTENSION) return
|
||||
val module = ModuleManager.getInstance(project).findModuleByName(event.file.nameWithoutExtension) ?: return
|
||||
|
||||
if (module.isLoaded && !module.isDisposed && module.moduleFilePath == event.oldPath) {
|
||||
changedModuleStorePaths.add(Pair(module, Path(event.newPath)))
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.isImlFile() = Files.getFileExtension(this) == ModuleFileType.DEFAULT_EXTENSION
|
||||
}
|
||||
@@ -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.workspaceModel.ide.impl.legacyBridge.watcher
|
||||
|
||||
import com.intellij.ide.highlighter.ModuleFileType
|
||||
import com.intellij.java.workspace.entities.JavaModuleSettingsEntity
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.project.Project
|
||||
@@ -150,16 +151,38 @@ private class EntitySourceFileWatcher<T : EntitySource>(
|
||||
for ((entitySource, entities) in entitiesMap) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val urlFromContainer = containerToUrl(entitySource as T)
|
||||
if (!FileUtil.startsWith(urlFromContainer, oldUrl)) continue
|
||||
|
||||
val newVfsUrl = virtualFileManager.getOrCreateFromUrl(newUrl + urlFromContainer.substring(oldUrl.length))
|
||||
val newEntitySource = createNewSource(entitySource, newVfsUrl)
|
||||
val newVfsUrl = when {
|
||||
FileUtil.startsWith(urlFromContainer, oldUrl) -> newUrl + urlFromContainer.substring(oldUrl.length)
|
||||
isImlFileOfModuleMoved(oldUrl, newUrl, urlFromContainer, entities) -> newUrl.substringBeforeLast('/')
|
||||
else -> continue
|
||||
}
|
||||
|
||||
val newEntitySource = createNewSource(entitySource, virtualFileManager.getOrCreateFromUrl(newVfsUrl))
|
||||
|
||||
entities.forEach { entity ->
|
||||
diff.modifyEntity(WorkspaceEntity.Builder::class.java, entity) { this.entitySource = newEntitySource }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects whether [oldUrl] points of an iml file of a module which was moved to a different directory.
|
||||
* We need to check this case separately because [ModuleEntity.entitySource] stores the path to the parent directory of iml file, not
|
||||
* path to iml file itself (see IJPL-158284).
|
||||
*/
|
||||
private fun isImlFileOfModuleMoved(
|
||||
oldUrl: String,
|
||||
newUrl: String,
|
||||
entitySourceUrl: String,
|
||||
entities: List<WorkspaceEntity>,
|
||||
): Boolean {
|
||||
if (!oldUrl.endsWith(ModuleFileType.DOT_DEFAULT_EXTENSION) || oldUrl.substringBeforeLast('/') != entitySourceUrl) return false
|
||||
val moduleFileName = oldUrl.substringAfterLast('/')
|
||||
if (moduleFileName != newUrl.substringAfterLast('/')) return false
|
||||
|
||||
val moduleNameFromUrl = moduleFileName.removeSuffix(ModuleFileType.DOT_DEFAULT_EXTENSION)
|
||||
return entities.any { (it as? ModuleEntity)?.name == moduleNameFromUrl }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user