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

Sbt doesn't recognise WSL UNC path - Invalid build URI (no handler available) #7135

Open
ghost opened this issue Jan 22, 2023 · 3 comments · May be fixed by sbt/io#374
Open

Sbt doesn't recognise WSL UNC path - Invalid build URI (no handler available) #7135

ghost opened this issue Jan 22, 2023 · 3 comments · May be fixed by sbt/io#374
Assignees
Labels

Comments

@ghost
Copy link

ghost commented Jan 22, 2023

steps

Start sbt-laucher.jar with a current UNC WSL directory, for example (starting from NuShell, because cmd.exe doesn't support UNC paths well):

\\wsl$\OracleLinux_9\home\user\project > C:\Users\user\apps\jdk-11.0.18\bin\java.exe -Dfile.encoding=UTF-8 -jar C:\Users\user\apps\sbt\bin\sbt-launcher.jar sbtVersion
[info] welcome to sbt 1.8.2 (Oracle Corporation Java 11.0.18)
java.lang.RuntimeException: Invalid build URI (no handler available): file:/wsl$/OracleLinux_9/home/user/project/
        at scala.sys.package$.error(package.scala:30)
        at sbt.internal.Load$.$anonfun$builtinLoader$1(Load.scala:489)
        at sbt.internal.BuildLoader.$anonfun$apply$3(BuildLoader.scala:244)
        at scala.Option.getOrElse(Option.scala:189)
        at sbt.internal.BuildLoader.apply(BuildLoader.scala:244)
        at sbt.internal.Load$.loadURI$1(Load.scala:554)
        at sbt.internal.Load$.loadAll(Load.scala:570)
        at sbt.internal.Load$.loadURI(Load.scala:500)
        at sbt.internal.Load$.load(Load.scala:479)
        at sbt.internal.Load$.$anonfun$apply$1(Load.scala:241)
        at sbt.internal.Load$.timed(Load.scala:1406)
        at sbt.internal.Load$.apply(Load.scala:241)
        at sbt.internal.Load$.defaultLoad(Load.scala:56)
        at sbt.BuiltinCommands$.liftedTree1$1(Main.scala:961)
        at sbt.BuiltinCommands$.doLoadProject(Main.scala:961)
        at sbt.BuiltinCommands$.$anonfun$loadProjectImpl$2(Main.scala:914)
        at sbt.Command$.$anonfun$applyEffect$4(Command.scala:150)
        at sbt.Command$.$anonfun$applyEffect$2(Command.scala:145)
        at sbt.Command$.process(Command.scala:189)
        at sbt.MainLoop$.$anonfun$processCommand$5(MainLoop.scala:245)
        at scala.Option.getOrElse(Option.scala:189)
        at sbt.MainLoop$.process$1(MainLoop.scala:245)
        at sbt.MainLoop$.processCommand(MainLoop.scala:278)
        at sbt.MainLoop$.$anonfun$next$5(MainLoop.scala:163)
        at sbt.State$StateOpsImpl$.runCmd$1(State.scala:289)
        at sbt.State$StateOpsImpl$.process$extension(State.scala:325)
        at sbt.MainLoop$.$anonfun$next$4(MainLoop.scala:163)
        at sbt.internal.util.ErrorHandling$.wideConvert(ErrorHandling.scala:23)
        at sbt.MainLoop$.next(MainLoop.scala:163)
        at sbt.MainLoop$.run(MainLoop.scala:144)
        at sbt.MainLoop$.$anonfun$runWithNewLog$1(MainLoop.scala:119)
        at sbt.io.Using.apply(Using.scala:27)
        at sbt.MainLoop$.runWithNewLog(MainLoop.scala:112)
        at sbt.MainLoop$.runAndClearLast(MainLoop.scala:66)
        at sbt.MainLoop$.runLoggedLoop(MainLoop.scala:51)
        at sbt.MainLoop$.runLogged(MainLoop.scala:42)
        at sbt.StandardMain$.runManaged(Main.scala:223)
        at sbt.xMain$.$anonfun$run$11(Main.scala:133)
        at scala.util.DynamicVariable.withValue(DynamicVariable.scala:62)
        at scala.Console$.withIn(Console.scala:230)
        at sbt.internal.util.Terminal$.withIn(Terminal.scala:578)
        at sbt.internal.util.Terminal$.$anonfun$withStreams$1(Terminal.scala:358)
        at scala.util.DynamicVariable.withValue(DynamicVariable.scala:62)
        at scala.Console$.withOut(Console.scala:167)
        at sbt.internal.util.Terminal$.$anonfun$withOut$2(Terminal.scala:568)
        at scala.util.DynamicVariable.withValue(DynamicVariable.scala:62)
        at scala.Console$.withErr(Console.scala:196)
        at sbt.internal.util.Terminal$.withOut(Terminal.scala:568)
        at sbt.internal.util.Terminal$.withStreams(Terminal.scala:358)
        at sbt.xMain$.withStreams$1(Main.scala:87)
        at sbt.xMain$.run(Main.scala:121)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at sbt.internal.XMainConfiguration.run(XMainConfiguration.java:57)
        at sbt.xMain.run(Main.scala:46)
        at xsbt.boot.Launch$.$anonfun$run$1(Launch.scala:149)
        at xsbt.boot.Launch$.withContextLoader(Launch.scala:176)
        at xsbt.boot.Launch$.run(Launch.scala:149)
        at xsbt.boot.Launch$.$anonfun$apply$1(Launch.scala:44)
        at xsbt.boot.Launch$.launch(Launch.scala:159)
        at xsbt.boot.Launch$.apply(Launch.scala:44)
        at xsbt.boot.Launch$.apply(Launch.scala:21)
        at xsbt.boot.Boot$.runImpl(Boot.scala:78)
        at xsbt.boot.Boot$.run(Boot.scala:73)
        at xsbt.boot.Boot$.main(Boot.scala:21)
        at xsbt.boot.Boot.main(Boot.scala)
[error] Invalid build URI (no handler available): file:/wsl$/OracleLinux_9/home/user/project/
[error] Use 'last' for the full log.
[warn] Project loading failed: (r)etry, (q)uit, (l)ast, or (i)gnore? (default: r)

problem

Sbt fails.

expectation

Sbt doesn't fail.

notes

JetBrains IDEA seems to work fine with WSL UNC paths, and quick research shows that Java supports UNC paths since the year 1999, so I'm guessing it's something in Sbt's logic?

@ghost ghost added the Bug label Jan 22, 2023
@ghost
Copy link
Author

ghost commented Jan 22, 2023

Looks like this is due to JDK's misdesign: https://bugs.openjdk.org/browse/JDK-4723726

Suggested JDK's workaround is to use file.toPath.toUri. Which means fixing https://github.com/sbt/io/blob/v1.8.0/io/src/main/scala/sbt/io/IO.scala#L1154 . And most likely a few other places that use File.toURI.normalize - Path.scala for one.

@ghost
Copy link
Author

ghost commented Jan 23, 2023

Fix for io's develop (tested with sbt 1.8.2):

diff --git a/io/src/main/scala/sbt/io/IO.scala b/io/src/main/scala/sbt/io/IO.scala
index 5c0e114..ac635f8 100644
--- a/io/src/main/scala/sbt/io/IO.scala
+++ b/io/src/main/scala/sbt/io/IO.scala
@@ -1151,7 +1151,7 @@ object IO {
    */
   def directoryURI(dir: File): URI = {
     assertAbsolute(dir)
-    directoryURI(dir.toURI.normalize)
+    directoryURI(dir.toPath.normalize.toUri)
   }
 
   /**
@@ -1162,13 +1162,18 @@ object IO {
   def directoryURI(uri: URI): URI = {
     if (!uri.isAbsolute) return uri; //assertAbsolute(uri)
     val str = uri.toASCIIString
+
+    if (uri.getScheme != FileScheme) {
+      uri.normalize()
+    }
+
     val dirURI =
-      if (str.endsWith("/") || uri.getScheme != FileScheme || (uri.getRawFragment ne null))
+      if (str.endsWith("/") || (uri.getRawFragment ne null))
         uri
       else
         new URI(str + "/")
 
-    dirURI.normalize
+    new File(dirURI).toPath.normalize.toUri
   }
 
   private[sbt] val isWindows: Boolean =
diff --git a/io/src/main/scala/sbt/io/Path.scala b/io/src/main/scala/sbt/io/Path.scala
index b1d6c65..e45fd91 100644
--- a/io/src/main/scala/sbt/io/Path.scala
+++ b/io/src/main/scala/sbt/io/Path.scala
@@ -291,7 +291,7 @@ object Path extends Mapper {
   def fileProperty(name: String): File = new File(System.getProperty(name))
   def userHome: File = fileProperty("user.home")
 
-  def absolute(file: File): File = new File(file.toURI.normalize).getAbsoluteFile
+  def absolute(file: File): File = new File(file.toPath.normalize.toUri).getAbsoluteFile
   def makeString(paths: Seq[File]): String = makeString(paths, File.pathSeparator)
   def makeString(paths: Seq[File], sep: String): String = {
     val separated = paths.map(_.getAbsolutePath)

@Friendseeker Friendseeker self-assigned this Nov 1, 2024
@Friendseeker
Copy link
Member

Thanks for the really detailed bug report!

I had tried the patch and it is working for sbt 1.10.4! Without the patch I got the exact same stacktrace as you.

\\wsl$\Ubuntu-24.04\home\jerrytan\testwsl> java -Dfile.encoding=UTF-8 -jar `C:\Users\Jerry Tan\AppData\Local\Coursier\cache\arc\https\github.com\sbt\sbt\releases\download\v1.10.4\sbt-1.10.4.zip\sbt\bin\sbt-launch.jar`
[info] welcome to sbt 1.10.4 (Oracle Corporation Java 17.0.6)
[info] loading project definition from \\wsl$\Ubuntu-24.04\home\jerrytan\testwsl\project
[info] loading settings for project root from build.sbt ...
[info] set current project to testwsl (in build file:////wsl$/Ubuntu-24.04/home/jerrytan/testwsl/)
[info] sbt server started at local:sbt-server-f3d60e1208b0f555d5bd
[info] started sbt server
sbt:testwsl> compile
[info] compiling 1 Scala source to \\wsl$\Ubuntu-24.04\home\jerrytan\testwsl\target\scala-3.3.4\classes ...
[success] Total time: 4 s, completed Nov. 1, 2024, 6:09:50 p.m.

@Friendseeker Friendseeker linked a pull request Nov 2, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant