work around URI problems with encoding and resolving. Fixes #725

This commit is contained in:
Mark Harrah 2013-04-12 12:47:44 -04:00
parent a4c059cb7e
commit 81babda6f6
3 changed files with 68 additions and 5 deletions

View File

@ -47,9 +47,10 @@ object Configuration
}
def configurationFromFile(path: String, baseDirectory: File): URL =
{
val pathURI = filePathURI(path)
def resolve(against: URI): Option[URL] =
{
val resolved = against.resolve(path)
val resolved = against.resolve(pathURI) // variant that accepts String doesn't properly escape (#725)
val exists = try { (new File(resolved)).exists } catch { case _: IllegalArgumentException => false }
if(exists) Some(resolved.toURL) else None
}
@ -111,8 +112,11 @@ object Configuration
Option(props.getProperty(SbtVersionProperty))
}
def resolveAgainst(baseDirectory: File): List[URI] = (baseDirectory toURI) :: (new File(System.getProperty("user.home")) toURI) ::
toDirectory(classLocation(getClass).toURI) :: Nil
def resolveAgainst(baseDirectory: File): List[URI] =
directoryURI(baseDirectory) ::
directoryURI(new File(System.getProperty("user.home"))) ::
toDirectory(classLocation(getClass).toURI) ::
Nil
def classLocation(cl: Class[_]): URL =
{
@ -120,12 +124,26 @@ object Configuration
if(codeSource == null) error("No class location for " + cl)
else codeSource.getLocation
}
// single-arg constructor doesn't properly escape
def filePathURI(path: String): URI = {
val f = new File(path)
new URI(if(f.isAbsolute) "file" else null, path, null)
}
def directoryURI(dir: File): URI = directoryURI(dir.toURI)
def directoryURI(uri: URI): URI =
{
assert(uri.isAbsolute)
val str = uri.toASCIIString
val dirStr = if(str.endsWith("/")) str else str + "/"
(new URI(dirStr)).normalize
}
def toDirectory(uri: URI): URI =
try
{
val file = new File(uri)
val newFile = if(file.isFile) file.getParentFile else file
newFile.toURI
directoryURI(newFile)
}
catch { case _: Exception => uri }
private[this] def neNull: AnyRef => Boolean = _ ne null

View File

@ -0,0 +1,43 @@
package xsbt.boot
import org.scalacheck._
import Prop._
import Configuration._
import java.io.File
import java.net.URI
object URITests extends Properties("URI Tests")
{
val FileProtocol = "file"
property("directoryURI adds trailing slash") = secure {
val dirURI = directoryURI(new File("/a/b/c"))
val directURI = filePathURI("/a/b/c/")
dirURI == directURI
}
property("directoryURI preserves trailing slash") = secure {
directoryURI(new File("/a/b/c/")) == filePathURI("/a/b/c/")
}
property("filePathURI encodes spaces") = secure {
val decoded = "has spaces"
val encoded = "has%20spaces"
val fpURI = filePathURI(decoded)
val directURI = new URI(encoded)
s"filePathURI: $fpURI" |:
s"direct URI: $directURI" |:
s"getPath: ${fpURI.getPath}" |:
s"getRawPath: ${fpURI.getRawPath}" |:
(fpURI == directURI) &&
(fpURI.getPath == decoded) &&
(fpURI.getRawPath == encoded)
}
property("filePathURI and File.toURI agree for absolute file") = secure {
val s = "/a/b'/has spaces"
val viaPath = filePathURI(s)
val viaFile = (new File(s)).toURI
s"via path: $viaPath" |:
s"via file: $viaFile" |:
(viaPath == viaFile)
}
}

View File

@ -724,7 +724,9 @@ object IO
(new URI(dirStr)).normalize
}
/** 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) f.toURI else new URI(normalizeName(f.getPath))
def toURI(f: File): URI =
// need to use the three argument URI constructor because the single argument version doesn't encode
if(f.isAbsolute) f.toURI else new URI(null, normalizeName(f.getPath), null)
def resolve(base: File, f: File): File =
{
assertAbsolute(base)