问题
How do I get SBT staging directory at build time?
I want to do a tricky clone of a remote repo, and the stagingDirectory
of SBT seems to be a nice fit.
How do I get the directory inside "Build.scala" ?
SBT source code: http://www.scala-sbt.org/0.13.1/sxr/sbt/BuildPaths.scala.html#sbt.BuildPaths.stagingDirectory
=======
Underlying problem NOT directly relevant to the question. I wanted to use a subdirectory of a git dependency in SBT. SBT doesn't provide this out of the box so I wrote a simple wrapper:
object Git {
def clone(cloneFrom: String, branch: String, subdirectory: String) = {
val uniqueHash = Hash.halfHashString(cloneFrom + branch)
val cloneTo = file(sys.props("user.home")) / ".sbt" / "staging" / uniqueHash
val clonedDir = creates(cloneTo) {
Resolvers.run("git", "clone", cloneFrom, cloneTo.absolutePath)
Resolvers.run(Some(cloneTo), "git", "checkout", "-q", branch)
}
clonedDir / subdirectory
}
}
usage:
lazy val myDependency = Git.clone(cloneFrom = "git://...someproject.git", branch = "v2.4", subdirectory = "someModule")
回答1:
Looking at the API from your link, there are two methods you can use getGlobalBase
and getStagingDirectory
, both take state.
import sbt._
import Keys._
import sbt.BuildPaths._
object MyBuild extends Build {
val outputStaging = taskKey[Unit]("Outputs staging")
lazy val root = project.in(file(".")).settings(
outputStaging := {
val s = state.value
println(getStagingDirectory(s, getGlobalBase(s)))
}
)
}
Edit
After your last comment, I think you're looking for a custom resolver. The custom resolver has an access to a ResolveInfo object, which has a property called staging
.
For example this is how you could achieve what you're looking for (actually without accessing staging
directly):
object MyBuild extends Build {
lazy val root = project.in(file(".")).dependsOn(RootProject(uri("dir+git://github.com/lpiepiora/test-repo.git#branch=master&dir=subdir")))
override def buildLoaders = BuildLoader.resolve(myCustomGitResolver) +: super.buildLoaders
def myCustomGitResolver(info: BuildLoader.ResolveInfo): Option[() => File] =
if(info.uri.getScheme != "dir+git") None
else {
import RichURI.fromURI
val uri = info.uri
val (branch, directory) = parseOutBranchNameAndDir(uri.getFragment)
val gitResolveInfo = new BuildLoader.ResolveInfo(
uri.copy(scheme = "git", fragment = branch), info.staging, info.config, info.state
)
println(uri.copy(scheme = "git", fragment = branch))
Resolvers.git(gitResolveInfo).map(fn => () => fn() / directory)
}
// just an ugly way to get the branch and the folder
// you may want something more sophisticated
private def parseOutBranchNameAndDir(fragment: String): (String, String) = {
val Array(branch, dir) = fragment.split('&')
(branch.split('=')(1), dir.split('=')(1))
}
}
The idea is that we delegate to the predefined git resolver, and we let it do it's work, after it's done, we'll return a subdirectory: fn() / directory
.
This is an example and of course you could stick to your logic of getting the repository. The staging directory will be available to you in the resolver method.
来源:https://stackoverflow.com/questions/23932906/how-do-i-get-sbt-staging-directory-at-build-time