Skip to content

Commit

Permalink
Improve toURI on Windows
Browse files Browse the repository at this point in the history
  • Loading branch information
eed3si9n committed Nov 27, 2020
1 parent f1dec11 commit 5671b9b
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 12 deletions.
34 changes: 23 additions & 11 deletions io/src/main/scala/sbt/io/IO.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import java.net.{ URI, URISyntaxException, URL }
import java.nio.charset.Charset
import java.nio.file.attribute.PosixFilePermissions
import java.nio.file.{ Path => NioPath, _ }
import java.util.Properties
import java.util.{ Locale, Properties }
import java.util.jar.{ Attributes, JarEntry, JarFile, JarOutputStream, Manifest }
import java.util.zip.{ CRC32, ZipEntry, ZipInputStream, ZipOutputStream }

Expand Down Expand Up @@ -674,7 +674,7 @@ object IO {
) = {
val files = sources
.flatMap {
case (file, name) => if (file.isFile) (file, normalizeName(name)) :: Nil else Nil
case (file, name) => if (file.isFile) (file, normalizeToSlash(name)) :: Nil else Nil
}
.sortBy {
case (_, name) => name
Expand Down Expand Up @@ -734,7 +734,7 @@ object IO {
private def allDirectoryPaths(files: Iterable[(File, String)]) =
TreeSet[String]() ++ (files flatMap { case (_, name) => directoryPaths(name) })

private def normalizeName(name: String) = {
private def normalizeToSlash(name: String) = {
val sep = File.separatorChar
if (sep == '/') name else name.replace(sep, '/')
}
Expand Down Expand Up @@ -1171,20 +1171,32 @@ object IO {
dirURI.normalize
}

private[sbt] val isWindows: Boolean =
System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("windows")

/** Converts the given File to a URI. If the File is relative, the URI is relative, unlike File.toURI*/
def toURI(f: File): URI =
if (f.isAbsolute) {
def toURI(f: File): URI = {
def ensureHeadSlash(name: String) =
if (name.nonEmpty && name.head != File.separatorChar) File.separatorChar + name
else name

val p = f.getPath
if (isWindows && p.nonEmpty && (p.head == '\\' || p.head == '/')) {
if (p.startsWith("""\\""")) {
// supports \\laptop\My Documents\Some.doc on Windows
new URI(FileScheme, normalizeToSlash(p), null)
} else {
// supports /tmp on Windows
new URI(FileScheme, "", normalizeToSlash(p), null)
}
} else if (f.isAbsolute) {
//not using f.toURI to avoid filesystem syscalls
//we use empty string as host to force file:// instead of just file:
new URI(FileScheme, "", normalizeName(slashify(f.getAbsolutePath)), null)
new URI(FileScheme, "", normalizeToSlash(ensureHeadSlash(f.getAbsolutePath)), null)
} else {
// need to use the three argument URI constructor because the single argument version doesn't encode
new URI(null, normalizeName(f.getPath), null)
new URI(null, normalizeToSlash(f.getPath), null)
}

private[this] def slashify(name: String) = {
if(name.nonEmpty && name.head != File.separatorChar) File.separatorChar + name
else name
}

/**
Expand Down
26 changes: 25 additions & 1 deletion io/src/test/scala/sbt/io/IOSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,22 @@ class IOSpec extends FunSuite {

test("toURI should make URI") {
val u = IO.toURI(file("/etc/hosts").getAbsoluteFile)
assert(u.toString.startsWith("file:///") && u.toString.endsWith("etc/hosts"))
assert(u.toString == "file:///etc/hosts")
}

test("it should make u0 URI from a relative path") {
val u = IO.toURI(file("src") / "main" / "scala")
assert(u.toString == "src/main/scala")
}

test("it should make u0 URI from a relative path on Windows") {
if (IO.isWindows) {
val input = file("""..\My Documents\test""")
val u = IO.toURI(input)
assert(u.toString == "../My%20Documents/test" && IO.toFile(u) == input)
} else ()
}

test("it should make URI that roundtrips") {
val u = IO.toURI(file("/etc/hosts").getAbsoluteFile)
assert(IO.toFile(u) == file("/etc/hosts").getAbsoluteFile)
Expand All @@ -103,6 +111,22 @@ class IOSpec extends FunSuite {
assert(IO.toFile(u) == (file("src") / "main" / "scala"))
}

test("it should make u3 URI for an absolute path on Windows that roundtrips") {
if (IO.isWindows) {
val input = file("""C:\Documents and Settings\""")
val u = IO.toURI(input)
assert(u.toString == "file:///C:/Documents%20and%20Settings" && IO.toFile(u) == input)
} else ()
}

test("it should make u2 URI for a UNC path on Windows that roundtrips") {
if (IO.isWindows) {
val input = file("""\\laptop\My Documents\Some.doc""")
val u = IO.toURI(input)
assert(u.toString == "file://laptop/My%20Documents/Some.doc" && IO.toFile(u) == input)
} else ()
}

test("getModifiedTimeOrZero should return 0L if the file doesn't exists") {
assert(IO.getModifiedTimeOrZero(file("/not/existing/path")) == 0L)
}
Expand Down

0 comments on commit 5671b9b

Please sign in to comment.