[eel][wsl] IJPL-196973 Compile error open target not source in wsl

- Split EelDescriptor in to EelDescriptor and the EelMachine
- Add EelPathBoundDescriptor

GitOrigin-RevId: e0b7e5d5f3532682498466642b034e1892ef3cda
This commit is contained in:
Andrii Zinchenko
2025-07-18 12:29:12 +02:00
committed by intellij-monorepo-bot
parent cc05795d91
commit 2fa1af099c
49 changed files with 422 additions and 360 deletions

View File

@@ -33,7 +33,7 @@ import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.platform.eel.EelDescriptor;
import com.intellij.platform.eel.EelMachine;
import com.intellij.platform.eel.provider.EelProviderUtil;
import com.intellij.util.Processor;
import com.intellij.util.SystemProperties;
@@ -676,7 +676,7 @@ public final class JarRepositoryManager {
final List<OrderRoot> result = new ArrayList<>();
final VirtualFileManager manager = VirtualFileManager.getInstance();
String repositoryPath = getJPSLocalMavenRepositoryForIdeaProject(project).toString();
EelDescriptor targetRepositoryDescriptor = EelProviderUtil.getEelDescriptor(Path.of(repositoryPath));
final EelMachine targetRepositoryMachine = EelProviderUtil.getEelDescriptor(Path.of(repositoryPath)).getMachine();
for (Artifact each : artifacts) {
long ms = System.currentTimeMillis();
try {
@@ -688,7 +688,7 @@ public final class JarRepositoryManager {
FileUtil.copy(repoFile, toFile);
}
}
else if (!targetRepositoryDescriptor.equals(EelProviderUtil.getEelDescriptor(Path.of(each.getFile().getPath())))) {
else if (!targetRepositoryMachine.equals(EelProviderUtil.getEelDescriptor(Path.of(each.getFile().getPath())).getMachine())) {
// if .m2 is located remotely, then we need to copy the files to the remote location
String suffix = repoFile.getAbsolutePath().substring(repositoryPath.length());
String actualPath = repositoryPath + suffix;

View File

@@ -5,6 +5,7 @@ import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.diagnostic.trace
import com.intellij.openapi.project.Project
import com.intellij.platform.eel.EelDescriptor
import com.intellij.platform.eel.EelPathBoundDescriptor
import com.intellij.platform.eel.annotations.MultiRoutingFileSystemPath
import com.intellij.platform.eel.isPosix
import com.intellij.platform.eel.path.EelPath
@@ -27,110 +28,45 @@ import java.nio.file.Path
*
* @throws IllegalArgumentException if the Eel API for [this] does not have a corresponding [java.nio.file.FileSystem]
*/
@Throws(IllegalArgumentException::class)
@ApiStatus.Internal
fun EelPath.asNioPath(): @MultiRoutingFileSystemPath Path =
asNioPath(null)
/**
* Converts [EelPath], which is likely a path from a remote machine, to a [Path] for the local machine.
*
* The [project] is important for targets like WSL: paths like `\\wsl.localhost\Ubuntu` and `\\wsl$\Ubuntu` are equivalent,
* but they have different string representation, and some functionality is confused when `wsl.localhost` and `wsl$` are confused.
* This function helps to choose the proper root according to the base path of the project.
*
* Example:
* ```kotlin
* val eelPath = EelPath.parse("/home/user", getWslDescriptorSomewhere())
*
* eelPath.asNioPath(getProject1()) ==
* Path.of("""\\wsl.localhost\Ubuntu\home\user""")
*
* eelPath.asNioPath(getProject2()) ==
* Path.of("""\\wsl$\Ubuntu\home\user""")
* ```
*/
@Throws(IllegalArgumentException::class)
@ApiStatus.Internal
fun EelPath.asNioPath(project: Project?): @MultiRoutingFileSystemPath Path {
return asNioPathOrNull(project)
fun EelPath.asNioPath(): @MultiRoutingFileSystemPath Path {
return asNioPathOrNull()
?: throw IllegalArgumentException("Could not convert $this to NIO path, descriptor is $descriptor")
}
private val EelDescriptor.rootsInternal: List<Path>?
get() = EelProvider.EP_NAME.extensionList
.firstNotNullOfOrNull { eelProvider -> eelProvider.getCustomRoots(this) }
?.takeIf { it.isNotEmpty() }
?.map(Path::of)
@get:ApiStatus.Internal
val EelDescriptor.roots: List<Path> get() = rootsInternal ?: error("No roots for $this")
@Throws(IllegalArgumentException::class)
@ApiStatus.Internal
@Deprecated("Use asNioPath() instead", replaceWith = ReplaceWith("asNioPath()"))
fun EelPath.asNioPath(project: Project?): @MultiRoutingFileSystemPath Path {
return asNioPath()
}
/** See docs for [asNioPath] */
@Deprecated("It never returns null anymore")
@ApiStatus.Internal
fun EelPath.asNioPathOrNull(): @MultiRoutingFileSystemPath Path? =
asNioPathOrNull(null)
/** See docs for [asNioPath] */
@Deprecated("It never returns null anymore")
@ApiStatus.Internal
fun EelPath.asNioPathOrNull(project: Project?): @MultiRoutingFileSystemPath Path? {
fun EelPath.asNioPathOrNull(): @MultiRoutingFileSystemPath Path? {
if (descriptor === LocalEelDescriptor) {
return Path.of(toString())
}
val eelRoots = descriptor.rootsInternal
// Comparing strings because `Path.of("\\wsl.localhost\distro\").equals(Path.of("\\wsl$\distro\")) == true`
// If the project works with `wsl$` paths, this function must return `wsl$` paths, and the same for `wsl.localhost`.
val projectBasePathNio = project?.basePath?.let(Path::of)
val root = (descriptor as? EelPathBoundDescriptor)?.rootPath ?: return null
LOG.trace {
"asNioPathOrNull():" +
" path=$this" +
" project=$project" +
" descriptor=$descriptor" +
" eelRoots=${eelRoots?.joinToString(prefix = "[", postfix = "]", separator = ", ") { path -> "$path (${path.javaClass.name})" }}" +
" projectBasePathNio=$projectBasePathNio"
" rootPath=$root"
}
if (eelRoots == null) {
return null
}
val eelRoot: Path = asNioPathOrNullImpl(projectBasePathNio, eelRoots, this)
@MultiRoutingFileSystemPath
val result = parts.fold(eelRoot, Path::resolve)
val result = parts.fold(root, Path::resolve)
LOG.trace {
"asNioPathOrNull(): path=$this project=$project result=$result"
"asNioPathOrNull(): path=$this basePath=$root result=$result"
}
return result
}
/**
* Choosing between not only paths belonging to the project, but also paths with the same root, e.g., mount drive on Windows.
* It's possible that some code in the project tries to access the file outside the project, f.i., accessing `~/.m2`.
*
* This function also tries to preserve the case in case-insensitive file systems, because some other parts of the IDE
* may compare paths as plain string despite the incorrectness of that approach.
*/
private fun asNioPathOrNullImpl(basePath: Path?, eelRoots: Collection<Path>, sourcePath: EelPath): Path {
if (basePath != null) {
for (eelRoot in eelRoots) {
if (basePath.startsWith(eelRoot)) {
var resultPath = basePath.root
if (eelRoot.nameCount > 0) {
resultPath = resultPath.resolve(basePath.subpath(0, eelRoot.nameCount))
}
return resultPath
}
}
}
return eelRoots.first()
}
/**
* Converts a path generated by the default NIO filesystem to [EelPath].
*
@@ -154,18 +90,10 @@ fun Path.asEelPath(): EelPath {
if (fileSystem != FileSystems.getDefault()) {
throw IllegalArgumentException("Could not convert $this to EelPath: the path does not belong to the default NIO FileSystem")
}
val (descriptor, eelProvider) =
EelProvider.EP_NAME.extensionList
.firstNotNullOfOrNull { eelProvider ->
eelProvider.getEelDescriptor(this)?.to(eelProvider)
}
?: return EelPath.parse(toString(), LocalEelDescriptor)
val descriptor = EelProvider.EP_NAME.extensionList.firstNotNullOfOrNull { eelProvider -> eelProvider.getEelDescriptor(this) }
?: return EelPath.parse(toString(), LocalEelDescriptor)
val root =
eelProvider.getCustomRoots(descriptor)
?.map { rootStr -> Path.of(rootStr) }
?.firstOrNull { rootCandidate -> startsWith(rootCandidate) }
?: throw NoSuchElementException("No roots for $descriptor match $this: ${eelProvider.getCustomRoots(descriptor)}")
val root = (descriptor as? EelPathBoundDescriptor)?.rootPath ?: throw NoSuchElementException("Cannot find a root for $this")
val relative = root.relativize(this)
if (descriptor.osFamily.isPosix) {

View File

@@ -90,31 +90,35 @@ val localEel: LocalEelApi by lazy {
@ApiStatus.Internal
fun EelDescriptor.upgradeBlocking(): EelApi = toEelApiBlocking()
fun EelMachine.toEelApiBlocking(): EelApi = runBlockingMaybeCancellable { toEelApi() }
@ApiStatus.Experimental
fun EelDescriptor.toEelApiBlocking(): EelApi {
if (this === LocalEelDescriptor) return localEel
return runBlockingMaybeCancellable { toEelApi() }
}
@ApiStatus.Experimental
data object LocalEelDescriptor : EelDescriptor {
data object LocalEelMachine : EelMachine {
private val LOG = logger<LocalEelDescriptor>()
override val userReadableDescription: @NonNls String = "Local: ${System.getProperty("os.name")}"
override val name: @NonNls String = "Local: ${System.getProperty("os.name")}"
override val osFamily: EelOsFamily by lazy {
when {
SystemInfo.isWindows -> EelOsFamily.Windows
SystemInfo.isMac || SystemInfo.isLinux || SystemInfo.isFreeBSD -> EelOsFamily.Posix
else -> {
LOG.info("Eel is not supported on current platform")
LocalEelMachine.LOG.info("Eel is not supported on current platform")
EelOsFamily.Posix
}
}
}
override suspend fun toEelApi(): EelApi {
return localEel
}
override suspend fun toEelApi(): EelApi = localEel
}
@ApiStatus.Experimental
data object LocalEelDescriptor : EelDescriptor {
override val machine: EelMachine = LocalEelMachine
}
@ApiStatus.Internal
@@ -146,10 +150,10 @@ interface EelProvider {
// TODO Better name.
// TODO Move it into the EelDescriptor?
fun getInternalName(eelDescriptor: EelDescriptor): String?
fun getInternalName(eelMachine: EelMachine): String?
// TODO Better name.
fun getEelDescriptorByInternalName(internalName: String): EelDescriptor?
fun getEelMachineByInternalName(internalName: String): EelMachine?
}
@ApiStatus.Internal

View File

@@ -4,6 +4,7 @@ package com.intellij.platform.eel
import com.intellij.platform.eel.path.EelPath.OS
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.annotations.NonNls
import java.nio.file.Path
/**
* A marker interface that indicates an environment where native file chooser dialogs should be disabled.
@@ -21,33 +22,92 @@ import org.jetbrains.annotations.NonNls
interface EelDescriptorWithoutNativeFileChooserSupport : EelDescriptor
/**
* A descriptor of an environment where [EelApi] may exist.
* Identifies a specific machine — such as a Docker container, WSL distribution, or SSH host.
*
* Multiple [EelDescriptor]s may map to the same machine.
* This interface is useful when caching, deduplicating, or sharing resources across descriptor instances.
*
* ## Examples
* 1. There is a singleton [LocalEelDescriptor] which always exists, and it denotes the environment where the IDE runs
* 2. On Windows, there can be [EelDescriptor] that corresponds to a WSL distribution.
* Each distribution gives rise to a unique [EelDescriptor]
* 3. Each separate Docker container has its own [EelDescriptor]
* 4. Each SSH host has its own [EelDescriptor]
* - For WSL: all descriptors with base paths like `\\wsl$\Ubuntu` and `\\wsl.localhost\Ubuntu` point to the same [EelMachine].
* - For Docker: descriptors with `/docker-<id>/...` paths share the same container machine.
*
* ## Purpose
* [EelDescriptor] is a marker of an environment, that is
* - **Lightweight**: it is opposed to [EelApi], which is a heavy object that takes considerable amount of resources to initialize.
* While it is not free to obtain [EelDescriptor] (i.e., you may need to interact with WSL services and Docker daemon), it is much cheaper than
* preparing an environment for deep interaction (i.e., running a WSL Distribution or a Docker container).
* - **Durable**: There is no guarantee that an instance of [EelApi] would be alive for a long time.
* For example, an SSH connection can be interrupted, and a Docker container can be restarted. These events do not affect the lifetime of [EelDescriptor].
* Use this when caching or pooling long-lived data thats stable across paths.
*/
@ApiStatus.Experimental
interface EelMachine {
/**
* The platform of an environment corresponding to this [EelMachine].
*/
@get:ApiStatus.Experimental
val osFamily: EelOsFamily
/**
* Describes machine in a user-readable manner, i.e: "Docker: <container_name>" or "Wsl: <distro name>".
* Format is *not* specified but guaranteed to be user-readable.
*/
@get:ApiStatus.Experimental
val name: @NonNls String
/**
* Converts this machine into a [EelApi] — starts or reuses a running environment.
*/
@ApiStatus.Experimental
suspend fun toEelApi(): EelApi
}
/**
* Specialization of [EelDescriptor] that resolves to a path-based environment.
*
* These descriptors are tied to a concrete filesystem root (e.g. `\\wsl$\Ubuntu` or `/docker-xyz`).
* Different paths to the same logical environment yield different descriptors — even if they point to the same [EelMachine].
*
* This allows tools to distinguish between environments even if the underlying host is the same.
*/
@ApiStatus.Experimental
interface EelPathBoundDescriptor : EelDescriptor {
/**
* A platform-specific base path representing the environment's root.
*
* Examples:
* - `\\wsl$\Ubuntu` for a WSL distribution
* - `/docker-12345/` for Docker containers
*/
val rootPath: Path
}
/**
* Represents an abstract description of an environment where [EelApi] may exist.
*
* ## Concepts
* - [EelDescriptor] describes a *specific path-based access* to an environment.
* - [EelMachine] describes the *physical or logical host* (e.g., WSL distribution, Docker container).
*
* For example, two descriptors like `\\wsl$\Ubuntu` and `\\wsl.localhost\Ubuntu` may point to the same [EelMachine],
* but they should be treated as distinct [EelDescriptor]s since tooling behavior or caching may differ per path.
*
* ## Use cases
* - If you're caching data that is *machine-wide*, prefer using [machine] as a cache key instead of [EelDescriptor].
* - If you're accessing a specific path (e.g., resolving symbolic links or permissions), use [EelDescriptor].
*
* ## Examples
* - [LocalEelDescriptor] refers to the machine where the IDE runs (same machine and descriptor).
* - WSL: Each distribution is a machine. Paths like `\\wsl$\Ubuntu` and `\\wsl.localhost\Ubuntu` are different descriptors pointing to the same machine.
* - Docker: Each container is a machine. Paths like `/docker-abc123/...` are descriptors.
* - SSH: Each remote host is a machine. A descriptor may correspond to a specific session or path.
*
* ## Lifecycle
* [EelDescriptor] is:
* - **Lightweight**: Unlike [EelApi], it does not represent a running environment.
* - **Durable**: It can persist even when [EelApi] becomes unavailable (e.g., Docker stopped).
*
* ## Access
* Use `getEelDescriptor()` to resolve a descriptor from a [Path] or [Project].
*
* ## Usage
* The intended way to obtain [EelDescriptor] is with the use of `getEelDescriptor`:
* ```kotlin
* Path.of("\\\\wsl.localhost\\Ubuntu\\home\\Jacob\\projects").getEelDescriptor()
* project.getEelDescriptor()
* val descriptor = Path.of("\\\\wsl.localhost\\Ubuntu\\home\\me").getEelDescriptor()
* val machine = descriptor.machine // Shared between paths pointing to the same distro/container
* val api = descriptor.toEelApi() // Starts or connects to the actual environment
* ```
*
* You are free to compare and store [EelDescriptor].
* TODO: In the future, [EelDescriptor] may also be serializable.
* If you need to access the remote environment, you can use the method [toEelApi], which can suspend for some time before returning a working instance of [EelApi]
*/
@ApiStatus.Experimental
interface EelDescriptor {
@@ -60,20 +120,24 @@ interface EelDescriptor {
}
/**
* Describes Eel in a user-readable manner, i.e: "Docker: <container_name>" or "Wsl: <distro name>".
* Format is *not* specified, but guaranteed to be user-readable.
* Returns the machine this descriptor belongs to.
*
* Multiple descriptors may resolve to the same [EelMachine], e.g.:
* - Docker paths with different mount points
* - WSL descriptors using `wsl$` vs `wsl.localhost`
*/
@get:ApiStatus.Internal
val userReadableDescription: @NonNls String
val machine: EelMachine
/**
* The platform of an environment corresponding to this [EelDescriptor].
*/
@get:ApiStatus.Experimental
val osFamily: EelOsFamily
val osFamily: EelOsFamily get() = machine.osFamily
@ApiStatus.Experimental
suspend fun toEelApi(): EelApi
suspend fun toEelApi(): EelApi {
return machine.toEelApi()
}
/**
* Retrieves an instance of [EelApi] corresponding to this [EelDescriptor].

View File

@@ -3,6 +3,7 @@ package com.intellij.platform.eel.path
import com.intellij.platform.eel.EelApi
import com.intellij.platform.eel.EelDescriptor
import com.intellij.platform.eel.EelMachine
import com.intellij.platform.eel.EelOsFamily
import io.kotest.matchers.shouldBe
import org.junit.jupiter.api.Assertions
@@ -70,10 +71,12 @@ class EelAbsolutePathTest {
}
class DummyEelDescriptor(override val osFamily: EelOsFamily) : EelDescriptor {
override val userReadableDescription: String = "mock"
override suspend fun toEelApi(): EelApi {
return Assertions.fail<Nothing>()
override val machine: EelMachine = object : EelMachine {
override val name: String = "mock"
override val osFamily: EelOsFamily = this@DummyEelDescriptor.osFamily
override suspend fun toEelApi(): EelApi {
return Assertions.fail<Nothing>()
}
}
}
}

View File

@@ -15,11 +15,8 @@ import com.intellij.execution.target.local.LocalTargetEnvironmentRequest;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.io.JarUtil;
import com.intellij.platform.eel.EelDescriptor;
import com.intellij.platform.eel.EelOsFamily;
import com.intellij.platform.eel.provider.EelProviderUtil;
import com.intellij.util.lang.JavaVersion;
import org.jetbrains.annotations.ApiStatus;
@@ -137,7 +134,7 @@ public final class JdkUtil {
* @return if the JDK can be run on this machine.
*/
public static boolean isCompatible(@NotNull Path jdkHomePath, @NotNull Project project) {
return EelProviderUtil.getEelDescriptor(jdkHomePath).equals(EelProviderUtil.getEelDescriptor(project));
return EelProviderUtil.getEelDescriptor(jdkHomePath).getMachine().equals(EelProviderUtil.getEelDescriptor(project).getMachine());
}
public static boolean checkForJre(@NotNull String homePath) {

View File

@@ -6,6 +6,7 @@ package com.intellij.openapi.projectRoots.impl
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.platform.eel.provider.LocalEelDescriptor
import com.intellij.platform.eel.provider.LocalEelMachine
import com.intellij.platform.eel.provider.getEelDescriptor
import com.intellij.platform.workspace.jps.entities.SdkEntity
import com.intellij.workspaceModel.ide.impl.GlobalWorkspaceModel
@@ -13,7 +14,7 @@ import org.jetbrains.annotations.ApiStatus
import java.nio.file.Path
fun findClashingSdk(sdkName: String, sdk: Sdk): SdkEntity? {
val descriptor = sdk.homePath?.let { Path.of(it) }?.getEelDescriptor() ?: LocalEelDescriptor
val relevantSnapshot = GlobalWorkspaceModel.getInstance(descriptor).currentSnapshot
val machine = sdk.homePath?.let { Path.of(it) }?.getEelDescriptor()?.machine ?: LocalEelMachine
val relevantSnapshot = GlobalWorkspaceModel.getInstance(machine).currentSnapshot
return relevantSnapshot.entities(SdkEntity::class.java).find { it.name == sdkName }
}

View File

@@ -130,7 +130,7 @@ public class ProjectSdksModel implements SdkModel {
if (sdkHomePath != null) {
try {
Path path = Path.of(sdkHomePath);
if (getEelDescriptor(path).equals(eelDescriptor)) {
if (getEelDescriptor(path).getMachine().equals(eelDescriptor.getMachine())) {
return true;
}
}

View File

@@ -80,7 +80,7 @@ private class ModuleBridgeLoaderService : InitProjectActivity {
workspaceModel = workspaceModel,
)
}
val globalWorkspaceModel = GlobalWorkspaceModel.getInstanceAsync(project.getEelDescriptor())
val globalWorkspaceModel = GlobalWorkspaceModel.getInstanceAsync(project.getEelDescriptor().machine)
backgroundWriteAction {
globalWorkspaceModel.applyStateToProject(project)
}
@@ -108,7 +108,7 @@ private class ModuleBridgeLoaderService : InitProjectActivity {
}
// Set the project synchronization job on the global synchronizer to prevent race conditions
val globalWorkspaceModel = GlobalWorkspaceModel.getInstanceAsync(project.getEelDescriptor())
val globalWorkspaceModel = GlobalWorkspaceModel.getInstanceAsync(project.getEelDescriptor().machine)
JpsGlobalModelSynchronizer.getInstance().setProjectSynchronizationJob(projectSyncJob)
}

View File

@@ -10,7 +10,7 @@ import com.intellij.openapi.projectRoots.ProjectJdkTable
import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl
import com.intellij.openapi.util.registry.Registry
import com.intellij.platform.backend.workspace.BridgeInitializer
import com.intellij.platform.eel.EelDescriptor
import com.intellij.platform.eel.EelMachine
import com.intellij.platform.eel.provider.getEelDescriptor
import com.intellij.platform.workspace.jps.entities.SdkEntity
import com.intellij.platform.workspace.storage.*
@@ -40,7 +40,7 @@ private class GlobalSdkBridgeInitializer : BridgeInitializer {
}
}
private class GlobalSdkBridgesLoader(private val descriptor: EelDescriptor) : GlobalSdkTableBridge {
private class GlobalSdkBridgesLoader(private val eelMachine: EelMachine) : GlobalSdkTableBridge {
override fun initializeBridgesAfterLoading(mutableStorage: MutableEntityStorage,
initialEntityStorage: VersionedEntityStorage): () -> Unit {
val sdks = mutableStorage
@@ -132,18 +132,18 @@ private class GlobalSdkBridgesLoader(private val descriptor: EelDescriptor) : Gl
if (!Registry.`is`("ide.workspace.model.per.environment.model.separation")) {
return false
}
return entity.homePath?.toPath()?.getEelDescriptor() != descriptor
return entity.homePath?.toPath()?.getEelDescriptor()?.machine != eelMachine
}
}
private val LOG = logger<GlobalSdkBridgesLoader>()
private class GlobalSdkTableBridgeRegistryImpl : GlobalSdkTableBridgeRegistry {
private val registry = ConcurrentHashMap<EelDescriptor, GlobalSdkTableBridge>()
private val registry = ConcurrentHashMap<EelMachine, GlobalSdkTableBridge>()
override fun getTableBridge(eelDescriptor: EelDescriptor): GlobalSdkTableBridge {
return registry.computeIfAbsent(eelDescriptor) {
GlobalSdkBridgesLoader(eelDescriptor)
override fun getTableBridge(eelMachine: EelMachine): GlobalSdkTableBridge {
return registry.computeIfAbsent(eelMachine) {
GlobalSdkBridgesLoader(eelMachine)
}
}
}

View File

@@ -62,7 +62,7 @@ class SdkTableBridgeImpl: SdkTableImplementationDelegate {
override fun addNewSdk(sdk: Sdk) {
val delegateSdk = (sdk as ProjectJdkImpl).delegate as SdkBridgeImpl
val descriptor = delegateSdk.homeDirectory?.toNioPath()?.getEelDescriptor() ?: LocalEelDescriptor
val globalWorkspaceModel = GlobalWorkspaceModel.getInstance(descriptor)
val globalWorkspaceModel = GlobalWorkspaceModel.getInstance(descriptor.machine)
val existingSdkEntity = globalWorkspaceModel.currentSnapshot.sdkMap.getFirstEntity(sdk)
if (existingSdkEntity != null) {
@@ -93,7 +93,7 @@ class SdkTableBridgeImpl: SdkTableImplementationDelegate {
override fun removeSdk(sdk: Sdk) {
val descriptor = sdk.homeDirectory?.toNioPath()?.getEelDescriptor() ?: LocalEelDescriptor
val globalWorkspaceModel = GlobalWorkspaceModel.getInstance(descriptor)
val globalWorkspaceModel = GlobalWorkspaceModel.getInstance(descriptor.machine)
// It's absolutely OK if we try to remove what does not yet exist in `ProjectJdkTable` SDK
// E.g. org.jetbrains.idea.maven.actions.AddMavenDependencyQuickFixTest
@@ -107,7 +107,7 @@ class SdkTableBridgeImpl: SdkTableImplementationDelegate {
modifiedSdk as ProjectJdkImpl
originalSdk as ProjectJdkImpl
val descriptor = modifiedSdk.homeDirectory?.toNioPath()?.getEelDescriptor() ?: LocalEelDescriptor
val globalWorkspaceModel = GlobalWorkspaceModel.getInstance(descriptor)
val globalWorkspaceModel = GlobalWorkspaceModel.getInstance(descriptor.machine)
val sdkEntity = (globalWorkspaceModel.currentSnapshot.entities(SdkEntity::class.java)
.firstOrNull { it.name == originalSdk.name && it.type == originalSdk.sdkType.name }
?: error("SDK entity for bridge `${originalSdk.name}` `${originalSdk.sdkType.name}` doesn't exist"))

View File

@@ -4,6 +4,7 @@ package com.intellij.platform.ide.impl.wsl
import com.intellij.execution.eel.MultiRoutingFileSystemUtils
import com.intellij.execution.ijent.nio.IjentEphemeralRootAwareFileSystemProvider
import com.intellij.execution.wsl.*
import com.intellij.execution.wsl.WSLDistribution
import com.intellij.openapi.components.service
import com.intellij.openapi.diagnostic.ControlFlowException
import com.intellij.openapi.diagnostic.logger
@@ -12,7 +13,9 @@ import com.intellij.openapi.util.registry.Registry
import com.intellij.platform.core.nio.fs.MultiRoutingFileSystemProvider
import com.intellij.platform.eel.EelApi
import com.intellij.platform.eel.EelDescriptor
import com.intellij.platform.eel.EelMachine
import com.intellij.platform.eel.EelOsFamily
import com.intellij.platform.eel.EelPathBoundDescriptor
import com.intellij.platform.eel.annotations.MultiRoutingFileSystemPath
import com.intellij.platform.eel.impl.fs.EelEarlyAccessChecker
import com.intellij.platform.eel.provider.EelProvider
@@ -60,34 +63,7 @@ class EelWslMrfsBackend(private val coroutineScope: CoroutineScope) : MultiRouti
private val reportedNonExistentWslIds = AtomicReference<List<String>>(listOf())
override fun compute(localFS: FileSystem, sanitizedPath: String): FileSystem? {
@MultiRoutingFileSystemPath
val wslRoot: String
val distributionId: String
run {
// https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats#unc-paths
// Although it's not clearly documented that a root of a UNC share must have a backslash at the end,
// it can be deducted by the nature of the root >directory<. Also, the examples from the docs allude to that.
// `WslPath.parseWindowsUncPath` and other platform functions parse according to the documentation,
// but `sanitizedPath` never has a backslash at the end.
val serverNameEndIdx = when {
sanitizedPath.startsWith("//wsl.localhost/", ignoreCase = true) -> 16
sanitizedPath.startsWith("//wsl$/", ignoreCase = true) -> 7
else -> return null
}
val shareNameEndIdx = sanitizedPath.indexOf('/', startIndex = serverNameEndIdx)
if (shareNameEndIdx == -1) {
wslRoot = sanitizedPath + "\\"
distributionId = sanitizedPath.substring(serverNameEndIdx)
}
else {
wslRoot = sanitizedPath.take(shareNameEndIdx + 1)
distributionId = sanitizedPath.substring(serverNameEndIdx, shareNameEndIdx)
}
}
val (wslRoot, distributionId) = WslEelProvider.parsePath(sanitizedPath) ?: return null
try {
if (!WslIjentAvailabilityService.getInstance().useIjentForWslNioFileSystem()) {
@@ -107,17 +83,12 @@ class EelWslMrfsBackend(private val coroutineScope: CoroutineScope) : MultiRouti
return providersCache.computeIfAbsent(key) {
service<EelEarlyAccessChecker>().check(sanitizedPath)
val descriptor = WslEelDescriptor(WSLDistribution(distributionId))
if (LOG.isDebugEnabled) {
LOG.debug("Triggered initialization of IJent for $descriptor, the path is $sanitizedPath", Throwable())
}
val ijentUri = URI("ijent", "wsl", "/$distributionId", null, null)
val ijentFsProvider = TracingFileSystemProvider(IjentNioFileSystemProvider.getInstance())
try {
val ijentFs = IjentFailSafeFileSystemPosixApi(coroutineScope, descriptor)
val ijentFs = IjentFailSafeFileSystemPosixApi(coroutineScope, WslEelDescriptor(WSLDistribution(distributionId), wslRoot))
val fs = ijentFsProvider.newFileSystem(ijentUri, IjentNioFileSystemProvider.newFileSystemMap(ijentFs))
coroutineScope.coroutineContext.job.invokeOnCompletion {
@@ -212,21 +183,22 @@ class WslEelProvider : EelProvider {
return WslEelDescriptor(
WSLDistribution(wslPath.distributionId),
root.toString()
)
}
override fun getInternalName(eelDescriptor: EelDescriptor): String? =
if (eelDescriptor is WslEelDescriptor)
"WSL-" + eelDescriptor.distribution.id
override fun getInternalName(eelMachine: EelMachine): String? =
if (eelMachine is WslEelMachine)
"WSL-" + eelMachine.distribution.id
else
null
override fun getCustomRoots(eelDescriptor: EelDescriptor): Collection<@MultiRoutingFileSystemPath String>? =
(eelDescriptor as? WslEelDescriptor)?.distribution?.roots
override fun getEelDescriptorByInternalName(internalName: String): EelDescriptor? =
override fun getEelMachineByInternalName(internalName: String): EelMachine? =
if (internalName.startsWith("WSL-"))
WslEelDescriptor(WSLDistribution(internalName.substring(4)))
WslEelMachine(WSLDistribution(internalName.substring(4)))
else
null
@@ -262,22 +234,82 @@ class WslEelProvider : EelProvider {
(getDefault().provider() as MultiRoutingFileSystemProvider).theOnlyFileSystem.getBackend(wslPath.wslRoot + "\\")
}
companion object {
// wsl root -> distribution id
internal fun parsePath(sanitizedPath: String): Pair<String, String>? {
@MultiRoutingFileSystemPath
val wslRoot: String
val distributionId: String
val serverNameEndIdx = when {
sanitizedPath.startsWith("//wsl.localhost/", ignoreCase = true) -> 16
sanitizedPath.startsWith("//wsl$/", ignoreCase = true) -> 7
else -> return null
}
val shareNameEndIdx = sanitizedPath.indexOf('/', startIndex = serverNameEndIdx)
if (shareNameEndIdx == -1) {
wslRoot = sanitizedPath + "\\"
distributionId = sanitizedPath.substring(serverNameEndIdx)
}
else {
wslRoot = sanitizedPath.take(shareNameEndIdx + 1)
distributionId = sanitizedPath.substring(serverNameEndIdx, shareNameEndIdx)
}
return wslRoot to distributionId
}
}
}
data class WslEelDescriptor(val distribution: WSLDistribution) : EelDescriptor {
class WslEelMachine(val distribution: WSLDistribution) : EelMachine {
override val osFamily: EelOsFamily = EelOsFamily.Posix
override val userReadableDescription: @NonNls String = "WSL: ${distribution.presentableName}"
override val name: @NonNls String = "WSL: ${distribution.presentableName}"
override suspend fun toEelApi(): EelApi {
return distribution.getIjent()
}
override fun equals(other: Any?): Boolean {
return other is WslEelDescriptor && other.distribution.id == distribution.id
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as WslEelMachine
if (distribution != other.distribution) return false
if (osFamily != other.osFamily) return false
return true
}
override fun hashCode(): Int {
return distribution.id.hashCode()
var result = distribution.hashCode()
result = 31 * result + osFamily.hashCode()
return result
}
}
class WslEelDescriptor(val distribution: WSLDistribution, internal val fsRoot: String) : EelPathBoundDescriptor {
override val rootPath: Path get() = fsRoot.let(::Path)
override val machine: EelMachine = WslEelMachine(distribution)
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as WslEelDescriptor
if (fsRoot != other.fsRoot) return false
if (machine != other.machine) return false
return true
}
override fun hashCode(): Int {
var result = fsRoot.hashCode()
result = 31 * result + machine.hashCode()
return result
}
}

View File

@@ -7,6 +7,7 @@ import com.intellij.execution.wsl.WSLDistribution
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.IntellijInternalApi
import com.intellij.openapi.util.registry.Registry
import com.intellij.platform.core.nio.fs.MultiRoutingFileSystem
import com.intellij.platform.eel.EelDescriptor
import com.intellij.platform.ijent.spi.IjentConnectionStrategy
import com.intellij.platform.ijent.spi.IjentDeployingOverShellProcessStrategy
@@ -22,7 +23,7 @@ class WslIjentDeployingStrategy(
override val ijentLabel: String,
private val distribution: WSLDistribution,
private val project: Project?,
private val wslCommandLineOptionsModifier: (WSLCommandLineOptions) -> Unit = {}
private val wslCommandLineOptionsModifier: (WSLCommandLineOptions) -> Unit = {},
) : IjentDeployingOverShellProcessStrategy(scope) {
override suspend fun mapPath(path: Path): String? =
distribution.getWslPath(path)
@@ -46,7 +47,10 @@ class WslIjentDeployingStrategy(
}
override suspend fun getTargetDescriptor(): EelDescriptor {
return WslEelDescriptor(distribution)
val root = project?.basePath?.let {
MultiRoutingFileSystem.sanitizeRoot(it)
}?.let(WslEelProvider::parsePath)?.first ?: distribution.getUNCRootPath().toString()
return WslEelDescriptor(distribution, root)
}
override suspend fun getConnectionStrategy(): IjentConnectionStrategy {

View File

@@ -4,6 +4,7 @@ package com.intellij.execution.ijent.nio
import com.intellij.openapi.util.Disposer
import com.intellij.platform.core.nio.fs.DelegatingFileSystemProvider
import com.intellij.platform.eel.EelDescriptor
import com.intellij.platform.eel.EelMachine
import com.intellij.platform.eel.provider.EelProvider
import com.intellij.platform.eel.annotations.MultiRoutingFileSystemPath
import com.intellij.platform.eel.provider.MultiRoutingFileSystemBackend
@@ -92,12 +93,12 @@ fun CoroutineScope.registerIjentNioFs(
if (eelDescriptor == ijent.descriptor) listOf(root)
else null
override fun getInternalName(eelDescriptor: EelDescriptor): String? =
if (eelDescriptor == ijent.descriptor) eelDescriptor.userReadableDescription
override fun getInternalName(eelMachine: EelMachine): String? =
if (eelMachine == ijent.descriptor.machine) ijent.descriptor.machine.name
else null
override fun getEelDescriptorByInternalName(internalName: String): EelDescriptor? =
if (internalName == ijent.descriptor.userReadableDescription) ijent.descriptor
override fun getEelMachineByInternalName(internalName: String): EelMachine? =
if (internalName == ijent.descriptor.machine.name) ijent.descriptor.machine
else null
},
disposable,

View File

@@ -12,6 +12,7 @@ import com.intellij.platform.backend.workspace.GlobalWorkspaceModelCache
import com.intellij.platform.diagnostic.telemetry.helpers.MillisecondsMeasurer
import com.intellij.platform.eel.provider.EelProvider
import com.intellij.platform.eel.provider.LocalEelDescriptor
import com.intellij.platform.eel.provider.LocalEelMachine
import com.intellij.platform.workspace.jps.JpsGlobalFileEntitySource
import com.intellij.platform.workspace.jps.entities.LibraryEntity
import com.intellij.platform.workspace.jps.entities.SdkEntity
@@ -289,12 +290,12 @@ open class JpsGlobalModelSynchronizerImpl(private val coroutineScope: CoroutineS
initialEntityStorage: VersionedEntityStorage,
notifyListeners: Boolean,
): () -> Unit {
val descriptor =
val eelMachine =
EelProvider.EP_NAME.extensionList.firstNotNullOfOrNull { eelProvider ->
eelProvider.getEelDescriptorByInternalName(environmentName.name)
eelProvider.getEelMachineByInternalName(environmentName.name)
}
?: LocalEelDescriptor
val callbacks = GlobalEntityBridgeAndEventHandler.getAllGlobalEntityHandlers(descriptor)
?: LocalEelMachine
val callbacks = GlobalEntityBridgeAndEventHandler.getAllGlobalEntityHandlers(eelMachine)
.map { it.initializeBridgesAfterLoading(mutableStorage, initialEntityStorage) }
return {
callbacks.forEach { it.invoke() }

View File

@@ -389,7 +389,7 @@ class JpsProjectModelSynchronizer(private val project: Project) : Disposable {
workspaceModel.entityTracer.printInfoAboutTracedEntity(builder, "JPS files")
childActivity = childActivity?.endAndStart("applying entities from global storage")
val mutableStorage = MutableEntityStorage.create()
GlobalWorkspaceModel.getInstanceAsync(project.getEelDescriptor()).applyStateToProjectBuilder(mutableStorage, workspaceModel)
GlobalWorkspaceModel.getInstanceAsync(project.getEelDescriptor().machine).applyStateToProjectBuilder(mutableStorage, workspaceModel)
builder.applyChangesFrom(mutableStorage)
childActivity = childActivity?.endAndStart("applying loaded changes (in queue)")
LoadedProjectEntities(builder, orphanage, unloadedEntitiesBuilder, sourcesToUpdate)

View File

@@ -522,11 +522,13 @@ private class MockIjentApi(private val adapter: GeneralCommandLine, val rootUser
override val descriptor: EelDescriptor
get() = object : EelDescriptor {
override val userReadableDescription: @NonNls String = "mock"
override val osFamily: EelOsFamily = this@MockIjentApi.platform.osFamily
override val machine: EelMachine = object : EelMachine {
override val name: @NonNls String = "mock"
override val osFamily: EelOsFamily = this@MockIjentApi.platform.osFamily
override suspend fun toEelApi(): EelApi {
throw UnsupportedOperationException()
override suspend fun toEelApi(): EelApi {
throw UnsupportedOperationException()
}
}
}

View File

@@ -5,6 +5,7 @@ import com.intellij.openapi.application.edtWriteAction
import com.intellij.openapi.roots.libraries.Library
import com.intellij.platform.backend.workspace.workspaceModel
import com.intellij.platform.eel.provider.LocalEelDescriptor
import com.intellij.platform.eel.provider.LocalEelMachine
import com.intellij.platform.workspace.jps.JpsGlobalFileEntitySource
import com.intellij.platform.workspace.jps.entities.*
import com.intellij.platform.workspace.storage.EntitySource
@@ -93,8 +94,8 @@ class ModuleDependencyIndexTest {
fun `test dependency on global library`() = runBlocking {
try {
edtWriteAction {
GlobalWorkspaceModel.getInstance(LocalEelDescriptor).updateModel("Test") {
val manager = GlobalWorkspaceModel.getInstance(LocalEelDescriptor).getVirtualFileUrlManager()
GlobalWorkspaceModel.getInstance(LocalEelMachine).updateModel("Test") {
val manager = GlobalWorkspaceModel.getInstance(LocalEelMachine).getVirtualFileUrlManager()
val globalEntitySource = JpsGlobalFileEntitySource(manager.getOrCreateFromUrl("/url"))
it addEntity LibraryEntity("GlobalLib", LibraryTableId.GlobalLibraryTableId("application"), emptyList(), globalEntitySource)
}
@@ -156,8 +157,8 @@ class ModuleDependencyIndexTest {
fun `test dependency on global library after rename`() = runBlocking {
try {
edtWriteAction {
GlobalWorkspaceModel.getInstance(LocalEelDescriptor).updateModel("Test") {
val manager = GlobalWorkspaceModel.getInstance(LocalEelDescriptor).getVirtualFileUrlManager()
GlobalWorkspaceModel.getInstance(LocalEelMachine).updateModel("Test") {
val manager = GlobalWorkspaceModel.getInstance(LocalEelMachine).getVirtualFileUrlManager()
val globalEntitySource = JpsGlobalFileEntitySource(manager.getOrCreateFromUrl("/url"))
it addEntity LibraryEntity("GlobalLib", LibraryTableId.GlobalLibraryTableId("application"), emptyList(), globalEntitySource)
}
@@ -168,7 +169,7 @@ class ModuleDependencyIndexTest {
}
edtWriteAction {
GlobalWorkspaceModel.getInstance(LocalEelDescriptor).updateModel("Test") {
GlobalWorkspaceModel.getInstance(LocalEelMachine).updateModel("Test") {
val resolved = it.resolve(LibraryId("GlobalLib", LibraryTableId.GlobalLibraryTableId("application")))!!
it.modifyLibraryEntity(resolved) {
this.name = "NewGlobalName"

View File

@@ -11,7 +11,7 @@ import com.intellij.openapi.roots.libraries.LibraryTable;
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
import com.intellij.platform.eel.provider.LocalEelDescriptor;
import com.intellij.platform.eel.provider.LocalEelMachine;
import com.intellij.workspaceModel.ide.legacyBridge.GlobalLibraryTableBridge;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -35,7 +35,7 @@ final class LibraryTablesRegistrarImpl extends LibraryTablesRegistrar implements
@Override
public @NotNull LibraryTable getLibraryTable() {
// todo: IJPL-175225 add possibility to select non-local global library tables
return GlobalLibraryTableBridge.Companion.getInstance(LocalEelDescriptor.INSTANCE);
return GlobalLibraryTableBridge.Companion.getInstance(LocalEelMachine.INSTANCE);
}
@Override

View File

@@ -14,9 +14,9 @@ import com.intellij.openapi.util.registry.Registry
import com.intellij.platform.backend.workspace.GlobalWorkspaceModelCache
import com.intellij.platform.backend.workspace.WorkspaceModel
import com.intellij.platform.diagnostic.telemetry.helpers.MillisecondsMeasurer
import com.intellij.platform.eel.EelDescriptor
import com.intellij.platform.eel.EelMachine
import com.intellij.platform.eel.provider.EelProvider
import com.intellij.platform.eel.provider.LocalEelDescriptor
import com.intellij.platform.eel.provider.LocalEelMachine
import com.intellij.platform.eel.provider.getEelDescriptor
import com.intellij.platform.workspace.jps.GlobalStorageEntitySource
import com.intellij.platform.workspace.jps.JpsGlobalFileEntitySource
@@ -57,9 +57,9 @@ class GlobalWorkspaceModel internal constructor(
* 1. Prevent entities from one environment from appearing for another one;
* 2. Ensure that the namespace of "global" entities (such as SDKs and global libraries) is local to each environment.
*/
private val eelDescriptor: EelDescriptor,
private val eelMachine: EelMachine,
private val internalEnvironmentName: GlobalWorkspaceModelCache.InternalEnvironmentName,
) {
) {
/**
* Store link to the project from which changes came from. It's needed to avoid redundant changes application at [applyStateToProject]
@@ -186,7 +186,7 @@ class GlobalWorkspaceModel internal constructor(
private fun initializeBridges(change: Map<Class<*>, List<EntityChange<*>>>, builder: MutableEntityStorage) {
ThreadingAssertions.assertWriteAccess()
GlobalEntityBridgeAndEventHandler.getAllGlobalEntityHandlers(eelDescriptor).forEach {
GlobalEntityBridgeAndEventHandler.getAllGlobalEntityHandlers(eelMachine).forEach {
logErrorOnEventHandling {
it.initializeBridges(change, builder)
}
@@ -196,19 +196,19 @@ class GlobalWorkspaceModel internal constructor(
private fun onBeforeChanged(change: VersionedStorageChange) {
ThreadingAssertions.assertWriteAccess()
GlobalEntityBridgeAndEventHandler.getAllGlobalEntityHandlers(eelDescriptor).forEach { it.handleBeforeChangeEvents(change) }
GlobalEntityBridgeAndEventHandler.getAllGlobalEntityHandlers(eelMachine).forEach { it.handleBeforeChangeEvents(change) }
}
@RequiresWriteLock
private fun onChanged(change: VersionedStorageChange) {
ThreadingAssertions.assertWriteAccess()
GlobalEntityBridgeAndEventHandler.getAllGlobalEntityHandlers(eelDescriptor).forEach { it.handleChangedEvents(change) }
GlobalEntityBridgeAndEventHandler.getAllGlobalEntityHandlers(eelMachine).forEach { it.handleChangedEvents(change) }
globalWorkspaceModelCache?.scheduleCacheSave()
isFromGlobalWorkspaceModel = true
for (project in ProjectManager.getInstance().openProjects) {
if (project.isDisposed || project.getEelDescriptor() != eelDescriptor) {
if (project.isDisposed || project.getEelDescriptor().machine != eelMachine) {
continue
}
applyStateToProject(project)
@@ -233,7 +233,7 @@ class GlobalWorkspaceModel internal constructor(
fun applyStateToProjectBuilder(
targetBuilder: MutableEntityStorage,
workspaceModel: WorkspaceModelImpl
workspaceModel: WorkspaceModelImpl,
): Unit = applyStateToProjectBuilderTimeMs.addMeasuredTime {
LOG.info("Sync global entities with mutable entity storage")
targetBuilder.replaceBySource(
@@ -287,7 +287,7 @@ class GlobalWorkspaceModel internal constructor(
val entitySourceCopy = (libraryEntity.entitySource as? JpsGlobalFileEntitySource)?.copy(vfuManager) ?: libraryEntity.entitySource
val excludedRootsCopy = libraryEntity.excludedRoots.map { it.copy(entitySourceCopy, vfuManager) }
val libraryPropertiesCopy = libraryEntity.libraryProperties?.copy(entitySourceCopy)
val libraryEntityCopy = mutableEntityStorage addEntity LibraryEntity(libraryEntity.name, libraryEntity.tableId, libraryRootsCopy, entitySourceCopy) {
val libraryEntityCopy = mutableEntityStorage addEntity LibraryEntity(libraryEntity.name, libraryEntity.tableId, libraryRootsCopy, entitySourceCopy) {
typeId = libraryEntity.typeId
excludedRoots = excludedRootsCopy
libraryProperties = libraryPropertiesCopy
@@ -331,12 +331,12 @@ class GlobalWorkspaceModel internal constructor(
@RequiresBlockingContext
@JvmStatic
fun getInstance(descriptor: EelDescriptor): GlobalWorkspaceModel {
return ApplicationManager.getApplication().service<GlobalWorkspaceModelRegistry>().getGlobalModel(descriptor)
fun getInstance(eelMachine: EelMachine): GlobalWorkspaceModel {
return ApplicationManager.getApplication().service<GlobalWorkspaceModelRegistry>().getGlobalModel(eelMachine)
}
suspend fun getInstanceAsync(descriptor: EelDescriptor): GlobalWorkspaceModel {
return ApplicationManager.getApplication().serviceAsync<GlobalWorkspaceModelRegistry>().getGlobalModel(descriptor)
suspend fun getInstanceAsync(eelMachine: EelMachine): GlobalWorkspaceModel {
return ApplicationManager.getApplication().serviceAsync<GlobalWorkspaceModelRegistry>().getGlobalModel(eelMachine)
}
suspend fun getInstanceByInternalName(name: GlobalWorkspaceModelCache.InternalEnvironmentName): GlobalWorkspaceModel {
@@ -404,31 +404,31 @@ class GlobalWorkspaceModelRegistry {
const val GLOBAL_WORKSPACE_MODEL_LOCAL_CACHE_ID: String = "Local"
}
private val environmentToModel = ConcurrentHashMap<EelDescriptor, GlobalWorkspaceModel>()
private val environmentToModel = ConcurrentHashMap<EelMachine, GlobalWorkspaceModel>()
fun getGlobalModel(descriptor: EelDescriptor): GlobalWorkspaceModel {
val protectedDescriptor = if (Registry.`is`("ide.workspace.model.per.environment.model.separation")) descriptor else LocalEelDescriptor
val internalName = if (protectedDescriptor is LocalEelDescriptor) {
fun getGlobalModel(eelMachine: EelMachine): GlobalWorkspaceModel {
val protectedMachine = if (Registry.`is`("ide.workspace.model.per.environment.model.separation")) eelMachine else LocalEelMachine
val internalName = if (protectedMachine is LocalEelMachine) {
GLOBAL_WORKSPACE_MODEL_LOCAL_CACHE_ID
}
else {
EelProvider.EP_NAME.extensionList.firstNotNullOfOrNull { eelProvider ->
eelProvider.getInternalName(protectedDescriptor)
eelProvider.getInternalName(protectedMachine)
}
?: throw IllegalArgumentException("Descriptor $protectedDescriptor must be registered before using in Workspace Model")
?: throw IllegalArgumentException("Descriptor $protectedMachine must be registered before using in Workspace Model")
}
return environmentToModel.computeIfAbsent(protectedDescriptor) { GlobalWorkspaceModel(protectedDescriptor, InternalEnvironmentNameImpl(internalName)) }
return environmentToModel.computeIfAbsent(protectedMachine) { GlobalWorkspaceModel(protectedMachine, InternalEnvironmentNameImpl(internalName)) }
}
fun getGlobalModelByDescriptorName(name: GlobalWorkspaceModelCache.InternalEnvironmentName): GlobalWorkspaceModel {
val protectedName = if (Registry.`is`("ide.workspace.model.per.environment.model.separation")) name.name else GLOBAL_WORKSPACE_MODEL_LOCAL_CACHE_ID
val descriptor = if (protectedName == GLOBAL_WORKSPACE_MODEL_LOCAL_CACHE_ID) {
LocalEelDescriptor
val machine = if (protectedName == GLOBAL_WORKSPACE_MODEL_LOCAL_CACHE_ID) {
LocalEelMachine
}
else {
EelProvider.EP_NAME.extensionList.firstNotNullOf { eelProvider -> eelProvider.getEelDescriptorByInternalName(protectedName) }
EelProvider.EP_NAME.extensionList.firstNotNullOf { eelProvider -> eelProvider.getEelMachineByInternalName(protectedName) }
}
val model = getGlobalModel(descriptor)
val model = getGlobalModel(machine)
return model
}
@@ -437,7 +437,7 @@ class GlobalWorkspaceModelRegistry {
environmentToModel.values.toList()
}
else {
listOf(getGlobalModel(LocalEelDescriptor))
listOf(getGlobalModel(LocalEelMachine))
}
}

View File

@@ -10,8 +10,8 @@ import com.intellij.platform.workspace.storage.impl.VersionedStorageChangeIntern
internal class GlobalWorkspaceModelSynchronizerListener(private val project: Project) : WorkspaceModelChangeListener {
override fun changed(event: VersionedStorageChange) {
val eelDescriptor = project.getEelDescriptor()
val globalWorkspaceModel = GlobalWorkspaceModel.getInstance(eelDescriptor)
val eelMachine = project.getEelDescriptor().machine
val globalWorkspaceModel = GlobalWorkspaceModel.getInstance(eelMachine)
// Avoid handling events if change was made by global workspace model
if (globalWorkspaceModel.isFromGlobalWorkspaceModel) return

View File

@@ -8,8 +8,8 @@ import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.roots.libraries.LibraryTable
import com.intellij.openapi.roots.libraries.LibraryTablePresentation
import com.intellij.openapi.util.Disposer
import com.intellij.platform.eel.EelDescriptor
import com.intellij.platform.eel.provider.LocalEelDescriptor
import com.intellij.platform.eel.EelMachine
import com.intellij.platform.eel.provider.LocalEelMachine
import com.intellij.platform.workspace.jps.GlobalStorageEntitySource
import com.intellij.platform.workspace.jps.entities.LibraryEntity
import com.intellij.platform.workspace.jps.entities.LibraryId
@@ -33,7 +33,7 @@ internal class CustomLibraryTableBridgeImpl(private val level: String, private v
private var tmpEntityStorage: EntityStorage? = null
private val entitySource = LegacyCustomLibraryEntitySource(tableLevel)
private val libraryTableId = LibraryTableId.GlobalLibraryTableId(tableLevel)
private val libraryTableDelegate = GlobalLibraryTableDelegate(this, getDescriptor(), libraryTableId)
private val libraryTableDelegate = GlobalLibraryTableDelegate(this, getMachine(), libraryTableId)
override fun initializeBridgesAfterLoading(mutableStorage: MutableEntityStorage,
initialEntityStorage: VersionedEntityStorage): () -> Unit {
@@ -80,7 +80,7 @@ internal class CustomLibraryTableBridgeImpl(private val level: String, private v
override fun getPresentation(): LibraryTablePresentation = presentation
override fun getModifiableModel(): LibraryTable.ModifiableModel {
return GlobalOrCustomModifiableLibraryTableBridgeImpl(this, getDescriptor(), entitySource)
return GlobalOrCustomModifiableLibraryTableBridgeImpl(this, getMachine(), entitySource)
}
override fun isEditable(): Boolean = false
@@ -90,7 +90,7 @@ internal class CustomLibraryTableBridgeImpl(private val level: String, private v
Disposer.dispose(libraryTableDelegate)
val runnable: () -> Unit = {
GlobalWorkspaceModel.getInstance(getDescriptor()).updateModel("Cleanup custom libraries after dispose") { storage ->
GlobalWorkspaceModel.getInstance(getMachine()).updateModel("Cleanup custom libraries after dispose") { storage ->
storage.entities(LibraryEntity::class.java).filter { it.entitySource == entitySource }.forEach {
storage.removeEntity(it)
}
@@ -112,7 +112,7 @@ internal class CustomLibraryTableBridgeImpl(private val level: String, private v
@OptIn(EntityStorageInstrumentationApi::class)
override fun readExternal(libraryTableTag: Element) {
val globalWorkspaceModel = GlobalWorkspaceModel.getInstance(getDescriptor())
val globalWorkspaceModel = GlobalWorkspaceModel.getInstance(getMachine())
val mutableEntityStorage = MutableEntityStorage.create()
libraryTableTag.getChildren(JpsLibraryTableSerializer.LIBRARY_TAG).forEach { libraryTag ->
@@ -138,7 +138,7 @@ internal class CustomLibraryTableBridgeImpl(private val level: String, private v
val libraryBridge = actualLibraryEntity.findLibraryBridge(entityStorage) ?: LibraryBridgeImpl(
libraryTable = this,
origin = LibraryOrigin.OfDescriptor(getDescriptor()),
origin = LibraryOrigin.OfMachine(getMachine()),
initialId = libraryEntity.symbolicId,
initialEntityStorage = storageOnBuilder,
targetBuilder = null
@@ -170,7 +170,7 @@ internal class CustomLibraryTableBridgeImpl(private val level: String, private v
}
override fun writeExternal(element: Element) {
GlobalWorkspaceModel.getInstance(LocalEelDescriptor).currentSnapshot.entities(LibraryEntity::class.java)
GlobalWorkspaceModel.getInstance(LocalEelMachine).currentSnapshot.entities(LibraryEntity::class.java)
.filter { it.tableId == libraryTableId }
.sortedBy { it.name }
.forEach { libraryEntity ->
@@ -189,8 +189,8 @@ internal class CustomLibraryTableBridgeImpl(private val level: String, private v
/**
* As for now, we permit custom library tables only for local projects. These tables are internal anyway.
*/
private fun getDescriptor(): EelDescriptor {
return LocalEelDescriptor
private fun getMachine(): EelMachine {
return LocalEelMachine
}
@ApiStatus.Internal

View File

@@ -20,8 +20,8 @@ internal class GlobalAndCustomLibraryTableBridgeInitializer : BridgeInitializer
override fun initializeBridges(project: Project,
changes: Map<Class<*>, List<EntityChange<*>>>,
builder: MutableEntityStorage) = GlobalLibraryTableBridgeImpl.initializeLibraryBridgesTimeMs.addMeasuredTime {
val descriptor = project.getEelDescriptor()
val entityStorage = GlobalWorkspaceModel.getInstance(descriptor).entityStorage
val machine = project.getEelDescriptor().machine
val entityStorage = GlobalWorkspaceModel.getInstance(machine).entityStorage
@Suppress("UNCHECKED_CAST")
val libraryChanges = (changes[LibraryEntity::class.java] as? List<EntityChange<LibraryEntity>>) ?: emptyList()
@@ -32,7 +32,7 @@ internal class GlobalAndCustomLibraryTableBridgeInitializer : BridgeInitializer
builder.mutableLibraryMap.getOrPutDataByEntity(addChange.newEntity) {
LibraryBridgeImpl(
libraryTable = getGlobalOrCustomLibraryTable(addChange.newEntity.symbolicId.tableId.level),
origin = LibraryOrigin.OfDescriptor(descriptor),
origin = LibraryOrigin.OfMachine(machine),
initialId = addChange.newEntity.symbolicId,
initialEntityStorage = entityStorage,
targetBuilder = builder

View File

@@ -9,7 +9,7 @@ import com.intellij.openapi.roots.libraries.LibraryTablePresentation
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar
import com.intellij.openapi.util.Disposer
import com.intellij.platform.diagnostic.telemetry.helpers.MillisecondsMeasurer
import com.intellij.platform.eel.EelDescriptor
import com.intellij.platform.eel.EelMachine
import com.intellij.platform.workspace.jps.JpsGlobalFileEntitySource
import com.intellij.platform.workspace.jps.entities.LibraryTableId
import com.intellij.platform.workspace.jps.serialization.impl.JpsGlobalEntitiesSerializers
@@ -22,8 +22,8 @@ import io.opentelemetry.api.metrics.Meter
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Internal
class GlobalLibraryTableBridgeImpl(val descriptor: EelDescriptor) : GlobalLibraryTableBridge, Disposable {
private val libraryTableDelegate = GlobalLibraryTableDelegate(this, descriptor, LibraryTableId.GlobalLibraryTableId(LibraryTablesRegistrar.APPLICATION_LEVEL))
class GlobalLibraryTableBridgeImpl(val eelMachine: EelMachine) : GlobalLibraryTableBridge, Disposable {
private val libraryTableDelegate = GlobalLibraryTableDelegate(this, eelMachine, LibraryTableId.GlobalLibraryTableId(LibraryTablesRegistrar.APPLICATION_LEVEL))
override fun initializeBridges(changes: Map<Class<*>, List<EntityChange<*>>>,
builder: MutableEntityStorage) = initializeLibraryBridgesTimeMs.addMeasuredTime {
@@ -67,7 +67,7 @@ class GlobalLibraryTableBridgeImpl(val descriptor: EelDescriptor) : GlobalLibrar
override fun getPresentation(): LibraryTablePresentation = GLOBAL_LIBRARY_TABLE_PRESENTATION
override fun getModifiableModel(): LibraryTable.ModifiableModel {
return GlobalOrCustomModifiableLibraryTableBridgeImpl(this, descriptor, createEntitySourceForGlobalLibrary())
return GlobalOrCustomModifiableLibraryTableBridgeImpl(this, eelMachine, createEntitySourceForGlobalLibrary())
}
override fun dispose(): Unit = Disposer.dispose(libraryTableDelegate)
@@ -79,7 +79,7 @@ class GlobalLibraryTableBridgeImpl(val descriptor: EelDescriptor) : GlobalLibrar
override fun removeListener(listener: LibraryTable.Listener) = libraryTableDelegate.removeListener(listener)
private fun createEntitySourceForGlobalLibrary(): EntitySource {
val virtualFileUrlManager = GlobalWorkspaceModel.getInstance(descriptor).getVirtualFileUrlManager()
val virtualFileUrlManager = GlobalWorkspaceModel.getInstance(eelMachine).getVirtualFileUrlManager()
val globalLibrariesFile = virtualFileUrlManager.getOrCreateFromUrl(PathManager.getOptionsFile(JpsGlobalEntitiesSerializers.GLOBAL_LIBRARIES_FILE_NAME).absolutePath)
return JpsGlobalFileEntitySource(globalLibrariesFile)
}

View File

@@ -8,7 +8,7 @@ import com.intellij.openapi.diagnostic.debug
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.roots.libraries.LibraryTable
import com.intellij.platform.eel.EelDescriptor
import com.intellij.platform.eel.EelMachine
import com.intellij.platform.workspace.jps.entities.LibraryEntity
import com.intellij.platform.workspace.jps.entities.LibraryId
import com.intellij.platform.workspace.jps.entities.LibraryTableId
@@ -19,11 +19,11 @@ import com.intellij.workspaceModel.ide.impl.GlobalWorkspaceModel
import com.intellij.workspaceModel.ide.impl.legacyBridge.library.ProjectLibraryTableBridgeImpl.Companion.libraryMap
import com.intellij.workspaceModel.ide.impl.legacyBridge.library.ProjectLibraryTableBridgeImpl.Companion.mutableLibraryMap
internal class GlobalLibraryTableDelegate(private val libraryTable: LibraryTable, val descriptor: EelDescriptor, private val libraryTableId: LibraryTableId) : Disposable {
internal class GlobalLibraryTableDelegate(private val libraryTable: LibraryTable, val eelMachine: EelMachine, private val libraryTableId: LibraryTableId) : Disposable {
private val dispatcher = EventDispatcher.create(LibraryTable.Listener::class.java)
internal fun initializeLibraryBridges(changes: Map<Class<*>, List<EntityChange<*>>>, builder: MutableEntityStorage) {
val entityStorage = GlobalWorkspaceModel.getInstance(descriptor).entityStorage
val entityStorage = GlobalWorkspaceModel.getInstance(eelMachine).entityStorage
@Suppress("UNCHECKED_CAST")
val libraryChanges = (changes[LibraryEntity::class.java] as? List<EntityChange<LibraryEntity>>) ?: emptyList()
@@ -34,7 +34,7 @@ internal class GlobalLibraryTableDelegate(private val libraryTable: LibraryTable
builder.mutableLibraryMap.getOrPutDataByEntity(addChange.newEntity) {
LibraryBridgeImpl(
libraryTable = libraryTable,
origin = LibraryOrigin.OfDescriptor(descriptor),
origin = LibraryOrigin.OfMachine(eelMachine),
initialId = addChange.newEntity.symbolicId,
initialEntityStorage = entityStorage,
targetBuilder = builder
@@ -52,7 +52,7 @@ internal class GlobalLibraryTableDelegate(private val libraryTable: LibraryTable
.map { libraryEntity ->
Pair(libraryEntity, LibraryBridgeImpl(
libraryTable = libraryTable,
origin = LibraryOrigin.OfDescriptor(descriptor),
origin = LibraryOrigin.OfMachine(eelMachine),
initialId = libraryEntity.symbolicId,
initialEntityStorage = initialEntityStorage,
targetBuilder = null
@@ -107,7 +107,7 @@ internal class GlobalLibraryTableDelegate(private val libraryTable: LibraryTable
val changes = event.getChanges(LibraryEntity::class.java).filterLibraryChanges(libraryTableId)
if (changes.isEmpty()) return
val entityStorage = GlobalWorkspaceModel.getInstance(descriptor).entityStorage
val entityStorage = GlobalWorkspaceModel.getInstance(eelMachine).entityStorage
for (change in changes) {
LOG.debug { "Process ${libraryTableId.level} library change $change" }
when (change) {
@@ -174,7 +174,7 @@ internal class GlobalLibraryTableDelegate(private val libraryTable: LibraryTable
}
internal fun getLibraries(): Array<Library> {
val entityStorage = GlobalWorkspaceModel.getInstance(descriptor).entityStorage
val entityStorage = GlobalWorkspaceModel.getInstance(eelMachine).entityStorage
val storage = entityStorage.current
val libraryEntitySequence = storage.entities(LibraryEntity::class.java).filter { it.tableId == libraryTableId }.toList()
val libs: Array<Library> = libraryEntitySequence.mapNotNull { storage.libraryMap.getDataByEntity(it) }
@@ -183,7 +183,7 @@ internal class GlobalLibraryTableDelegate(private val libraryTable: LibraryTable
}
internal fun getLibraryByName(name: String): Library? {
val entityStorage = GlobalWorkspaceModel.getInstance(descriptor).entityStorage
val entityStorage = GlobalWorkspaceModel.getInstance(eelMachine).entityStorage
val libraryId = LibraryId(name, libraryTableId)
val library = entityStorage.current.resolve(libraryId)?.let { entity ->
entityStorage.current.libraryMap.getDataByEntity(entity)

View File

@@ -6,7 +6,7 @@ import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.roots.libraries.LibraryTable
import com.intellij.openapi.roots.libraries.PersistentLibraryKind
import com.intellij.openapi.util.Disposer
import com.intellij.platform.eel.EelDescriptor
import com.intellij.platform.eel.EelMachine
import com.intellij.platform.workspace.jps.entities.*
import com.intellij.platform.workspace.storage.EntitySource
import com.intellij.platform.workspace.storage.MutableEntityStorage
@@ -19,8 +19,8 @@ import com.intellij.workspaceModel.ide.impl.legacyBridge.library.ProjectLibraryT
import com.intellij.workspaceModel.ide.impl.legacyBridge.library.ProjectLibraryTableBridgeImpl.Companion.mutableLibraryMap
import org.jetbrains.jps.model.serialization.library.JpsLibraryTableSerializer
internal class GlobalOrCustomModifiableLibraryTableBridgeImpl(private val libraryTable: LibraryTable, val descriptor: EelDescriptor, private val entitySource: EntitySource) :
LegacyBridgeModifiableBase(MutableEntityStorage.from(GlobalWorkspaceModel.getInstance(descriptor).currentSnapshot), true),
internal class GlobalOrCustomModifiableLibraryTableBridgeImpl(private val libraryTable: LibraryTable, val machine: EelMachine, private val entitySource: EntitySource) :
LegacyBridgeModifiableBase(MutableEntityStorage.from(GlobalWorkspaceModel.getInstance(machine).currentSnapshot), true),
LibraryTable.ModifiableModel {
private val myAddedLibraries = mutableListOf<LibraryBridgeImpl>()
@@ -54,7 +54,7 @@ internal class GlobalOrCustomModifiableLibraryTableBridgeImpl(private val librar
val library = LibraryBridgeImpl(
libraryTable = libraryTable,
origin = LibraryOrigin.OfDescriptor(descriptor),
origin = LibraryOrigin.OfMachine(machine),
initialId = LibraryId(name, libraryTableId),
initialEntityStorage = entityStorageOnDiff,
targetBuilder = this.diff
@@ -78,7 +78,7 @@ internal class GlobalOrCustomModifiableLibraryTableBridgeImpl(private val librar
}
override fun commit() {
GlobalWorkspaceModel.getInstance(descriptor).updateModel("${libraryTableId.level} library table commit") {
GlobalWorkspaceModel.getInstance(machine).updateModel("${libraryTableId.level} library table commit") {
it.applyChangesFrom(diff)
}
libraries.forEach { library -> (library as LibraryBridgeImpl).clearTargetBuilder() }

View File

@@ -19,7 +19,7 @@ import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.TraceableDisposable
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.platform.backend.workspace.WorkspaceModel
import com.intellij.platform.eel.EelDescriptor
import com.intellij.platform.eel.EelMachine
import com.intellij.platform.workspace.jps.entities.LibraryId
import com.intellij.platform.workspace.jps.entities.LibraryRootTypeId
import com.intellij.platform.workspace.jps.serialization.impl.LibraryNameGenerator
@@ -49,7 +49,7 @@ interface LibraryBridge : LibraryEx {
@ApiStatus.Internal
sealed interface LibraryOrigin {
class OfProject(val project: Project) : LibraryOrigin
class OfDescriptor(val descriptor: EelDescriptor) : LibraryOrigin
class OfMachine(val eelMachine: EelMachine) : LibraryOrigin
}
@ApiStatus.Internal
@@ -126,7 +126,7 @@ class LibraryBridgeImpl(
override fun getModifiableModel(builder: MutableEntityStorage): LibraryEx.ModifiableModelEx {
val virtualFileUrlManager = when (origin) {
is LibraryOrigin.OfDescriptor -> GlobalWorkspaceModel.getInstance(origin.descriptor).getVirtualFileUrlManager()
is LibraryOrigin.OfMachine -> GlobalWorkspaceModel.getInstance(origin.eelMachine).getVirtualFileUrlManager()
is LibraryOrigin.OfProject -> WorkspaceModel.getInstance(origin.project).getVirtualFileUrlManager()
}
return LibraryModifiableModelBridgeImpl(this, librarySnapshot, builder, targetBuilder, virtualFileUrlManager, false)
@@ -185,7 +185,7 @@ class LibraryBridgeImpl(
}
val isDisposedGlobally = libraryEntity?.let {
val snapshot = when (origin) {
is LibraryOrigin.OfDescriptor -> GlobalWorkspaceModel.getInstance(origin.descriptor).currentSnapshot
is LibraryOrigin.OfMachine -> GlobalWorkspaceModel.getInstance(origin.eelMachine).currentSnapshot
is LibraryOrigin.OfProject -> WorkspaceModel.getInstance(origin.project).currentSnapshot
}
snapshot.libraryMap.getDataByEntity(it)?.isDisposed
@@ -196,7 +196,7 @@ class LibraryBridgeImpl(
Entity: ${libraryEntity.run { "$name, $this" }}
Is disposed in ${
when (origin) {
is LibraryOrigin.OfProject -> "project"; is LibraryOrigin.OfDescriptor -> "global (${origin.descriptor})"
is LibraryOrigin.OfProject -> "project"; is LibraryOrigin.OfMachine -> "global (${origin.eelMachine})"
}
} model: ${isDisposedGlobally != false}
Stack trace: $stackTrace

View File

@@ -103,8 +103,8 @@ internal class LibraryModifiableModelBridgeImpl(
it.applyChangesFrom(diff)
}
}
is LibraryOrigin.OfDescriptor -> {
GlobalWorkspaceModel.getInstance(o.descriptor).updateModel("Library model commit") {
is LibraryOrigin.OfMachine -> {
GlobalWorkspaceModel.getInstance(o.eelMachine).updateModel("Library model commit") {
it.applyChangesFrom(diff)
}
}

View File

@@ -16,7 +16,7 @@ import com.intellij.openapi.util.registry.Registry
import com.intellij.openapi.vfs.StandardFileSystems
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.platform.backend.workspace.virtualFile
import com.intellij.platform.eel.provider.LocalEelDescriptor
import com.intellij.platform.eel.provider.LocalEelMachine
import com.intellij.platform.workspace.jps.JpsGlobalFileEntitySource
import com.intellij.platform.workspace.jps.entities.SdkEntity
import com.intellij.platform.workspace.jps.entities.SdkRoot
@@ -276,6 +276,6 @@ fun SdkEntity.Builder.applyChangesFrom(fromSdk: SdkEntity) {
}
private fun getVirtualFileUrlManager(): VirtualFileUrlManager {
// here we can use LocalEelDescriptor, as we simply need to get the virtual file url manager
return GlobalWorkspaceModel.getInstance(LocalEelDescriptor).getVirtualFileUrlManager()
// here we can use LocalEelMachine, as we simply need to get the virtual file url manager
return GlobalWorkspaceModel.getInstance(LocalEelMachine).getVirtualFileUrlManager()
}

View File

@@ -9,8 +9,8 @@ import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.util.JDOMUtil
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.platform.backend.workspace.virtualFile
import com.intellij.platform.eel.EelDescriptor
import com.intellij.platform.eel.provider.LocalEelDescriptor
import com.intellij.platform.eel.EelMachine
import com.intellij.platform.eel.provider.LocalEelMachine
import com.intellij.platform.eel.provider.getEelDescriptor
import com.intellij.platform.workspace.jps.entities.*
import com.intellij.platform.workspace.jps.serialization.impl.ELEMENT_ADDITIONAL
@@ -55,7 +55,7 @@ internal class SdkModificatorBridgeImpl(private val originalEntity: SdkEntity.Bu
override fun setHomePath(path: String?) {
modifiedSdkEntity.homePath = if (path != null) {
val descriptor = getDescriptor(path)
val descriptor = getMachine(path)
val globalInstance = GlobalWorkspaceModel.getInstance(descriptor).getVirtualFileUrlManager()
globalInstance.getOrCreateFromUrl(path)
} else {
@@ -86,7 +86,7 @@ internal class SdkModificatorBridgeImpl(private val originalEntity: SdkEntity.Bu
}
override fun addRoot(root: VirtualFile, rootType: OrderRootType) {
val virtualFileUrlManager = GlobalWorkspaceModel.getInstance(LocalEelDescriptor).getVirtualFileUrlManager()
val virtualFileUrlManager = GlobalWorkspaceModel.getInstance(LocalEelMachine).getVirtualFileUrlManager()
modifiedSdkEntity.roots.add(
SdkRoot(virtualFileUrlManager.getOrCreateFromUrl(root.url), rootTypes[rootType.customName]!!)
)
@@ -111,7 +111,7 @@ internal class SdkModificatorBridgeImpl(private val originalEntity: SdkEntity.Bu
ThreadingAssertions.assertWriteAccess()
if (isCommitted) error("Modification already completed")
val descriptor = getDescriptor(modifiedSdkEntity.homePath?.toString())
val descriptor = getMachine(modifiedSdkEntity.homePath?.toString())
val globalWorkspaceModel = GlobalWorkspaceModel.getInstance(descriptor)
@@ -169,14 +169,14 @@ internal class SdkModificatorBridgeImpl(private val originalEntity: SdkEntity.Bu
return "$name Version:$versionString Path:($homePath)"
}
private fun getDescriptor(path: String?): EelDescriptor {
path ?: return LocalEelDescriptor
private fun getMachine(path: String?): EelMachine {
path ?: return LocalEelMachine
return try {
Path.of(path).getEelDescriptor()
Path.of(path).getEelDescriptor().machine
}
catch (_: InvalidPathException) {
// sometimes (in Ruby) the SDK home is set to 'temp:///root/nostubs'
LocalEelDescriptor
LocalEelMachine
}
}
}

View File

@@ -3,7 +3,7 @@ package com.intellij.workspaceModel.ide.legacyBridge
import com.intellij.openapi.roots.impl.libraries.CustomLibraryTableImpl
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar
import com.intellij.platform.eel.EelDescriptor
import com.intellij.platform.eel.EelMachine
import com.intellij.platform.workspace.storage.EntityChange
import com.intellij.platform.workspace.storage.MutableEntityStorage
import com.intellij.platform.workspace.storage.VersionedEntityStorage
@@ -18,10 +18,10 @@ interface GlobalEntityBridgeAndEventHandler {
fun handleChangedEvents(event: VersionedStorageChange)
companion object {
fun getAllGlobalEntityHandlers(descriptor: EelDescriptor): List<GlobalEntityBridgeAndEventHandler> {
fun getAllGlobalEntityHandlers(eelMachine: EelMachine): List<GlobalEntityBridgeAndEventHandler> {
val result = mutableListOf<GlobalEntityBridgeAndEventHandler>()
result.add(GlobalLibraryTableBridge.getInstance(descriptor))
result.add(GlobalSdkTableBridge.getInstance(descriptor))
result.add(GlobalLibraryTableBridge.getInstance(eelMachine))
result.add(GlobalSdkTableBridge.getInstance(eelMachine))
LibraryTablesRegistrar.getInstance().customLibraryTables.forEach { customLibraryTable ->
customLibraryTable as CustomLibraryTableImpl
result.add(customLibraryTable.getDelegate() as CustomLibraryTableBridge)

View File

@@ -5,7 +5,7 @@ import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.roots.libraries.LibraryTable
import com.intellij.platform.eel.EelDescriptor
import com.intellij.platform.eel.EelMachine
import com.intellij.workspaceModel.ide.impl.legacyBridge.library.GlobalLibraryTableBridgeImpl
import org.jetbrains.annotations.ApiStatus
import java.util.concurrent.ConcurrentHashMap
@@ -16,16 +16,16 @@ import java.util.concurrent.ConcurrentHashMap
@ApiStatus.Internal
interface GlobalLibraryTableBridge : GlobalEntityBridgeAndEventHandler, LibraryTable {
companion object {
fun getInstance(descriptor: EelDescriptor): GlobalLibraryTableBridge = ApplicationManager.getApplication().service<GlobalLibraryTableBridgeRegistry>().getTableBridge(descriptor)
fun getInstance(eelMachine: EelMachine): GlobalLibraryTableBridge = ApplicationManager.getApplication().service<GlobalLibraryTableBridgeRegistry>().getTableBridge(eelMachine)
}
}
@Service(Service.Level.APP)
private class GlobalLibraryTableBridgeRegistry {
private val registry: MutableMap<EelDescriptor, GlobalLibraryTableBridge> = ConcurrentHashMap()
private val registry: MutableMap<EelMachine, GlobalLibraryTableBridge> = ConcurrentHashMap()
fun getTableBridge(eelDescriptor: EelDescriptor): GlobalLibraryTableBridge {
return registry.computeIfAbsent(eelDescriptor) { GlobalLibraryTableBridgeImpl(it) }
fun getTableBridge(eelMachine: EelMachine): GlobalLibraryTableBridge {
return registry.computeIfAbsent(eelMachine) { GlobalLibraryTableBridgeImpl(it) }
}
}

View File

@@ -3,17 +3,17 @@ package com.intellij.workspaceModel.ide.legacyBridge
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.service
import com.intellij.platform.eel.EelDescriptor
import com.intellij.platform.eel.EelMachine
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Internal
interface GlobalSdkTableBridge: GlobalEntityBridgeAndEventHandler {
companion object {
fun getInstance(descriptor: EelDescriptor): GlobalSdkTableBridge = ApplicationManager.getApplication().service<GlobalSdkTableBridgeRegistry>().getTableBridge(descriptor)
fun getInstance(eelMachine: EelMachine): GlobalSdkTableBridge = ApplicationManager.getApplication().service<GlobalSdkTableBridgeRegistry>().getTableBridge(eelMachine)
}
}
@ApiStatus.Internal
interface GlobalSdkTableBridgeRegistry {
fun getTableBridge(eelDescriptor: EelDescriptor): GlobalSdkTableBridge
fun getTableBridge(eelMachine: EelMachine): GlobalSdkTableBridge
}

View File

@@ -3,24 +3,38 @@ package com.intellij.platform.testFramework.junit5.eel.impl
import com.intellij.platform.eel.EelApi
import com.intellij.platform.eel.EelDescriptor
import com.intellij.platform.eel.EelMachine
import com.intellij.platform.eel.EelOsFamily
import com.intellij.platform.eel.EelPathBoundDescriptor
import org.jetbrains.annotations.NonNls
import java.nio.file.Path
internal class EelTestDescriptor(val id: String, override val osFamily: EelOsFamily, val apiProvider: () -> EelApi) : EelDescriptor {
override val userReadableDescription: @NonNls String = "mock $id"
internal class EelTestDescriptor(override val rootPath: Path, val id: String, override val osFamily: EelOsFamily, val apiProvider: () -> EelApi) : EelPathBoundDescriptor {
override val machine: EelMachine = object : EelMachine {
override val name: @NonNls String = "mock $id"
override val osFamily: EelOsFamily get() = this@EelTestDescriptor.osFamily
override suspend fun toEelApi(): EelApi = apiProvider()
}
override suspend fun toEelApi(): EelApi {
return apiProvider()
}
override fun equals(other: Any?): Boolean {
return other is EelTestDescriptor && other.id == id
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as EelTestDescriptor
if (rootPath != other.rootPath) return false
if (id != other.id) return false
return true
}
override fun hashCode(): Int {
var result = id.hashCode()
result = 31 * result + apiProvider.hashCode()
var result = rootPath.hashCode()
result = 31 * result + id.hashCode()
return result
}
}

View File

@@ -8,6 +8,7 @@ import com.intellij.openapi.util.SystemInfo
import com.intellij.platform.core.nio.fs.MultiRoutingFileSystem
import com.intellij.platform.eel.EelApi
import com.intellij.platform.eel.EelDescriptor
import com.intellij.platform.eel.EelMachine
import com.intellij.platform.eel.EelPlatform
import com.intellij.platform.eel.annotations.MultiRoutingFileSystemPath
import com.intellij.platform.eel.fs.createTemporaryDirectory
@@ -25,14 +26,16 @@ import com.intellij.util.io.delete
import org.junit.jupiter.api.Assumptions
import java.nio.file.*
import java.util.concurrent.atomic.AtomicReference
import kotlin.io.path.Path
import kotlin.io.path.name
internal const val FAKE_WINDOWS_ROOT = "\\\\dummy-ij-root\\test-eel\\"
private val EelPlatform.name: String get() = when (this) {
is EelPlatform.Posix -> "posix"
is EelPlatform.Windows -> "windows"
}
private val EelPlatform.name: String
get() = when (this) {
is EelPlatform.Posix -> "posix"
is EelPlatform.Windows -> "windows"
}
internal val currentOs: EelPlatform
get() = if (SystemInfo.isWindows) {
@@ -67,7 +70,7 @@ internal fun eelInitializer(os: EelPlatform): TestFixtureInitializer<IsolatedFil
val fakeLocalFileSystem = EelUnitTestFileSystem(EelUnitTestFileSystemProvider(defaultProvider), os, directory, fakeRoot)
val apiRef = AtomicReference<EelApi>(null)
val descriptor = EelTestDescriptor(Ksuid.generate().toString(), os.osFamily, apiRef::get)
val descriptor = EelTestDescriptor(Path(fakeRoot), Ksuid.generate().toString(), os.osFamily, apiRef::get)
val disposable = Disposer.newDisposable()
@@ -102,12 +105,12 @@ internal fun eelInitializer(os: EelPlatform): TestFixtureInitializer<IsolatedFil
if (eelDescriptor == descriptor) listOf(fakeRoot)
else null
override fun getInternalName(eelDescriptor: EelDescriptor): String? =
if (eelDescriptor == descriptor) meaningfulDirName
override fun getInternalName(eelMachine: EelMachine): String? =
if (eelMachine == descriptor.machine) meaningfulDirName
else null
override fun getEelDescriptorByInternalName(internalName: String): EelDescriptor? =
if (internalName == meaningfulDirName) descriptor
override fun getEelMachineByInternalName(internalName: String): EelMachine? =
if (internalName == meaningfulDirName) descriptor.machine
else null
},
disposable,

View File

@@ -13,6 +13,7 @@ import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.JDOMUtil
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.platform.eel.provider.LocalEelDescriptor
import com.intellij.platform.eel.provider.LocalEelMachine
import com.intellij.platform.testFramework.projectModel.library.MockCustomLibraryTableDescription
import com.intellij.platform.testFramework.projectModel.library.NewMockCustomLibraryTableDescription
import com.intellij.platform.workspace.jps.entities.LibraryEntity
@@ -57,7 +58,7 @@ class CustomLibraryBridgeTest {
}
}
val globalWorkspaceModel = GlobalWorkspaceModel.getInstance(LocalEelDescriptor)
val globalWorkspaceModel = GlobalWorkspaceModel.getInstance(LocalEelMachine)
globalWorkspaceModel.currentSnapshot.entities(LibraryEntity::class.java)
.onEach { assertEquals(it.tableId, LibraryTableId.GlobalLibraryTableId("Mock")) }
.onEach { assertTrue(libraryNames.contains(it.name)) }
@@ -175,7 +176,7 @@ class CustomLibraryBridgeTest {
}
assertEquals(firstLibraryName, customLibraryTable.libraries.single().name)
val globalWorkspaceModel = GlobalWorkspaceModel.getInstance(LocalEelDescriptor)
val globalWorkspaceModel = GlobalWorkspaceModel.getInstance(LocalEelMachine)
assertEquals(1, globalWorkspaceModel.currentSnapshot.entities(LibraryEntity::class.java).toList().size)
val mockCustomLibraryTableDescription = MockCustomLibraryTableDescription()

View File

@@ -47,17 +47,17 @@ class GlobalWorkspaceModelEelTest {
assumeRegistryValueSet()
application.service<GlobalWorkspaceModelRegistry>().dropCaches()
val globalWorkspaceModelEel = GlobalWorkspaceModel.getInstance(eelProject.get().getEelDescriptor())
val globalWorkspaceModelEel = GlobalWorkspaceModel.getInstance(eelProject.get().getEelDescriptor().machine)
edtWriteAction {
globalWorkspaceModelEel.updateModel("A test update") { mutableStorage ->
mutableStorage.addEntity(StringEntity("sample", SampleEntitySource("test eel")))
}
}
val eelEntities = GlobalWorkspaceModel.getInstance(eelProject.get().getEelDescriptor()).currentSnapshot.entities(StringEntity::class.java).toList()
val eelEntities = GlobalWorkspaceModel.getInstance(eelProject.get().getEelDescriptor().machine).currentSnapshot.entities(StringEntity::class.java).toList()
Assertions.assertFalse(eelEntities.isEmpty())
val localEntities = GlobalWorkspaceModel.getInstance(localProject.get().getEelDescriptor()).currentSnapshot.entities(StringEntity::class.java).toList()
val localEntities = GlobalWorkspaceModel.getInstance(localProject.get().getEelDescriptor().machine).currentSnapshot.entities(StringEntity::class.java).toList()
Assertions.assertTrue(localEntities.isEmpty())
}
@@ -67,8 +67,8 @@ class GlobalWorkspaceModelEelTest {
assumeRegistryValueSet()
application.service<GlobalWorkspaceModelRegistry>().dropCaches()
val globalWorkspaceModelEel = GlobalWorkspaceModel.getInstance(eelProject.get().getEelDescriptor())
val globalWorkspaceModelLocal = GlobalWorkspaceModel.getInstance(localProject.get().getEelDescriptor())
val globalWorkspaceModelEel = GlobalWorkspaceModel.getInstance(eelProject.get().getEelDescriptor().machine)
val globalWorkspaceModelLocal = GlobalWorkspaceModel.getInstance(localProject.get().getEelDescriptor().machine)
edtWriteAction {
@@ -83,15 +83,15 @@ class GlobalWorkspaceModelEelTest {
application.service<GlobalWorkspaceModelCache>().saveCacheNow()
application.service<GlobalWorkspaceModelRegistry>().dropCaches()
val eelModel = GlobalWorkspaceModel.getInstance(eelProject.get().getEelDescriptor())
val eelModel = GlobalWorkspaceModel.getInstance(eelProject.get().getEelDescriptor().machine)
Assertions.assertTrue(eelModel.loadedFromCache)
val eelEntities = eelModel.currentSnapshot.entities(StringEntity::class.java).toList()
Assertions.assertTrue(eelEntities.find { it.data == "eel sample" } != null)
Assertions.assertFalse(eelEntities.find { it.data == "local sample" } != null)
val localModel = GlobalWorkspaceModel.getInstance(localProject.get().getEelDescriptor())
val localModel = GlobalWorkspaceModel.getInstance(localProject.get().getEelDescriptor().machine)
Assertions.assertTrue(localModel.loadedFromCache)
val localEntities = GlobalWorkspaceModel.getInstance(localProject.get().getEelDescriptor()).currentSnapshot.entities(StringEntity::class.java).toList()
val localEntities = GlobalWorkspaceModel.getInstance(localProject.get().getEelDescriptor().machine).currentSnapshot.entities(StringEntity::class.java).toList()
Assertions.assertTrue(localEntities.find { it.data == "local sample" } != null)
Assertions.assertFalse(localEntities.find { it.data == "eel sample" } != null)
}

View File

@@ -4,6 +4,7 @@ package com.intellij.workspaceModel.ide.impl.jps.serialization
import com.intellij.openapi.projectRoots.ProjectJdkTable
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar
import com.intellij.platform.eel.provider.LocalEelDescriptor
import com.intellij.platform.eel.provider.LocalEelMachine
import com.intellij.platform.workspace.jps.JpsGlobalFileEntitySource
import com.intellij.platform.workspace.jps.entities.LibraryEntity
import com.intellij.platform.workspace.jps.entities.LibraryRootTypeId
@@ -46,7 +47,7 @@ class JpsGlobalEntitiesLoaderTest {
Assert.assertEquals(librariesNames.size, libraryBridges.size)
UsefulTestCase.assertSameElements(librariesNames, libraryBridges.map { it.name })
val workspaceModel = GlobalWorkspaceModel.getInstance(LocalEelDescriptor)
val workspaceModel = GlobalWorkspaceModel.getInstance(LocalEelMachine)
val libraryEntities = workspaceModel.currentSnapshot.entities(LibraryEntity::class.java).toList()
Assert.assertEquals(librariesNames.size, libraryEntities.size)
UsefulTestCase.assertSameElements(librariesNames, libraryEntities.map { it.name })
@@ -73,7 +74,7 @@ class JpsGlobalEntitiesLoaderTest {
Assert.assertEquals(sdkInfos.size, sdkBridges.size)
UsefulTestCase.assertSameElements(sdkInfos, sdkBridges.map { SdkTestInfo(it.name, it.versionString!!, it.sdkType.name) })
val workspaceModel = GlobalWorkspaceModel.getInstance(LocalEelDescriptor)
val workspaceModel = GlobalWorkspaceModel.getInstance(LocalEelMachine)
val sdkEntities = workspaceModel.currentSnapshot.entities(SdkEntity::class.java).toList()
Assert.assertEquals(sdkInfos.size, sdkEntities.size)
UsefulTestCase.assertSameElements(sdkInfos, sdkEntities.map { SdkTestInfo(it.name, it.version!!, it.type) })

View File

@@ -9,6 +9,7 @@ import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.roots.PersistentOrderRootType
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar
import com.intellij.platform.eel.provider.LocalEelDescriptor
import com.intellij.platform.eel.provider.LocalEelMachine
import com.intellij.platform.workspace.jps.entities.*
import com.intellij.testFramework.ApplicationRule
import com.intellij.testFramework.DisposableRule
@@ -44,7 +45,7 @@ class JpsGlobalEntitiesSavingTest {
libraryTable as GlobalLibraryTableBridgeImpl
Assert.assertEquals(0, libraryTable.libraries.size)
val workspaceModel = GlobalWorkspaceModel.getInstance(LocalEelDescriptor)
val workspaceModel = GlobalWorkspaceModel.getInstance(LocalEelMachine)
Assert.assertEquals(0, workspaceModel.currentSnapshot.entities(LibraryEntity::class.java).toList().size)
val virtualFileManager = workspaceModel.getVirtualFileUrlManager()
@@ -80,7 +81,7 @@ class JpsGlobalEntitiesSavingTest {
val sdks = ProjectJdkTable.getInstance().allJdks
Assert.assertEquals(0, sdks.size)
val workspaceModel = GlobalWorkspaceModel.getInstance(LocalEelDescriptor)
val workspaceModel = GlobalWorkspaceModel.getInstance(LocalEelMachine)
Assert.assertEquals(0, workspaceModel.currentSnapshot.entities(SdkEntity::class.java).toList().size)
val virtualFileManager = workspaceModel.getVirtualFileUrlManager()

View File

@@ -12,6 +12,7 @@ import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar
import com.intellij.openapi.util.io.FileUtil
import com.intellij.platform.backend.workspace.WorkspaceModel
import com.intellij.platform.eel.provider.LocalEelDescriptor
import com.intellij.platform.eel.provider.LocalEelMachine
import com.intellij.platform.workspace.jps.entities.*
import com.intellij.testFramework.ApplicationRule
import com.intellij.testFramework.DisposableRule
@@ -50,7 +51,7 @@ class JpsGlobalEntitiesSyncTest {
parentDisposable = disposableRule.disposable, ) { _, entitySource ->
val sdkInfos = mutableListOf(SdkTestInfo("corretto-20", "Amazon Corretto version 20.0.2", "JavaSDK"),
SdkTestInfo("jbr-17", "java version \"17.0.7\"", "JavaSDK"))
val sdkEntities = GlobalWorkspaceModel.getInstance(LocalEelDescriptor).currentSnapshot.entities(SdkEntity::class.java).toList()
val sdkEntities = GlobalWorkspaceModel.getInstance(LocalEelMachine).currentSnapshot.entities(SdkEntity::class.java).toList()
UsefulTestCase.assertSameElements(sdkInfos, sdkEntities.map { SdkTestInfo(it.name, it.version!!, it.type) })
val loadedProjects = listOf(loadProject(), loadProject())
@@ -59,7 +60,7 @@ class JpsGlobalEntitiesSyncTest {
ApplicationManager.getApplication().invokeAndWait {
runWriteAction {
GlobalWorkspaceModel.getInstance(LocalEelDescriptor).updateModel("Test update") { builder ->
GlobalWorkspaceModel.getInstance(LocalEelMachine).updateModel("Test update") { builder ->
val sdkEntity = builder.entities(SdkEntity::class.java).first { it.name == "corretto-20" }
val sdkNameToRemove = sdkEntity.name
builder.removeEntity(sdkEntity)
@@ -111,7 +112,7 @@ class JpsGlobalEntitiesSyncTest {
val sdkBridges = ProjectJdkTable.getInstance().allJdks
UsefulTestCase.assertSameElements(sdkBridges.map { SdkTestInfo(it.name, it.versionString!!, it.sdkType.name) }, sdkInfos)
val globalWorkspaceModel = GlobalWorkspaceModel.getInstance(LocalEelDescriptor)
val globalWorkspaceModel = GlobalWorkspaceModel.getInstance(LocalEelMachine)
val globalVirtualFileUrlManager = globalWorkspaceModel.getVirtualFileUrlManager()
val sdkEntities = globalWorkspaceModel.currentSnapshot.entities(SdkEntity::class.java).toList()
@@ -144,7 +145,7 @@ class JpsGlobalEntitiesSyncTest {
val projectLibrariesNames = mutableListOf("spring", "junit", "kotlin")
val globalLibrariesNames = mutableListOf("aws.s3", "org.maven.common", "com.google.plugin", "org.microsoft")
val globalLibraryEntities = GlobalWorkspaceModel.getInstance(LocalEelDescriptor).currentSnapshot.entities(LibraryEntity::class.java).toList()
val globalLibraryEntities = GlobalWorkspaceModel.getInstance(LocalEelMachine).currentSnapshot.entities(LibraryEntity::class.java).toList()
UsefulTestCase.assertSameElements(globalLibrariesNames, globalLibraryEntities.map { it.name })
val loadedProjects = listOf(loadProject(), loadProject())
@@ -153,7 +154,7 @@ class JpsGlobalEntitiesSyncTest {
ApplicationManager.getApplication().invokeAndWait {
runWriteAction {
GlobalWorkspaceModel.getInstance(LocalEelDescriptor).updateModel("Test update") { builder ->
GlobalWorkspaceModel.getInstance(LocalEelMachine).updateModel("Test update") { builder ->
val libraryEntity = builder.entities(LibraryEntity::class.java).first{ it.name == "aws.s3" }
val libraryNameToRemove = libraryEntity.name
builder.removeEntity(libraryEntity)
@@ -201,7 +202,7 @@ class JpsGlobalEntitiesSyncTest {
val libraryBridges = libraryTable.libraries
UsefulTestCase.assertSameElements(globalLibrariesNames, libraryBridges.map { it.name })
val globalWorkspaceModel = GlobalWorkspaceModel.getInstance(LocalEelDescriptor)
val globalWorkspaceModel = GlobalWorkspaceModel.getInstance(LocalEelMachine)
val globalVirtualFileUrlManager = globalWorkspaceModel.getVirtualFileUrlManager()
val globalLibraryEntities = globalWorkspaceModel.currentSnapshot.entities(LibraryEntity::class.java).associateBy { it.name }

View File

@@ -22,6 +22,7 @@ import com.intellij.openapi.util.text.StringUtil
import com.intellij.openapi.vfs.VfsUtil
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.platform.eel.provider.LocalEelDescriptor
import com.intellij.platform.eel.provider.LocalEelMachine
import com.intellij.platform.workspace.jps.*
import com.intellij.platform.workspace.jps.entities.LibraryEntity
import com.intellij.platform.workspace.jps.serialization.impl.*
@@ -460,7 +461,7 @@ internal fun copyAndLoadGlobalEntities(originalFile: String? = null,
ApplicationManager.getApplication().replaceService(GlobalWorkspaceModelRegistry::class.java, GlobalWorkspaceModelRegistry(), parentDisposable)
// Entity source for global entities
val virtualFileManager = GlobalWorkspaceModel.getInstance(LocalEelDescriptor).getVirtualFileUrlManager()
val virtualFileManager = GlobalWorkspaceModel.getInstance(LocalEelMachine).getVirtualFileUrlManager()
val globalLibrariesFile = virtualFileManager.getOrCreateFromUrl("$testDir/options/applicationLibraries.xml")
val libraryEntitySource = JpsGlobalFileEntitySource(globalLibrariesFile)
@@ -473,7 +474,7 @@ internal fun copyAndLoadGlobalEntities(originalFile: String? = null,
application.invokeAndWait { saveDocumentsAndProjectsAndApp(true) }
val globalEntitiesFolder = File(PathManagerEx.getCommunityHomePath(),
"platform/workspace/jps/tests/testData/serialization/global/$expectedFile")
val entityStorage = GlobalWorkspaceModel.getInstance(LocalEelDescriptor).entityStorage.current
val entityStorage = GlobalWorkspaceModel.getInstance(LocalEelMachine).entityStorage.current
if (entityStorage.entities(LibraryEntity::class.java).toList().isEmpty()) {
optionsFolder.assertMatches(directoryContentOf(globalEntitiesFolder.toPath()),
filePathFilter = { it.contains("jdk.table.xml") })

View File

@@ -12,7 +12,7 @@ import com.intellij.platform.eel.EelTunnelsApi.HostAddress
import com.intellij.platform.eel.fs.getPath
import com.intellij.platform.eel.provider.LocalEelDescriptor
import com.intellij.platform.eel.provider.asEelPath
import com.intellij.platform.eel.provider.asNioPathOrNull
import com.intellij.platform.eel.provider.asNioPath
import com.intellij.platform.eel.provider.getEelDescriptor
import com.intellij.platform.eel.provider.utils.forwardLocalPort
import com.intellij.util.PathMapper
@@ -43,7 +43,7 @@ class EelTargetEnvironmentConfigurationProvider(val eel: EelApi, val project: Pr
override fun convertToLocal(remotePath: String): String {
val nio = Path.of(remotePath)
val eelPath = eel.fs.getPath(nio.toCanonicalPath())
return eelPath.asNioPathOrNull(project)!!.toCanonicalPath()
return eelPath.asNioPath().toCanonicalPath()
}
override fun canReplaceRemote(remotePath: String): Boolean {

View File

@@ -347,7 +347,7 @@ class MavenShCommandLineState(val environment: ExecutionEnvironment, private val
if (type is MavenWrapper) {
val path = getPathToWrapperScript()
val file = workingDir.resolve(path)
if (file.asNioPath(myConfiguration.project).exists()) {
if (file.asNioPath().exists()) {
return path
}
return getMavenExecutablePath(BundledMaven3, eel)

View File

@@ -55,7 +55,7 @@ class EelRemotePathTransformFactory : RemotePathTransformerFactory {
val canonicalPath = Paths.get(remotePath).toCanonicalPath()
return runCatching {
val eelPath = eel.fs.getPath(canonicalPath)
val fullyQualifiedPath = eelPath.asNioPath(project)
val fullyQualifiedPath = eelPath.asNioPath()
return@runCatching fullyQualifiedPath.toString()
}.getOrNull() ?: remotePath
}

View File

@@ -12,6 +12,7 @@ import com.intellij.openapi.util.NlsSafe
import com.intellij.openapi.util.text.HtmlChunk
import com.intellij.openapi.util.text.StringUtil
import com.intellij.platform.eel.EelDescriptor
import com.intellij.platform.eel.EelMachine
import com.intellij.platform.eel.path.EelPath.Companion.parse
import com.intellij.platform.eel.pathSeparator
import com.intellij.platform.eel.provider.asNioPath
@@ -87,14 +88,14 @@ internal class ShDocumentationProvider(private val scope: CoroutineScope) : Docu
return contextElement
}
private val myManExecutableCache = ConcurrentHashMap<EelDescriptor, SuspendingLazy<String?>>()
private val myManCache = ConcurrentHashMap<Pair<EelDescriptor, String>, SuspendingLazy<String>>()
private val myManExecutableCache = ConcurrentHashMap<EelMachine, SuspendingLazy<String?>>()
private val myManCache = ConcurrentHashMap<Pair<EelMachine, String>, SuspendingLazy<String>>()
private fun fetchInfo(commandName: String?, project: Project): @NlsSafe String? {
val eelDescriptor = project.getEelDescriptor()
if (commandName == null) return null
val manExecutablePromise = myManExecutableCache.computeIfAbsent(eelDescriptor) {
val manExecutablePromise = myManExecutableCache.computeIfAbsent(eelDescriptor.machine) {
scope.suspendingLazy {
val eel = eelDescriptor.toEelApi()
val path = eel.exec.fetchLoginShellEnvVariables()["PATH"]
@@ -115,7 +116,7 @@ internal class ShDocumentationProvider(private val scope: CoroutineScope) : Docu
}
return runBlockingMaybeCancellable { // fixme: is this good idea call blocking code here?
myManCache.computeIfAbsent(eelDescriptor to commandName) {
myManCache.computeIfAbsent(eelDescriptor.machine to commandName) {
scope.suspendingLazy {
val manExecutable = manExecutablePromise.getValue()

View File

@@ -58,7 +58,7 @@ suspend fun ExecService.execGetStdout(
procListener: PyProcessListener? = null,
): PyResult<String> {
val binary = eelApi.exec.findExeFilesInPath(binaryName).firstOrNull()?.asNioPath()
?: return PyResult.localizedError(PyExecBundle.message("py.exec.fileNotFound", binaryName, eelApi.descriptor.userReadableDescription))
?: return PyResult.localizedError(PyExecBundle.message("py.exec.fileNotFound", binaryName, eelApi.descriptor.machine.name))
return execGetStdout(binary, args, options, procListener)
}

View File

@@ -78,7 +78,7 @@ class ExecServiceShowCaseTest {
}
SimpleApiExecType.FULL_PATH -> {
var fullPath = eel.exec.findExeFilesInPath(binary).firstOrNull()
?: error("no $binary found on ${eel.descriptor.userReadableDescription}")
?: error("no $binary found on ${eel.descriptor.machine.name}")
if (rainyDay) {
fullPath = fullPath.resolve("junk")
}

View File

@@ -8,6 +8,7 @@ import com.intellij.openapi.diagnostic.fileLogger
import com.intellij.openapi.util.registry.RegistryManager
import com.intellij.platform.eel.EelApi
import com.intellij.platform.eel.EelDescriptor
import com.intellij.platform.eel.EelMachine
import com.intellij.platform.eel.provider.getEelDescriptor
import com.intellij.platform.eel.provider.localEel
import com.intellij.python.community.impl.installer.PySdkToInstallManager
@@ -49,13 +50,13 @@ internal suspend fun getCacheTimeout(): Duration? =
@Internal
internal class SystemPythonServiceImpl(scope: CoroutineScope) : SystemPythonService, SimplePersistentStateComponent<MyServiceState>(MyServiceState()) {
private val findPythonsMutex = Mutex()
private val _cacheImpl: CompletableDeferred<Cache<EelDescriptor, SystemPython>?> = CompletableDeferred()
private val _cacheImpl: CompletableDeferred<Cache<EelMachine, SystemPython>?> = CompletableDeferred()
private suspend fun cache() = _cacheImpl.await()
init {
scope.launch {
_cacheImpl.complete(getCacheTimeout()?.let { interval ->
Cache<EelDescriptor, SystemPython>(scope, interval) { eelDescriptor ->
Cache<EelMachine, SystemPython>(scope, interval) { eelDescriptor ->
searchPythonsPhysicallyNoCache(eelDescriptor.toEelApi())
}
})
@@ -67,7 +68,7 @@ internal class SystemPythonServiceImpl(scope: CoroutineScope) : SystemPythonServ
.getOr(PySystemPythonBundle.message("py.system.python.service.python.is.broken", pythonPath)) { return it }
val systemPython = SystemPython(pythonWithLangLevel, null)
state.userProvidedPythons.add(pythonPath.pathString)
cache()?.get(pythonPath.getEelDescriptor())?.add(systemPython)
cache()?.get(pythonPath.getEelDescriptor().machine)?.add(systemPython)
return Result.success(systemPython)
}
@@ -80,10 +81,10 @@ internal class SystemPythonServiceImpl(scope: CoroutineScope) : SystemPythonServ
cache.startUpdate()
if (forceRefresh) {
logger.info("pythons refresh requested")
cache.updateCache(eelApi.descriptor) // Update cache and suspend till update finished
cache.updateCache(eelApi.descriptor.machine) // Update cache and suspend till update finished
}
else {
cache.get(eelApi.descriptor)
cache.get(eelApi.descriptor.machine)
}.sorted()
} ?: searchPythonsPhysicallyNoCache(eelApi).sorted()

View File

@@ -50,7 +50,7 @@ suspend fun detectPipEnvExecutable(): PyResult<Path> {
}
val executablePath = localEel.exec.where(name)?.asNioPath()
if (executablePath == null) {
return PyResult.localizedError(PyBundle.message("cannot.find.executable", name, localEel.descriptor.userReadableDescription))
return PyResult.localizedError(PyBundle.message("cannot.find.executable", name, localEel.descriptor.machine.name))
}
return PyResult.success(executablePath)