Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

set default nio system provider #8

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ plugins {
id("org.jetbrains.intellij") version "1.17.2"
}

tasks.runIde {
jvmArgs("java.nio.file.spi.DefaultFileSystemProvider=com.wsl.symlinks.vfs.WslfsFileSystemProvider")
}

group = "com.wsl.symlinks"
version = "2024.1.5"
Expand Down
146 changes: 136 additions & 10 deletions src/main/kotlin/com/wsl/symlinks/vfs/WslVirtualFileSystem.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,34 +12,154 @@ import com.intellij.openapi.vfs.impl.local.LocalFileSystemImpl
import com.intellij.openapi.vfs.newvfs.impl.StubVirtualFile
import com.intellij.platform.workspace.storage.url.VirtualFileUrl
import com.intellij.util.io.URLUtil
import com.intellij.util.lang.PathClassLoader
import java.io.*
import java.net.URI
import java.nio.channels.SeekableByteChannel
import java.nio.file.*
import java.nio.file.attribute.BasicFileAttributes
import java.nio.file.attribute.FileAttribute
import java.nio.file.attribute.FileAttributeView
import java.nio.file.spi.FileSystemProvider
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.TimeUnit
import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.thread
import kotlin.concurrent.withLock
import kotlin.io.path.absolutePathString


class WslfsFileSystemProvider(val provider: FileSystemProvider): FileSystemProvider() {
val fs = WslVirtualFileSystem()

class WslAttrs(val vfile: VirtualFile, attrs: BasicFileAttributes): BasicFileAttributes by attrs {
override fun isSymbolicLink(): Boolean {
val provider = WslSymlinksProvider.getWslSymlinksProviders(vfile.getWSLDistribution()!!)
return provider.isWslSymlink(vfile)
}
}

override fun getScheme(): String {
return provider.scheme
}

override fun newFileSystem(uri: URI?, env: MutableMap<String, *>?): FileSystem {
return provider.newFileSystem(uri, env)
}

override fun getFileSystem(uri: URI?): FileSystem {
return provider.getFileSystem(uri)
}

override fun getPath(uri: URI?): Path {
return provider.getPath(uri)
}

override fun newByteChannel(
path: Path?,
options: MutableSet<out OpenOption>?,
vararg attrs: FileAttribute<*>?
): SeekableByteChannel {
return provider.newByteChannel(path, options, *attrs)
}

override fun newDirectoryStream(dir: Path?, filter: DirectoryStream.Filter<in Path>?): DirectoryStream<Path> {
return provider.newDirectoryStream(dir, filter)
}

override fun createDirectory(dir: Path?, vararg attrs: FileAttribute<*>?) {
return provider.createDirectory(dir, *attrs)
}

override fun delete(path: Path?) {
return provider.delete(path)
}

override fun copy(source: Path?, target: Path?, vararg options: CopyOption?) {
return provider.copy(source, target, *options)
}

override fun move(source: Path?, target: Path?, vararg options: CopyOption?) {
return provider.move(source, target, *options)
}

override fun isSameFile(path: Path?, path2: Path?): Boolean {
return provider.isSameFile(path, path2)
}

override fun isHidden(path: Path?): Boolean {
return provider.isHidden(path)
}

override fun getFileStore(path: Path?): FileStore {
return provider.getFileStore(path)
}

override fun checkAccess(path: Path?, vararg modes: AccessMode?) {
return provider.checkAccess(path, *modes)
}

override fun <V : FileAttributeView?> getFileAttributeView(
path: Path?,
type: Class<V>?,
vararg options: LinkOption?
): V {
return provider.getFileAttributeView(path, type, *options)
}

override fun <A : BasicFileAttributes?> readAttributes(
path: Path,
type: Class<A>,
vararg options: LinkOption?
): A {
val attrs = provider.readAttributes(path, type, *options)
val vfile = FakeVirtualFile(path.absolutePathString(), null, fs)
if (vfile.isFromWSL()) {
return WslAttrs(vfile, attrs as BasicFileAttributes) as A
}
return attrs
}

override fun readAttributes(
path: Path,
attributes: String,
vararg options: LinkOption
): MutableMap<String, Any> {
val attrs = provider.readAttributes(path, attributes, *options)
val vfile = FakeVirtualFile(path.absolutePathString(), null, fs)
if (vfile.isFromWSL()) {

}
return attrs
}

override fun setAttribute(path: Path?, attribute: String?, value: Any?, vararg options: LinkOption?) {
return provider.setAttribute(path, attribute, value, *options)
}
}


class StartupListener: AppLifecycleListener {
override fun appFrameCreated(commandLineArgs: MutableList<String>) {
System.setProperty("java.nio.file.spi.DefaultFileSystemProvider", "com.wsl.symlinks.vfs.WslfsFileSystemProvider");
val point = VirtualFileSystem.EP_NAME.point
val extension = point.extensionList.find { it.instance is LocalFileSystemImpl && it.instance.javaClass.name.contains("LocalFileSystemImpl") }
point.unregisterExtension(extension)
}
}

class FakeVirtualFile(val resPath: String, val vfile: VirtualFile, val fs: WslVirtualFileSystem): StubVirtualFile(fs) {
class FakeVirtualFile(val resPath: String, val vfile: VirtualFile?, val fs: WslVirtualFileSystem): StubVirtualFile(fs) {
override fun getPath(): String {
return resPath
}

override fun getLength(): Long {
return fs.getAttributes(vfile)?.length ?: 0
return vfile?.let { fs.getAttributes(it) }?.length ?: 0
}

override fun getParent(): VirtualFile? {
return vfile.parent
return vfile?.parent
}
}

Expand All @@ -65,6 +185,7 @@ fun <T>Boolean.ifFalse(value: T): T? {
}



class WslSymlinksProvider(distro: String) {
val LOGGER = Logger.getInstance(WslSymlinksProvider::class.java)

Expand Down Expand Up @@ -99,7 +220,6 @@ class WslSymlinksProvider(distro: String) {
init {
LOGGER.info("starting WslSymlinksProvider for distro: $distro")


fun setupProcess() {
val bash = {}.javaClass.getResource("/files.sh")?.readText()!!
val location = "\\\\wsl.localhost\\$distro\\var\\tmp\\intellij-idea-wsl-symlinks.sh"
Expand Down Expand Up @@ -220,14 +340,23 @@ class WslSymlinksProvider(distro: String) {
}
return false
}

companion object {
private var wslSymlinksProviders: MutableMap<String, WslSymlinksProvider> = HashMap()
fun getWslSymlinksProviders(distro: String): WslSymlinksProvider {
if (!this.wslSymlinksProviders.containsKey(distro)) {
this.wslSymlinksProviders[distro] = WslSymlinksProvider(distro)
}
return this.wslSymlinksProviders[distro]!!
}
}
}

class WslVirtualFileSystem: LocalFileSystemImpl() {
val LOGGER = Logger.getInstance(WslVirtualFileSystem::class.java)
private var wslSymlinksProviders: MutableMap<String, WslSymlinksProvider> = HashMap()

init {

System.setProperty("java.nio.file.spi.DefaultFileSystemProvider", "sun.nio.fs.WindowsFileSystemProvider,com.wsl.symlinks.vfs.WslfsFileSystemProvider");
}

override fun getProtocol(): String {
Expand All @@ -236,10 +365,7 @@ class WslVirtualFileSystem: LocalFileSystemImpl() {

fun getWslSymlinksProviders(file: VirtualFile): WslSymlinksProvider {
val distro = file.getWSLDistribution()!!
if (!this.wslSymlinksProviders.containsKey(distro)) {
this.wslSymlinksProviders[distro] = WslSymlinksProvider(distro)
}
return this.wslSymlinksProviders[distro]!!
return WslSymlinksProvider.getWslSymlinksProviders(distro)
}

fun getRealPath(file: VirtualFile): String {
Expand Down
Loading