mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 15:19:59 +07:00
[vfs] BAZEL-1041: avoid calls to UnixPath.toRealPath in WorkspaceModelImpl.replaceProjectModel
GitOrigin-RevId: 4769be486102e3026c3002a219b4fad6a107dfe7
This commit is contained in:
committed by
intellij-monorepo-bot
parent
70377c686e
commit
6927db41ac
@@ -239,8 +239,20 @@ public abstract class ArchiveFileSystem extends NewVirtualFileSystem {
|
||||
* or {@code null} if the local file is of incorrect type.
|
||||
*/
|
||||
public @Nullable VirtualFile findLocalByRootPath(@NotNull String rootPath) {
|
||||
return findLocalByRootPath(rootPath, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a local file of an archive which hosts a root with the given path
|
||||
* (i.e.: "jar:///path/to/jar.jar!/" => file:///path/to/jar.jar),
|
||||
* or {@code null} if the local file is of incorrect type.
|
||||
* @param pathCanonicallyCased {@code true} if the caller guarantees that the path is canonically cased in a case-insensitive FS
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
public @Nullable VirtualFile findLocalByRootPath(@NotNull String rootPath, boolean pathCanonicallyCased) {
|
||||
String localPath = extractLocalPath(rootPath);
|
||||
VirtualFile local = StandardFileSystems.local().findFileByPath(localPath);
|
||||
VirtualFileSystem localFS = StandardFileSystems.local();
|
||||
VirtualFile local = pathCanonicallyCased ? localFS.findFileByCanonicallyCasedPath(localPath) : localFS.findFileByPath(localPath);
|
||||
return local != null && isCorrectFileType(local) ? local : null;
|
||||
}
|
||||
|
||||
|
||||
@@ -75,4 +75,9 @@ public abstract class ManagingFS implements FileSystemInterface {
|
||||
|
||||
@ApiStatus.Internal
|
||||
protected abstract @NotNull <P, R> Function<P, R> accessDiskWithCheckCanceled(Function<? super P, ? extends R> function);
|
||||
|
||||
@ApiStatus.Internal
|
||||
public @Nullable NewVirtualFile findRoot(@NotNull String path, @NotNull NewVirtualFileSystem fs, boolean pathCanonicallyCased) {
|
||||
return findRoot(path, fs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,4 +108,9 @@ public abstract class NewVirtualFile extends VirtualFile implements VirtualFileW
|
||||
public @NotNull Iterable<VirtualFile> iterInDbChildrenWithoutLoadingVfsFromOtherProjects() {
|
||||
return iterInDbChildren();
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public @Nullable NewVirtualFile findChildByCanonicallyCasedName(@NotNull @NonNls String name) {
|
||||
return findChild(name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.intellij.platform.workspace.storage.impl.VersionedEntityStorageImpl
|
||||
import com.intellij.platform.workspace.storage.impl.query.Diff
|
||||
import com.intellij.platform.workspace.storage.query.CollectionQuery
|
||||
import com.intellij.platform.workspace.storage.query.StorageQuery
|
||||
import com.intellij.platform.workspace.storage.url.VirtualFileUrlManager
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.annotations.NonNls
|
||||
@@ -82,5 +83,15 @@ public interface WorkspaceModelInternal: WorkspaceModel {
|
||||
|
||||
@ApiStatus.Experimental
|
||||
public suspend fun <T> flowOfDiff(query: CollectionQuery<T>): Flow<Diff<T>>
|
||||
|
||||
/**
|
||||
* Returns an instance of [VirtualFileUrlManager] which always assumes
|
||||
* that the URL passed to [VirtualFileUrlManager.getOrCreateFromUrl] is canonically cased.
|
||||
* This is identical to just always calling [VirtualFileUrlManager.getOrCreateFromCanonicallyCasedUrl].
|
||||
* This speeds up replacing the project model on case-insensitive file systems (Windows, macOS).
|
||||
* @see getVirtualFileUrlManager
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
public fun getCanonicallyCasedVirtualFileUrlManager(): VirtualFileUrlManager
|
||||
}
|
||||
|
||||
|
||||
@@ -232,4 +232,18 @@ public abstract class VirtualFileManager implements ModificationTracker {
|
||||
|
||||
@ApiStatus.Internal
|
||||
public abstract @NotNull CharSequence getVFileName(int nameId);
|
||||
|
||||
/**
|
||||
* Searches for a file specified by the given {@link VirtualFile#getUrl() URL}.
|
||||
* The caller guarantees that the URL is canonically cased if the filesystem is case-insensitive.
|
||||
* This method is faster than {@link VirtualFileSystem#findFileByPath} for case-insensitive filesystems.
|
||||
*
|
||||
* @param url the URL to find file by
|
||||
* @return <code>{@link VirtualFile}</code> if the file was found, {@code null} otherwise
|
||||
* @see VirtualFileSystem#findFileByPath
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
public @Nullable VirtualFile findFileByCanonicallyCasedUrl(@NonNls @NotNull String url) {
|
||||
return findFileByUrl(url);
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.util.KeyedLazyInstance;
|
||||
import com.intellij.util.KeyedLazyInstanceEP;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -176,4 +177,19 @@ public abstract class VirtualFileSystem {
|
||||
public @Nullable Path getNioPath(@NotNull VirtualFile file) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for a file specified by the given path.
|
||||
* The caller guarantees that the path is canonically cased if the filesystem is case-insensitive.
|
||||
* The path is a string that uniquely identifies file within given {@link VirtualFileSystem}.
|
||||
* Format of the path depends on the concrete file system.
|
||||
* For {@code LocalFileSystem} it is an absolute path (both Unix- and Windows-style separator chars are allowed).
|
||||
*
|
||||
* @param path the path to find file by
|
||||
* @return a virtual file if found, {@code null} otherwise
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
public @Nullable VirtualFile findFileByCanonicallyCasedPath(@NotNull @NonNls String path) {
|
||||
return findFileByPath(path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -356,20 +356,32 @@ public class VirtualFileManagerImpl extends VirtualFileManager implements Dispos
|
||||
|
||||
@Override
|
||||
public VirtualFile findFileByUrl(@NotNull String url) {
|
||||
return findByUrl(url, false);
|
||||
return findByUrl(url, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VirtualFile refreshAndFindFileByUrl(@NotNull String url) {
|
||||
return findByUrl(url, true);
|
||||
return findByUrl(url, true, false);
|
||||
}
|
||||
|
||||
private @Nullable VirtualFile findByUrl(@NotNull String url, boolean refresh) {
|
||||
@Override
|
||||
@ApiStatus.Internal
|
||||
public @Nullable VirtualFile findFileByCanonicallyCasedUrl(@NotNull String url) {
|
||||
return findByUrl(url, false, true);
|
||||
}
|
||||
|
||||
private @Nullable VirtualFile findByUrl(@NotNull String url, boolean refresh, boolean urlCanonicallyCased) {
|
||||
int protocolSepIndex = url.indexOf(URLUtil.SCHEME_SEPARATOR);
|
||||
VirtualFileSystem fileSystem = protocolSepIndex < 0 ? null : getFileSystem(url.substring(0, protocolSepIndex));
|
||||
if (fileSystem == null) return null;
|
||||
String path = url.substring(protocolSepIndex + URLUtil.SCHEME_SEPARATOR.length());
|
||||
return refresh ? fileSystem.refreshAndFindFileByPath(path) : fileSystem.findFileByPath(path);
|
||||
if (refresh) {
|
||||
return fileSystem.refreshAndFindFileByPath(path);
|
||||
} else if (urlCanonicallyCased) {
|
||||
return fileSystem.findFileByCanonicallyCasedPath(path);
|
||||
} else {
|
||||
return fileSystem.findFileByPath(path);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -37,7 +37,18 @@ public final class VfsImplUtil {
|
||||
private VfsImplUtil() { }
|
||||
|
||||
public static @Nullable NewVirtualFile findFileByPath(@NotNull NewVirtualFileSystem vfs, @NotNull String path) {
|
||||
Pair<NewVirtualFile, Iterable<String>> rootAndPath = prepare(vfs, path);
|
||||
return findFileByPath(vfs, path, false);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static @Nullable NewVirtualFile findFileByCanonicallyCasedPath(@NotNull NewVirtualFileSystem vfs, @NotNull String path) {
|
||||
return findFileByPath(vfs, path, true);
|
||||
}
|
||||
|
||||
private static @Nullable NewVirtualFile findFileByPath(@NotNull NewVirtualFileSystem vfs,
|
||||
@NotNull String path,
|
||||
boolean pathCanonicallyCased) {
|
||||
Pair<NewVirtualFile, Iterable<String>> rootAndPath = prepare(vfs, path, pathCanonicallyCased);
|
||||
if (rootAndPath == null) return null;
|
||||
|
||||
NewVirtualFile file = rootAndPath.first;
|
||||
@@ -53,7 +64,7 @@ public final class VfsImplUtil {
|
||||
}
|
||||
}
|
||||
else {
|
||||
file = file.findChild(pathElement);
|
||||
file = pathCanonicallyCased ? file.findChildByCanonicallyCasedName(pathElement) : file.findChild(pathElement);
|
||||
}
|
||||
|
||||
if (file == null) return null;
|
||||
@@ -67,7 +78,7 @@ public final class VfsImplUtil {
|
||||
}
|
||||
|
||||
public static @NotNull Pair<NewVirtualFile, NewVirtualFile> findCachedFileByPath(@NotNull NewVirtualFileSystem vfs, @NotNull String path) {
|
||||
Pair<NewVirtualFile, Iterable<String>> rootAndPath = prepare(vfs, path);
|
||||
Pair<NewVirtualFile, Iterable<String>> rootAndPath = prepare(vfs, path, false);
|
||||
if (rootAndPath == null) return Pair.empty();
|
||||
|
||||
NewVirtualFile file = rootAndPath.first;
|
||||
@@ -98,7 +109,7 @@ public final class VfsImplUtil {
|
||||
}
|
||||
|
||||
public static @Nullable NewVirtualFile refreshAndFindFileByPath(@NotNull NewVirtualFileSystem vfs, @NotNull String path) {
|
||||
Pair<NewVirtualFile, Iterable<String>> rootAndPath = prepare(vfs, path);
|
||||
Pair<NewVirtualFile, Iterable<String>> rootAndPath = prepare(vfs, path, false);
|
||||
if (rootAndPath == null) return null;
|
||||
|
||||
NewVirtualFile file = rootAndPath.first;
|
||||
@@ -128,7 +139,7 @@ public final class VfsImplUtil {
|
||||
@ApiStatus.Experimental
|
||||
public static void refreshAndFindFileByPath(@NotNull NewVirtualFileSystem vfs, @NotNull String path, @NotNull Consumer<? super @Nullable NewVirtualFile> consumer) {
|
||||
ProcessIOExecutorService.INSTANCE.execute(() -> {
|
||||
Pair<NewVirtualFile, Iterable<String>> rootAndPath = prepare(vfs, path);
|
||||
Pair<NewVirtualFile, Iterable<String>> rootAndPath = prepare(vfs, path, false);
|
||||
if (rootAndPath == null) {
|
||||
consumer.accept(null);
|
||||
}
|
||||
@@ -175,8 +186,10 @@ public final class VfsImplUtil {
|
||||
}
|
||||
}
|
||||
|
||||
private static @Nullable Pair<NewVirtualFile, Iterable<String>> prepare(@NotNull NewVirtualFileSystem vfs, @NotNull String path) {
|
||||
PathFromRoot pair = extractRootFromPath(vfs, path);
|
||||
private static @Nullable Pair<NewVirtualFile, Iterable<String>> prepare(@NotNull NewVirtualFileSystem vfs,
|
||||
@NotNull String path,
|
||||
boolean pathCanonicallyCased) {
|
||||
PathFromRoot pair = extractRootFromPath(vfs, path, pathCanonicallyCased);
|
||||
if (pair == null) return null;
|
||||
Iterable<String> parts = StringUtil.tokenize(pair.pathFromRoot(), FILE_SEPARATORS);
|
||||
return Pair.create(pair.root(), parts);
|
||||
@@ -189,6 +202,10 @@ public final class VfsImplUtil {
|
||||
* {@code extractRootFromPath(JarFileSystem.getInstance, "/temp/temp.jar!/com/foo/bar")} -> ("/temp/temp.jar!/", "/com/foo/bar")
|
||||
*/
|
||||
public static PathFromRoot extractRootFromPath(@NotNull NewVirtualFileSystem vfs, @NotNull String path) {
|
||||
return extractRootFromPath(vfs, path, false);
|
||||
}
|
||||
|
||||
private static PathFromRoot extractRootFromPath(@NotNull NewVirtualFileSystem vfs, @NotNull String path, boolean pathCanonicallyCased) {
|
||||
String normalizedPath = NewVirtualFileSystem.normalizePath(vfs, path);
|
||||
if (normalizedPath == null || normalizedPath.isBlank()) {
|
||||
return null;
|
||||
@@ -200,7 +217,7 @@ public final class VfsImplUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
NewVirtualFile root = ManagingFS.getInstance().findRoot(rootPath, vfs);
|
||||
NewVirtualFile root = ManagingFS.getInstance().findRoot(rootPath, vfs, pathCanonicallyCased);
|
||||
if (root == null || !root.exists()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.impl.ZipHandler;
|
||||
import com.intellij.openapi.vfs.impl.ZipHandlerBase;
|
||||
import com.intellij.openapi.vfs.newvfs.VfsImplUtil;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
@@ -79,6 +80,12 @@ public class JarFileSystemImpl extends JarFileSystem implements IntegrityCheckCa
|
||||
return isValid(path) ? VfsImplUtil.refreshAndFindFileByPath(this, path) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ApiStatus.Internal
|
||||
public @Nullable VirtualFile findFileByCanonicallyCasedPath(@NotNull String path) {
|
||||
return isValid(path) ? VfsImplUtil.findFileByCanonicallyCasedPath(this, path) : null;
|
||||
}
|
||||
|
||||
private static boolean isValid(String path) {
|
||||
return path.contains(JAR_SEPARATOR);
|
||||
}
|
||||
|
||||
@@ -64,6 +64,11 @@ public abstract class LocalFileSystemBase extends LocalFileSystem {
|
||||
return VfsImplUtil.refreshAndFindFileByPath(this, path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable VirtualFile findFileByCanonicallyCasedPath(@NotNull String path) {
|
||||
return VfsImplUtil.findFileByCanonicallyCasedPath(this, path);
|
||||
}
|
||||
|
||||
protected static @NotNull String toIoPath(@NotNull VirtualFile file) {
|
||||
var path = file.getPath();
|
||||
if (path.length() == 2 && SystemInfo.isWindows && OSAgnosticPathUtil.startsWithWindowsDrive(path)) {
|
||||
|
||||
@@ -79,11 +79,12 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
|
||||
private @Nullable VirtualFileSystemEntry findChild(@NotNull String name,
|
||||
boolean doRefresh,
|
||||
boolean ensureCanonicalName,
|
||||
boolean nameCanonicallyCased,
|
||||
@NotNull NewVirtualFileSystem fs) {
|
||||
owningPersistentFS().incrementFindChildByNameCount();
|
||||
|
||||
updateCaseSensitivityIfUnknown(name);
|
||||
VirtualFileSystemEntry result = doFindChild(name, ensureCanonicalName, fs, isCaseSensitive());
|
||||
VirtualFileSystemEntry result = doFindChild(name, ensureCanonicalName, fs, isCaseSensitive(), nameCanonicallyCased);
|
||||
|
||||
//noinspection UseVirtualFileEquals
|
||||
if (result == NULL_VIRTUAL_FILE) {
|
||||
@@ -91,7 +92,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
|
||||
}
|
||||
else if (result != null && doRefresh && fs.isDirectory(result) != result.isDirectory()) {
|
||||
RefreshQueue.getInstance().refresh(false, false, null, result);
|
||||
result = findChild(name, false, ensureCanonicalName, fs);
|
||||
result = findChild(name, false, ensureCanonicalName, nameCanonicallyCased, fs);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -112,7 +113,8 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
|
||||
private @Nullable VirtualFileSystemEntry doFindChild(@NotNull String name,
|
||||
boolean ensureCanonicalName,
|
||||
@NotNull NewVirtualFileSystem fs,
|
||||
boolean isCaseSensitive) {
|
||||
boolean isCaseSensitive,
|
||||
boolean nameCanonicallyCased) {
|
||||
if (name.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
@@ -137,13 +139,14 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
|
||||
return NULL_VIRTUAL_FILE;
|
||||
}
|
||||
|
||||
return findInPersistence(name, ensureCanonicalName, fs, isCaseSensitive);
|
||||
return findInPersistence(name, ensureCanonicalName, fs, isCaseSensitive, nameCanonicallyCased);
|
||||
}
|
||||
|
||||
private @Nullable VirtualFileSystemEntry findInPersistence(@NotNull String name,
|
||||
boolean ensureCanonicalName,
|
||||
@NotNull NewVirtualFileSystem fs,
|
||||
boolean isCaseSensitive) {
|
||||
boolean isCaseSensitive,
|
||||
boolean nameCanonicallyCased) {
|
||||
VirtualFileSystemEntry child;
|
||||
synchronized (myData) {
|
||||
// maybe another doFindChild() sneaked in the middle
|
||||
@@ -155,7 +158,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
|
||||
|
||||
// do not extract getId outside the synchronized block since it will cause a concurrency problem.
|
||||
PersistentFS pfs = owningPersistentFS();
|
||||
ChildInfo childInfo = pfs.findChildInfo(this, name, fs);
|
||||
ChildInfo childInfo = pfs.findChildInfo(this, name, fs, nameCanonicallyCased);
|
||||
if (childInfo == null) {
|
||||
myData.addAdoptedName(name, isCaseSensitive);
|
||||
return null;
|
||||
@@ -354,7 +357,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
|
||||
|
||||
@Override
|
||||
public @Nullable NewVirtualFile refreshAndFindChild(@NotNull String name) {
|
||||
return findChild(name, true, true, getFileSystem());
|
||||
return findChild(name, true, true, false, getFileSystem());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -394,7 +397,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
|
||||
String[] names = owningPersistentFS().listPersisted(this);
|
||||
NewVirtualFileSystem fs = getFileSystem();
|
||||
for (String name : names) {
|
||||
findChild(name, false, false, fs);
|
||||
findChild(name, false, false, false, fs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -537,7 +540,13 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
|
||||
|
||||
@Override
|
||||
public @Nullable VirtualFileSystemEntry findChild(@NotNull String name) {
|
||||
return findChild(name, false, true, getFileSystem());
|
||||
return findChild(name, false, true, false, getFileSystem());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ApiStatus.Internal
|
||||
public @Nullable NewVirtualFile findChildByCanonicallyCasedName(@NotNull String name) {
|
||||
return findChild(name, false, true, true, getFileSystem());
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
@@ -562,7 +571,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
|
||||
|
||||
PersistentFSImpl persistence = owningPersistentFS();
|
||||
String name = persistence.getName(id);
|
||||
VirtualFileSystemEntry fileByName = findChild(name, false, false, getFileSystem());
|
||||
VirtualFileSystemEntry fileByName = findChild(name, false, false, false, getFileSystem());
|
||||
if (fileByName != null && fileByName.getId() != id) {
|
||||
// a child with the same name and different ID was recreated after a refresh session -
|
||||
// it doesn't make sense to check it earlier because it is executed outside the VFS' read/write lock
|
||||
|
||||
@@ -64,7 +64,7 @@ public abstract class PersistentFS extends ManagingFS {
|
||||
public abstract @NotNull List<? extends ChildInfo> listAll(@NotNull VirtualFile parent);
|
||||
|
||||
@ApiStatus.Internal
|
||||
public abstract ChildInfo findChildInfo(@NotNull VirtualFile parent, @NotNull String childName, @NotNull NewVirtualFileSystem fs);
|
||||
public abstract ChildInfo findChildInfo(@NotNull VirtualFile parent, @NotNull String childName, @NotNull NewVirtualFileSystem fs, boolean childNameCanonicallyCased);
|
||||
|
||||
public abstract @NotNull String getName(int id);
|
||||
|
||||
|
||||
@@ -36,7 +36,6 @@ import com.intellij.openapi.vfs.newvfs.persistent.recovery.VFSRecoveryInfo;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
|
||||
import com.intellij.platform.diagnostic.telemetry.PlatformScopesKt;
|
||||
import com.intellij.platform.diagnostic.telemetry.TelemetryManager;
|
||||
import com.intellij.openapi.util.io.ContentTooBigException;
|
||||
import com.intellij.util.*;
|
||||
import com.intellij.util.concurrency.ThreadingAssertions;
|
||||
import com.intellij.util.containers.*;
|
||||
@@ -548,7 +547,8 @@ public final class PersistentFSImpl extends PersistentFS implements Disposable {
|
||||
@ApiStatus.Internal
|
||||
public ChildInfo findChildInfo(@NotNull VirtualFile parent,
|
||||
@NotNull String childName,
|
||||
@NotNull NewVirtualFileSystem fs) {
|
||||
@NotNull NewVirtualFileSystem fs,
|
||||
boolean childNameCanonicallyCased) {
|
||||
checkReadAccess();
|
||||
|
||||
int parentId = fileId(parent);
|
||||
@@ -583,7 +583,7 @@ public final class PersistentFSImpl extends PersistentFS implements Disposable {
|
||||
// or it is the new file, and VFS hasn't received the update yet
|
||||
|
||||
String canonicalName;
|
||||
if (parent.isCaseSensitive()) {
|
||||
if (childNameCanonicallyCased || parent.isCaseSensitive()) {
|
||||
canonicalName = childName;
|
||||
}
|
||||
else {
|
||||
@@ -1593,6 +1593,12 @@ public final class PersistentFSImpl extends PersistentFS implements Disposable {
|
||||
|
||||
@Override
|
||||
public @Nullable VirtualFileSystemEntry findRoot(@NotNull String path, @NotNull NewVirtualFileSystem fs) {
|
||||
return findRoot(path, fs, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ApiStatus.Internal
|
||||
public @Nullable VirtualFileSystemEntry findRoot(@NotNull String path, @NotNull NewVirtualFileSystem fs, boolean pathCanonicallyCased) {
|
||||
if (!myConnected.get()) {
|
||||
LOG.info("VFS disconnected. Can't provide root for " + path + " in " + fs);
|
||||
return null;
|
||||
@@ -1617,7 +1623,7 @@ public final class PersistentFSImpl extends PersistentFS implements Disposable {
|
||||
// path(/x/y/z.jar!/) -> localFile(/x/y/z.jar) -> rootPath(/x/y/z.jar!/)
|
||||
// So this branch is basically assigns rootName to jar-file name (instead of root path)
|
||||
// and attributes to _archive_ attributes, instead of file attributes
|
||||
VirtualFile localFile = afs.findLocalByRootPath(path);
|
||||
VirtualFile localFile = afs.findLocalByRootPath(path, pathCanonicallyCased);
|
||||
if (localFile == null) return null;
|
||||
rootName = localFile.getName();
|
||||
rootPath = afs.getRootPathByLocal(localFile);// '/x/y/z.jar' -> '/x/y/z.jar!/'
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// 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
|
||||
|
||||
import com.intellij.platform.workspace.storage.url.VirtualFileUrl
|
||||
import com.intellij.platform.workspace.storage.url.VirtualFileUrlManager
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Internal
|
||||
class CanonicallyCasedVirtualFileUrlManager(delegate: VirtualFileUrlManager) : VirtualFileUrlManager by delegate {
|
||||
override fun getOrCreateFromUrl(uri: String): VirtualFileUrl = getOrCreateFromCanonicallyCasedUrl(uri)
|
||||
}
|
||||
@@ -11,7 +11,7 @@ class IdeVirtualFileUrlManagerImpl : VirtualFileUrlManagerImpl() {
|
||||
override val virtualFileUrlImplementationClass: Class<out VirtualFileUrl>
|
||||
get() = VirtualFileUrlBridge::class.java
|
||||
|
||||
override fun createVirtualFileUrl(id: Int, manager: VirtualFileUrlManagerImpl): VirtualFileUrlImpl {
|
||||
return VirtualFileUrlBridge(id, manager)
|
||||
override fun createVirtualFileUrl(id: Int, manager: VirtualFileUrlManagerImpl, urlCanonicallyCased: Boolean): VirtualFileUrlImpl {
|
||||
return VirtualFileUrlBridge(id, manager, urlCanonicallyCased)
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,11 @@ import com.intellij.platform.workspace.storage.impl.url.VirtualFileUrlManagerImp
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Internal
|
||||
class VirtualFileUrlBridge(id: Int, manager: VirtualFileUrlManagerImpl) :
|
||||
class VirtualFileUrlBridge(
|
||||
id: Int,
|
||||
manager: VirtualFileUrlManagerImpl,
|
||||
private val urlCanonicallyCased: Boolean = false,
|
||||
) :
|
||||
VirtualFileUrlImpl(id, manager), VirtualFilePointer {
|
||||
@Volatile
|
||||
private var file: VirtualFile? = null
|
||||
@@ -38,7 +42,11 @@ class VirtualFileUrlBridge(id: Int, manager: VirtualFileUrlManagerImpl) :
|
||||
val cachedResults = file
|
||||
return if (timestamp == fileManager.modificationCount) cachedResults
|
||||
else {
|
||||
file = fileManager.findFileByUrl(url)
|
||||
file = if (urlCanonicallyCased) {
|
||||
fileManager.findFileByCanonicallyCasedUrl(url)
|
||||
} else {
|
||||
fileManager.findFileByUrl(url)
|
||||
}
|
||||
timestampOfCachedFiles = fileManager.modificationCount
|
||||
file
|
||||
}
|
||||
|
||||
@@ -67,6 +67,8 @@ open class WorkspaceModelImpl(private val project: Project, private val cs: Coro
|
||||
|
||||
private val virtualFileManager: VirtualFileUrlManager = IdeVirtualFileUrlManagerImpl()
|
||||
|
||||
private val canonicallyCasedVirtualFileUrlManager = CanonicallyCasedVirtualFileUrlManager(virtualFileManager)
|
||||
|
||||
override val currentSnapshot: ImmutableEntityStorage
|
||||
get() = entityStorage.current
|
||||
|
||||
@@ -134,6 +136,8 @@ open class WorkspaceModelImpl(private val project: Project, private val cs: Coro
|
||||
|
||||
override fun getVirtualFileUrlManager(): VirtualFileUrlManager = virtualFileManager
|
||||
|
||||
override fun getCanonicallyCasedVirtualFileUrlManager(): VirtualFileUrlManager = canonicallyCasedVirtualFileUrlManager
|
||||
|
||||
/**
|
||||
* Used only in Rider IDE
|
||||
*/
|
||||
|
||||
@@ -416,4 +416,5 @@ com.intellij.platform.workspace.storage.url.VirtualFileUrlIndex
|
||||
com.intellij.platform.workspace.storage.url.VirtualFileUrlManager
|
||||
- a:findByUrl(java.lang.String):com.intellij.platform.workspace.storage.url.VirtualFileUrl
|
||||
- a:fromPath(java.lang.String):com.intellij.platform.workspace.storage.url.VirtualFileUrl
|
||||
- *a:getOrCreateFromCanonicallyCasedUrl(java.lang.String):com.intellij.platform.workspace.storage.url.VirtualFileUrl
|
||||
- a:getOrCreateFromUrl(java.lang.String):com.intellij.platform.workspace.storage.url.VirtualFileUrl
|
||||
|
||||
@@ -28,6 +28,11 @@ public open class VirtualFileUrlManagerImpl : VirtualFileUrlManager {
|
||||
return add(uri)
|
||||
}
|
||||
|
||||
override fun getOrCreateFromCanonicallyCasedUrl(uri: String): VirtualFileUrl {
|
||||
if (uri.isEmpty()) return getEmptyUrl()
|
||||
return add(uri, urlCanonicallyCased = true)
|
||||
}
|
||||
|
||||
override fun findByUrl(uri: String): VirtualFileUrl? {
|
||||
return findBySegments(splitNames(uri))
|
||||
}
|
||||
@@ -103,19 +108,23 @@ public open class VirtualFileUrlManagerImpl : VirtualFileUrlManager {
|
||||
public open val virtualFileUrlImplementationClass: Class<out VirtualFileUrl>
|
||||
get() = VirtualFileUrlImpl::class.java
|
||||
|
||||
protected open fun createVirtualFileUrl(id: Int, manager: VirtualFileUrlManagerImpl): VirtualFileUrl {
|
||||
protected open fun createVirtualFileUrl(
|
||||
id: Int,
|
||||
manager: VirtualFileUrlManagerImpl,
|
||||
urlCanonicallyCased: Boolean = false,
|
||||
): VirtualFileUrl {
|
||||
return VirtualFileUrlImpl(id, manager)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
public fun getCachedVirtualFileUrls(): List<VirtualFileUrl> = id2NodeMapping.values.mapNotNull(FilePathNode::getCachedVirtualFileUrl)
|
||||
|
||||
internal fun add(path: String, parentNode: FilePathNode? = null): VirtualFileUrl {
|
||||
internal fun add(path: String, parentNode: FilePathNode? = null, urlCanonicallyCased: Boolean = false): VirtualFileUrl {
|
||||
val segments = splitNames(path)
|
||||
return addSegments(parentNode, segments)
|
||||
return addSegments(parentNode, segments, urlCanonicallyCased)
|
||||
}
|
||||
|
||||
private fun addSegments(parentNode: FilePathNode?, segments: List<String>): VirtualFileUrl {
|
||||
private fun addSegments(parentNode: FilePathNode?, segments: List<String>, urlCanonicallyCased: Boolean = false): VirtualFileUrl {
|
||||
var latestNode: FilePathNode? = parentNode ?: findRootNode(segments.first())
|
||||
val latestElement = segments.size - 1
|
||||
for (index in segments.indices) {
|
||||
@@ -128,7 +137,7 @@ public open class VirtualFileUrlManagerImpl : VirtualFileUrlManager {
|
||||
// If it's the latest name of folder or files, save entity Id as node value
|
||||
if (index == latestElement) {
|
||||
rootNode.addChild(newNode)
|
||||
return newNode.getVirtualFileUrl(this)
|
||||
return newNode.getVirtualFileUrl(this, urlCanonicallyCased)
|
||||
}
|
||||
latestNode = newNode
|
||||
rootNode.addChild(newNode)
|
||||
@@ -138,7 +147,7 @@ public open class VirtualFileUrlManagerImpl : VirtualFileUrlManager {
|
||||
// Handling reuse of the root node
|
||||
if (latestNode === findRootNode(latestNode.contentId) && index == 0) {
|
||||
if (latestNode.contentId == nameId) {
|
||||
if (latestElement == 0) return latestNode.getVirtualFileUrl(this)
|
||||
if (latestElement == 0) return latestNode.getVirtualFileUrl(this, urlCanonicallyCased)
|
||||
continue
|
||||
}
|
||||
}
|
||||
@@ -151,11 +160,11 @@ public open class VirtualFileUrlManagerImpl : VirtualFileUrlManager {
|
||||
latestNode.addChild(newNode)
|
||||
latestNode = newNode
|
||||
// If it's the latest name of folder or files, save entity Id as node value
|
||||
if (index == latestElement) return newNode.getVirtualFileUrl(this)
|
||||
if (index == latestElement) return newNode.getVirtualFileUrl(this, urlCanonicallyCased)
|
||||
}
|
||||
else {
|
||||
// If it's the latest name of folder or files, save entity Id as node value
|
||||
if (index == latestElement) return node.getVirtualFileUrl(this)
|
||||
if (index == latestElement) return node.getVirtualFileUrl(this, urlCanonicallyCased)
|
||||
latestNode = node
|
||||
}
|
||||
}
|
||||
@@ -299,10 +308,13 @@ public open class VirtualFileUrlManagerImpl : VirtualFileUrlManager {
|
||||
children?.remove(node)
|
||||
}
|
||||
|
||||
fun getVirtualFileUrl(virtualFileUrlManager: VirtualFileUrlManagerImpl): VirtualFileUrl {
|
||||
fun getVirtualFileUrl(
|
||||
virtualFileUrlManager: VirtualFileUrlManagerImpl,
|
||||
urlCanonicallyCased: Boolean = false,
|
||||
): VirtualFileUrl {
|
||||
val cachedValue = virtualFileUrl
|
||||
if (cachedValue != null) return cachedValue
|
||||
val url = virtualFileUrlManager.createVirtualFileUrl(nodeId, virtualFileUrlManager)
|
||||
val url = virtualFileUrlManager.createVirtualFileUrl(nodeId, virtualFileUrlManager, urlCanonicallyCased)
|
||||
virtualFileUrl = url
|
||||
return url
|
||||
}
|
||||
|
||||
@@ -21,6 +21,13 @@ public interface VirtualFileUrlManager {
|
||||
*/
|
||||
public fun getOrCreateFromUrl(uri: String): VirtualFileUrl
|
||||
|
||||
/**
|
||||
* Same as [getOrCreateFromUrl], but the caller guarantees that [uri] is canonically cased if the filesystem is case-insensitive.
|
||||
* This makes modifying the workspace model quicker on case-insensitive filesystems (Windows, macOS).
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
public fun getOrCreateFromCanonicallyCasedUrl(uri: String): VirtualFileUrl
|
||||
|
||||
/**
|
||||
* Returns an existing instance of [VirtualFileUrl] for the given URL or `null` if no instance was registered.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user