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

Improve IO.toFile for Windows (URI has an authority component) #3088

Merged
merged 2 commits into from Apr 8, 2017

Conversation

eed3si9n
Copy link
Member

@eed3si9n eed3si9n commented Apr 8, 2017

The URL encoding of Windows path that works out of the box is:

  • file:///C:/Users/foo for path on the local machine.
  • file:////unc/Users/foo for UNC path.

Even thought this is not the most modern/canonical encoding, it allows file:/// to be used as a cross-platform prefix file:///${user.home} since on Mac and Linux user.home would look like /Users/foo, it would come out as file:////Users/foo.

original PR

This adds support to convert from an URL to a File on Windows in several ways.

scala> val u0 = new URL("file:C:\\Users\\foo/.sbt/preloaded")
u0: java.net.URL = file:C:/Users/foo/.sbt/preloaded

scala> toFile(u0)
res0: java.io.File = C:\Users\foo\.sbt\preloaded

scala> val u1 = new URL("file:/C:\\Users\\foo/.sbt/preloaded")
u1: java.net.URL = file:/C:/Users/foo/.sbt/preloaded

scala> toFile(u1)
res2: java.io.File = C:\Users\foo\.sbt\preloaded

scala> val u2 = new URL("file://unc/Users/foo/.sbt/preloaded")
u2: java.net.URL = file://unc/Users/foo/.sbt/preloaded

scala> toFile(u2)
res4: java.io.File = \\unc\Users\foo\.sbt\preloaded

scala> val u3 = new URL("file:///C:\\Users\\foo/.sbt/preloaded")
u3: java.net.URL = file:/C:/Users/foo/.sbt/preloaded

scala> toFile(u3)
res5: java.io.File = C:\Users\foo\.sbt\preloaded

scala> val u4 = new URL("file:////unc/Users/foo/.sbt/preloaded")
u4: java.net.URL = file:////unc/Users/foo/.sbt/preloaded

scala> toFile(u4)
res8: java.io.File = \\unc\Users\foo\.sbt\preloaded

This is an improvement over the constructor of File, which is unable to handle u0 and u2 cases:

scala> val u0 = new URL("file:C:\\Users\\foo/.sbt/preloaded")
u0: java.net.URL = file:C:/Users/foo/.sbt/preloaded

scala> new File(u0.toURI)
java.lang.IllegalArgumentException: URI is not hierarchical
        at java.io.File.<init>(File.java:418)

scala> val u2 = new URL("file://unc/Users/foo/.sbt/preloaded")
u2: java.net.URL = file://unc/Users/foo/.sbt/preloaded

scala> new File(u2.toURI)
java.lang.IllegalArgumentException: URI has an authority component
        at java.io.File.<init>(File.java:423)

The error case for two slashes "URI has an authority component" shows up in many cases, most recently borking 0.13.14 in #3086. Note that it might be intuitive to encode file path by starting with file:// similar to http://, however this is specified by Microsoft to be an UNC path, so the URI file://C:/Users/foo/.sbt/preloaded is illegal. Since the authority component after //, in this case C: should denote the remote host name.

This complicates trying to specify sbt global base (default ~/.sbt/) path in a cross platform way.

  local-preloaded-ivy: file://${sbt.preloaded-${sbt.global.base-${user.home}/.sbt}/preloaded/}, [organization]/[module]/[revision]/[type]s/[artifact](-[classifier]).[ext]
  local-preloaded: file://${sbt.preloaded-${sbt.global.base-${user.home}/.sbt}/preloaded/}

The above original is incorrect because on Windows, ${user.home} would return C:\Users\foo\. The solution is to encode without the prefix slashes like u0.

  local-preloaded-ivy: file:${sbt.preloaded-${sbt.global.base-${user.home}/.sbt}/preloaded/}, [organization]/[module]/[revision]/[type]s/[artifact](-[classifier]).[ext]
  local-preloaded: file:${sbt.preloaded-${sbt.global.base-${user.home}/.sbt}/preloaded/}

Fixes #3086
Fixes #2150

@eed3si9n eed3si9n changed the title Improve IO.toFile's for Windows Improve IO.toFile for Windows Apr 8, 2017
@eed3si9n eed3si9n requested a review from dwijnand April 8, 2017 06:46
Improve IO.toFile's handling for Windows, and use it for identifying resolvers.

This adds support to convert URL to File on Windows in several ways:

```
val u0 = new URL("file:C:\\Users\\foo/.sbt/preloaded")
val u1 = new URL("file:/C:\\Users\\foo/.sbt/preloaded")
val u2 = new URL("file://unc/Users/foo/.sbt/preloaded")
val u3 = new URL("file:///C:\\Users\\foo/.sbt/preloaded")
val u4 = new URL("file:////unc/Users/foo/.sbt/preloaded")
```

Note that `u0` and `u2` are something `new File(u.toURI)` won't handle. This also correctly handles UNC convention specified by Microsoft in https://blogs.msdn.microsoft.com/ie/2006/12/06/file-uris-in-windows/.

Fixes sbt#3086
Fixes sbt#2150
On Mac and Linux, user.home should return `/home/foo`, resulting to `file:/home/foo`.

On Windows, user.home should return `C:\Users\foo`, resulting to `file:C:/Users/foo`.
@fommil
Copy link
Contributor

fommil commented Apr 8, 2017

I hit this so much, I solved it in class-monkey, you should have asked :-P

@eed3si9n eed3si9n merged commit c31dfda into sbt:0.13 Apr 8, 2017
@eed3si9n eed3si9n deleted the wip/windows_file branch April 8, 2017 19:17
@eed3si9n eed3si9n changed the title Improve IO.toFile for Windows Improve IO.toFile for Windows (URI has an authority component) Apr 8, 2017
eed3si9n added a commit to eed3si9n/sbt that referenced this pull request Apr 9, 2017
sbt#3088 attemped to fix the sbt#3086, but by putting no slashes in `sbt.boot.properties` the launcher created by 0.13.15-* becomes incompatible for all previous sbt versions.

The uglier but backward compatible fix for sbt#3086 is to use u3 format with three slashes. This on Windows will resolve to `file:///C:/Users/foo/.sbt/preloaded`, and on Mac and Linux `file:////root/.sbt/preloaded/`. Mac and Linux are both tolerant of extra slashes on the front:

```
> eval new File(new URL("file:////Users/foo/.sbt/preloaded/").toURI)
[info] ans: java.io.File = /Users/foo/.sbt/preloaded
```
eed3si9n added a commit to eed3si9n/sbt that referenced this pull request Sep 25, 2017
Node didn't seem to like read URI out of the box, and I am not sure if File -> URI -> File conversion is universally accepted.

Ref sbt#3088
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants