IJPL-194952 Revert "[wsl-eel] IJPL-186144: Get rid of IjentWslNioFsToggler"

This reverts commit dae3a216


(cherry picked from commit b7ba1c026d1bcbf8d51f57a64646ce8d3a1db483)

IJ-MR-167682

GitOrigin-RevId: ea15fa242203ade09290ad23e02f767ca03ab72a
This commit is contained in:
Vladimir Lagunov
2025-07-01 14:58:44 +02:00
committed by intellij-monorepo-bot
parent b0537e456c
commit 70908d094a
12 changed files with 389 additions and 205 deletions

View File

@@ -7,9 +7,10 @@ import com.intellij.platform.eel.EelDescriptor
import com.intellij.platform.eel.provider.EelNioBridgeService
import com.intellij.util.containers.forEachGuaranteed
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.job
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.annotations.TestOnly
import org.jetbrains.annotations.VisibleForTesting
import java.io.Closeable
import java.nio.file.FileSystem
import java.nio.file.FileSystems
import java.nio.file.Path
@@ -20,19 +21,13 @@ import kotlin.io.path.pathString
@ApiStatus.Internal
@VisibleForTesting
class EelNioBridgeServiceImpl(coroutineScope: CoroutineScope) : EelNioBridgeService {
class EelNioBridgeServiceImpl(private val coroutineScope: CoroutineScope) : EelNioBridgeService {
private val multiRoutingFileSystemProvider = FileSystems.getDefault().provider()
private val rootRegistry = ConcurrentHashMap<EelDescriptor, MutableSet<Path>>()
private val fsRegistry = ConcurrentHashMap<String, FileSystem>()
private val idRegistry = ConcurrentHashMap<EelDescriptor, String>()
init {
coroutineScope.coroutineContext.job.invokeOnCompletion {
idRegistry.keys().asSequence().forEach { unregister(it) }
}
}
override fun tryGetEelDescriptor(nioPath: Path): EelDescriptor? {
return rootRegistry.entries.asSequence()
.flatMap { (descriptor, paths) -> paths.map { path -> descriptor to path } }
@@ -93,4 +88,36 @@ class EelNioBridgeServiceImpl(coroutineScope: CoroutineScope) : EelNioBridgeServ
return true
}
@TestOnly
fun temporarilyResetState(): Closeable {
val oldRootRegistry = HashMap(rootRegistry)
val oldFsRegistry = HashMap(fsRegistry)
val oldIdRegistry = HashMap(idRegistry)
for (descriptor in rootRegistry.keys.toList()) {
val roots = rootRegistry.remove(descriptor)!!
for (localRoot in roots) {
fsRegistry.compute(localRoot.toString()) { _, existingFileSystem ->
MultiRoutingFileSystemProvider.computeBackend(multiRoutingFileSystemProvider, localRoot.toString(), false, false) { underlyingProvider, actualFs ->
require(existingFileSystem == actualFs)
null
}
null
}
}
}
idRegistry.clear()
return Closeable {
rootRegistry.putAll(oldRootRegistry)
fsRegistry.putAll(oldFsRegistry)
idRegistry.putAll(oldIdRegistry)
for ((localRootString, fs) in fsRegistry) {
MultiRoutingFileSystemProvider.computeBackend(multiRoutingFileSystemProvider, localRootString, false, false) { _, _ -> fs }
}
}
}
}

View File

@@ -16,6 +16,5 @@
<orderEntry type="module" module-name="intellij.platform.testFramework" />
<orderEntry type="module" module-name="intellij.platform.util.coroutines" />
<orderEntry type="module" module-name="intellij.platform.ide.impl.wsl" />
<orderEntry type="module" module-name="intellij.platform.execution" />
</component>
</module>

View File

@@ -1,24 +1,17 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@file:JvmName("WslIjentTestUtil")
package com.intellij.ijent.testFramework.wsl
import com.intellij.execution.wsl.WSLDistribution
import com.intellij.execution.wsl.WslIjentManager
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.extensions.BaseExtensionPointName
import com.intellij.openapi.util.Disposer
import com.intellij.platform.eel.impl.provider.EelNioBridgeServiceImpl
import com.intellij.platform.eel.provider.EelInitialization
import com.intellij.platform.eel.provider.EelNioBridgeService
import com.intellij.platform.eel.provider.EelProvider
import com.intellij.platform.ide.impl.wsl.ProductionWslIjentManager
import com.intellij.platform.ide.impl.wsl.WslEelProvider
import com.intellij.platform.ide.impl.wsl.ijent.nio.toggle.IjentWslNioFsToggler
import com.intellij.platform.util.coroutines.childScope
import com.intellij.testFramework.registerExtension
import com.intellij.testFramework.replaceService
import com.intellij.util.asDisposable
import kotlinx.coroutines.*
import java.util.concurrent.CancellationException
@@ -30,17 +23,14 @@ fun replaceProductionWslIjentManager(newServiceScope: CoroutineScope) {
replaceService(WslIjentManager::class.java, ::ProductionWslIjentManager, newServiceScope)
}
suspend fun replaceWslServicesAndRunWslEelInitialization(newServiceScope: CoroutineScope, wsl: WSLDistribution) {
replaceProductionWslIjentManager(newServiceScope)
replaceService(EelNioBridgeService::class.java, ::EelNioBridgeServiceImpl, newServiceScope)
replaceExtension(newServiceScope, EelProvider.EP_NAME, WslEelProvider(newServiceScope))
EelInitialization.runEelInitialization(wsl.getUNCRootPath().toString())
fun replaceIjentWslNioFsToggler(newServiceScope: CoroutineScope) {
replaceService(IjentWslNioFsToggler::class.java, ::IjentWslNioFsToggler, newServiceScope)
}
private fun <T : Any> replaceExtension(scope: CoroutineScope, name: BaseExtensionPointName<*>, instance: T) {
ApplicationManager.getApplication().apply {
extensionArea.getExtensionPoint<T>(name.name).unregisterExtension(instance.javaClass)
registerExtension(name, instance, scope.asDisposable())
fun temporarilyResetEelNioBridge(serviceScope: CoroutineScope) {
val guard = (EelNioBridgeService.getInstanceSync() as EelNioBridgeServiceImpl).temporarilyResetState()
serviceScope.coroutineContext.job.invokeOnCompletion {
guard.close()
}
}

View File

@@ -310,14 +310,17 @@ internal object SystemHealthMonitor {
}
}
private fun checkEelVmOptions() {
// TODO: remove this check
private suspend fun checkEelVmOptions() {
if (!WslIjentAvailabilityService.getInstance().useIjentForWslNioFileSystem()) return
val changedOptions = MultiRoutingFileSystemVmOptionsSetter.ensureInVmOptions()
when {
changedOptions.isEmpty() -> Unit
changedOptions.isEmpty() -> {
// Since IjentWslNioFsToggler was moved from the core to the module, it can't be accessed here anymore.
// And probably, it's not required anymore.
// IjentWslNioFsToggler.instanceAsync().enableForAllWslDistributions()
}
PluginManagerCore.isRunningFromSources() || AppMode.isDevServer() -> {
logger<MultiRoutingFileSystemVmOptionsSetter>().warn(
changedOptions.joinToString(

View File

@@ -1,6 +1,6 @@
<idea-plugin>
<extensions defaultExtensionNs="com.intellij">
<eelProvider implementation="com.intellij.platform.ide.impl.wsl.WslEelProvider" os="windows"/>
<eelProvider implementation="com.intellij.platform.ide.impl.wsl.ijent.nio.toggle.IjentWslNioFsToggler$WslEelProvider" os="windows"/>
<applicationService serviceInterface="com.intellij.execution.wsl.WslIjentManager"
serviceImplementation="com.intellij.platform.ide.impl.wsl.ProductionWslIjentManager"/>
</extensions>

View File

@@ -1,171 +1 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
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.openapi.components.serviceAsync
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.util.registry.Registry
import com.intellij.platform.eel.EelApi
import com.intellij.platform.eel.EelDescriptor
import com.intellij.platform.eel.EelOsFamily
import com.intellij.platform.eel.provider.EelNioBridgeService
import com.intellij.platform.eel.provider.EelProvider
import com.intellij.platform.eel.provider.LocalEelDescriptor
import com.intellij.platform.ide.impl.wsl.ijent.nio.IjentWslNioFileSystemProvider
import com.intellij.platform.ijent.IjentPosixApi
import com.intellij.platform.ijent.community.impl.IjentFailSafeFileSystemPosixApi
import com.intellij.platform.ijent.community.impl.nio.IjentNioFileSystemProvider
import com.intellij.platform.ijent.community.impl.nio.telemetry.TracingFileSystemProvider
import com.intellij.util.containers.ContainerUtil
import com.intellij.util.containers.forEachGuaranteed
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.job
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.annotations.NonNls
import java.net.URI
import java.nio.file.FileSystemAlreadyExistsException
import java.nio.file.Path
import java.nio.file.spi.FileSystemProvider
import kotlin.io.path.Path
private val WSLDistribution.roots: Set<String>
get() {
val localRoots = mutableSetOf(getWindowsPath("/"))
localRoots.single().let {
localRoots += it.replace("wsl.localhost", "wsl$")
localRoots += it.replace("wsl$", "wsl.localhost")
}
return localRoots
}
private suspend fun WSLDistribution.getIjent(): IjentPosixApi {
return WslIjentManager.instanceAsync().getIjentApi(this, null, false)
}
@ApiStatus.Internal
class WslEelProvider(private val coroutineScope: CoroutineScope) : EelProvider {
private val providersCache = ContainerUtil.createConcurrentWeakMap<String, FileSystemProvider>()
companion object {
private val LOG = logger<WslEelProvider>()
}
override suspend fun tryInitialize(path: String) {
if (!serviceAsync<WslIjentAvailabilityService>().useIjentForWslNioFileSystem()) {
return
}
if (!MultiRoutingFileSystemUtils.isMultiRoutingFsEnabled) {
return
}
if (!WslPath.isWslUncPath(path)) {
return
}
val allWslDistributions = serviceAsync<WslDistributionManager>().installedDistributions
val path = Path.of(path)
val service = serviceAsync<EelNioBridgeService>()
val descriptor = service.tryGetEelDescriptor(path)
if (descriptor != null && descriptor !== LocalEelDescriptor) {
check(descriptor is WslEelDescriptor)
return
}
for (distro in allWslDistributions) {
val matches =
try {
distro.getWslPath(path) != null
}
catch (_: IllegalArgumentException) {
false
}
if (matches) {
service.registerNioWslFs(distro)
}
}
}
private suspend fun EelNioBridgeService.registerNioWslFs(distro: WSLDistribution) {
val descriptor = distro.getIjent().descriptor as WslEelDescriptor
val ijentFsProvider = TracingFileSystemProvider(IjentNioFileSystemProvider.getInstance())
val ijentUri = URI("ijent", "wsl", "/${distro.id}", null, null)
try {
val ijentFs = IjentFailSafeFileSystemPosixApi(coroutineScope) { distro.getIjent() }
val fs = ijentFsProvider.newFileSystem(ijentUri, IjentNioFileSystemProvider.newFileSystemMap(ijentFs))
coroutineScope.coroutineContext.job.invokeOnCompletion {
fs?.close()
}
}
catch (_: FileSystemAlreadyExistsException) {
// Nothing.
}
descriptor.distribution.roots.forEachGuaranteed { localRoot ->
register(localRoot, descriptor, descriptor.distribution.id, false, false) { underlyingProvider, _ ->
val key = if (Registry.`is`("wsl.use.new.filesystem")) localRoot else distro.id
val fileSystemProvider = providersCache.computeIfAbsent(key) {
if (Registry.`is`("wsl.use.new.filesystem")) {
IjentEphemeralRootAwareFileSystemProvider(
root = Path(localRoot),
ijentFsProvider = ijentFsProvider,
originalFsProvider = TracingFileSystemProvider(underlyingProvider),
// FIXME: is this behavior really correct?
//
// It is known that `originalFs.rootDirectories` always returns all WSL drives.
// Also, it is known that `ijentFs.rootDirectories` returns a single WSL drive,
// which is already mentioned in `originalFs.rootDirectories`.
//
// `ijentFs` is usually represented by `IjentFailSafeFileSystemPosixApi`,
// which launches IJent and the corresponding WSL containers lazily.
//
// This function avoids fetching root directories directly from IJent.
// This way, various UI file trees don't start all WSL containers during loading the file system root.
useRootDirectoriesFromOriginalFs = true,
)
}
else {
IjentWslNioFileSystemProvider(
wslDistribution = distro,
ijentFsProvider = ijentFsProvider,
originalFsProvider = TracingFileSystemProvider(underlyingProvider),
)
}
}
val fileSystem = if (fileSystemProvider is IjentEphemeralRootAwareFileSystemProvider) {
fileSystemProvider.getFileSystem(ijentUri)
}
else {
fileSystemProvider.getFileSystem(distro.getUNCRootPath().toUri())
}
LOG.info("Switching $distro to IJent WSL nio.FS: $fileSystem")
fileSystem
}
}
}
}
data class WslEelDescriptor(val distribution: WSLDistribution) : EelDescriptor {
override val osFamily: EelOsFamily = EelOsFamily.Posix
override val userReadableDescription: @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
}
override fun hashCode(): Int {
return distribution.id.hashCode()
}
}

View File

@@ -8,6 +8,7 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.util.IntellijInternalApi
import com.intellij.openapi.util.registry.Registry
import com.intellij.platform.eel.EelDescriptor
import com.intellij.platform.ide.impl.wsl.ijent.nio.toggle.WslEelDescriptor
import com.intellij.platform.ijent.spi.IjentConnectionStrategy
import com.intellij.platform.ijent.spi.IjentDeployingOverShellProcessStrategy
import com.intellij.util.io.computeDetached

View File

@@ -0,0 +1,163 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.platform.ide.impl.wsl.ijent.nio.toggle
import com.intellij.execution.wsl.WSLDistribution
import com.intellij.execution.wsl.WslDistributionManager
import com.intellij.execution.wsl.WslIjentManager
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.progress.runBlockingMaybeCancellable
import com.intellij.platform.eel.provider.EelNioBridgeService
import com.intellij.platform.ide.impl.wsl.ijent.nio.IjentWslNioFileSystemProvider
import com.intellij.platform.ijent.IjentPosixApi
import com.intellij.platform.ijent.community.impl.IjentFailSafeFileSystemPosixApi
import com.intellij.platform.ijent.community.impl.nio.IjentNioFileSystemProvider
import com.intellij.platform.ijent.community.impl.nio.telemetry.TracingFileSystemProvider
import com.intellij.util.containers.ContainerUtil
import com.intellij.util.containers.forEachGuaranteed
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.job
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.annotations.VisibleForTesting
import java.net.URI
import java.nio.file.FileSystem
import java.nio.file.FileSystemAlreadyExistsException
import java.nio.file.spi.FileSystemProvider
import java.util.concurrent.ConcurrentHashMap
import java.util.function.BiConsumer
private suspend fun WSLDistribution.getIjent(): IjentPosixApi {
return WslIjentManager.instanceAsync().getIjentApi(this, null, false)
}
@ApiStatus.Internal
@VisibleForTesting
class IjentWslNioFsToggleStrategy(
private val coroutineScope: CoroutineScope,
) {
internal val enabledInDistros: MutableMap<WSLDistribution, WslEelDescriptor> = ConcurrentHashMap()
private val providersCache = ContainerUtil.createConcurrentWeakMap<String, IjentWslNioFileSystemProvider>()
init {
coroutineScope.coroutineContext.job.invokeOnCompletion {
unregisterAll()
}
}
fun enableForAllWslDistributions() {
val listener = BiConsumer<Set<WSLDistribution>, Set<WSLDistribution>> { old, new ->
// TODO The code is race prone. Frequent creations and deletions of WSL containers may break the state.
for (distro in new - old) {
handleWslDistributionAddition(distro)
}
for (distro in old - new) {
handleWslDistributionDeletion(distro)
}
}
val wslDistributionManager = WslDistributionManager.getInstance()
wslDistributionManager.addWslDistributionsChangeListener(listener)
coroutineScope.coroutineContext.job.invokeOnCompletion {
wslDistributionManager.removeWslDistributionsChangeListener(listener)
}
for (distro in wslDistributionManager.installedDistributions) {
handleWslDistributionAddition(distro)
}
}
private fun handleWslDistributionAddition(distro: WSLDistribution) {
switchToIjentFs(distro)
}
private fun handleWslDistributionDeletion(distro: WSLDistribution) {
val descriptor = enabledInDistros.remove(distro)
if (descriptor != null) {
recomputeEel(descriptor) { _, actualFs ->
actualFs
}
}
}
fun switchToIjentFs(distro: WSLDistribution) {
val ijentFsProvider = TracingFileSystemProvider(IjentNioFileSystemProvider.getInstance())
val descriptor = runBlockingMaybeCancellable { distro.getIjent() }.descriptor as WslEelDescriptor
enabledInDistros[distro] = descriptor
try {
val ijentFs = IjentFailSafeFileSystemPosixApi(coroutineScope) { distro.getIjent() }
ijentFsProvider.newFileSystem(
URI("ijent", "wsl", "/${distro.id}", null, null),
IjentNioFileSystemProvider.newFileSystemMap(ijentFs),
)
}
catch (_: FileSystemAlreadyExistsException) {
// Nothing.
}
recomputeEel(descriptor) { underlyingProvider, _ ->
val fileSystemProvider = providersCache.computeIfAbsent(distro.id) {
IjentWslNioFileSystemProvider(
wslDistribution = distro,
ijentFsProvider = ijentFsProvider,
originalFsProvider = TracingFileSystemProvider(underlyingProvider),
)
}
val fileSystem = fileSystemProvider.getFileSystem(distro.getUNCRootPath().toUri())
LOG.info("Switching $distro to IJent WSL nio.FS: $fileSystem")
fileSystem
}
}
fun switchToTracingWsl9pFs(descriptor: WslEelDescriptor) {
recomputeEel(descriptor) { underlyingProvider, previousFs ->
LOG.info("Switching $descriptor to the original file system but with tracing")
try {
previousFs?.close()
}
catch (_: UnsupportedOperationException) {
// It is expected that the default file system always throws that exception on calling close(),
// but for the sake of following contracts, this method is nonetheless called.
}
TracingFileSystemProvider(underlyingProvider).getLocalFileSystem()
}
}
fun unregisterAll() {
val service = EelNioBridgeService.getInstanceSync()
enabledInDistros.entries.forEachGuaranteed { (_, descriptor) ->
service.unregister(descriptor)
}
enabledInDistros.clear()
}
}
private fun FileSystemProvider.getLocalFileSystem(): FileSystem = getFileSystem(URI.create("file:/"))
private val LOG = logger<IjentWslNioFsToggleStrategy>()
private val WSLDistribution.roots: Set<String>
get() {
val localRoots = mutableSetOf(getWindowsPath("/"))
localRoots.single().let {
localRoots += it.replace("wsl.localhost", "wsl$")
localRoots += it.replace("wsl$", "wsl.localhost")
}
return localRoots
}
private fun recomputeEel(
descriptor: WslEelDescriptor,
action: (underlyingProvider: FileSystemProvider, previousFs: FileSystem?) -> FileSystem?,
) {
val service = EelNioBridgeService.getInstanceSync()
descriptor.distribution.roots.forEachGuaranteed { localRoot ->
service.register(localRoot, descriptor, descriptor.distribution.id, false, false, action)
}
}

View File

@@ -0,0 +1,173 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.platform.ide.impl.wsl.ijent.nio.toggle
import com.intellij.diagnostic.VMOptions
import com.intellij.execution.wsl.*
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.components.serviceAsync
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.openapi.util.SystemInfo
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.EelOsFamily
import com.intellij.platform.eel.provider.EelProvider
import com.intellij.platform.ide.impl.wsl.ijent.nio.toggle.IjentWslNioFsToggler.WslEelProvider
import kotlinx.coroutines.*
import org.jetbrains.annotations.ApiStatus.Internal
import org.jetbrains.annotations.NonNls
import org.jetbrains.annotations.TestOnly
import org.jetbrains.annotations.VisibleForTesting
import java.io.BufferedReader
import java.nio.file.FileSystems
import java.nio.file.Path
import kotlin.io.path.bufferedReader
/**
* This service, along with listeners inside it, enables and disables access to WSL drives through IJent.
*/
@Internal
@Service
@VisibleForTesting
class IjentWslNioFsToggler(private val coroutineScope: CoroutineScope) {
companion object {
suspend fun instanceAsync(): IjentWslNioFsToggler = serviceAsync()
fun instance(): IjentWslNioFsToggler = service()
}
val isAvailable: Boolean get() = strategy != null
fun enableForAllWslDistributions() {
logErrorIfNotWindows()
strategy?.enableForAllWslDistributions()
}
@TestOnly
fun switchToIjentFs(distro: WSLDistribution) {
logErrorIfNotWindows()
strategy ?: error("Not available")
strategy.switchToIjentFs(distro)
}
@TestOnly
fun switchToTracingWsl9pFs(descriptor: WslEelDescriptor) {
logErrorIfNotWindows()
strategy ?: error("Not available")
strategy.switchToTracingWsl9pFs(descriptor)
}
@TestOnly
fun unregisterAll() {
logErrorIfNotWindows()
strategy ?: error("Not available")
strategy.unregisterAll()
}
private fun logErrorIfNotWindows() {
if (!SystemInfo.isWindows) {
thisLogger().error("${javaClass.name} should be requested only on Windows")
}
}
// TODO Move to ijent.impl?
internal class WslEelProvider : EelProvider {
suspend fun getApiByDistribution(distro: WSLDistribution): EelApi {
val enabledDistros = serviceAsync<IjentWslNioFsToggler>().strategy?.enabledInDistros
if (enabledDistros == null || distro !in enabledDistros) {
throw IllegalStateException("IJent is not enabled in $distro")
}
return WslIjentManager.getInstance().getIjentApi(distro, null, rootUser = false)
}
override suspend fun tryInitialize(path: String) = tryInitializeEelOnWsl(path)
}
private val strategy = run {
val defaultProvider = FileSystems.getDefault().provider()
when {
!WslIjentAvailabilityService.getInstance().useIjentForWslNioFileSystem() -> null
defaultProvider.javaClass.name == MultiRoutingFileSystemProvider::class.java.name -> {
IjentWslNioFsToggleStrategy(coroutineScope)
}
else -> {
val vmOptions = runCatching {
VMOptions.getUserOptionsFile()?.bufferedReader()?.use<BufferedReader, String> { it.readText() }
?: "<null>"
}.getOrElse<String, String> { err -> err.stackTraceToString() }
val systemProperties = runCatching {
System.getProperties().entries.joinToString("\n") { (k, v) -> "$k=$v" }
}.getOrElse<String, String> { err -> err.stackTraceToString() }
val message = "The default filesystem ${FileSystems.getDefault()} is not ${MultiRoutingFileSystemProvider::class.java}"
logger<IjentWslNioFsToggler>().warn("$message\nVM Options:\n$vmOptions\nSystem properties:\n$systemProperties")
null
}
}
}
}
private suspend fun tryInitializeEelOnWsl(path: String) {
if (!WslIjentAvailabilityService.getInstance().useIjentForWslNioFileSystem()) {
return
}
if (!WslPath.isWslUncPath(path)) {
return
}
val ijentWslNioFsToggler = IjentWslNioFsToggler.instanceAsync()
coroutineScope {
launch {
ijentWslNioFsToggler.enableForAllWslDistributions()
}
val allWslDistributions = async(Dispatchers.IO) {
serviceAsync<WslDistributionManager>().installedDistributions
}
val path = Path.of(path)
for (distro in allWslDistributions.await()) {
val matches =
try {
distro.getWslPath(path) != null
}
catch (_: IllegalArgumentException) {
false
}
if (matches) {
launch {
serviceAsync<WslIjentManager>().getIjentApi(distro, null, false)
}
}
}
}
}
data class WslEelDescriptor(val distribution: WSLDistribution) : EelDescriptor {
override val osFamily: EelOsFamily = EelOsFamily.Posix
override val userReadableDescription: @NonNls String = "WSL: ${distribution.presentableName}"
override suspend fun toEelApi(): EelApi {
return WslEelProvider().getApiByDistribution(distribution)
}
override fun equals(other: Any?): Boolean {
return other is WslEelDescriptor && other.distribution.id == distribution.id
}
override fun hashCode(): Int {
return distribution.id.hashCode()
}
}

View File

@@ -1,5 +1,5 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@ApiStatus.Internal
package com.intellij.platform.ide.impl.wsl;
package com.intellij.platform.ide.impl.wsl.ijent.nio.toggle;
import org.jetbrains.annotations.ApiStatus;

View File

@@ -2,12 +2,10 @@
package com.intellij.execution.eel
import com.intellij.diagnostic.VMOptions
import com.intellij.execution.wsl.WslIjentAvailabilityService
import com.intellij.openapi.diagnostic.logger
import com.intellij.platform.core.nio.fs.MultiRoutingFileSystem
import com.intellij.platform.core.nio.fs.MultiRoutingFileSystemProvider
import org.jetbrains.annotations.ApiStatus
import java.io.BufferedReader
import java.nio.file.FileSystems
import kotlin.io.path.bufferedReader

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.execution.wsl
import com.intellij.openapi.diagnostic.logger