diff --git a/main/Build.scala b/main/Build.scala index 6ab7bb043..cc2cc32da 100644 --- a/main/Build.scala +++ b/main/Build.scala @@ -5,6 +5,7 @@ package sbt import java.io.File import java.net.URI + import BuildLoader.ResolveInfo import compiler.{Eval, EvalImports} import complete.DefaultParsers.validID import Compiler.Compilers @@ -38,78 +39,25 @@ object Build } object RetrieveUnit { - def apply(tempDir: File, base: URI): Option[() => File] = + def apply(info: ResolveInfo): Option[() => File] = { - lazy val tmp = temporary(tempDir, base) - base.getScheme match - { - case "git" => gitApply(tmp, base) - case _ if isGitPath(base.getPath) => gitApply(tmp, base) - case "http" | "https" => Some { () => downloadAndExtract(base, tmp); tmp } - case "file" => - val f = new File(base) - if(f.isDirectory) - { - val finalDir = if (!f.canWrite) retrieveRODir(f, tmp) else f - Some(() => finalDir) - } - else None + info.uri match { + case Scheme("git") => Resolvers.git(info) + case Path(path) if path.endsWith(".git") => Resolvers.git(info) + case Scheme("http") | Scheme("https") | Scheme("ftp") => Resolvers.remote(info) + case Scheme("file") => Resolvers.local(info) case _ => None } } - def isGitPath(path: String) = path.endsWith(".git") - private[this] def gitApply(tmp: File, base: URI) = Some { () => gitRetrieve(base, tmp); tmp } - def retrieveRODir(base: File, tempDir: File): File = - { - if (!tempDir.exists) - { - try { - IO.copyDirectory(base, tempDir) - } catch { - case e => - IO.delete(tempDir) - throw e - } - } - tempDir - } - def downloadAndExtract(base: URI, tempDir: File): Unit = if(!tempDir.exists) IO.unzipURL(base.toURL, tempDir) - def temporary(tempDir: File, uri: URI): File = new File(tempDir, Hash.halve(hash(uri))) - def hash(uri: URI): String = Hash.toHex(Hash(uri.toASCIIString)) - import Process._ - def gitRetrieve(base: URI, tempDir: File): Unit = - if(!tempDir.exists) - { - try { - IO.createDirectory(tempDir) - gitClone(dropFragment(base), tempDir) - Option(base.getFragment) foreach { branch => gitCheckout(tempDir, branch) } - } catch { - case e => IO.delete(tempDir) - throw e - } - } - def dropFragment(base: URI): URI = if(base.getFragment eq null) base else new URI(base.getScheme, base.getSchemeSpecificPart, null) - - def gitClone(base: URI, tempDir: File): Unit = - git("clone" :: dropFragment(base).toASCIIString :: tempDir.getAbsolutePath :: Nil, tempDir) ; - def gitCheckout(tempDir: File, branch: String): Unit = - git("checkout" :: "-q" :: branch :: Nil, tempDir) - def git(args: List[String], cwd: File): Unit = - if(isWindowsShell) run(List("cmd", "/c", "git") ++ args, cwd) - else run("git" +: args, cwd) - lazy val isWindowsShell = { - val ostype = System.getenv("OSTYPE") - val isCygwin = ostype != null && ostype.toLowerCase.contains("cygwin") - val isWindows = System.getProperty("os.name", "").toLowerCase.contains("windows") - isWindows && !isCygwin - } - def run(command: List[String], cwd: File): Unit = + object Scheme { - val result = Process(command, cwd) ! ; - if(result != 0) - error("Nonzero exit code (" + result + "): " + command.mkString(" ")) + def unapply(uri: URI) = Option(uri.getScheme) + } + + object Path + { + def unapply(uri: URI) = Option(uri.getPath) } } object EvaluateConfigurations diff --git a/main/Load.scala b/main/Load.scala index 4437a7c89..dd3e60d31 100755 --- a/main/Load.scala +++ b/main/Load.scala @@ -231,7 +231,7 @@ object Load def load(file: File, s: State, config: LoadBuildConfiguration): PartBuild = { val fail = (uri: URI) => error("Invalid build URI (no handler available): " + uri) - val resolver = (info: BuildLoader.ResolveInfo) => RetrieveUnit(info.staging, info.uri) + val resolver = (info: BuildLoader.ResolveInfo) => RetrieveUnit(info) val build = (info: BuildLoader.BuildInfo) => Some(() => loadUnit(info.uri, info.base, info.state, info.config)) val components = BuildLoader.components(resolver, build, full = BuildLoader.componentLoader) val builtinLoader = BuildLoader(components, fail, s, config) diff --git a/main/Resolvers.scala b/main/Resolvers.scala new file mode 100644 index 000000000..1ad6a1c71 --- /dev/null +++ b/main/Resolvers.scala @@ -0,0 +1,105 @@ +/* sbt -- Simple Build Tool + * Copyright 2011 Sanjin Sehic + */ + +package sbt + +import java.io.File +import java.net.URI + +import BuildLoader.ResolveInfo +import RichURI.fromURI + +object Resolvers +{ + type Resolver = BuildLoader.Resolver + + val local: Resolver = (info: ResolveInfo) => { + def retrieveRODir(at: File, into: File) = creates(into) {IO.copyDirectory(at, into)} + + val uri = info.uri + val dir = new File(uri) + if (dir.isDirectory) { + Some { + () => + if (dir.canWrite) + dir + else + retrieveRODir(at = dir, into = uniqueSubdirectoryFor(uri, in = info.staging)) + } + } else None + } + + val remote: Resolver = (info: ResolveInfo) => { + def downloadAndExtract(at: URI, into: File) = creates(into) {IO.unzipURL(at.toURL, into)} + + val uri = info.uri + Some { + () => + downloadAndExtract(at = uri, into = uniqueSubdirectoryFor(uri, in = info.staging)) + } + } + + val git: Resolver = (info: ResolveInfo) => { + def clone(at: String, into: File) + { + run(None, "git", "clone", at, into.getAbsolutePath) + } + + def checkout(branch: String, in: File) + { + run(Some(in), "git", "checkout", "-q", branch) + } + + def retrieveLocalCopy(at: URI, into: File) = + { + creates(into) { + clone(at.withoutFragment.toASCIIString, into) + if (at.hasFragment) + checkout(branch = at.getFragment, in = into) + } + } + + val uri = info.uri + Some { + () => + retrieveLocalCopy(at = uri, into = uniqueSubdirectoryFor(uri, in = info.staging)) + } + } + + private lazy val onWindows = { + val os = System.getenv("OSTYPE") + val isCygwin = (os != null) && os.toLowerCase.contains("cygwin") + val isWindows = System.getProperty("os.name", "").toLowerCase.contains("windows") + isWindows && !isCygwin + } + + def run(cwd: Option[File], command: String*) + { + val result = + Process( + if (onWindows) + "cmd" +: "/c" +: command + else + command, + cwd + ) !; + if (result != 0) + error("Nonzero exit code (" + result + "): " + command.mkString(" ")) + } + + def creates(file: File)(f: => Unit) = + { + try { + if (!file.exists) + f + file + } catch { + case e => + IO.delete(file) + throw e + } + } + + def uniqueSubdirectoryFor(uri: URI, in: File) = new File(in, Hash.halfHashString(uri.toASCIIString)) +} diff --git a/util/io/RichURI.scala b/util/io/RichURI.scala new file mode 100644 index 000000000..7e46af660 --- /dev/null +++ b/util/io/RichURI.scala @@ -0,0 +1,23 @@ +/* sbt -- Simple Build Tool + * Copyright 2011 Sanjin Sehic + */ + +package sbt + +import java.net.URI + +class RichURI(uri: URI) +{ + def hasFragment = uri.getFragment ne null + + def withoutFragment = + if (hasFragment) + new URI(uri.getScheme, uri.getSchemeSpecificPart, null) + else + uri +} + +object RichURI +{ + implicit def fromURI(uri: URI) = new RichURI(uri) +}