mirror of https://github.com/sbt/sbt.git
Merge branch '0.12' of git://github.com/harrah/xsbt into 0.12
This commit is contained in:
commit
1f0a45e950
|
|
@ -61,7 +61,7 @@ class ComponentManager(globalLock: xsbti.GlobalLock, provider: xsbti.ComponentPr
|
||||||
/** Retrieve the file for component 'id' from the local repository. */
|
/** Retrieve the file for component 'id' from the local repository. */
|
||||||
private def update(id: String): Unit = ivyCache.withCachedJar(sbtModuleID(id), Some(globalLock), log)(jar => define(id, Seq(jar)) )
|
private def update(id: String): Unit = ivyCache.withCachedJar(sbtModuleID(id), Some(globalLock), log)(jar => define(id, Seq(jar)) )
|
||||||
|
|
||||||
private def sbtModuleID(id: String) = ModuleID("org.scala-tools.sbt", id, ComponentManager.stampedVersion)
|
private def sbtModuleID(id: String) = ModuleID(SbtArtifacts.Organization, id, ComponentManager.stampedVersion)
|
||||||
/** Install the files for component 'id' to the local repository. This is usually used after writing files to the directory returned by 'location'. */
|
/** Install the files for component 'id' to the local repository. This is usually used after writing files to the directory returned by 'location'. */
|
||||||
def cache(id: String): Unit = ivyCache.cacheJar(sbtModuleID(id), file(id)(IfMissing.Fail), Some(globalLock), log)
|
def cache(id: String): Unit = ivyCache.cacheJar(sbtModuleID(id), file(id)(IfMissing.Fail), Some(globalLock), log)
|
||||||
def clearCache(id: String): Unit = lockGlobalCache { ivyCache.clearCachedJar(sbtModuleID(id), Some(globalLock), log) }
|
def clearCache(id: String): Unit = lockGlobalCache { ivyCache.clearCachedJar(sbtModuleID(id), Some(globalLock), log) }
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ package sbt
|
||||||
final case class ConflictWarning(label: String, filter: ModuleFilter, group: ModuleID => String, level: Level.Value, failOnConflict: Boolean)
|
final case class ConflictWarning(label: String, filter: ModuleFilter, group: ModuleID => String, level: Level.Value, failOnConflict: Boolean)
|
||||||
object ConflictWarning
|
object ConflictWarning
|
||||||
{
|
{
|
||||||
def default(label: String): ConflictWarning = ConflictWarning(label, moduleFilter(organization = GlobFilter("org.scala-tools.sbt") | GlobFilter("org.scala-lang")), (_: ModuleID).organization, Level.Warn, false)
|
def default(label: String): ConflictWarning = ConflictWarning(label, moduleFilter(organization = GlobFilter(SbtArtifacts.Organization) | GlobFilter(ScalaArtifacts.Organization)), (_: ModuleID).organization, Level.Warn, false)
|
||||||
|
|
||||||
def apply(config: ConflictWarning, report: UpdateReport, log: Logger)
|
def apply(config: ConflictWarning, report: UpdateReport, log: Logger)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
package sbt
|
||||||
|
|
||||||
|
final case class ScalaVersion(full: String, binary: String)
|
||||||
|
|
||||||
|
sealed trait CrossVersion
|
||||||
|
object CrossVersion
|
||||||
|
{
|
||||||
|
val TransitionScalaVersion = "2.10"
|
||||||
|
val TransitionSbtVersion = "0.12"
|
||||||
|
|
||||||
|
object Disabled extends CrossVersion { override def toString = "disabled" }
|
||||||
|
final class Binary(val remapVersion: String => String) extends CrossVersion {
|
||||||
|
override def toString = "Binary"
|
||||||
|
}
|
||||||
|
final class Full(val remapVersion: String => String) extends CrossVersion {
|
||||||
|
override def toString = "Full"
|
||||||
|
}
|
||||||
|
|
||||||
|
def full: CrossVersion = new Full(idFun)
|
||||||
|
def fullMapped(remapVersion: String => String): CrossVersion = new Full(remapVersion)
|
||||||
|
|
||||||
|
def binary: CrossVersion = new Binary(idFun)
|
||||||
|
def binaryMapped(remapVersion: String => String): CrossVersion = new Full(remapVersion)
|
||||||
|
|
||||||
|
private[this] def idFun[T]: T => T = x => x
|
||||||
|
def append(s: String): Option[String => String] = Some(x => crossName(x, s))
|
||||||
|
|
||||||
|
def apply(cross: CrossVersion, fullVersion: String, binaryVersion: String): Option[String => String] =
|
||||||
|
cross match
|
||||||
|
{
|
||||||
|
case Disabled => None
|
||||||
|
case b: Binary => append(b.remapVersion(binaryVersion))
|
||||||
|
case f: Full => append(f.remapVersion(fullVersion))
|
||||||
|
}
|
||||||
|
|
||||||
|
def apply(module: ModuleID, is: IvyScala): Option[String => String] =
|
||||||
|
CrossVersion(module.crossVersion, is.scalaFullVersion, is.scalaBinaryVersion)
|
||||||
|
|
||||||
|
def apply(module: ModuleID, is: Option[IvyScala]): Option[String => String] =
|
||||||
|
is flatMap { i => apply(module, i) }
|
||||||
|
|
||||||
|
def substituteCross(artifacts: Seq[Artifact], cross: Option[String => String]): Seq[Artifact] =
|
||||||
|
cross match {
|
||||||
|
case None => artifacts
|
||||||
|
case Some(is) => substituteCrossA(artifacts, cross)
|
||||||
|
}
|
||||||
|
|
||||||
|
def applyCross(s: String, fopt: Option[String => String]): String =
|
||||||
|
fopt match {
|
||||||
|
case None => s
|
||||||
|
case Some(fopt) => fopt(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
def crossName(name: String, cross: String): String =
|
||||||
|
name + "_" + cross
|
||||||
|
def substituteCross(a: Artifact, cross: Option[String => String]): Artifact =
|
||||||
|
a.copy(name = applyCross(a.name, cross))
|
||||||
|
def substituteCrossA(as: Seq[Artifact], cross: Option[String => String]): Seq[Artifact] =
|
||||||
|
as.map(art => substituteCross(art, cross))
|
||||||
|
|
||||||
|
def apply(scalaFullVersion: String, scalaBinaryVersion: String): ModuleID => ModuleID = m =>
|
||||||
|
{
|
||||||
|
val cross = apply(m.crossVersion, scalaFullVersion, scalaBinaryVersion)
|
||||||
|
if(cross.isDefined)
|
||||||
|
m.copy(name = applyCross(m.name, cross), explicitArtifacts = substituteCrossA(m.explicitArtifacts, cross))
|
||||||
|
else
|
||||||
|
m
|
||||||
|
}
|
||||||
|
|
||||||
|
def isStable(v: String): Boolean = !v.contains("-")
|
||||||
|
def selectVersion(full: String, binary: String): String = if(isStable(full)) binary else full
|
||||||
|
|
||||||
|
val PartialVersion = """(\d+)\.(\d+)(?:\..+)?""".r
|
||||||
|
def partialVersion(s: String): Option[(Int,Int)] =
|
||||||
|
s match {
|
||||||
|
case PartialVersion(major, minor) => Some(major.toInt, minor.toInt)
|
||||||
|
case _ => None
|
||||||
|
}
|
||||||
|
private[this] def isNewer(major: Int, minor: Int, minMajor: Int, minMinor: Int): Boolean =
|
||||||
|
major > minMajor || (major == minMajor && minor >= minMinor)
|
||||||
|
|
||||||
|
def binaryScalaVersion(full: String): String = binaryVersion(full, TransitionScalaVersion)
|
||||||
|
def binarySbtVersion(full: String): String = binaryVersion(full, TransitionSbtVersion)
|
||||||
|
def binaryVersion(full: String, cutoff: String): String =
|
||||||
|
{
|
||||||
|
def sub(major: Int, minor: Int) = major + "." + minor
|
||||||
|
(partialVersion(full), partialVersion(cutoff)) match {
|
||||||
|
case (Some((major, minor)), None) => sub(major, minor)
|
||||||
|
case (Some((major, minor)), Some((minMajor, minMinor))) if isNewer(major, minor, minMajor, minMinor) => sub(major, minor)
|
||||||
|
case _ => full
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -27,21 +27,28 @@ trait DependencyBuilders
|
||||||
|
|
||||||
final class GroupID private[sbt] (groupID: String)
|
final class GroupID private[sbt] (groupID: String)
|
||||||
{
|
{
|
||||||
def % (artifactID: String) = groupArtifact(artifactID, None)
|
def % (artifactID: String) = groupArtifact(artifactID, CrossVersion.Disabled)
|
||||||
def %% (artifactID: String, crossVersion: String => String = identity) = groupArtifact(artifactID, Some(crossVersion))
|
def %% (artifactID: String): GroupArtifactID = groupArtifact(artifactID, CrossVersion.binary)
|
||||||
def %% (artifactID: String, alternatives: (String, String)*) = groupArtifact(artifactID, Some(Map(alternatives: _*) orElse { case s => s }))
|
|
||||||
private def groupArtifact(artifactID: String, cross: Option[String => String]) =
|
@deprecated(deprecationMessage, "0.12.0")
|
||||||
|
def %% (artifactID: String, crossVersion: String => String) = groupArtifact(artifactID, CrossVersion.binaryMapped(crossVersion))
|
||||||
|
@deprecated(deprecationMessage, "0.12.0")
|
||||||
|
def %% (artifactID: String, alternatives: (String, String)*) = groupArtifact(artifactID, CrossVersion.binaryMapped(Map(alternatives: _*) orElse { case s => s }))
|
||||||
|
|
||||||
|
private def groupArtifact(artifactID: String, cross: CrossVersion) =
|
||||||
{
|
{
|
||||||
nonEmpty(artifactID, "Artifact ID")
|
nonEmpty(artifactID, "Artifact ID")
|
||||||
new GroupArtifactID(groupID, artifactID, cross)
|
new GroupArtifactID(groupID, artifactID, cross)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private[this] def deprecationMessage = """Use the cross method on the constructed ModuleID. For example: ("a" % "b" % "1").cross(...)"""
|
||||||
}
|
}
|
||||||
final class GroupArtifactID private[sbt] (groupID: String, artifactID: String, crossVersion: Option[String => String])
|
final class GroupArtifactID private[sbt] (groupID: String, artifactID: String, crossVersion: CrossVersion)
|
||||||
{
|
{
|
||||||
def % (revision: String): ModuleID =
|
def % (revision: String): ModuleID =
|
||||||
{
|
{
|
||||||
nonEmpty(revision, "Revision")
|
nonEmpty(revision, "Revision")
|
||||||
ModuleID(groupID, artifactID, revision).cross(!crossVersion.isEmpty, crossVersion.getOrElse(identity))
|
ModuleID(groupID, artifactID, revision).cross(crossVersion)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final class ModuleIDConfigurable private[sbt] (moduleID: ModuleID)
|
final class ModuleIDConfigurable private[sbt] (moduleID: ModuleID)
|
||||||
|
|
|
||||||
|
|
@ -299,24 +299,19 @@ private object IvySbt
|
||||||
}
|
}
|
||||||
|
|
||||||
private def substituteCross(m: ModuleSettings): ModuleSettings =
|
private def substituteCross(m: ModuleSettings): ModuleSettings =
|
||||||
m.ivyScala match { case None => m; case Some(is) => substituteCross(m, is.substituteCross) }
|
m.ivyScala match {
|
||||||
private def substituteCross(m: ModuleSettings, sub: ModuleID => ModuleID): ModuleSettings =
|
case None => m
|
||||||
|
case Some(is) => substituteCross(m, is.scalaFullVersion, is.scalaBinaryVersion)
|
||||||
|
}
|
||||||
|
private def substituteCross(m: ModuleSettings, scalaFullVersion: String, scalaBinaryVersion: String): ModuleSettings =
|
||||||
|
{
|
||||||
|
val sub = CrossVersion(scalaFullVersion, scalaBinaryVersion)
|
||||||
m match {
|
m match {
|
||||||
case ec: EmptyConfiguration => ec.copy(module = sub(ec.module))
|
case ec: EmptyConfiguration => ec.copy(module = sub(ec.module))
|
||||||
case ic: InlineConfiguration => ic.copy(module = sub(ic.module), dependencies = ic.dependencies map sub)
|
case ic: InlineConfiguration => ic.copy(module = sub(ic.module), dependencies = ic.dependencies map sub)
|
||||||
case _ => m
|
case _ => m
|
||||||
}
|
}
|
||||||
def crossName(name: String, cross: String): String =
|
}
|
||||||
name + "_" + cross
|
|
||||||
def substituteCross(a: Artifact, cross: String): Artifact =
|
|
||||||
a.copy(name = crossName(a.name, cross))
|
|
||||||
def substituteCrossA(as: Seq[Artifact], cross: String): Seq[Artifact] =
|
|
||||||
as.map(art => substituteCross(art, cross))
|
|
||||||
def substituteCross(m: ModuleID, cross: String): ModuleID =
|
|
||||||
if(m.crossVersion)
|
|
||||||
m.copy(name = crossName(m.name, m.crossVersionRemap(cross)), explicitArtifacts = substituteCrossA(m.explicitArtifacts, cross))
|
|
||||||
else
|
|
||||||
m
|
|
||||||
|
|
||||||
private def toIvyArtifact(moduleID: ModuleDescriptor, a: Artifact, configurations: Iterable[String]): MDArtifact =
|
private def toIvyArtifact(moduleID: ModuleDescriptor, a: Artifact, configurations: Iterable[String]): MDArtifact =
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -88,8 +88,8 @@ object IvyActions
|
||||||
val resolver = ivy.getSettings.getResolver(resolverName)
|
val resolver = ivy.getSettings.getResolver(resolverName)
|
||||||
if(resolver eq null) error("Undefined resolver '" + resolverName + "'")
|
if(resolver eq null) error("Undefined resolver '" + resolverName + "'")
|
||||||
val ivyArtifact = ivyFile map { file => (MDArtifact.newIvyArtifact(md), file) }
|
val ivyArtifact = ivyFile map { file => (MDArtifact.newIvyArtifact(md), file) }
|
||||||
val is = crossIvyScala(module.moduleSettings)
|
val cross = crossVersionMap(module.moduleSettings)
|
||||||
val as = mapArtifacts(md, is, artifacts) ++ ivyArtifact.toList
|
val as = mapArtifacts(md, cross, artifacts) ++ ivyArtifact.toList
|
||||||
withChecksums(resolver, checksums) { publish(md, as, resolver, overwrite = true) }
|
withChecksums(resolver, checksums) { publish(md, as, resolver, overwrite = true) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -102,18 +102,16 @@ object IvyActions
|
||||||
try { act }
|
try { act }
|
||||||
finally { resolver.setChecksums(previous mkString ",") }
|
finally { resolver.setChecksums(previous mkString ",") }
|
||||||
}
|
}
|
||||||
private def crossIvyScala(moduleSettings: ModuleSettings): Option[IvyScala] =
|
private def crossVersionMap(moduleSettings: ModuleSettings): Option[String => String] =
|
||||||
moduleSettings match {
|
moduleSettings match {
|
||||||
case i: InlineConfiguration if i.module.crossVersion => i.ivyScala
|
case i: InlineConfiguration => CrossVersion(i.module, i.ivyScala)
|
||||||
case e: EmptyConfiguration if e.module.crossVersion => e.ivyScala
|
case e: EmptyConfiguration => CrossVersion(e.module, e.ivyScala)
|
||||||
case _ => None
|
case _ => None
|
||||||
}
|
}
|
||||||
def substituteCross(ivyScala: Option[IvyScala], artifacts: Seq[Artifact]): Seq[Artifact] =
|
def mapArtifacts(module: ModuleDescriptor, cross: Option[String => String], artifacts: Map[Artifact, File]): Seq[(IArtifact, File)] =
|
||||||
ivyScala match { case None => artifacts; case Some(is) => IvySbt.substituteCrossA(artifacts, is.scalaVersion) }
|
|
||||||
def mapArtifacts(module: ModuleDescriptor, ivyScala: Option[IvyScala], artifacts: Map[Artifact, File]): Seq[(IArtifact, File)] =
|
|
||||||
{
|
{
|
||||||
val rawa = artifacts.keys.toSeq
|
val rawa = artifacts.keys.toSeq
|
||||||
val seqa = substituteCross(ivyScala, rawa)
|
val seqa = CrossVersion.substituteCross(rawa, cross)
|
||||||
val zipped = rawa zip IvySbt.mapArtifacts(module, seqa)
|
val zipped = rawa zip IvySbt.mapArtifacts(module, seqa)
|
||||||
zipped map { case (a, ivyA) => (ivyA, artifacts(a)) }
|
zipped map { case (a, ivyA) => (ivyA, artifacts(a)) }
|
||||||
}
|
}
|
||||||
|
|
@ -199,7 +197,7 @@ object IvyActions
|
||||||
report.allMissing flatMap { case (_, mod, art) => art.classifier.map { c => (restrictedCopy(mod, false), c) } } groupBy(_._1) map { case (mod, pairs) => (mod, pairs.map(_._2).toSet) }
|
report.allMissing flatMap { case (_, mod, art) => art.classifier.map { c => (restrictedCopy(mod, false), c) } } groupBy(_._1) map { case (mod, pairs) => (mod, pairs.map(_._2).toSet) }
|
||||||
|
|
||||||
private[this] def restrictedCopy(m: ModuleID, confs: Boolean) =
|
private[this] def restrictedCopy(m: ModuleID, confs: Boolean) =
|
||||||
ModuleID(m.organization, m.name, m.revision, crossVersion = m.crossVersion, crossVersionRemap = m.crossVersionRemap, extraAttributes = m.extraAttributes, configurations = if(confs) m.configurations else None)
|
ModuleID(m.organization, m.name, m.revision, crossVersion = m.crossVersion, extraAttributes = m.extraAttributes, configurations = if(confs) m.configurations else None)
|
||||||
private[this] def resolve(logging: UpdateLogging.Value)(ivy: Ivy, module: DefaultModuleDescriptor, defaultConf: String): (ResolveReport, Option[ResolveException]) =
|
private[this] def resolve(logging: UpdateLogging.Value)(ivy: Ivy, module: DefaultModuleDescriptor, defaultConf: String): (ResolveReport, Option[ResolveException]) =
|
||||||
{
|
{
|
||||||
val resolveOptions = new ResolveOptions
|
val resolveOptions = new ResolveOptions
|
||||||
|
|
|
||||||
|
|
@ -9,14 +9,21 @@ import scala.xml.NodeSeq
|
||||||
import org.apache.ivy.plugins.resolver.{DependencyResolver, IBiblioResolver}
|
import org.apache.ivy.plugins.resolver.{DependencyResolver, IBiblioResolver}
|
||||||
import org.apache.ivy.util.url.CredentialsStore
|
import org.apache.ivy.util.url.CredentialsStore
|
||||||
|
|
||||||
final case class ModuleID(organization: String, name: String, revision: String, configurations: Option[String] = None, isChanging: Boolean = false, isTransitive: Boolean = true, explicitArtifacts: Seq[Artifact] = Nil, exclusions: Seq[ExclusionRule] = Nil, extraAttributes: Map[String,String] = Map.empty, crossVersion: Boolean = false, crossVersionRemap: String => String = identity)
|
final case class ModuleID(organization: String, name: String, revision: String, configurations: Option[String] = None, isChanging: Boolean = false, isTransitive: Boolean = true, explicitArtifacts: Seq[Artifact] = Nil, exclusions: Seq[ExclusionRule] = Nil, extraAttributes: Map[String,String] = Map.empty, crossVersion: CrossVersion = CrossVersion.Disabled)
|
||||||
{
|
{
|
||||||
override def toString =
|
override def toString =
|
||||||
organization + ":" + name + ":" + revision +
|
organization + ":" + name + ":" + revision +
|
||||||
(configurations match { case Some(s) => ":" + s; case None => "" }) +
|
(configurations match { case Some(s) => ":" + s; case None => "" }) +
|
||||||
(if(extraAttributes.isEmpty) "" else " " + extraString)
|
(if(extraAttributes.isEmpty) "" else " " + extraString)
|
||||||
def extraString = extraAttributes.map { case (k,v) => k + "=" + v } mkString("(",", ",")")
|
def extraString = extraAttributes.map { case (k,v) => k + "=" + v } mkString("(",", ",")")
|
||||||
def cross(v: Boolean, verRemap: String => String = identity) = copy(crossVersion = v, crossVersionRemap = verRemap)
|
|
||||||
|
@deprecated("Use the variant accepting a CrossVersion value constructed by a member of the CrossVersion object.", "0.12.0")
|
||||||
|
def cross(v: Boolean): ModuleID = cross(if(v) CrossVersion.binary else CrossVersion.Disabled)
|
||||||
|
@deprecated("Use the variant accepting a CrossVersion value constructed by a member of the CrossVersion object.", "0.12.0")
|
||||||
|
def cross(v: Boolean, verRemap: String => String): ModuleID = cross(if(v) CrossVersion.binaryMapped(verRemap) else CrossVersion.Disabled)
|
||||||
|
|
||||||
|
def cross(v: CrossVersion): ModuleID = copy(crossVersion = v)
|
||||||
|
|
||||||
// () required for chaining
|
// () required for chaining
|
||||||
def notTransitive() = intransitive()
|
def notTransitive() = intransitive()
|
||||||
def intransitive() = copy(isTransitive = false)
|
def intransitive() = copy(isTransitive = false)
|
||||||
|
|
@ -199,8 +206,7 @@ object Resolver
|
||||||
def withDefaultResolvers(userResolvers: Seq[Resolver], mavenCentral: Boolean, scalaTools: Boolean): Seq[Resolver] =
|
def withDefaultResolvers(userResolvers: Seq[Resolver], mavenCentral: Boolean, scalaTools: Boolean): Seq[Resolver] =
|
||||||
Seq(Resolver.defaultLocal) ++
|
Seq(Resolver.defaultLocal) ++
|
||||||
userResolvers ++
|
userResolvers ++
|
||||||
single(DefaultMavenRepository, mavenCentral)++
|
single(DefaultMavenRepository, mavenCentral)
|
||||||
single(ScalaToolsReleases, scalaTools)
|
|
||||||
private def single[T](value: T, nonEmpty: Boolean): Seq[T] = if(nonEmpty) Seq(value) else Nil
|
private def single[T](value: T, nonEmpty: Boolean): Seq[T] = if(nonEmpty) Seq(value) else Nil
|
||||||
|
|
||||||
/** A base class for defining factories for interfaces to Ivy repositories that require a hostname , port, and patterns. */
|
/** A base class for defining factories for interfaces to Ivy repositories that require a hostname , port, and patterns. */
|
||||||
|
|
@ -419,14 +425,14 @@ object Artifact
|
||||||
val base = if(i >= 0) name.substring(0, i) else name
|
val base = if(i >= 0) name.substring(0, i) else name
|
||||||
Artifact(base, extract(name, DefaultType), extract(name, DefaultExtension), None, Nil, Some(file.toURI.toURL))
|
Artifact(base, extract(name, DefaultType), extract(name, DefaultExtension), None, Nil, Some(file.toURI.toURL))
|
||||||
}
|
}
|
||||||
def artifactName(scalaVersion: String, module: ModuleID, artifact: Artifact): String =
|
def artifactName(scalaVersion: ScalaVersion, module: ModuleID, artifact: Artifact): String =
|
||||||
{
|
{
|
||||||
import artifact._
|
import artifact._
|
||||||
val classifierStr = classifier match { case None => ""; case Some(c) => "-" + c }
|
val classifierStr = classifier match { case None => ""; case Some(c) => "-" + c }
|
||||||
val base = if(module.crossVersion) IvySbt.crossName(artifact.name, module.crossVersionRemap(scalaVersion)) else artifact.name
|
val cross = CrossVersion(module.crossVersion, scalaVersion.full, scalaVersion.binary)
|
||||||
|
val base = CrossVersion.applyCross(artifact.name, cross)
|
||||||
base + "-" + module.revision + classifierStr + "." + artifact.extension
|
base + "-" + module.revision + classifierStr + "." + artifact.extension
|
||||||
}
|
}
|
||||||
def cross(enable: Boolean, scalaVersion: String): String = if(enable) "_" + scalaVersion else ""
|
|
||||||
|
|
||||||
val classifierConfMap = Map(SourceClassifier -> Sources, DocClassifier -> Docs)
|
val classifierConfMap = Map(SourceClassifier -> Sources, DocClassifier -> Docs)
|
||||||
val classifierTypeMap = Map(SourceClassifier -> SourceType, DocClassifier -> DocType)
|
val classifierTypeMap = Map(SourceClassifier -> SourceType, DocClassifier -> DocType)
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,14 @@ object ScalaArtifacts
|
||||||
val CompilerID = "scala-compiler"
|
val CompilerID = "scala-compiler"
|
||||||
def libraryDependency(version: String): ModuleID = ModuleID(Organization, LibraryID, version)
|
def libraryDependency(version: String): ModuleID = ModuleID(Organization, LibraryID, version)
|
||||||
}
|
}
|
||||||
|
object SbtArtifacts
|
||||||
|
{
|
||||||
|
val Organization = "org.scala-sbt"
|
||||||
|
}
|
||||||
|
|
||||||
import ScalaArtifacts._
|
import ScalaArtifacts._
|
||||||
|
|
||||||
final case class IvyScala(scalaVersion: String, configurations: Iterable[Configuration], checkExplicit: Boolean, filterImplicit: Boolean, overrideScalaVersion: Boolean, substituteCross: ModuleID => ModuleID)
|
final case class IvyScala(scalaFullVersion: String, scalaBinaryVersion: String, configurations: Iterable[Configuration], checkExplicit: Boolean, filterImplicit: Boolean, overrideScalaVersion: Boolean)
|
||||||
|
|
||||||
private object IvyScala
|
private object IvyScala
|
||||||
{
|
{
|
||||||
|
|
@ -30,11 +34,11 @@ private object IvyScala
|
||||||
def checkModule(module: DefaultModuleDescriptor, conf: String)(check: IvyScala)
|
def checkModule(module: DefaultModuleDescriptor, conf: String)(check: IvyScala)
|
||||||
{
|
{
|
||||||
if(check.checkExplicit)
|
if(check.checkExplicit)
|
||||||
checkDependencies(module, check.scalaVersion, check.configurations)
|
checkDependencies(module, check.scalaBinaryVersion, check.configurations)
|
||||||
if(check.filterImplicit)
|
if(check.filterImplicit)
|
||||||
excludeScalaJars(module, check.configurations)
|
excludeScalaJars(module, check.configurations)
|
||||||
if(check.overrideScalaVersion)
|
if(check.overrideScalaVersion)
|
||||||
overrideScalaVersion(module, check.scalaVersion)
|
overrideScalaVersion(module, check.scalaFullVersion)
|
||||||
}
|
}
|
||||||
def overrideScalaVersion(module: DefaultModuleDescriptor, version: String)
|
def overrideScalaVersion(module: DefaultModuleDescriptor, version: String)
|
||||||
{
|
{
|
||||||
|
|
@ -50,14 +54,15 @@ private object IvyScala
|
||||||
|
|
||||||
/** Checks the immediate dependencies of module for dependencies on scala jars and verifies that the version on the
|
/** Checks the immediate dependencies of module for dependencies on scala jars and verifies that the version on the
|
||||||
* dependencies matches scalaVersion. */
|
* dependencies matches scalaVersion. */
|
||||||
private def checkDependencies(module: ModuleDescriptor, scalaVersion: String, configurations: Iterable[Configuration])
|
private def checkDependencies(module: ModuleDescriptor, scalaBinaryVersion: String, configurations: Iterable[Configuration])
|
||||||
{
|
{
|
||||||
val configSet = if(configurations.isEmpty) (c: String) => true else configurationSet(configurations)
|
val configSet = if(configurations.isEmpty) (c: String) => true else configurationSet(configurations)
|
||||||
for(dep <- module.getDependencies.toList)
|
for(dep <- module.getDependencies.toList)
|
||||||
{
|
{
|
||||||
val id = dep.getDependencyRevisionId
|
val id = dep.getDependencyRevisionId
|
||||||
if(id.getOrganisation == Organization && id.getRevision != scalaVersion && dep.getModuleConfigurations.exists(configSet))
|
val depBinaryVersion = CrossVersion.binaryScalaVersion(id.getRevision)
|
||||||
error("Version specified for dependency " + id + " differs from Scala version in project (" + scalaVersion + ").")
|
if(id.getOrganisation == Organization && depBinaryVersion != scalaBinaryVersion && dep.getModuleConfigurations.exists(configSet))
|
||||||
|
error("Binary version for dependency " + id + " (" + depBinaryVersion + ") differs from Scala binary version in project (" + scalaBinaryVersion + ").")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private def configurationSet(configurations: Iterable[Configuration]) = configurations.map(_.toString).toSet
|
private def configurationSet(configurations: Iterable[Configuration]) = configurations.map(_.toString).toSet
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ private object BootConfiguration
|
||||||
|
|
||||||
val JUnitName = "junit"
|
val JUnitName = "junit"
|
||||||
|
|
||||||
val SbtOrg = "org.scala-tools.sbt"
|
val SbtOrg = "org.scala-sbt"
|
||||||
|
|
||||||
/** The Ivy conflict manager to use for updating.*/
|
/** The Ivy conflict manager to use for updating.*/
|
||||||
val ConflictManagerName = "latest-revision"
|
val ConflictManagerName = "latest-revision"
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,7 @@ class ConfigurationParser
|
||||||
|
|
||||||
def getApplication(m: LabelMap): (Application, Value[List[String]]) =
|
def getApplication(m: LabelMap): (Application, Value[List[String]]) =
|
||||||
{
|
{
|
||||||
val (org, m1) = id(m, "org", "org.scala-tools.sbt")
|
val (org, m1) = id(m, "org", BootConfiguration.SbtOrg)
|
||||||
val (name, m2) = id(m1, "name", "sbt")
|
val (name, m2) = id(m1, "name", "sbt")
|
||||||
val (rev, m3) = getVersion(m2, name + " version", name + ".version")
|
val (rev, m3) = getVersion(m2, name + " version", name + ".version")
|
||||||
val (main, m4) = id(m3, "class", "xsbt.Main")
|
val (main, m4) = id(m3, "class", "xsbt.Main")
|
||||||
|
|
@ -171,7 +171,7 @@ class ConfigurationParser
|
||||||
m.toList.map {
|
m.toList.map {
|
||||||
case (key, None) => Predefined(key)
|
case (key, None) => Predefined(key)
|
||||||
case (key, Some(value)) =>
|
case (key, Some(value)) =>
|
||||||
val r = trim(value.split(",",3))
|
val r = trim(substituteVariables(value).split(",",3))
|
||||||
val url = try { new URL(r(0)) } catch { case e: MalformedURLException => error("Invalid URL specified for '" + key + "': " + e.getMessage) }
|
val url = try { new URL(r(0)) } catch { case e: MalformedURLException => error("Invalid URL specified for '" + key + "': " + e.getMessage) }
|
||||||
if(r.length == 3) Ivy(key, url, r(1), r(2)) else if(r.length == 2) Ivy(key, url, r(1), r(1)) else Maven(key, url)
|
if(r.length == 3) Ivy(key, url, r(1), r(2)) else if(r.length == 2) Ivy(key, url, r(1), r(1)) else Maven(key, url)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,6 @@
|
||||||
local
|
local
|
||||||
${{repositories}}
|
${{repositories}}
|
||||||
maven-central
|
maven-central
|
||||||
scala-tools-releases
|
|
||||||
scala-tools-snapshots
|
|
||||||
|
|
||||||
[boot]
|
[boot]
|
||||||
directory: ${sbt.boot.directory-${sbt.global.base-${user.home}/.sbt}/boot/}
|
directory: ${sbt.boot.directory-${sbt.global.base-${user.home}/.sbt}/boot/}
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ object ScalaProviderTest extends Specification
|
||||||
object LaunchTest
|
object LaunchTest
|
||||||
{
|
{
|
||||||
def testApp(main: String): Application = testApp(main, Array[File]())
|
def testApp(main: String): Application = testApp(main, Array[File]())
|
||||||
def testApp(main: String, extra: Array[File]): Application = Application("org.scala-tools.sbt", "launch-test", new Explicit(AppVersion), main, Nil, false, extra)
|
def testApp(main: String, extra: Array[File]): Application = Application("org.scala-sbt", "launch-test", new Explicit(AppVersion), main, Nil, false, extra)
|
||||||
import Predefined._
|
import Predefined._
|
||||||
def testRepositories = List(Local, ScalaToolsReleases, ScalaToolsSnapshots).map(Repository.Predefined.apply)
|
def testRepositories = List(Local, ScalaToolsReleases, ScalaToolsSnapshots).map(Repository.Predefined.apply)
|
||||||
def withLauncher[T](f: xsbti.Launcher => T): T =
|
def withLauncher[T](f: xsbti.Launcher => T): T =
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ package sbt
|
||||||
import DefaultParsers._
|
import DefaultParsers._
|
||||||
import Types.idFun
|
import Types.idFun
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import CommandSupport.ShowCommand
|
import CommandStrings.ShowCommand
|
||||||
|
|
||||||
final class ParsedKey(val key: ScopedKey[_], val mask: ScopeMask)
|
final class ParsedKey(val key: ScopedKey[_], val mask: ScopeMask)
|
||||||
object Act
|
object Act
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ final object Aggregation
|
||||||
Dag.topologicalSort(key) { k =>
|
Dag.topologicalSort(key) { k =>
|
||||||
if(reverse)
|
if(reverse)
|
||||||
reverseAggregatedKeys(k, extra, mask)
|
reverseAggregatedKeys(k, extra, mask)
|
||||||
else if(aggregationEnabled(key, extra.data))
|
else if(aggregationEnabled(k, extra.data))
|
||||||
aggregatedKeys(k, extra, mask)
|
aggregatedKeys(k, extra, mask)
|
||||||
else
|
else
|
||||||
Nil
|
Nil
|
||||||
|
|
|
||||||
|
|
@ -38,4 +38,12 @@ object Append
|
||||||
def appendValues(a: Classpath, b: Seq[File]): Classpath = a ++ Attributed.blankSeq(b)
|
def appendValues(a: Classpath, b: Seq[File]): Classpath = a ++ Attributed.blankSeq(b)
|
||||||
def appendValue(a: Classpath, b: File): Classpath = a :+ Attributed.blank(b)
|
def appendValue(a: Classpath, b: File): Classpath = a :+ Attributed.blank(b)
|
||||||
}
|
}
|
||||||
|
implicit def appendSet[T, V <: T]: Sequence[Set[T], Set[V], V] = new Sequence[Set[T], Set[V], V] {
|
||||||
|
def appendValues(a: Set[T], b: Set[V]): Set[T] = a ++ b
|
||||||
|
def appendValue(a: Set[T], b: V): Set[T] = a + b
|
||||||
|
}
|
||||||
|
implicit def appendMap[A,B, X <: A, Y <: B]: Sequence[Map[A,B], Map[X,Y], (X,Y)] = new Sequence[Map[A,B], Map[X,Y], (X,Y)] {
|
||||||
|
def appendValues(a: Map[A,B], b: Map[X,Y]): Map[A,B] = a ++ b
|
||||||
|
def appendValue(a: Map[A,B], b: (X,Y)): Map[A,B] = a + b
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3,37 +3,15 @@
|
||||||
*/
|
*/
|
||||||
package sbt
|
package sbt
|
||||||
|
|
||||||
import complete.HistoryCommands
|
object CommandStrings
|
||||||
import scala.annotation.tailrec
|
|
||||||
|
|
||||||
import java.io.File
|
|
||||||
import Path._
|
|
||||||
|
|
||||||
object CommandSupport
|
|
||||||
{
|
{
|
||||||
def logger(s: State) = globalLogging(s).full
|
@deprecated("Use the `log` member of a State instance directly.", "0.12.0")
|
||||||
def globalLogging(s: State) = s get Keys.globalLogging getOrElse error("Global logging misconfigured")
|
def logger(s: State) = s.log
|
||||||
|
|
||||||
// slightly better fallback in case of older launcher
|
@deprecated("Use the `globalLogging` member of a State instance directly.", "0.12.0")
|
||||||
def bootDirectory(state: State): File =
|
def globalLogging(s: State) = s.globalLogging
|
||||||
try { state.configuration.provider.scalaProvider.launcher.bootDirectory }
|
|
||||||
catch { case e: NoSuchMethodError => new File(".").getAbsoluteFile }
|
|
||||||
|
|
||||||
private def canRead = (_: File).canRead
|
|
||||||
def notReadable(files: Seq[File]): Seq[File] = files filterNot canRead
|
|
||||||
def readable(files: Seq[File]): Seq[File] = files filter canRead
|
|
||||||
def sbtRCs(s: State): Seq[File] =
|
|
||||||
(Path.userHome / sbtrc) ::
|
|
||||||
(s.baseDir / sbtrc asFile) ::
|
|
||||||
Nil
|
|
||||||
|
|
||||||
def readLines(files: Seq[File]): Seq[String] = files flatMap (line => IO.readLines(line)) flatMap processLine
|
|
||||||
def processLine(s: String) = { val trimmed = s.trim; if(ignoreLine(trimmed)) None else Some(trimmed) }
|
|
||||||
def ignoreLine(s: String) = s.isEmpty || s.startsWith("#")
|
|
||||||
|
|
||||||
/** The prefix used to identify a request to execute the remaining input on source changes.*/
|
/** The prefix used to identify a request to execute the remaining input on source changes.*/
|
||||||
val ContinuousExecutePrefix = "~"
|
|
||||||
val HelpCommand = "help"
|
|
||||||
val AboutCommand = "about"
|
val AboutCommand = "about"
|
||||||
val TasksCommand = "tasks"
|
val TasksCommand = "tasks"
|
||||||
val ProjectCommand = "project"
|
val ProjectCommand = "project"
|
||||||
|
|
@ -41,8 +19,14 @@ object CommandSupport
|
||||||
val ShowCommand = "show"
|
val ShowCommand = "show"
|
||||||
val BootCommand = "boot"
|
val BootCommand = "boot"
|
||||||
|
|
||||||
val Exit = "exit"
|
@deprecated("Moved to BasicCommandStrings", "0.12.0")
|
||||||
val Quit = "quit"
|
val ContinuousExecutePrefix = BasicCommandStrings.ContinuousExecutePrefix
|
||||||
|
|
||||||
|
@deprecated("Moved to BasicCommandStrings", "0.12.0")
|
||||||
|
val Exit = BasicCommandStrings.Exit
|
||||||
|
|
||||||
|
@deprecated("Moved to BasicCommandStrings", "0.12.0")
|
||||||
|
val Quit = BasicCommandStrings.Quit
|
||||||
|
|
||||||
val EvalCommand = "eval"
|
val EvalCommand = "eval"
|
||||||
val evalBrief = (EvalCommand + " <expression>", "Evaluates the given Scala expression and prints the result and type.")
|
val evalBrief = (EvalCommand + " <expression>", "Evaluates the given Scala expression and prints the result and type.")
|
||||||
|
|
@ -128,9 +112,8 @@ SetCommand + """ <setting-expression>
|
||||||
def sessionBrief = (SessionCommand + " <session-command>", "Manipulates session settings. For details, run 'help " + SessionCommand + "'.")
|
def sessionBrief = (SessionCommand + " <session-command>", "Manipulates session settings. For details, run 'help " + SessionCommand + "'.")
|
||||||
|
|
||||||
/** The command name to terminate the program.*/
|
/** The command name to terminate the program.*/
|
||||||
val TerminateAction: String = Exit
|
@deprecated("Moved to BasicCommandStrings", "0.12.0")
|
||||||
|
val TerminateAction: String = BasicCommandStrings.TerminateAction
|
||||||
def continuousBriefHelp = (ContinuousExecutePrefix + " <command>", "Executes the specified command whenever source files change.")
|
|
||||||
|
|
||||||
def tasksPreamble = """
|
def tasksPreamble = """
|
||||||
This is a list of tasks defined for the current project.
|
This is a list of tasks defined for the current project.
|
||||||
|
|
@ -140,11 +123,6 @@ Tasks produce values. Use the 'show' command to run the task and print the resu
|
||||||
def tasksBrief = "Displays the tasks defined for the current project."
|
def tasksBrief = "Displays the tasks defined for the current project."
|
||||||
def tasksDetailed = "Displays the tasks defined directly or indirectly for the current project."
|
def tasksDetailed = "Displays the tasks defined directly or indirectly for the current project."
|
||||||
|
|
||||||
def helpBrief = (HelpCommand + " [command]*", "Displays this help message or prints detailed help on requested commands.")
|
|
||||||
def helpDetailed = """
|
|
||||||
If an argument is provided, this prints detailed help for that command.
|
|
||||||
Otherwise, this prints a help summary."""
|
|
||||||
|
|
||||||
def aboutBrief = "Displays basic information about sbt and the build."
|
def aboutBrief = "Displays basic information about sbt and the build."
|
||||||
def aboutDetailed = aboutBrief
|
def aboutDetailed = aboutBrief
|
||||||
|
|
||||||
|
|
@ -175,126 +153,23 @@ ProjectCommand +
|
||||||
def projectsBrief = projectsDetailed
|
def projectsBrief = projectsDetailed
|
||||||
def projectsDetailed = "Displays the names of available projects."
|
def projectsDetailed = "Displays the names of available projects."
|
||||||
|
|
||||||
def historyHelp = Help.briefDetail(HistoryCommands.descriptions)
|
|
||||||
|
|
||||||
def exitBrief = "Terminates the build."
|
|
||||||
|
|
||||||
def sbtrc = ".sbtrc"
|
def sbtrc = ".sbtrc"
|
||||||
|
|
||||||
def ReadCommand = "<"
|
@deprecated("Moved to BasicCommandStrings", "0.12.0")
|
||||||
def ReadFiles = " file1 file2 ..."
|
def ReadCommand = BasicCommandStrings.ReadCommand
|
||||||
def ReadBrief = (ReadCommand + " <file>*", "Reads command lines from the provided files.")
|
|
||||||
def ReadDetailed =
|
|
||||||
ReadCommand + ReadFiles + """
|
|
||||||
|
|
||||||
Reads the lines from the given files and inserts them as commands.
|
|
||||||
All empty lines and lines that start with '#' are ignored.
|
|
||||||
If a file does not exist or is not readable, this command fails.
|
|
||||||
|
|
||||||
All the lines from all the files are read before any of the commands
|
|
||||||
are executed. Thus, if any file is not readable, none of commands
|
|
||||||
from any of the files (even the existing ones) will be run.
|
|
||||||
|
|
||||||
You probably need to escape this command if entering it at your shell."""
|
|
||||||
|
|
||||||
def ApplyCommand = "apply"
|
|
||||||
def ApplyBrief = (ApplyCommand + " <module-name>*", ApplyDetailed)
|
|
||||||
def ApplyDetailed = "Transforms the current State by calling <module-name>.apply(currentState) for each listed."
|
|
||||||
|
|
||||||
def DefaultsCommand = "add-default-commands"
|
def DefaultsCommand = "add-default-commands"
|
||||||
def DefaultsBrief = (DefaultsCommand, DefaultsDetailed)
|
def DefaultsBrief = (DefaultsCommand, DefaultsDetailed)
|
||||||
def DefaultsDetailed = "Registers default built-in commands"
|
def DefaultsDetailed = "Registers default built-in commands"
|
||||||
|
|
||||||
|
@deprecated("Moved to BasicCommandStrings", "0.12.0")
|
||||||
def RebootCommand = "reboot"
|
def RebootCommand = "reboot"
|
||||||
def RebootSummary = RebootCommand + " [full]"
|
|
||||||
def RebootBrief = (RebootSummary, "Reboots sbt and then executes the remaining commands.")
|
|
||||||
def RebootDetailed =
|
|
||||||
RebootSummary + """
|
|
||||||
|
|
||||||
This command is equivalent to exiting sbt, restarting, and running the
|
|
||||||
remaining commands with the exception that the JVM is not shut down.
|
|
||||||
|
|
||||||
If 'full' is specified, the boot directory (`~/.sbt/boot` by default)
|
|
||||||
is deleted before restarting. This forces an update of sbt and Scala
|
|
||||||
and is useful when working with development versions of sbt or Scala."""
|
|
||||||
|
|
||||||
|
@deprecated("Moved to BasicCommandStrings", "0.12.0")
|
||||||
def Multi = ";"
|
def Multi = ";"
|
||||||
def MultiBrief = (Multi + " <command> (" + Multi + " <command>)*", "Runs the provided semicolon-separated commands.")
|
|
||||||
def MultiDetailed =
|
|
||||||
Multi + " command1 " + Multi + """ command2 ...
|
|
||||||
|
|
||||||
Runs the specified commands."""
|
|
||||||
|
|
||||||
|
@deprecated("Moved to BasicCommandStrings", "0.12.0")
|
||||||
def AppendCommand = "append"
|
def AppendCommand = "append"
|
||||||
def AppendLastBrief = (AppendCommand + " <command>", AppendLastDetailed)
|
|
||||||
def AppendLastDetailed = "Appends 'command' to list of commands to run."
|
|
||||||
|
|
||||||
val AliasCommand = "alias"
|
|
||||||
def AliasBrief = (AliasCommand, "Adds, removes, or prints command aliases.")
|
|
||||||
def AliasDetailed =
|
|
||||||
AliasCommand + """
|
|
||||||
|
|
||||||
Prints a list of defined aliases.
|
|
||||||
|
|
||||||
""" +
|
|
||||||
AliasCommand + """ name
|
|
||||||
|
|
||||||
Prints the alias defined for `name`.
|
|
||||||
|
|
||||||
""" +
|
|
||||||
AliasCommand + """ name=value
|
|
||||||
|
|
||||||
Sets the alias `name` to `value`, replacing any existing alias with that name.
|
|
||||||
Whenever `name` is entered, the corresponding `value` is run.
|
|
||||||
If any argument is provided to `name`, it is appended as argument to `value`.
|
|
||||||
|
|
||||||
""" +
|
|
||||||
AliasCommand + """ name=
|
|
||||||
|
|
||||||
Removes the alias for `name`."""
|
|
||||||
|
|
||||||
def Discover = "discover"
|
|
||||||
def DiscoverBrief = (DiscoverSyntax, "Finds annotated classes and subclasses.")
|
|
||||||
def DiscoverSyntax = Discover + " [-module true|false] [-sub <names>] [-annot <names>]"
|
|
||||||
def DiscoverDetailed =
|
|
||||||
DiscoverSyntax + """
|
|
||||||
|
|
||||||
Looks for public, concrete classes that match the requested query using the current sbt.inc.Analysis instance.
|
|
||||||
|
|
||||||
-module
|
|
||||||
Specifies whether modules (true) or classes (false) are found.
|
|
||||||
The default is classes/traits (false).
|
|
||||||
|
|
||||||
-sub
|
|
||||||
Specifies comma-separated class names.
|
|
||||||
Classes that have one or more of these classes as an ancestor are included in the resulting list.
|
|
||||||
|
|
||||||
-annot
|
|
||||||
Specifies comma-separated annotation names.
|
|
||||||
Classes with one or more of these annotations on the class or one of its non-private methods are included in the resulting list.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def CompileName = "direct-compile"
|
|
||||||
def CompileBrief = (CompileSyntax, "Incrementally compiles the provided sources.")
|
|
||||||
def CompileSyntax = CompileName + " -src <paths> [-cp <paths>] [-d <path>]"
|
|
||||||
def CompileDetailed =
|
|
||||||
CompileSyntax + """
|
|
||||||
|
|
||||||
Incrementally compiles Scala and Java sources.
|
|
||||||
|
|
||||||
<paths> are explicit paths separated by the platform path separator.
|
|
||||||
|
|
||||||
The specified output path will contain the following directory structure:
|
|
||||||
|
|
||||||
scala_<version>/
|
|
||||||
classes/
|
|
||||||
cache/
|
|
||||||
|
|
||||||
Compiled classes will be written to the 'classes' directory.
|
|
||||||
Cached information about the compilation will be written to 'cache'.
|
|
||||||
"""
|
|
||||||
|
|
||||||
val FailureWall = "---"
|
|
||||||
|
|
||||||
def Load = "load"
|
def Load = "load"
|
||||||
def LoadLabel = "a project"
|
def LoadLabel = "a project"
|
||||||
|
|
@ -308,31 +183,20 @@ CompileSyntax + """
|
||||||
def LoadProjectBrief = (LoadProject, LoadProjectDetailed)
|
def LoadProjectBrief = (LoadProject, LoadProjectDetailed)
|
||||||
def LoadProjectDetailed = "Loads the project in the current directory"
|
def LoadProjectDetailed = "Loads the project in the current directory"
|
||||||
|
|
||||||
def Shell = "shell"
|
@deprecated("Moved to State", "0.12.0")
|
||||||
def ShellBrief = ShellDetailed
|
val FailureWall = State.FailureWall
|
||||||
def ShellDetailed = "Provides an interactive prompt from which commands can be run."
|
|
||||||
|
|
||||||
|
@deprecated("Moved to BasicCommandStrings", "0.12.0")
|
||||||
|
def Shell = BasicCommandStrings.Shell
|
||||||
|
|
||||||
|
@deprecated("Moved to BasicCommandStrings", "0.12.0")
|
||||||
def ClearOnFailure = "--"
|
def ClearOnFailure = "--"
|
||||||
|
|
||||||
|
@deprecated("Moved to BasicCommandStrings", "0.12.0")
|
||||||
def OnFailure = "-"
|
def OnFailure = "-"
|
||||||
def OnFailureBrief = (OnFailure + " command", "Registers 'command' to run if a command fails.")
|
|
||||||
def OnFailureDetailed =
|
|
||||||
OnFailure + """ command
|
|
||||||
|
|
||||||
Registers 'command' to run when a command fails to complete normally.
|
|
||||||
|
|
||||||
Only one failure command may be registered at a time, so this command
|
|
||||||
replaces the previous command if there is one.
|
|
||||||
|
|
||||||
The failure command resets when it runs once, so it must be added
|
|
||||||
again if desired."""
|
|
||||||
|
|
||||||
|
@deprecated("Moved to BasicCommandStrings", "0.12.0")
|
||||||
def IfLast = "iflast"
|
def IfLast = "iflast"
|
||||||
def IfLastBrief = (IfLast + " <command>", IfLastCommon)
|
|
||||||
def IfLastCommon = "If there are no more commands after this one, 'command' is run."
|
|
||||||
def IfLastDetailed =
|
|
||||||
IfLast + """ command
|
|
||||||
|
|
||||||
""" + IfLastCommon
|
|
||||||
|
|
||||||
def InitCommand = "initialize"
|
def InitCommand = "initialize"
|
||||||
def InitBrief = (InitCommand, "Initializes command processing.")
|
def InitBrief = (InitCommand, "Initializes command processing.")
|
||||||
|
|
@ -352,4 +216,12 @@ load-commands -base ~/.sbt/commands
|
||||||
< .sbtrc
|
< .sbtrc
|
||||||
Runs commands from ~/.sbtrc and ./.sbtrc if they exist
|
Runs commands from ~/.sbtrc and ./.sbtrc if they exist
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
import Path._
|
||||||
|
|
||||||
|
def sbtRCs(s: State): Seq[File] =
|
||||||
|
(Path.userHome / sbtrc) ::
|
||||||
|
(s.baseDir / sbtrc asFile) ::
|
||||||
|
Nil
|
||||||
}
|
}
|
||||||
|
|
@ -10,6 +10,7 @@ package sbt
|
||||||
import Load.LoadedBuild
|
import Load.LoadedBuild
|
||||||
import Artifact.{DocClassifier, SourceClassifier}
|
import Artifact.{DocClassifier, SourceClassifier}
|
||||||
import Configurations.{Compile, CompilerPlugin, IntegrationTest, names, Provided, Runtime, Test}
|
import Configurations.{Compile, CompilerPlugin, IntegrationTest, names, Provided, Runtime, Test}
|
||||||
|
import CrossVersion.{binarySbtVersion, binaryScalaVersion, isStable, selectVersion}
|
||||||
import complete._
|
import complete._
|
||||||
import std.TaskExtra._
|
import std.TaskExtra._
|
||||||
import inc.{FileValueCache, Locate}
|
import inc.{FileValueCache, Locate}
|
||||||
|
|
@ -48,16 +49,16 @@ object Defaults extends BuildCommon
|
||||||
def buildCore: Seq[Setting[_]] = thisBuildCore ++ globalCore
|
def buildCore: Seq[Setting[_]] = thisBuildCore ++ globalCore
|
||||||
def thisBuildCore: Seq[Setting[_]] = inScope(GlobalScope.copy(project = Select(ThisBuild)))(Seq(
|
def thisBuildCore: Seq[Setting[_]] = inScope(GlobalScope.copy(project = Select(ThisBuild)))(Seq(
|
||||||
managedDirectory <<= baseDirectory(_ / "lib_managed")
|
managedDirectory <<= baseDirectory(_ / "lib_managed")
|
||||||
|
|
||||||
))
|
))
|
||||||
def globalCore: Seq[Setting[_]] = inScope(GlobalScope)(Seq(
|
def globalCore: Seq[Setting[_]] = inScope(GlobalScope)(Seq(
|
||||||
|
crossVersion :== CrossVersion.Disabled,
|
||||||
buildDependencies <<= buildDependencies or Classpaths.constructBuildDependencies,
|
buildDependencies <<= buildDependencies or Classpaths.constructBuildDependencies,
|
||||||
taskTemporaryDirectory := IO.createTemporaryDirectory,
|
taskTemporaryDirectory := IO.createTemporaryDirectory,
|
||||||
onComplete <<= taskTemporaryDirectory { dir => () => IO.delete(dir); IO.createDirectory(dir) },
|
onComplete <<= taskTemporaryDirectory { dir => () => IO.delete(dir); IO.createDirectory(dir) },
|
||||||
concurrentRestrictions <<= concurrentRestrictions or defaultRestrictions,
|
concurrentRestrictions <<= concurrentRestrictions or defaultRestrictions,
|
||||||
parallelExecution :== true,
|
parallelExecution :== true,
|
||||||
sbtVersion <<= appConfiguration { _.provider.id.version },
|
sbtVersion <<= appConfiguration { _.provider.id.version },
|
||||||
sbtBinaryVersion <<= sbtVersion(v => binaryVersion(v, "0.12")),
|
sbtBinaryVersion <<= sbtVersion apply binarySbtVersion,
|
||||||
sbtResolver <<= sbtVersion { sbtV => if(sbtV endsWith "-SNAPSHOT") Classpaths.typesafeSnapshots else Classpaths.typesafeResolver },
|
sbtResolver <<= sbtVersion { sbtV => if(sbtV endsWith "-SNAPSHOT") Classpaths.typesafeSnapshots else Classpaths.typesafeResolver },
|
||||||
pollInterval :== 500,
|
pollInterval :== 500,
|
||||||
logBuffered :== false,
|
logBuffered :== false,
|
||||||
|
|
@ -190,7 +191,13 @@ object Defaults extends BuildCommon
|
||||||
scalacOptions in GlobalScope :== Nil,
|
scalacOptions in GlobalScope :== Nil,
|
||||||
scalaInstance <<= scalaInstanceSetting,
|
scalaInstance <<= scalaInstanceSetting,
|
||||||
scalaVersion in GlobalScope <<= appConfiguration( _.provider.scalaProvider.version),
|
scalaVersion in GlobalScope <<= appConfiguration( _.provider.scalaProvider.version),
|
||||||
scalaBinaryVersion <<= scalaVersion(v => binaryVersion(v, "2.10")),
|
scalaBinaryVersion in GlobalScope <<= scalaVersion apply binaryScalaVersion,
|
||||||
|
crossVersion <<= (crossPaths, scalaVersion) { (enabled, sv) =>
|
||||||
|
if(enabled)
|
||||||
|
if(isStable(sv)) CrossVersion.binary else CrossVersion.full
|
||||||
|
else
|
||||||
|
CrossVersion.Disabled
|
||||||
|
},
|
||||||
crossScalaVersions in GlobalScope <<= Seq(scalaVersion).join,
|
crossScalaVersions in GlobalScope <<= Seq(scalaVersion).join,
|
||||||
crossTarget <<= (target, scalaBinaryVersion, sbtBinaryVersion, sbtPlugin, crossPaths)(makeCrossTarget)
|
crossTarget <<= (target, scalaBinaryVersion, sbtBinaryVersion, sbtPlugin, crossPaths)(makeCrossTarget)
|
||||||
)
|
)
|
||||||
|
|
@ -211,7 +218,7 @@ object Defaults extends BuildCommon
|
||||||
discoveredMainClasses <<= compile map discoverMainClasses storeAs discoveredMainClasses triggeredBy compile,
|
discoveredMainClasses <<= compile map discoverMainClasses storeAs discoveredMainClasses triggeredBy compile,
|
||||||
definedSbtPlugins <<= discoverPlugins,
|
definedSbtPlugins <<= discoverPlugins,
|
||||||
inTask(run)(runnerTask :: Nil).head,
|
inTask(run)(runnerTask :: Nil).head,
|
||||||
selectMainClass <<= discoveredMainClasses map selectRunMain,
|
selectMainClass <<= (discoveredMainClasses, mainClass) map { (classes, explicit) => explicit orElse selectRunMain(classes) },
|
||||||
mainClass in run <<= selectMainClass in run,
|
mainClass in run <<= selectMainClass in run,
|
||||||
mainClass <<= discoveredMainClasses map selectPackageMain,
|
mainClass <<= discoveredMainClasses map selectPackageMain,
|
||||||
run <<= runTask(fullClasspath, mainClass in run, runner in run),
|
run <<= runTask(fullClasspath, mainClass in run, runner in run),
|
||||||
|
|
@ -357,10 +364,8 @@ object Defaults extends BuildCommon
|
||||||
packageTasks(packageSrc, packageSrcTask) ++
|
packageTasks(packageSrc, packageSrcTask) ++
|
||||||
packageTasks(packageDoc, packageDocTask)
|
packageTasks(packageDoc, packageDocTask)
|
||||||
|
|
||||||
private[this] val allSubpaths = (dir: File) => (dir.*** --- dir) x (relativeTo(dir)|flat)
|
def packageBinTask = products map { _ flatMap Path.allSubpaths }
|
||||||
|
def packageDocTask = doc map { p => Path.allSubpaths(p).toSeq }
|
||||||
def packageBinTask = products map { ps => ps flatMap { p => allSubpaths(p) } }
|
|
||||||
def packageDocTask = doc map allSubpaths
|
|
||||||
def packageSrcTask = concatMappings(resourceMappings, sourceMappings)
|
def packageSrcTask = concatMappings(resourceMappings, sourceMappings)
|
||||||
|
|
||||||
private type Mappings = Initialize[Task[Seq[(File, String)]]]
|
private type Mappings = Initialize[Task[Seq[(File, String)]]]
|
||||||
|
|
@ -368,18 +373,21 @@ object Defaults extends BuildCommon
|
||||||
|
|
||||||
// drop base directories, since there are no valid mappings for these
|
// drop base directories, since there are no valid mappings for these
|
||||||
def sourceMappings = (unmanagedSources, unmanagedSourceDirectories, baseDirectory) map { (srcs, sdirs, base) =>
|
def sourceMappings = (unmanagedSources, unmanagedSourceDirectories, baseDirectory) map { (srcs, sdirs, base) =>
|
||||||
( (srcs --- sdirs --- base) x (relativeTo(sdirs)|relativeTo(base)|flat)) toSeq
|
( (srcs --- sdirs --- base) pair (relativeTo(sdirs)|relativeTo(base)|flat)) toSeq
|
||||||
}
|
}
|
||||||
def resourceMappings = relativeMappings(unmanagedResources, unmanagedResourceDirectories)
|
def resourceMappings = relativeMappings(unmanagedResources, unmanagedResourceDirectories)
|
||||||
def relativeMappings(files: ScopedTaskable[Seq[File]], dirs: ScopedTaskable[Seq[File]]): Initialize[Task[Seq[(File, String)]]] =
|
def relativeMappings(files: ScopedTaskable[Seq[File]], dirs: ScopedTaskable[Seq[File]]): Initialize[Task[Seq[(File, String)]]] =
|
||||||
(files, dirs) map { (rs, rdirs) =>
|
(files, dirs) map { (rs, rdirs) =>
|
||||||
(rs --- rdirs) x (relativeTo(rdirs)|flat) toSeq
|
(rs --- rdirs) pair (relativeTo(rdirs)|flat) toSeq
|
||||||
}
|
}
|
||||||
|
|
||||||
def collectFiles(dirs: ScopedTaskable[Seq[File]], filter: ScopedTaskable[FileFilter], excludes: ScopedTaskable[FileFilter]): Initialize[Task[Seq[File]]] =
|
def collectFiles(dirs: ScopedTaskable[Seq[File]], filter: ScopedTaskable[FileFilter], excludes: ScopedTaskable[FileFilter]): Initialize[Task[Seq[File]]] =
|
||||||
(dirs, filter, excludes) map { (d,f,excl) => d.descendantsExcept(f,excl).get }
|
(dirs, filter, excludes) map { (d,f,excl) => d.descendantsExcept(f,excl).get }
|
||||||
|
|
||||||
def artifactPathSetting(art: SettingKey[Artifact]) = (crossTarget, projectID, art, scalaBinaryVersion in artifactName, artifactName) { (t, module, a, sv, toString) => t / toString(sv, module, a) asFile }
|
def artifactPathSetting(art: SettingKey[Artifact]) = (crossTarget, projectID, art, scalaVersion in artifactName, scalaBinaryVersion in artifactName, artifactName) {
|
||||||
|
(t, module, a, sv, sbv, toString) =>
|
||||||
|
t / toString(ScalaVersion(sv, sbv), module, a) asFile
|
||||||
|
}
|
||||||
def artifactSetting = ((artifact, artifactClassifier).identity zipWith configuration.?) { case ((a,classifier),cOpt) =>
|
def artifactSetting = ((artifact, artifactClassifier).identity zipWith configuration.?) { case ((a,classifier),cOpt) =>
|
||||||
val cPart = cOpt flatMap { c => if(c == Compile) None else Some(c.name) }
|
val cPart = cOpt flatMap { c => if(c == Compile) None else Some(c.name) }
|
||||||
val combined = cPart.toList ++ classifier.toList
|
val combined = cPart.toList ++ classifier.toList
|
||||||
|
|
@ -511,7 +519,8 @@ object Defaults extends BuildCommon
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
def sbtPluginExtra(m: ModuleID, sbtV: String, scalaV: String): ModuleID = m.extra(CustomPomParser.SbtVersionKey -> sbtV, CustomPomParser.ScalaVersionKey -> scalaV).copy(crossVersion = false)
|
def sbtPluginExtra(m: ModuleID, sbtV: String, scalaV: String): ModuleID =
|
||||||
|
m.extra(CustomPomParser.SbtVersionKey -> sbtV, CustomPomParser.ScalaVersionKey -> scalaV).copy(crossVersion = CrossVersion.Disabled)
|
||||||
def writePluginsDescriptor(plugins: Set[String], dir: File): Seq[File] =
|
def writePluginsDescriptor(plugins: Set[String], dir: File): Seq[File] =
|
||||||
{
|
{
|
||||||
val descriptor: File = dir / "sbt" / "sbt.plugins"
|
val descriptor: File = dir / "sbt" / "sbt.plugins"
|
||||||
|
|
@ -537,7 +546,7 @@ object Defaults extends BuildCommon
|
||||||
def copyResourcesTask =
|
def copyResourcesTask =
|
||||||
(classDirectory, cacheDirectory, resources, resourceDirectories, streams) map { (target, cache, resrcs, dirs, s) =>
|
(classDirectory, cacheDirectory, resources, resourceDirectories, streams) map { (target, cache, resrcs, dirs, s) =>
|
||||||
val cacheFile = cache / "copy-resources"
|
val cacheFile = cache / "copy-resources"
|
||||||
val mappings = (resrcs --- dirs) x (rebase(dirs, target) | flat(target))
|
val mappings = (resrcs --- dirs) pair (rebase(dirs, target) | flat(target))
|
||||||
s.log.debug("Copy resource mappings: " + mappings.mkString("\n\t","\n\t",""))
|
s.log.debug("Copy resource mappings: " + mappings.mkString("\n\t","\n\t",""))
|
||||||
Sync(cacheFile)( mappings )
|
Sync(cacheFile)( mappings )
|
||||||
mappings
|
mappings
|
||||||
|
|
@ -597,25 +606,6 @@ object Defaults extends BuildCommon
|
||||||
(if(aggregate) p.aggregate else Nil)
|
(if(aggregate) p.aggregate else Nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
val PartialVersion = """(\d+)\.(\d+)(?:\..+)?""".r
|
|
||||||
def partialVersion(s: String): Option[(Int,Int)] =
|
|
||||||
s match {
|
|
||||||
case PartialVersion(major, minor) => Some(major.toInt, minor.toInt)
|
|
||||||
case _ => None
|
|
||||||
}
|
|
||||||
private[this] def isNewer(major: Int, minor: Int, minMajor: Int, minMinor: Int): Boolean =
|
|
||||||
major > minMajor || (major == minMajor && minor >= minMinor)
|
|
||||||
|
|
||||||
def binaryVersion(full: String, cutoff: String): String =
|
|
||||||
{
|
|
||||||
def sub(major: Int, minor: Int) = major + "." + minor
|
|
||||||
(partialVersion(full), partialVersion(cutoff)) match {
|
|
||||||
case (Some((major, minor)), None) => sub(major, minor)
|
|
||||||
case (Some((major, minor)), Some((minMajor, minMinor))) if isNewer(major, minor, minMajor, minMinor) => sub(major, minor)
|
|
||||||
case _ => full
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val CompletionsID = "completions"
|
val CompletionsID = "completions"
|
||||||
|
|
||||||
def noAggregation: Seq[Scoped] = Seq(run, console, consoleQuick, consoleProject)
|
def noAggregation: Seq[Scoped] = Seq(run, console, consoleQuick, consoleProject)
|
||||||
|
|
@ -744,16 +734,16 @@ object Classpaths
|
||||||
ivyLoggingLevel in GlobalScope :== UpdateLogging.DownloadOnly,
|
ivyLoggingLevel in GlobalScope :== UpdateLogging.DownloadOnly,
|
||||||
ivyXML in GlobalScope :== NodeSeq.Empty,
|
ivyXML in GlobalScope :== NodeSeq.Empty,
|
||||||
ivyValidate in GlobalScope :== false,
|
ivyValidate in GlobalScope :== false,
|
||||||
ivyScala <<= ivyScala or (scalaHome, scalaVersion, scalaBinaryVersion in update) { (sh,v,vu) =>
|
ivyScala <<= ivyScala or (scalaHome, scalaVersion in update, scalaBinaryVersion in update) { (sh,fv,bv) =>
|
||||||
Some(new IvyScala(v, Nil, filterImplicit = true, checkExplicit = true, overrideScalaVersion = sh.isEmpty, substituteCross = x => IvySbt.substituteCross(x, vu)))
|
Some(new IvyScala(fv, bv, Nil, filterImplicit = true, checkExplicit = true, overrideScalaVersion = sh.isEmpty))
|
||||||
},
|
},
|
||||||
moduleConfigurations in GlobalScope :== Nil,
|
moduleConfigurations in GlobalScope :== Nil,
|
||||||
publishTo in GlobalScope :== None,
|
publishTo in GlobalScope :== None,
|
||||||
artifactPath in makePom <<= artifactPathSetting(artifact in makePom),
|
artifactPath in makePom <<= artifactPathSetting(artifact in makePom),
|
||||||
publishArtifact in makePom <<= publishMavenStyle,
|
publishArtifact in makePom <<= publishMavenStyle,
|
||||||
artifact in makePom <<= moduleName(Artifact.pom),
|
artifact in makePom <<= moduleName(Artifact.pom),
|
||||||
projectID <<= (organization,moduleName,version,artifacts,crossPaths){ (org,module,version,as,crossEnabled) =>
|
projectID <<= (organization,moduleName,version,artifacts,crossVersion in projectID){ (org,module,version,as,cross) =>
|
||||||
ModuleID(org, module, version).cross(crossEnabled).artifacts(as : _*)
|
ModuleID(org, module, version).cross(cross).artifacts(as : _*)
|
||||||
},
|
},
|
||||||
projectID <<= pluginProjectID,
|
projectID <<= pluginProjectID,
|
||||||
resolvers in GlobalScope :== Nil,
|
resolvers in GlobalScope :== Nil,
|
||||||
|
|
@ -797,12 +787,19 @@ object Classpaths
|
||||||
} tag(Tags.Update, Tags.Network),
|
} tag(Tags.Update, Tags.Network),
|
||||||
sbtDependency in GlobalScope <<= appConfiguration { app =>
|
sbtDependency in GlobalScope <<= appConfiguration { app =>
|
||||||
val id = app.provider.id
|
val id = app.provider.id
|
||||||
val base = ModuleID(id.groupID, id.name, id.version, crossVersion = id.crossVersioned)
|
val scalaVersion = app.provider.scalaProvider.version
|
||||||
IvySbt.substituteCross(base, app.provider.scalaProvider.version).copy(crossVersion = false)
|
val binVersion = binaryScalaVersion(scalaVersion)
|
||||||
|
val cross = if(id.crossVersioned) if(isStable(scalaVersion)) CrossVersion.binary else CrossVersion.full else CrossVersion.Disabled
|
||||||
|
val base = ModuleID(id.groupID, id.name, id.version, crossVersion = cross)
|
||||||
|
CrossVersion(scalaVersion, binVersion)(base).copy(crossVersion = CrossVersion.Disabled)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
def pluginProjectID: Initialize[ModuleID] = (sbtBinaryVersion in update, scalaBinaryVersion in update, projectID, sbtPlugin) { (sbtV, scalaV, pid, isPlugin) =>
|
def pluginProjectID: Initialize[ModuleID] = (sbtVersion in update, sbtBinaryVersion in update, scalaVersion in update, scalaBinaryVersion in update, projectID, sbtPlugin) {
|
||||||
if(isPlugin) sbtPluginExtra(pid, sbtV, scalaV) else pid
|
(sbtV, sbtBV, scalaV, scalaBV, pid, isPlugin) =>
|
||||||
|
if(isPlugin)
|
||||||
|
sbtPluginExtra(pid, selectVersion(sbtV, sbtBV), selectVersion(scalaV, scalaBV))
|
||||||
|
else
|
||||||
|
pid
|
||||||
}
|
}
|
||||||
def ivySbt0: Initialize[Task[IvySbt]] =
|
def ivySbt0: Initialize[Task[IvySbt]] =
|
||||||
(ivyConfiguration, credentials, streams) map { (conf, creds, s) =>
|
(ivyConfiguration, credentials, streams) map { (conf, creds, s) =>
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ object GlobalPlugin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val globalPluginSettings = inScope(Scope.GlobalScope in LocalRootProject)(Seq(
|
val globalPluginSettings = inScope(Scope.GlobalScope in LocalRootProject)(Seq(
|
||||||
organization := "org.scala-tools.sbt",
|
organization := "org.scala-sbt",
|
||||||
onLoadMessage <<= Keys.baseDirectory("Loading global plugins from " + _),
|
onLoadMessage <<= Keys.baseDirectory("Loading global plugins from " + _),
|
||||||
name := "global-plugin",
|
name := "global-plugin",
|
||||||
sbtPlugin := true,
|
sbtPlugin := true,
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ object IvyConsole
|
||||||
lazy val command =
|
lazy val command =
|
||||||
Command.command(Name) { state =>
|
Command.command(Name) { state =>
|
||||||
val Dependencies(managed, repos, unmanaged) = parseDependencies(state.remainingCommands, state.log)
|
val Dependencies(managed, repos, unmanaged) = parseDependencies(state.remainingCommands, state.log)
|
||||||
val base = new File(CommandSupport.bootDirectory(state), Name)
|
val base = new File(CommandUtil.bootDirectory(state), Name)
|
||||||
IO.createDirectory(base)
|
IO.createDirectory(base)
|
||||||
|
|
||||||
val (eval, structure) = Load.defaultLoad(state, base, state.log)
|
val (eval, structure) = Load.defaultLoad(state, base, state.log)
|
||||||
|
|
@ -56,7 +56,9 @@ object IvyConsole
|
||||||
def parseManaged(arg: String, log: Logger): Seq[ModuleID] =
|
def parseManaged(arg: String, log: Logger): Seq[ModuleID] =
|
||||||
arg match
|
arg match
|
||||||
{
|
{
|
||||||
case DepPattern(group, cross, name, version) => ModuleID(group.trim, name.trim, version.trim, crossVersion = !cross.trim.isEmpty) :: Nil
|
case DepPattern(group, cross, name, version) =>
|
||||||
|
val crossV = if(cross.trim.isEmpty) CrossVersion.Disabled else CrossVersion.binary
|
||||||
|
ModuleID(group.trim, name.trim, version.trim, crossVersion = crossV) :: Nil
|
||||||
case _ => log.warn("Ignoring invalid argument '" + arg + "'"); Nil
|
case _ => log.warn("Ignoring invalid argument '" + arg + "'"); Nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,11 +56,10 @@ object Keys
|
||||||
// val onComplete = SettingKey[RMap[Task,Result] => RMap[Task,Result]]("on-complete", "Transformation to apply to the final task result map. This may also be used to register hooks to run when task evaluation completes.")
|
// val onComplete = SettingKey[RMap[Task,Result] => RMap[Task,Result]]("on-complete", "Transformation to apply to the final task result map. This may also be used to register hooks to run when task evaluation completes.")
|
||||||
|
|
||||||
// Command keys
|
// Command keys
|
||||||
val globalLogging = AttributeKey[GlobalLogging]("global-logging", "Provides a global Logger, including command logging.")
|
val historyPath = SettingKey(BasicKeys.historyPath)
|
||||||
val historyPath = SettingKey[Option[File]]("history", "The location where command line history is persisted.")
|
val shellPrompt = SettingKey(BasicKeys.shellPrompt)
|
||||||
val shellPrompt = SettingKey[State => String]("shell-prompt", "The function that constructs the command prompt from the current build state.")
|
|
||||||
val analysis = AttributeKey[inc.Analysis]("analysis", "Analysis of compilation, including dependencies and generated outputs.")
|
val analysis = AttributeKey[inc.Analysis]("analysis", "Analysis of compilation, including dependencies and generated outputs.")
|
||||||
val watch = SettingKey[Watched]("watch", "Continuous execution configuration.")
|
val watch = SettingKey(BasicKeys.watch)
|
||||||
val pollInterval = SettingKey[Int]("poll-interval", "Interval between checks for modified sources by the continuous execution command.")
|
val pollInterval = SettingKey[Int]("poll-interval", "Interval between checks for modified sources by the continuous execution command.")
|
||||||
val watchSources = TaskKey[Seq[File]]("watch-sources", "Defines the sources in this project for continuous execution to watch for changes.")
|
val watchSources = TaskKey[Seq[File]]("watch-sources", "Defines the sources in this project for continuous execution to watch for changes.")
|
||||||
val watchTransitiveSources = TaskKey[Seq[File]]("watch-transitive-sources", "Defines the sources in all projects for continuous execution to watch.")
|
val watchTransitiveSources = TaskKey[Seq[File]]("watch-transitive-sources", "Defines the sources in all projects for continuous execution to watch.")
|
||||||
|
|
@ -138,6 +137,7 @@ object Keys
|
||||||
val scalaVersion = SettingKey[String]("scala-version", "The version of Scala used for building.")
|
val scalaVersion = SettingKey[String]("scala-version", "The version of Scala used for building.")
|
||||||
val scalaBinaryVersion = SettingKey[String]("scala-binary-version", "The Scala version substring describing binary compatibility.")
|
val scalaBinaryVersion = SettingKey[String]("scala-binary-version", "The Scala version substring describing binary compatibility.")
|
||||||
val crossScalaVersions = SettingKey[Seq[String]]("cross-scala-versions", "The versions of Scala used when cross-building.")
|
val crossScalaVersions = SettingKey[Seq[String]]("cross-scala-versions", "The versions of Scala used when cross-building.")
|
||||||
|
val crossVersion = SettingKey[CrossVersion]("cross-version", "Configures handling of the Scala version when cross-building.")
|
||||||
val classpathOptions = SettingKey[ClasspathOptions]("classpath-options", "Configures handling of Scala classpaths.")
|
val classpathOptions = SettingKey[ClasspathOptions]("classpath-options", "Configures handling of Scala classpaths.")
|
||||||
val definedSbtPlugins = TaskKey[Set[String]]("defined-sbt-plugins", "The set of names of Plugin implementations defined by this project.")
|
val definedSbtPlugins = TaskKey[Set[String]]("defined-sbt-plugins", "The set of names of Plugin implementations defined by this project.")
|
||||||
val sbtPlugin = SettingKey[Boolean]("sbt-plugin", "If true, enables adding sbt as a dependency and auto-generation of the plugin descriptor file.")
|
val sbtPlugin = SettingKey[Boolean]("sbt-plugin", "If true, enables adding sbt as a dependency and auto-generation of the plugin descriptor file.")
|
||||||
|
|
@ -165,7 +165,7 @@ object Keys
|
||||||
val artifactPath = SettingKey[File]("artifact-path", "The location of a generated artifact.")
|
val artifactPath = SettingKey[File]("artifact-path", "The location of a generated artifact.")
|
||||||
val artifact = SettingKey[Artifact]("artifact", "Describes an artifact.")
|
val artifact = SettingKey[Artifact]("artifact", "Describes an artifact.")
|
||||||
val artifactClassifier = SettingKey[Option[String]]("artifact-classifier", "Sets the classifier used by the default artifact definition.")
|
val artifactClassifier = SettingKey[Option[String]]("artifact-classifier", "Sets the classifier used by the default artifact definition.")
|
||||||
val artifactName = SettingKey[(String, ModuleID, Artifact) => String]("artifact-name", "Function that produces the artifact name from its definition.")
|
val artifactName = SettingKey[(ScalaVersion, ModuleID, Artifact) => String]("artifact-name", "Function that produces the artifact name from its definition.")
|
||||||
val mappings = TaskKey[Seq[(File,String)]]("mappings", "Defines the mappings from a file to a path, used by packaging, for example.")
|
val mappings = TaskKey[Seq[(File,String)]]("mappings", "Defines the mappings from a file to a path, used by packaging, for example.")
|
||||||
val fileMappings = TaskKey[Seq[(File,File)]]("file-mappings", "Defines the mappings from a file to a file, used for copying files, for example.")
|
val fileMappings = TaskKey[Seq[(File,File)]]("file-mappings", "Defines the mappings from a file to a file, used for copying files, for example.")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ package sbt
|
||||||
import inc.{FileValueCache, Locate}
|
import inc.{FileValueCache, Locate}
|
||||||
import Project.{inScope, ScopedKey, ScopeLocal, Setting}
|
import Project.{inScope, ScopedKey, ScopeLocal, Setting}
|
||||||
import Keys.{appConfiguration, baseDirectory, configuration, streams, Streams, thisProject, thisProjectRef}
|
import Keys.{appConfiguration, baseDirectory, configuration, streams, Streams, thisProject, thisProjectRef}
|
||||||
import Keys.{globalLogging, isDummy, loadedBuild, parseResult, resolvedScoped, taskDefinitionKey}
|
import Keys.{isDummy, loadedBuild, parseResult, resolvedScoped, taskDefinitionKey}
|
||||||
import tools.nsc.reporters.ConsoleReporter
|
import tools.nsc.reporters.ConsoleReporter
|
||||||
import Build.{analyzed, data}
|
import Build.{analyzed, data}
|
||||||
import Scope.{GlobalScope, ThisScope}
|
import Scope.{GlobalScope, ThisScope}
|
||||||
|
|
@ -489,7 +489,7 @@ object Load
|
||||||
val inputs = Compiler.inputs(data(classpath), sources, target, Nil, Nil, definesClass, Compiler.DefaultMaxErrors, CompileOrder.Mixed)(compilers, log)
|
val inputs = Compiler.inputs(data(classpath), sources, target, Nil, Nil, definesClass, Compiler.DefaultMaxErrors, CompileOrder.Mixed)(compilers, log)
|
||||||
val analysis =
|
val analysis =
|
||||||
try { Compiler(inputs, log) }
|
try { Compiler(inputs, log) }
|
||||||
catch { case _: xsbti.CompileFailed => throw new NoMessageException } // compiler already logged errors
|
catch { case _: xsbti.CompileFailed => throw new AlreadyHandledException } // compiler already logged errors
|
||||||
(inputs, analysis)
|
(inputs, analysis)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ package sbt
|
||||||
import std.Transform
|
import std.Transform
|
||||||
import Project.ScopedKey
|
import Project.ScopedKey
|
||||||
import Scope.GlobalScope
|
import Scope.GlobalScope
|
||||||
|
import MainLogging._
|
||||||
import Keys.{logLevel, logManager, persistLogLevel, persistTraceLevel, state, traceLevel}
|
import Keys.{logLevel, logManager, persistLogLevel, persistTraceLevel, state, traceLevel}
|
||||||
|
|
||||||
object LogManager
|
object LogManager
|
||||||
|
|
@ -21,11 +22,6 @@ object LogManager
|
||||||
lazy val default: LogManager = withLoggers()
|
lazy val default: LogManager = withLoggers()
|
||||||
def defaults(extra: ScopedKey[_] => Seq[AbstractLogger]): LogManager = withLoggers(extra = extra)
|
def defaults(extra: ScopedKey[_] => Seq[AbstractLogger]): LogManager = withLoggers(extra = extra)
|
||||||
|
|
||||||
def defaultScreen: AbstractLogger = ConsoleLogger()
|
|
||||||
|
|
||||||
def defaultBacked(useColor: Boolean = ConsoleLogger.formatEnabled): PrintWriter => ConsoleLogger =
|
|
||||||
to => ConsoleLogger(ConsoleLogger.printWriterOut(to), useColor = useColor) // TODO: should probably filter ANSI codes when useColor=false
|
|
||||||
|
|
||||||
def withScreenLogger(mk: => AbstractLogger): LogManager = withLoggers(mk)
|
def withScreenLogger(mk: => AbstractLogger): LogManager = withLoggers(mk)
|
||||||
|
|
||||||
def withLoggers(screen: => AbstractLogger = defaultScreen, backed: PrintWriter => AbstractLogger = defaultBacked(), extra: ScopedKey[_] => Seq[AbstractLogger] = _ => Nil): LogManager =
|
def withLoggers(screen: => AbstractLogger = defaultScreen, backed: PrintWriter => AbstractLogger = defaultBacked(), extra: ScopedKey[_] => Seq[AbstractLogger] = _ => Nil): LogManager =
|
||||||
|
|
@ -42,40 +38,12 @@ object LogManager
|
||||||
val backingLevel = getOr(persistLogLevel.key, Level.Debug)
|
val backingLevel = getOr(persistLogLevel.key, Level.Debug)
|
||||||
val screenTrace = getOr(traceLevel.key, -1)
|
val screenTrace = getOr(traceLevel.key, -1)
|
||||||
val backingTrace = getOr(persistTraceLevel.key, Int.MaxValue)
|
val backingTrace = getOr(persistTraceLevel.key, Int.MaxValue)
|
||||||
val extraBacked = (state get Keys.globalLogging).map(_.backed).toList
|
val extraBacked = state.globalLogging.backed :: Nil
|
||||||
multiLogger( new MultiLoggerConfig(console, backed, extraBacked ::: extra, screenLevel, backingLevel, screenTrace, backingTrace) )
|
multiLogger( new MultiLoggerConfig(console, backed, extraBacked ::: extra, screenLevel, backingLevel, screenTrace, backingTrace) )
|
||||||
}
|
}
|
||||||
def multiLogger(config: MultiLoggerConfig): Logger =
|
|
||||||
{
|
|
||||||
import config._
|
|
||||||
val multi = new MultiLogger(console :: backed :: extra)
|
|
||||||
// sets multi to the most verbose for clients that inspect the current level
|
|
||||||
multi setLevel Level.unionAll(backingLevel :: screenLevel :: extra.map(_.getLevel))
|
|
||||||
// set the specific levels
|
|
||||||
console setLevel screenLevel
|
|
||||||
backed setLevel backingLevel
|
|
||||||
console setTrace screenTrace
|
|
||||||
backed setTrace backingTrace
|
|
||||||
multi: Logger
|
|
||||||
}
|
|
||||||
def globalDefault(writer: PrintWriter, backing: GlobalLogBacking): GlobalLogging =
|
|
||||||
{
|
|
||||||
val backed = defaultBacked()(writer)
|
|
||||||
val full = multiLogger(defaultMultiConfig( backed ) )
|
|
||||||
GlobalLogging(full, backed, backing)
|
|
||||||
}
|
|
||||||
|
|
||||||
def defaultMultiConfig(backing: AbstractLogger): MultiLoggerConfig =
|
|
||||||
new MultiLoggerConfig(defaultScreen, backing, Nil, Level.Info, Level.Debug, -1, Int.MaxValue)
|
|
||||||
}
|
}
|
||||||
final case class MultiLoggerConfig(console: AbstractLogger, backed: AbstractLogger, extra: List[AbstractLogger], screenLevel: Level.Value, backingLevel: Level.Value, screenTrace: Int, backingTrace: Int)
|
|
||||||
trait LogManager
|
trait LogManager
|
||||||
{
|
{
|
||||||
def apply(data: Settings[Scope], state: State, task: ScopedKey[_], writer: PrintWriter): Logger
|
def apply(data: Settings[Scope], state: State, task: ScopedKey[_], writer: PrintWriter): Logger
|
||||||
}
|
}
|
||||||
final case class GlobalLogBacking(file: File, last: Option[File])
|
|
||||||
{
|
|
||||||
def shift(newFile: File) = GlobalLogBacking(newFile, Some(file))
|
|
||||||
def unshift = GlobalLogBacking(last getOrElse file, None)
|
|
||||||
}
|
|
||||||
final case class GlobalLogging(full: Logger, backed: ConsoleLogger, backing: GlobalLogBacking)
|
|
||||||
|
|
|
||||||
370
main/Main.scala
370
main/Main.scala
|
|
@ -3,132 +3,64 @@
|
||||||
*/
|
*/
|
||||||
package sbt
|
package sbt
|
||||||
|
|
||||||
import Execute.NodeView
|
import complete.{DefaultParsers, Parser}
|
||||||
import complete.{DefaultParsers, HistoryCommands, Parser}
|
|
||||||
import HistoryCommands.{Start => HistoryPrefix}
|
|
||||||
import compiler.EvalImports
|
import compiler.EvalImports
|
||||||
import Types.{const,idFun}
|
import Types.idFun
|
||||||
import Aggregation.AnyKeys
|
import Aggregation.AnyKeys
|
||||||
|
|
||||||
import Command.applyEffect
|
|
||||||
import Keys.{analysis,historyPath,globalLogging,shellPrompt}
|
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
import scala.collection.JavaConversions._
|
|
||||||
import Function.tupled
|
|
||||||
import java.net.URI
|
|
||||||
import java.lang.reflect.InvocationTargetException
|
|
||||||
import Path._
|
import Path._
|
||||||
|
import StandardMain._
|
||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.net.URI
|
||||||
|
|
||||||
/** This class is the entry point for sbt.*/
|
/** This class is the entry point for sbt.*/
|
||||||
final class xMain extends xsbti.AppMain
|
final class xMain extends xsbti.AppMain
|
||||||
{
|
{
|
||||||
def run(configuration: xsbti.AppConfiguration): xsbti.MainResult =
|
def run(configuration: xsbti.AppConfiguration): xsbti.MainResult =
|
||||||
{
|
{
|
||||||
import BuiltinCommands.{initialAttributes, initialize, defaults, DefaultBootCommands}
|
import BuiltinCommands.{initialize, defaults}
|
||||||
import CommandSupport.{BootCommand, DefaultsCommand, InitCommand}
|
import CommandStrings.{BootCommand, DefaultsCommand, InitCommand}
|
||||||
val initialCommandDefs = Seq(initialize, defaults)
|
MainLoop.runLogged( initialState(configuration,
|
||||||
val commands = DefaultsCommand +: InitCommand +: BootCommand +: configuration.arguments.map(_.trim)
|
Seq(initialize, defaults),
|
||||||
val state = State( configuration, initialCommandDefs, Set.empty, None, commands, State.newHistory, initialAttributes, State.Continue )
|
DefaultsCommand :: InitCommand :: BootCommand :: Nil)
|
||||||
MainLoop.runLogged(state)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final class ScriptMain extends xsbti.AppMain
|
final class ScriptMain extends xsbti.AppMain
|
||||||
{
|
{
|
||||||
def run(configuration: xsbti.AppConfiguration): xsbti.MainResult =
|
def run(configuration: xsbti.AppConfiguration): xsbti.MainResult =
|
||||||
{
|
MainLoop.runLogged( initialState(configuration,
|
||||||
import BuiltinCommands.{initialAttributes, ScriptCommands}
|
BuiltinCommands.ScriptCommands,
|
||||||
val commands = Script.Name +: configuration.arguments.map(_.trim)
|
Script.Name :: Nil)
|
||||||
val state = State( configuration, ScriptCommands, Set.empty, None, commands, State.newHistory, initialAttributes, State.Continue )
|
)
|
||||||
MainLoop.runLogged(state)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
final class ConsoleMain extends xsbti.AppMain
|
final class ConsoleMain extends xsbti.AppMain
|
||||||
{
|
{
|
||||||
def run(configuration: xsbti.AppConfiguration): xsbti.MainResult =
|
def run(configuration: xsbti.AppConfiguration): xsbti.MainResult =
|
||||||
{
|
MainLoop.runLogged( initialState(configuration,
|
||||||
import BuiltinCommands.{initialAttributes, ConsoleCommands}
|
BuiltinCommands.ConsoleCommands,
|
||||||
val commands = IvyConsole.Name +: configuration.arguments.map(_.trim)
|
IvyConsole.Name :: Nil)
|
||||||
val state = State( configuration, ConsoleCommands, Set.empty, None, commands, State.newHistory, initialAttributes, State.Continue )
|
)
|
||||||
MainLoop.runLogged(state)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
object MainLoop
|
|
||||||
|
object StandardMain
|
||||||
{
|
{
|
||||||
/** Entry point to run the remaining commands in State with managed global logging.*/
|
def initialState(configuration: xsbti.AppConfiguration, initialDefinitions: Seq[Command], preCommands: Seq[String]): State =
|
||||||
def runLogged(state: State): xsbti.MainResult =
|
{
|
||||||
runLoggedLoop(state, GlobalLogBacking(newBackingFile(), None))
|
val commands = preCommands ++ configuration.arguments.map(_.trim)
|
||||||
|
State( configuration, initialDefinitions, Set.empty, None, commands, State.newHistory, BuiltinCommands.initialAttributes, initialGlobalLogging, State.Continue )
|
||||||
/** Constructs a new, (weakly) unique, temporary file to use as the backing for global logging. */
|
}
|
||||||
def newBackingFile(): File = File.createTempFile("sbt",".log")
|
def initialGlobalLogging: GlobalLogging =
|
||||||
|
GlobalLogging.initial(MainLogging.globalDefault _, File.createTempFile("sbt",".log"))
|
||||||
/** Run loop that evaluates remaining commands and manages changes to global logging configuration.*/
|
|
||||||
@tailrec def runLoggedLoop(state: State, logBacking: GlobalLogBacking): xsbti.MainResult =
|
|
||||||
runAndClearLast(state, logBacking) match {
|
|
||||||
case ret: Return => // delete current and last log files when exiting normally
|
|
||||||
logBacking.file.delete()
|
|
||||||
deleteLastLog(logBacking)
|
|
||||||
ret.result
|
|
||||||
case clear: ClearGlobalLog => // delete previous log file, move current to previous, and start writing to a new file
|
|
||||||
deleteLastLog(logBacking)
|
|
||||||
runLoggedLoop(clear.state, logBacking shift newBackingFile())
|
|
||||||
case keep: KeepGlobalLog => // make previous log file the current log file
|
|
||||||
logBacking.file.delete
|
|
||||||
runLoggedLoop(keep.state, logBacking.unshift)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Runs the next sequence of commands, cleaning up global logging after any exceptions. */
|
|
||||||
def runAndClearLast(state: State, logBacking: GlobalLogBacking): RunNext =
|
|
||||||
try
|
|
||||||
runWithNewLog(state, logBacking)
|
|
||||||
catch {
|
|
||||||
case e: xsbti.FullReload =>
|
|
||||||
deleteLastLog(logBacking)
|
|
||||||
throw e // pass along a reboot request
|
|
||||||
case e =>
|
|
||||||
System.err.println("sbt appears to be exiting abnormally.\n The log file for this session is at " + logBacking.file)
|
|
||||||
deleteLastLog(logBacking)
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Deletes the previous global log file. */
|
|
||||||
def deleteLastLog(logBacking: GlobalLogBacking): Unit =
|
|
||||||
logBacking.last.foreach(_.delete())
|
|
||||||
|
|
||||||
/** Runs the next sequence of commands with global logging in place. */
|
|
||||||
def runWithNewLog(state: State, logBacking: GlobalLogBacking): RunNext =
|
|
||||||
Using.fileWriter(append = true)(logBacking.file) { writer =>
|
|
||||||
val out = new java.io.PrintWriter(writer)
|
|
||||||
val loggedState = state.put(globalLogging, LogManager.globalDefault(out, logBacking))
|
|
||||||
try run(loggedState) finally out.close()
|
|
||||||
}
|
|
||||||
sealed trait RunNext
|
|
||||||
final class ClearGlobalLog(val state: State) extends RunNext
|
|
||||||
final class KeepGlobalLog(val state: State) extends RunNext
|
|
||||||
final class Return(val result: xsbti.MainResult) extends RunNext
|
|
||||||
|
|
||||||
/** Runs the next sequence of commands that doesn't require global logging changes.*/
|
|
||||||
@tailrec def run(state: State): RunNext =
|
|
||||||
state.next match
|
|
||||||
{
|
|
||||||
case State.Continue => run(next(state))
|
|
||||||
case State.ClearGlobalLog => new ClearGlobalLog(state.continue)
|
|
||||||
case State.KeepLastLog => new KeepGlobalLog(state.continue)
|
|
||||||
case ret: State.Return => new Return(ret.result)
|
|
||||||
}
|
|
||||||
|
|
||||||
def next(state: State): State =
|
|
||||||
ErrorHandling.wideConvert { state.process(Command.process) } match
|
|
||||||
{
|
|
||||||
case Right(s) => s
|
|
||||||
case Left(t: xsbti.FullReload) => throw t
|
|
||||||
case Left(t) => BuiltinCommands.handleException(t, state)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
import DefaultParsers._
|
import DefaultParsers._
|
||||||
import CommandSupport._
|
import CommandStrings._
|
||||||
|
import BasicCommands._
|
||||||
|
import CommandUtil._
|
||||||
|
|
||||||
object BuiltinCommands
|
object BuiltinCommands
|
||||||
{
|
{
|
||||||
def initialAttributes = AttributeMap.empty
|
def initialAttributes = AttributeMap.empty
|
||||||
|
|
@ -140,22 +72,9 @@ object BuiltinCommands
|
||||||
def DefaultBootCommands: Seq[String] = LoadProject :: (IfLast + " " + Shell) :: Nil
|
def DefaultBootCommands: Seq[String] = LoadProject :: (IfLast + " " + Shell) :: Nil
|
||||||
|
|
||||||
def boot = Command.make(BootCommand)(bootParser)
|
def boot = Command.make(BootCommand)(bootParser)
|
||||||
def nop = Command.custom(s => success(() => s))
|
|
||||||
def ignore = Command.command(FailureWall)(idFun)
|
|
||||||
|
|
||||||
def detail(selected: Seq[String], detailMap: Map[String, String]): Seq[String] =
|
|
||||||
selected.distinct flatMap { detailMap get _ }
|
|
||||||
|
|
||||||
def help = Command.make(HelpCommand, helpBrief, helpDetailed)(helpParser)
|
|
||||||
def about = Command.command(AboutCommand, aboutBrief, aboutDetailed) { s => logger(s).info(aboutString(s)); s }
|
def about = Command.command(AboutCommand, aboutBrief, aboutDetailed) { s => logger(s).info(aboutString(s)); s }
|
||||||
|
|
||||||
def helpParser(s: State) =
|
|
||||||
{
|
|
||||||
val h = (Help.empty /: s.definedCommands)(_ ++ _.help(s))
|
|
||||||
val helpCommands = h.detail.keySet
|
|
||||||
val args = (token(Space) ~> token( NotSpace examples helpCommands )).*
|
|
||||||
applyEffect(args)(runHelp(s, h))
|
|
||||||
}
|
|
||||||
// This parser schedules the default boot commands unless overridden by an alias
|
// This parser schedules the default boot commands unless overridden by an alias
|
||||||
def bootParser(s: State) =
|
def bootParser(s: State) =
|
||||||
{
|
{
|
||||||
|
|
@ -163,16 +82,6 @@ object BuiltinCommands
|
||||||
delegateToAlias(BootCommand, success(orElse) )(s)
|
delegateToAlias(BootCommand, success(orElse) )(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
def runHelp(s: State, h: Help)(args: Seq[String]): State =
|
|
||||||
{
|
|
||||||
val message =
|
|
||||||
if(args.isEmpty)
|
|
||||||
aligned(" ", " ", h.brief).mkString("\n", "\n", "\n")
|
|
||||||
else
|
|
||||||
detail(args, h.detail) mkString("\n", "\n\n", "\n")
|
|
||||||
System.out.println(message)
|
|
||||||
s
|
|
||||||
}
|
|
||||||
def sbtVersion(s: State): String = s.configuration.provider.id.version
|
def sbtVersion(s: State): String = s.configuration.provider.id.version
|
||||||
def scalaVersion(s: State): String = s.configuration.provider.scalaProvider.version
|
def scalaVersion(s: State): String = s.configuration.provider.scalaProvider.version
|
||||||
def aboutString(s: State): String =
|
def aboutString(s: State): String =
|
||||||
|
|
@ -230,154 +139,15 @@ object BuiltinCommands
|
||||||
aligned(" ", " ", taskDetail(s)) mkString("\n", "\n", "")
|
aligned(" ", " ", taskDetail(s)) mkString("\n", "\n", "")
|
||||||
|
|
||||||
def taskStrings(key: AttributeKey[_]): Option[(String, String)] = key.description map { d => (key.label, d) }
|
def taskStrings(key: AttributeKey[_]): Option[(String, String)] = key.description map { d => (key.label, d) }
|
||||||
def aligned(pre: String, sep: String, in: Seq[(String, String)]): Seq[String] =
|
|
||||||
{
|
|
||||||
val width = in.map(_._1.length).max
|
|
||||||
in.map { case (a, b) => (" " + fill(a, width) + sep + b) }
|
|
||||||
}
|
|
||||||
def fill(s: String, size: Int) = s + " " * math.max(size - s.length, 0)
|
|
||||||
|
|
||||||
def alias = Command.make(AliasCommand, AliasBrief, AliasDetailed) { s =>
|
|
||||||
val name = token(OpOrID.examples( aliasNames(s) : _*) )
|
|
||||||
val assign = token(OptSpace ~ '=' ~ OptSpace)
|
|
||||||
val sfree = removeAliases(s)
|
|
||||||
val to = matched(sfree.combinedParser, partial = true) | any.+.string
|
|
||||||
val base = (OptSpace ~> (name ~ (assign ~> to.?).?).?)
|
|
||||||
applyEffect(base)(t => runAlias(s, t) )
|
|
||||||
}
|
|
||||||
|
|
||||||
def runAlias(s: State, args: Option[(String, Option[Option[String]])]): State =
|
|
||||||
args match
|
|
||||||
{
|
|
||||||
case None => printAliases(s); s
|
|
||||||
case Some(x ~ None) if !x.isEmpty => printAlias(s, x.trim); s
|
|
||||||
case Some(name ~ Some(None)) => removeAlias(s, name.trim)
|
|
||||||
case Some(name ~ Some(Some(value))) => addAlias(s, name.trim, value.trim)
|
|
||||||
}
|
|
||||||
|
|
||||||
def shell = Command.command(Shell, ShellBrief, ShellDetailed) { s =>
|
|
||||||
val history = (s get historyPath.key) getOrElse Some((s.baseDir / ".history").asFile)
|
|
||||||
val prompt = (s get shellPrompt.key) match { case Some(pf) => pf(s); case None => "> " }
|
|
||||||
val reader = new FullReader(history, s.combinedParser)
|
|
||||||
val line = reader.readLine(prompt)
|
|
||||||
line match {
|
|
||||||
case Some(line) =>
|
|
||||||
val newState = s.copy(onFailure = Some(Shell), remainingCommands = line +: Shell +: s.remainingCommands)
|
|
||||||
if(line.trim.isEmpty) newState else newState.clearGlobalLog
|
|
||||||
case None => s
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def multiParser(s: State): Parser[Seq[String]] =
|
|
||||||
{
|
|
||||||
val nonSemi = token(charClass(_ != ';').+, hide= const(true))
|
|
||||||
( token(';' ~> OptSpace) flatMap { _ => matched((s.combinedParser&nonSemi) | nonSemi) <~ token(OptSpace) } map (_.trim) ).+
|
|
||||||
}
|
|
||||||
|
|
||||||
def multiApplied(s: State) =
|
|
||||||
Command.applyEffect( multiParser(s) )( _ ::: s )
|
|
||||||
|
|
||||||
def multi = Command.custom(multiApplied, Help(Multi, MultiBrief, MultiDetailed) )
|
|
||||||
|
|
||||||
lazy val otherCommandParser = (s: State) => token(OptSpace ~> combinedLax(s, any.+) )
|
|
||||||
def combinedLax(s: State, any: Parser[_]): Parser[String] =
|
|
||||||
matched(s.combinedParser | token(any, hide= const(true)))
|
|
||||||
|
|
||||||
def ifLast = Command(IfLast, IfLastBrief, IfLastDetailed)(otherCommandParser) { (s, arg) =>
|
|
||||||
if(s.remainingCommands.isEmpty) arg :: s else s
|
|
||||||
}
|
|
||||||
def append = Command(AppendCommand, AppendLastBrief, AppendLastDetailed)(otherCommandParser) { (s, arg) =>
|
|
||||||
s.copy(remainingCommands = s.remainingCommands :+ arg)
|
|
||||||
}
|
|
||||||
|
|
||||||
def setOnFailure = Command(OnFailure, OnFailureBrief, OnFailureDetailed)(otherCommandParser) { (s, arg) =>
|
|
||||||
s.copy(onFailure = Some(arg))
|
|
||||||
}
|
|
||||||
def clearOnFailure = Command.command(ClearOnFailure)(s => s.copy(onFailure = None))
|
|
||||||
|
|
||||||
def reboot = Command(RebootCommand, RebootBrief, RebootDetailed)(rebootParser) { (s, full) =>
|
|
||||||
s.reboot(full)
|
|
||||||
}
|
|
||||||
def rebootParser(s: State) = token(Space ~> "full" ^^^ true) ?? false
|
|
||||||
|
|
||||||
def defaults = Command.command(DefaultsCommand) { s =>
|
def defaults = Command.command(DefaultsCommand) { s =>
|
||||||
s ++ DefaultCommands
|
s ++ DefaultCommands
|
||||||
}
|
}
|
||||||
def call = Command(ApplyCommand, ApplyBrief, ApplyDetailed)(_ => spaceDelimited("<class name>")) { (state,args) =>
|
|
||||||
val loader = getClass.getClassLoader
|
|
||||||
val loaded = args.map(arg => ModuleUtilities.getObject(arg, loader))
|
|
||||||
(state /: loaded) { case (s, obj: (State => State)) => obj(s) }
|
|
||||||
}
|
|
||||||
|
|
||||||
def initialize = Command.command(InitCommand) { s =>
|
def initialize = Command.command(InitCommand) { s =>
|
||||||
/*"load-commands -base ~/.sbt/commands" :: */readLines( readable( sbtRCs(s) ) ) ::: s
|
/*"load-commands -base ~/.sbt/commands" :: */readLines( readable( sbtRCs(s) ) ) ::: s
|
||||||
}
|
}
|
||||||
|
|
||||||
def readParser(s: State) =
|
|
||||||
{
|
|
||||||
val files = (token(Space) ~> fileParser(s.baseDir)).+
|
|
||||||
val portAndSuccess = token(OptSpace) ~> Port
|
|
||||||
portAndSuccess || files
|
|
||||||
}
|
|
||||||
|
|
||||||
def read = Command.make(ReadCommand, ReadBrief, ReadDetailed)(s => applyEffect(readParser(s))(doRead(s)) )
|
|
||||||
|
|
||||||
def doRead(s: State)(arg: Either[Int, Seq[File]]): State =
|
|
||||||
arg match
|
|
||||||
{
|
|
||||||
case Left(portAndSuccess) =>
|
|
||||||
val port = math.abs(portAndSuccess)
|
|
||||||
val previousSuccess = portAndSuccess >= 0
|
|
||||||
readMessage(port, previousSuccess) match
|
|
||||||
{
|
|
||||||
case Some(message) => (message :: (ReadCommand + " " + port) :: s).copy(onFailure = Some(ReadCommand + " " + (-port)))
|
|
||||||
case None =>
|
|
||||||
System.err.println("Connection closed.")
|
|
||||||
s.fail
|
|
||||||
}
|
|
||||||
case Right(from) =>
|
|
||||||
val notFound = notReadable(from)
|
|
||||||
if(notFound.isEmpty)
|
|
||||||
readLines(from) ::: s // this means that all commands from all files are loaded, parsed, and inserted before any are executed
|
|
||||||
else {
|
|
||||||
logger(s).error("Command file(s) not readable: \n\t" + notFound.mkString("\n\t"))
|
|
||||||
s
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private def readMessage(port: Int, previousSuccess: Boolean): Option[String] =
|
|
||||||
{
|
|
||||||
// split into two connections because this first connection ends the previous communication
|
|
||||||
xsbt.IPC.client(port) { _.send(previousSuccess.toString) }
|
|
||||||
// and this second connection starts the next communication
|
|
||||||
xsbt.IPC.client(port) { ipc =>
|
|
||||||
val message = ipc.receive
|
|
||||||
if(message eq null) None else Some(message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def continuous =
|
|
||||||
Command(ContinuousExecutePrefix, Help(continuousBriefHelp) )(otherCommandParser) { (s, arg) =>
|
|
||||||
withAttribute(s, Watched.Configuration, "Continuous execution not configured.") { w =>
|
|
||||||
val repeat = ContinuousExecutePrefix + (if(arg.startsWith(" ")) arg else " " + arg)
|
|
||||||
Watched.executeContinuously(w, s, arg, repeat)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def history = Command.custom(historyParser, historyHelp)
|
|
||||||
def historyParser(s: State): Parser[() => State] =
|
|
||||||
Command.applyEffect(HistoryCommands.actionParser) { histFun =>
|
|
||||||
val logError = (msg: String) => s.log.error(msg)
|
|
||||||
val hp = s get historyPath.key getOrElse None
|
|
||||||
val lines = hp.toList.flatMap( p => IO.readLines(p) ).toIndexedSeq
|
|
||||||
histFun( complete.History(lines, hp, logError) ) match
|
|
||||||
{
|
|
||||||
case Some(commands) =>
|
|
||||||
commands foreach println //printing is more appropriate than logging
|
|
||||||
(commands ::: s).continue
|
|
||||||
case None => s.fail
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def eval = Command.single(EvalCommand, evalBrief, evalDetailed) { (s, arg) =>
|
def eval = Command.single(EvalCommand, evalBrief, evalDetailed) { (s, arg) =>
|
||||||
val log = logger(s)
|
val log = logger(s)
|
||||||
val extracted = Project extract s
|
val extracted = Project extract s
|
||||||
|
|
@ -482,7 +252,7 @@ object BuiltinCommands
|
||||||
/** Determines the log file that last* commands should operate on. See also isLastOnly. */
|
/** Determines the log file that last* commands should operate on. See also isLastOnly. */
|
||||||
def lastLogFile(s: State) =
|
def lastLogFile(s: State) =
|
||||||
{
|
{
|
||||||
val backing = CommandSupport.globalLogging(s).backing
|
val backing = s.globalLogging.backing
|
||||||
if(isLastOnly(s)) backing.last else Some(backing.file)
|
if(isLastOnly(s)) backing.last else Some(backing.file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -514,7 +284,7 @@ object BuiltinCommands
|
||||||
}
|
}
|
||||||
|
|
||||||
def act = Command.customHelp(Act.actParser, actHelp)
|
def act = Command.customHelp(Act.actParser, actHelp)
|
||||||
def actHelp = (s: State) => CommandSupport.showHelp ++ keysHelp(s)
|
def actHelp = (s: State) => CommandStrings.showHelp ++ keysHelp(s)
|
||||||
def keysHelp(s: State): Help =
|
def keysHelp(s: State): Help =
|
||||||
if(Project.isProjectLoaded(s))
|
if(Project.isProjectLoaded(s))
|
||||||
Help.detailOnly(taskDetail(s))
|
Help.detailOnly(taskDetail(s))
|
||||||
|
|
@ -530,16 +300,9 @@ object BuiltinCommands
|
||||||
for( (uri, build) <- structure.units if curi != uri) listBuild(uri, build, false, cid, log)
|
for( (uri, build) <- structure.units if curi != uri) listBuild(uri, build, false, cid, log)
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
def withAttribute[T](s: State, key: AttributeKey[T], ifMissing: String)(f: T => State): State =
|
|
||||||
(s get key) match {
|
|
||||||
case None => logger(s).error(ifMissing); s.fail
|
|
||||||
case Some(nav) => f(nav)
|
|
||||||
}
|
|
||||||
|
|
||||||
def project = Command.make(ProjectCommand, projectBrief, projectDetailed)(ProjectNavigation.command)
|
def project = Command.make(ProjectCommand, projectBrief, projectDetailed)(ProjectNavigation.command)
|
||||||
|
|
||||||
def exit = Command.command(TerminateAction, exitBrief, exitBrief ) ( _ exit true )
|
|
||||||
|
|
||||||
def loadFailed = Command.command(LoadFailed)(handleLoadFailed)
|
def loadFailed = Command.command(LoadFailed)(handleLoadFailed)
|
||||||
@tailrec def handleLoadFailed(s: State): State =
|
@tailrec def handleLoadFailed(s: State): State =
|
||||||
{
|
{
|
||||||
|
|
@ -576,71 +339,4 @@ object BuiltinCommands
|
||||||
SessionSettings.checkSession(session, s)
|
SessionSettings.checkSession(session, s)
|
||||||
Project.setProject(session, structure, s)
|
Project.setProject(session, structure, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
def handleException(e: Throwable, s: State): State =
|
|
||||||
handleException(e, s, logger(s))
|
|
||||||
def handleException(e: Throwable, s: State, log: Logger): State =
|
|
||||||
{
|
|
||||||
e match
|
|
||||||
{
|
|
||||||
case _: Incomplete => () // already handled by evaluateTask
|
|
||||||
case _: NoMessageException => ()
|
|
||||||
case ite: InvocationTargetException =>
|
|
||||||
val cause = ite.getCause
|
|
||||||
if(cause == null || cause == ite) logFullException(ite, log) else handleException(cause, s, log)
|
|
||||||
case _: MessageOnlyException => log.error(e.toString)
|
|
||||||
case _: Project.Uninitialized => logFullException(e, log, true)
|
|
||||||
case _ => logFullException(e, log)
|
|
||||||
}
|
|
||||||
s.fail
|
|
||||||
}
|
|
||||||
def logFullException(e: Throwable, log: Logger, messageOnly: Boolean = false)
|
|
||||||
{
|
|
||||||
log.trace(e)
|
|
||||||
log.error(if(messageOnly) e.getMessage else ErrorHandling reducedToString e)
|
|
||||||
log.error("Use 'last' for the full log.")
|
|
||||||
}
|
|
||||||
|
|
||||||
def addAlias(s: State, name: String, value: String): State =
|
|
||||||
if(Command validID name) {
|
|
||||||
val removed = removeAlias(s, name)
|
|
||||||
if(value.isEmpty) removed else removed.copy(definedCommands = newAlias(name, value) +: removed.definedCommands)
|
|
||||||
} else {
|
|
||||||
System.err.println("Invalid alias name '" + name + "'.")
|
|
||||||
s.fail
|
|
||||||
}
|
|
||||||
|
|
||||||
def removeAliases(s: State): State = removeTagged(s, CommandAliasKey)
|
|
||||||
def removeAlias(s: State, name: String): State = s.copy(definedCommands = s.definedCommands.filter(c => !isAliasNamed(name, c)) )
|
|
||||||
|
|
||||||
def removeTagged(s: State, tag: AttributeKey[_]): State = s.copy(definedCommands = removeTagged(s.definedCommands, tag))
|
|
||||||
def removeTagged(as: Seq[Command], tag: AttributeKey[_]): Seq[Command] = as.filter(c => ! (c.tags contains tag))
|
|
||||||
|
|
||||||
def isAliasNamed(name: String, c: Command): Boolean = isNamed(name, getAlias(c))
|
|
||||||
def isNamed(name: String, alias: Option[(String,String)]): Boolean = alias match { case None => false; case Some((n,_)) => name == n }
|
|
||||||
|
|
||||||
def getAlias(c: Command): Option[(String,String)] = c.tags get CommandAliasKey
|
|
||||||
def printAlias(s: State, name: String): Unit = printAliases(aliases(s,(n,v) => n == name) )
|
|
||||||
def printAliases(s: State): Unit = printAliases(allAliases(s))
|
|
||||||
def printAliases(as: Seq[(String,String)]): Unit =
|
|
||||||
for( (name,value) <- as)
|
|
||||||
println("\t" + name + " = " + value)
|
|
||||||
|
|
||||||
def aliasNames(s: State): Seq[String] = allAliases(s).map(_._1)
|
|
||||||
def allAliases(s: State): Seq[(String,String)] = aliases(s, (n,v) => true)
|
|
||||||
def aliases(s: State, pred: (String,String) => Boolean): Seq[(String,String)] =
|
|
||||||
s.definedCommands.flatMap(c => getAlias(c).filter(tupled(pred)))
|
|
||||||
|
|
||||||
def newAlias(name: String, value: String): Command =
|
|
||||||
Command.make(name, (name, "'" + value + "'"), "Alias of '" + value + "'")(aliasBody(name, value)).tag(CommandAliasKey, (name, value))
|
|
||||||
def aliasBody(name: String, value: String)(state: State): Parser[() => State] =
|
|
||||||
OptSpace ~> Parser(Command.combine(removeAlias(state,name).definedCommands)(state))(value)
|
|
||||||
|
|
||||||
def delegateToAlias(name: String, orElse: Parser[() => State])(state: State): Parser[() => State] =
|
|
||||||
aliases(state, (nme,_) => nme == name).headOption match {
|
|
||||||
case None => orElse
|
|
||||||
case Some((n,v)) => aliasBody(n,v)(state)
|
|
||||||
}
|
|
||||||
|
|
||||||
val CommandAliasKey = AttributeKey[(String,String)]("is-command-alias", "Internal: marker for Commands created as aliases for another command.")
|
|
||||||
}
|
}
|
||||||
|
|
@ -203,7 +203,7 @@ object Project extends Init[Scope] with ProjectExtra
|
||||||
val prompt = get(shellPrompt)
|
val prompt = get(shellPrompt)
|
||||||
val watched = get(watch)
|
val watched = get(watch)
|
||||||
val commandDefs = allCommands.distinct.flatten[Command].map(_ tag (projectCommand, true))
|
val commandDefs = allCommands.distinct.flatten[Command].map(_ tag (projectCommand, true))
|
||||||
val newDefinedCommands = commandDefs ++ BuiltinCommands.removeTagged(s.definedCommands, projectCommand)
|
val newDefinedCommands = commandDefs ++ BasicCommands.removeTagged(s.definedCommands, projectCommand)
|
||||||
val newAttrs = setCond(Watched.Configuration, watched, s.attributes).put(historyPath.key, history)
|
val newAttrs = setCond(Watched.Configuration, watched, s.attributes).put(historyPath.key, history)
|
||||||
s.copy(attributes = setCond(shellPrompt.key, prompt, newAttrs), definedCommands = newDefinedCommands)
|
s.copy(attributes = setCond(shellPrompt.key, prompt, newAttrs), definedCommands = newDefinedCommands)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ object Script
|
||||||
val scriptArg = state.remainingCommands.headOption getOrElse error("No script file specified")
|
val scriptArg = state.remainingCommands.headOption getOrElse error("No script file specified")
|
||||||
val script = new File(scriptArg).getAbsoluteFile
|
val script = new File(scriptArg).getAbsoluteFile
|
||||||
val hash = Hash.halve(Hash.toHex(Hash(script.getAbsolutePath)))
|
val hash = Hash.halve(Hash.toHex(Hash(script.getAbsolutePath)))
|
||||||
val base = new File(CommandSupport.bootDirectory(state), hash)
|
val base = new File(CommandUtil.bootDirectory(state), hash)
|
||||||
IO.createDirectory(base)
|
IO.createDirectory(base)
|
||||||
|
|
||||||
val (eval, structure) = Load.defaultLoad(state, base, state.log)
|
val (eval, structure) = Load.defaultLoad(state, base, state.log)
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,6 @@ object TaskData
|
||||||
private[this] def fakeState(structure: BuildStructure): State =
|
private[this] def fakeState(structure: BuildStructure): State =
|
||||||
{
|
{
|
||||||
val config = Keys.appConfiguration in Scope.GlobalScope get structure.data
|
val config = Keys.appConfiguration in Scope.GlobalScope get structure.data
|
||||||
State(config.get, Nil, Set.empty, None, Nil, State.newHistory, AttributeMap.empty, State.Continue)
|
State(config.get, Nil, Set.empty, None, Nil, State.newHistory, AttributeMap.empty, StandardMain.initialGlobalLogging, State.Continue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ package sbt
|
||||||
import FileInfo.{exists, hash}
|
import FileInfo.{exists, hash}
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import Types.:+:
|
import Types.{:+:, idFun}
|
||||||
import scala.xml.NodeSeq
|
import scala.xml.NodeSeq
|
||||||
import sbinary.{DefaultProtocol,Format}
|
import sbinary.{DefaultProtocol,Format}
|
||||||
import DefaultProtocol.{immutableMapFormat, immutableSetFormat, optionsAreFormat}
|
import DefaultProtocol.{immutableMapFormat, immutableSetFormat, optionsAreFormat}
|
||||||
|
|
@ -80,8 +80,19 @@ object CacheIvy
|
||||||
)
|
)
|
||||||
implicit def exclusionRuleFormat(implicit sf: Format[String]): Format[ExclusionRule] =
|
implicit def exclusionRuleFormat(implicit sf: Format[String]): Format[ExclusionRule] =
|
||||||
wrap[ExclusionRule, (String, String, String, Seq[String])]( e => (e.organization, e.name, e.artifact, e.configurations), { case (o,n,a,cs) => ExclusionRule(o,n,a,cs) })
|
wrap[ExclusionRule, (String, String, String, Seq[String])]( e => (e.organization, e.name, e.artifact, e.configurations), { case (o,n,a,cs) => ExclusionRule(o,n,a,cs) })
|
||||||
|
|
||||||
|
implicit def crossVersionFormat: Format[CrossVersion] = wrap(crossToInt, crossFromInt)
|
||||||
|
|
||||||
|
private[this] final val DisabledValue = 0
|
||||||
|
private[this] final val BinaryValue = 1
|
||||||
|
private[this] final val FullValue = 2
|
||||||
|
|
||||||
|
import CrossVersion.{Binary, Disabled, Full}
|
||||||
|
private[this] val crossFromInt = (i: Int) => i match { case BinaryValue => new Binary(idFun); case FullValue => new Full(idFun); case _ => Disabled }
|
||||||
|
private[this] val crossToInt = (c: CrossVersion) => c match { case Disabled => 0; case b: Binary => BinaryValue; case f: Full => FullValue }
|
||||||
|
|
||||||
implicit def moduleIDFormat(implicit sf: Format[String], af: Format[Artifact], bf: Format[Boolean], ef: Format[ExclusionRule]): Format[ModuleID] =
|
implicit def moduleIDFormat(implicit sf: Format[String], af: Format[Artifact], bf: Format[Boolean], ef: Format[ExclusionRule]): Format[ModuleID] =
|
||||||
wrap[ModuleID, ((String,String,String,Option[String]),(Boolean,Boolean,Seq[Artifact],Seq[ExclusionRule],Map[String,String],Boolean))](
|
wrap[ModuleID, ((String,String,String,Option[String]),(Boolean,Boolean,Seq[Artifact],Seq[ExclusionRule],Map[String,String],CrossVersion))](
|
||||||
m => ((m.organization,m.name,m.revision,m.configurations), (m.isChanging, m.isTransitive, m.explicitArtifacts, m.exclusions, m.extraAttributes, m.crossVersion)),
|
m => ((m.organization,m.name,m.revision,m.configurations), (m.isChanging, m.isTransitive, m.explicitArtifacts, m.exclusions, m.extraAttributes, m.crossVersion)),
|
||||||
{ case ((o,n,r,cs),(ch,t,as,excl,x,cv)) => ModuleID(o,n,r,cs,ch,t,as,excl,x,cv) }
|
{ case ((o,n,r,cs),(ch,t,as,excl,x,cv)) => ModuleID(o,n,r,cs,ch,t,as,excl,x,cv) }
|
||||||
)
|
)
|
||||||
|
|
@ -144,6 +155,7 @@ object CacheIvy
|
||||||
|
|
||||||
implicit def artifactToHL = (a: Artifact) => a.name :+: a.`type` :+: a.extension :+: a.classifier :+: names(a.configurations) :+: a.url :+: a.extraAttributes :+: HNil
|
implicit def artifactToHL = (a: Artifact) => a.name :+: a.`type` :+: a.extension :+: a.classifier :+: names(a.configurations) :+: a.url :+: a.extraAttributes :+: HNil
|
||||||
implicit def exclusionToHL = (e: ExclusionRule) => e.organization :+: e.name :+: e.artifact :+: e.configurations :+: HNil
|
implicit def exclusionToHL = (e: ExclusionRule) => e.organization :+: e.name :+: e.artifact :+: e.configurations :+: HNil
|
||||||
|
implicit def crossToHL = (c: CrossVersion) => crossToInt(c) :+: HNil
|
||||||
|
|
||||||
/* implicit def deliverConfToHL = (p: DeliverConfiguration) => p.deliverIvyPattern :+: p.status :+: p.configurations :+: HNil
|
/* implicit def deliverConfToHL = (p: DeliverConfiguration) => p.deliverIvyPattern :+: p.status :+: p.configurations :+: HNil
|
||||||
implicit def publishConfToHL = (p: PublishConfiguration) => p.ivyFile :+: p.resolverName :+: p.artifacts :+: HNil*/
|
implicit def publishConfToHL = (p: PublishConfiguration) => p.ivyFile :+: p.resolverName :+: p.artifacts :+: HNil*/
|
||||||
|
|
@ -156,13 +168,14 @@ object CacheIvy
|
||||||
implicit def connectionIC: InputCache[SshConnection] = wrapIn
|
implicit def connectionIC: InputCache[SshConnection] = wrapIn
|
||||||
implicit def artifactIC: InputCache[Artifact] = wrapIn
|
implicit def artifactIC: InputCache[Artifact] = wrapIn
|
||||||
implicit def exclusionIC: InputCache[ExclusionRule] = wrapIn
|
implicit def exclusionIC: InputCache[ExclusionRule] = wrapIn
|
||||||
|
implicit def crossVersionIC: InputCache[CrossVersion] = wrapIn
|
||||||
/* implicit def publishConfIC: InputCache[PublishConfiguration] = wrapIn
|
/* implicit def publishConfIC: InputCache[PublishConfiguration] = wrapIn
|
||||||
implicit def deliverConfIC: InputCache[DeliverConfiguration] = wrapIn*/
|
implicit def deliverConfIC: InputCache[DeliverConfiguration] = wrapIn*/
|
||||||
|
|
||||||
object L1 {
|
object L1 {
|
||||||
implicit def retrieveToHL = (r: RetrieveConfiguration) => exists(r.retrieveDirectory) :+: r.outputPattern :+: HNil
|
implicit def retrieveToHL = (r: RetrieveConfiguration) => exists(r.retrieveDirectory) :+: r.outputPattern :+: HNil
|
||||||
implicit def ivyPathsToHL = (p: IvyPaths) => exists(p.baseDirectory) :+: p.ivyHome.map(exists.apply) :+: HNil
|
implicit def ivyPathsToHL = (p: IvyPaths) => exists(p.baseDirectory) :+: p.ivyHome.map(exists.apply) :+: HNil
|
||||||
implicit def ivyScalaHL = (i: IvyScala) => i.scalaVersion :+: names(i.configurations) :+: i.checkExplicit :+: i.filterImplicit :+: HNil
|
implicit def ivyScalaHL = (i: IvyScala) => i.scalaFullVersion :+: i.scalaBinaryVersion :+: names(i.configurations) :+: i.checkExplicit :+: i.filterImplicit :+: HNil
|
||||||
implicit def configurationToHL = (c: Configuration) => c.name :+: c.description :+: c.isPublic :+: names(c.extendsConfigs) :+: c.transitive :+: HNil
|
implicit def configurationToHL = (c: Configuration) => c.name :+: c.description :+: c.isPublic :+: names(c.extendsConfigs) :+: c.transitive :+: HNil
|
||||||
|
|
||||||
implicit def passwordToHL = (s: PasswordAuthentication) => Hash(s.user) :+: password(s.password) :+: HNil
|
implicit def passwordToHL = (s: PasswordAuthentication) => Hash(s.user) :+: password(s.password) :+: HNil
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,126 @@
|
||||||
|
/* sbt -- Simple Build Tool
|
||||||
|
* Copyright 2010 Mark Harrah
|
||||||
|
*/
|
||||||
|
package sbt
|
||||||
|
|
||||||
|
import complete.HistoryCommands
|
||||||
|
import scala.annotation.tailrec
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
import Path._
|
||||||
|
|
||||||
|
object BasicCommandStrings
|
||||||
|
{
|
||||||
|
val HelpCommand = "help"
|
||||||
|
val Exit = "exit"
|
||||||
|
val Quit = "quit"
|
||||||
|
|
||||||
|
/** The command name to terminate the program.*/
|
||||||
|
val TerminateAction: String = Exit
|
||||||
|
|
||||||
|
def helpBrief = (HelpCommand + " [command]*", "Displays this help message or prints detailed help on requested commands.")
|
||||||
|
def helpDetailed = """
|
||||||
|
If an argument is provided, this prints detailed help for that command.
|
||||||
|
Otherwise, this prints a help summary."""
|
||||||
|
|
||||||
|
def historyHelp = Help.briefDetail(HistoryCommands.descriptions)
|
||||||
|
|
||||||
|
def exitBrief = "Terminates the build."
|
||||||
|
|
||||||
|
def ReadCommand = "<"
|
||||||
|
def ReadFiles = " file1 file2 ..."
|
||||||
|
def ReadBrief = (ReadCommand + " <file>*", "Reads command lines from the provided files.")
|
||||||
|
def ReadDetailed =
|
||||||
|
ReadCommand + ReadFiles + """
|
||||||
|
|
||||||
|
Reads the lines from the given files and inserts them as commands.
|
||||||
|
All empty lines and lines that start with '#' are ignored.
|
||||||
|
If a file does not exist or is not readable, this command fails.
|
||||||
|
|
||||||
|
All the lines from all the files are read before any of the commands
|
||||||
|
are executed. Thus, if any file is not readable, none of commands
|
||||||
|
from any of the files (even the existing ones) will be run.
|
||||||
|
|
||||||
|
You probably need to escape this command if entering it at your shell."""
|
||||||
|
|
||||||
|
def ApplyCommand = "apply"
|
||||||
|
def ApplyBrief = (ApplyCommand + " <module-name>*", ApplyDetailed)
|
||||||
|
def ApplyDetailed = "Transforms the current State by calling <module-name>.apply(currentState) for each listed module name."
|
||||||
|
|
||||||
|
def RebootCommand = "reboot"
|
||||||
|
def RebootSummary = RebootCommand + " [full]"
|
||||||
|
def RebootBrief = (RebootSummary, "Reboots sbt and then executes the remaining commands.")
|
||||||
|
def RebootDetailed =
|
||||||
|
RebootSummary + """
|
||||||
|
|
||||||
|
This command is equivalent to exiting sbt, restarting, and running the
|
||||||
|
remaining commands with the exception that the JVM is not shut down.
|
||||||
|
|
||||||
|
If 'full' is specified, the boot directory (`~/.sbt/boot` by default)
|
||||||
|
is deleted before restarting. This forces an update of sbt and Scala
|
||||||
|
and is useful when working with development versions of sbt or Scala."""
|
||||||
|
|
||||||
|
def Multi = ";"
|
||||||
|
def MultiBrief = (Multi + " <command> (" + Multi + " <command>)*", "Runs the provided semicolon-separated commands.")
|
||||||
|
def MultiDetailed =
|
||||||
|
Multi + " command1 " + Multi + """ command2 ...
|
||||||
|
|
||||||
|
Runs the specified commands."""
|
||||||
|
|
||||||
|
def AppendCommand = "append"
|
||||||
|
def AppendLastBrief = (AppendCommand + " <command>", AppendLastDetailed)
|
||||||
|
def AppendLastDetailed = "Appends 'command' to list of commands to run."
|
||||||
|
|
||||||
|
val AliasCommand = "alias"
|
||||||
|
def AliasBrief = (AliasCommand, "Adds, removes, or prints command aliases.")
|
||||||
|
def AliasDetailed =
|
||||||
|
AliasCommand + """
|
||||||
|
|
||||||
|
Prints a list of defined aliases.
|
||||||
|
|
||||||
|
""" +
|
||||||
|
AliasCommand + """ name
|
||||||
|
|
||||||
|
Prints the alias defined for `name`.
|
||||||
|
|
||||||
|
""" +
|
||||||
|
AliasCommand + """ name=value
|
||||||
|
|
||||||
|
Sets the alias `name` to `value`, replacing any existing alias with that name.
|
||||||
|
Whenever `name` is entered, the corresponding `value` is run.
|
||||||
|
If any argument is provided to `name`, it is appended as argument to `value`.
|
||||||
|
|
||||||
|
""" +
|
||||||
|
AliasCommand + """ name=
|
||||||
|
|
||||||
|
Removes the alias for `name`."""
|
||||||
|
|
||||||
|
def Shell = "shell"
|
||||||
|
def ShellBrief = ShellDetailed
|
||||||
|
def ShellDetailed = "Provides an interactive prompt from which commands can be run."
|
||||||
|
|
||||||
|
def ClearOnFailure = "--"
|
||||||
|
def OnFailure = "-"
|
||||||
|
def OnFailureBrief = (OnFailure + " command", "Registers 'command' to run if a command fails.")
|
||||||
|
def OnFailureDetailed =
|
||||||
|
OnFailure + """ command
|
||||||
|
|
||||||
|
Registers 'command' to run when a command fails to complete normally.
|
||||||
|
|
||||||
|
Only one failure command may be registered at a time, so this command
|
||||||
|
replaces the previous command if there is one.
|
||||||
|
|
||||||
|
The failure command resets when it runs once, so it must be added
|
||||||
|
again if desired."""
|
||||||
|
|
||||||
|
def IfLast = "iflast"
|
||||||
|
def IfLastBrief = (IfLast + " <command>", IfLastCommon)
|
||||||
|
def IfLastCommon = "If there are no more commands after this one, 'command' is run."
|
||||||
|
def IfLastDetailed =
|
||||||
|
IfLast + """ command
|
||||||
|
|
||||||
|
""" + IfLastCommon
|
||||||
|
|
||||||
|
val ContinuousExecutePrefix = "~"
|
||||||
|
def continuousBriefHelp = (ContinuousExecutePrefix + " <command>", "Executes the specified command whenever source files change.")
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,223 @@
|
||||||
|
package sbt
|
||||||
|
|
||||||
|
import complete.{DefaultParsers, HistoryCommands, Parser}
|
||||||
|
import DefaultParsers._
|
||||||
|
import Types.{const,idFun}
|
||||||
|
import Function.tupled
|
||||||
|
import Command.applyEffect
|
||||||
|
import State.FailureWall
|
||||||
|
import HistoryCommands.{Start => HistoryPrefix}
|
||||||
|
import BasicCommandStrings._
|
||||||
|
import CommandUtil._
|
||||||
|
import BasicKeys._
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
object BasicCommands
|
||||||
|
{
|
||||||
|
lazy val allBasicCommands = Seq(nop, ignore, help, multi, ifLast, append, setOnFailure, clearOnFailure, reboot, call, exit, continuous, history, shell, read, alias)
|
||||||
|
|
||||||
|
def nop = Command.custom(s => success(() => s))
|
||||||
|
def ignore = Command.command(FailureWall)(idFun)
|
||||||
|
|
||||||
|
def help = Command.make(HelpCommand, helpBrief, helpDetailed)(helpParser)
|
||||||
|
|
||||||
|
def helpParser(s: State) =
|
||||||
|
{
|
||||||
|
val h = (Help.empty /: s.definedCommands)(_ ++ _.help(s))
|
||||||
|
val helpCommands = h.detail.keySet
|
||||||
|
val args = (token(Space) ~> token( NotSpace examples helpCommands )).*
|
||||||
|
applyEffect(args)(runHelp(s, h))
|
||||||
|
}
|
||||||
|
|
||||||
|
def runHelp(s: State, h: Help)(args: Seq[String]): State =
|
||||||
|
{
|
||||||
|
val message =
|
||||||
|
if(args.isEmpty)
|
||||||
|
aligned(" ", " ", h.brief).mkString("\n", "\n", "\n")
|
||||||
|
else
|
||||||
|
detail(args, h.detail) mkString("\n", "\n\n", "\n")
|
||||||
|
System.out.println(message)
|
||||||
|
s
|
||||||
|
}
|
||||||
|
def detail(selected: Seq[String], detailMap: Map[String, String]): Seq[String] =
|
||||||
|
selected.distinct flatMap { detailMap get _ }
|
||||||
|
|
||||||
|
def multiParser(s: State): Parser[Seq[String]] =
|
||||||
|
{
|
||||||
|
val nonSemi = token(charClass(_ != ';').+, hide= const(true))
|
||||||
|
( token(';' ~> OptSpace) flatMap { _ => matched((s.combinedParser&nonSemi) | nonSemi) <~ token(OptSpace) } map (_.trim) ).+
|
||||||
|
}
|
||||||
|
|
||||||
|
def multiApplied(s: State) =
|
||||||
|
Command.applyEffect( multiParser(s) )( _ ::: s )
|
||||||
|
|
||||||
|
def multi = Command.custom(multiApplied, Help(Multi, MultiBrief, MultiDetailed) )
|
||||||
|
|
||||||
|
lazy val otherCommandParser = (s: State) => token(OptSpace ~> combinedLax(s, any.+) )
|
||||||
|
def combinedLax(s: State, any: Parser[_]): Parser[String] =
|
||||||
|
matched(s.combinedParser | token(any, hide= const(true)))
|
||||||
|
|
||||||
|
def ifLast = Command(IfLast, IfLastBrief, IfLastDetailed)(otherCommandParser) { (s, arg) =>
|
||||||
|
if(s.remainingCommands.isEmpty) arg :: s else s
|
||||||
|
}
|
||||||
|
def append = Command(AppendCommand, AppendLastBrief, AppendLastDetailed)(otherCommandParser) { (s, arg) =>
|
||||||
|
s.copy(remainingCommands = s.remainingCommands :+ arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
def setOnFailure = Command(OnFailure, OnFailureBrief, OnFailureDetailed)(otherCommandParser) { (s, arg) =>
|
||||||
|
s.copy(onFailure = Some(arg))
|
||||||
|
}
|
||||||
|
def clearOnFailure = Command.command(ClearOnFailure)(s => s.copy(onFailure = None))
|
||||||
|
|
||||||
|
def reboot = Command(RebootCommand, RebootBrief, RebootDetailed)(rebootParser) { (s, full) =>
|
||||||
|
s.reboot(full)
|
||||||
|
}
|
||||||
|
def rebootParser(s: State) = token(Space ~> "full" ^^^ true) ?? false
|
||||||
|
|
||||||
|
def call = Command(ApplyCommand, ApplyBrief, ApplyDetailed)(_ => spaceDelimited("<class name>")) { (state,args) =>
|
||||||
|
val loader = getClass.getClassLoader
|
||||||
|
val loaded = args.map(arg => ModuleUtilities.getObject(arg, loader))
|
||||||
|
(state /: loaded) { case (s, obj: (State => State)) => obj(s) }
|
||||||
|
}
|
||||||
|
|
||||||
|
def exit = Command.command(TerminateAction, exitBrief, exitBrief ) ( _ exit true )
|
||||||
|
|
||||||
|
|
||||||
|
def continuous =
|
||||||
|
Command(ContinuousExecutePrefix, Help(continuousBriefHelp) )(otherCommandParser) { (s, arg) =>
|
||||||
|
withAttribute(s, Watched.Configuration, "Continuous execution not configured.") { w =>
|
||||||
|
val repeat = ContinuousExecutePrefix + (if(arg.startsWith(" ")) arg else " " + arg)
|
||||||
|
Watched.executeContinuously(w, s, arg, repeat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def history = Command.custom(historyParser, BasicCommandStrings.historyHelp)
|
||||||
|
def historyParser(s: State): Parser[() => State] =
|
||||||
|
Command.applyEffect(HistoryCommands.actionParser) { histFun =>
|
||||||
|
val logError = (msg: String) => s.log.error(msg)
|
||||||
|
val hp = s get historyPath getOrElse None
|
||||||
|
val lines = hp.toList.flatMap( p => IO.readLines(p) ).toIndexedSeq
|
||||||
|
histFun( complete.History(lines, hp, logError) ) match
|
||||||
|
{
|
||||||
|
case Some(commands) =>
|
||||||
|
commands foreach println //printing is more appropriate than logging
|
||||||
|
(commands ::: s).continue
|
||||||
|
case None => s.fail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def shell = Command.command(Shell, ShellBrief, ShellDetailed) { s =>
|
||||||
|
val history = (s get historyPath) getOrElse Some(new File(s.baseDir, ".history"))
|
||||||
|
val prompt = (s get shellPrompt) match { case Some(pf) => pf(s); case None => "> " }
|
||||||
|
val reader = new FullReader(history, s.combinedParser)
|
||||||
|
val line = reader.readLine(prompt)
|
||||||
|
line match {
|
||||||
|
case Some(line) =>
|
||||||
|
val newState = s.copy(onFailure = Some(Shell), remainingCommands = line +: Shell +: s.remainingCommands)
|
||||||
|
if(line.trim.isEmpty) newState else newState.clearGlobalLog
|
||||||
|
case None => s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def read = Command.make(ReadCommand, ReadBrief, ReadDetailed)(s => applyEffect(readParser(s))(doRead(s)) )
|
||||||
|
def readParser(s: State) =
|
||||||
|
{
|
||||||
|
val files = (token(Space) ~> fileParser(s.baseDir)).+
|
||||||
|
val portAndSuccess = token(OptSpace) ~> Port
|
||||||
|
portAndSuccess || files
|
||||||
|
}
|
||||||
|
def doRead(s: State)(arg: Either[Int, Seq[File]]): State =
|
||||||
|
arg match
|
||||||
|
{
|
||||||
|
case Left(portAndSuccess) =>
|
||||||
|
val port = math.abs(portAndSuccess)
|
||||||
|
val previousSuccess = portAndSuccess >= 0
|
||||||
|
readMessage(port, previousSuccess) match
|
||||||
|
{
|
||||||
|
case Some(message) => (message :: (ReadCommand + " " + port) :: s).copy(onFailure = Some(ReadCommand + " " + (-port)))
|
||||||
|
case None =>
|
||||||
|
System.err.println("Connection closed.")
|
||||||
|
s.fail
|
||||||
|
}
|
||||||
|
case Right(from) =>
|
||||||
|
val notFound = notReadable(from)
|
||||||
|
if(notFound.isEmpty)
|
||||||
|
readLines(from) ::: s // this means that all commands from all files are loaded, parsed, and inserted before any are executed
|
||||||
|
else {
|
||||||
|
s.log.error("Command file(s) not readable: \n\t" + notFound.mkString("\n\t"))
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private def readMessage(port: Int, previousSuccess: Boolean): Option[String] =
|
||||||
|
{
|
||||||
|
// split into two connections because this first connection ends the previous communication
|
||||||
|
xsbt.IPC.client(port) { _.send(previousSuccess.toString) }
|
||||||
|
// and this second connection starts the next communication
|
||||||
|
xsbt.IPC.client(port) { ipc =>
|
||||||
|
val message = ipc.receive
|
||||||
|
if(message eq null) None else Some(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def alias = Command.make(AliasCommand, AliasBrief, AliasDetailed) { s =>
|
||||||
|
val name = token(OpOrID.examples( aliasNames(s) : _*) )
|
||||||
|
val assign = token(OptSpace ~ '=' ~ OptSpace)
|
||||||
|
val sfree = removeAliases(s)
|
||||||
|
val to = matched(sfree.combinedParser, partial = true) | any.+.string
|
||||||
|
val base = (OptSpace ~> (name ~ (assign ~> to.?).?).?)
|
||||||
|
applyEffect(base)(t => runAlias(s, t) )
|
||||||
|
}
|
||||||
|
|
||||||
|
def runAlias(s: State, args: Option[(String, Option[Option[String]])]): State =
|
||||||
|
args match
|
||||||
|
{
|
||||||
|
case None => printAliases(s); s
|
||||||
|
case Some(x ~ None) if !x.isEmpty => printAlias(s, x.trim); s
|
||||||
|
case Some(name ~ Some(None)) => removeAlias(s, name.trim)
|
||||||
|
case Some(name ~ Some(Some(value))) => addAlias(s, name.trim, value.trim)
|
||||||
|
}
|
||||||
|
def addAlias(s: State, name: String, value: String): State =
|
||||||
|
if(Command validID name) {
|
||||||
|
val removed = removeAlias(s, name)
|
||||||
|
if(value.isEmpty) removed else removed.copy(definedCommands = newAlias(name, value) +: removed.definedCommands)
|
||||||
|
} else {
|
||||||
|
System.err.println("Invalid alias name '" + name + "'.")
|
||||||
|
s.fail
|
||||||
|
}
|
||||||
|
|
||||||
|
def removeAliases(s: State): State = removeTagged(s, CommandAliasKey)
|
||||||
|
def removeAlias(s: State, name: String): State = s.copy(definedCommands = s.definedCommands.filter(c => !isAliasNamed(name, c)) )
|
||||||
|
|
||||||
|
def removeTagged(s: State, tag: AttributeKey[_]): State = s.copy(definedCommands = removeTagged(s.definedCommands, tag))
|
||||||
|
def removeTagged(as: Seq[Command], tag: AttributeKey[_]): Seq[Command] = as.filter(c => ! (c.tags contains tag))
|
||||||
|
|
||||||
|
def isAliasNamed(name: String, c: Command): Boolean = isNamed(name, getAlias(c))
|
||||||
|
def isNamed(name: String, alias: Option[(String,String)]): Boolean = alias match { case None => false; case Some((n,_)) => name == n }
|
||||||
|
|
||||||
|
def getAlias(c: Command): Option[(String,String)] = c.tags get CommandAliasKey
|
||||||
|
def printAlias(s: State, name: String): Unit = printAliases(aliases(s,(n,v) => n == name) )
|
||||||
|
def printAliases(s: State): Unit = printAliases(allAliases(s))
|
||||||
|
def printAliases(as: Seq[(String,String)]): Unit =
|
||||||
|
for( (name,value) <- as)
|
||||||
|
println("\t" + name + " = " + value)
|
||||||
|
|
||||||
|
def aliasNames(s: State): Seq[String] = allAliases(s).map(_._1)
|
||||||
|
def allAliases(s: State): Seq[(String,String)] = aliases(s, (n,v) => true)
|
||||||
|
def aliases(s: State, pred: (String,String) => Boolean): Seq[(String,String)] =
|
||||||
|
s.definedCommands.flatMap(c => getAlias(c).filter(tupled(pred)))
|
||||||
|
|
||||||
|
def newAlias(name: String, value: String): Command =
|
||||||
|
Command.make(name, (name, "'" + value + "'"), "Alias of '" + value + "'")(aliasBody(name, value)).tag(CommandAliasKey, (name, value))
|
||||||
|
def aliasBody(name: String, value: String)(state: State): Parser[() => State] =
|
||||||
|
OptSpace ~> Parser(Command.combine(removeAlias(state,name).definedCommands)(state))(value)
|
||||||
|
|
||||||
|
def delegateToAlias(name: String, orElse: Parser[() => State])(state: State): Parser[() => State] =
|
||||||
|
aliases(state, (nme,_) => nme == name).headOption match {
|
||||||
|
case None => orElse
|
||||||
|
case Some((n,v)) => aliasBody(n,v)(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
val CommandAliasKey = AttributeKey[(String,String)]("is-command-alias", "Internal: marker for Commands created as aliases for another command.")
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
package sbt
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
object BasicKeys
|
||||||
|
{
|
||||||
|
val historyPath = AttributeKey[Option[File]]("history", "The location where command line history is persisted.")
|
||||||
|
val shellPrompt = AttributeKey[State => String]("shell-prompt", "The function that constructs the command prompt from the current build state.")
|
||||||
|
val watch = AttributeKey[Watched]("watch", "Continuous execution configuration.")
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
package sbt
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
object CommandUtil
|
||||||
|
{
|
||||||
|
def readLines(files: Seq[File]): Seq[String] = files flatMap (line => IO.readLines(line)) flatMap processLine
|
||||||
|
def processLine(s: String) = { val trimmed = s.trim; if(ignoreLine(trimmed)) None else Some(trimmed) }
|
||||||
|
def ignoreLine(s: String) = s.isEmpty || s.startsWith("#")
|
||||||
|
|
||||||
|
private def canRead = (_: File).canRead
|
||||||
|
def notReadable(files: Seq[File]): Seq[File] = files filterNot canRead
|
||||||
|
def readable(files: Seq[File]): Seq[File] = files filter canRead
|
||||||
|
|
||||||
|
// slightly better fallback in case of older launcher
|
||||||
|
def bootDirectory(state: State): File =
|
||||||
|
try { state.configuration.provider.scalaProvider.launcher.bootDirectory }
|
||||||
|
catch { case e: NoSuchMethodError => new File(".").getAbsoluteFile }
|
||||||
|
|
||||||
|
def aligned(pre: String, sep: String, in: Seq[(String, String)]): Seq[String] =
|
||||||
|
{
|
||||||
|
val width = in.map(_._1.length).max
|
||||||
|
in.map { case (a, b) => (" " + fill(a, width) + sep + b) }
|
||||||
|
}
|
||||||
|
def fill(s: String, size: Int) = s + " " * math.max(size - s.length, 0)
|
||||||
|
|
||||||
|
def withAttribute[T](s: State, key: AttributeKey[T], ifMissing: String)(f: T => State): State =
|
||||||
|
(s get key) match {
|
||||||
|
case None => s.log.error(ifMissing); s.fail
|
||||||
|
case Some(nav) => f(nav)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
/* sbt -- Simple Build Tool
|
||||||
|
* Copyright 2008, 2009, 2010, 2011 Mark Harrah
|
||||||
|
*/
|
||||||
|
package sbt
|
||||||
|
|
||||||
|
import scala.annotation.tailrec
|
||||||
|
import java.io.{File, PrintWriter}
|
||||||
|
import java.lang.reflect.InvocationTargetException
|
||||||
|
|
||||||
|
object MainLoop
|
||||||
|
{
|
||||||
|
/** Entry point to run the remaining commands in State with managed global logging.*/
|
||||||
|
def runLogged(state: State): xsbti.MainResult =
|
||||||
|
runLoggedLoop(state, state.globalLogging.backing)
|
||||||
|
|
||||||
|
/** Run loop that evaluates remaining commands and manages changes to global logging configuration.*/
|
||||||
|
@tailrec def runLoggedLoop(state: State, logBacking: GlobalLogBacking): xsbti.MainResult =
|
||||||
|
runAndClearLast(state, logBacking) match {
|
||||||
|
case ret: Return => // delete current and last log files when exiting normally
|
||||||
|
logBacking.file.delete()
|
||||||
|
deleteLastLog(logBacking)
|
||||||
|
ret.result
|
||||||
|
case clear: ClearGlobalLog => // delete previous log file, move current to previous, and start writing to a new file
|
||||||
|
deleteLastLog(logBacking)
|
||||||
|
runLoggedLoop(clear.state, logBacking.shiftNew())
|
||||||
|
case keep: KeepGlobalLog => // make previous log file the current log file
|
||||||
|
logBacking.file.delete
|
||||||
|
runLoggedLoop(keep.state, logBacking.unshift)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Runs the next sequence of commands, cleaning up global logging after any exceptions. */
|
||||||
|
def runAndClearLast(state: State, logBacking: GlobalLogBacking): RunNext =
|
||||||
|
try
|
||||||
|
runWithNewLog(state, logBacking)
|
||||||
|
catch {
|
||||||
|
case e: xsbti.FullReload =>
|
||||||
|
deleteLastLog(logBacking)
|
||||||
|
throw e // pass along a reboot request
|
||||||
|
case e =>
|
||||||
|
System.err.println("sbt appears to be exiting abnormally.\n The log file for this session is at " + logBacking.file)
|
||||||
|
deleteLastLog(logBacking)
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Deletes the previous global log file. */
|
||||||
|
def deleteLastLog(logBacking: GlobalLogBacking): Unit =
|
||||||
|
logBacking.last.foreach(_.delete())
|
||||||
|
|
||||||
|
/** Runs the next sequence of commands with global logging in place. */
|
||||||
|
def runWithNewLog(state: State, logBacking: GlobalLogBacking): RunNext =
|
||||||
|
Using.fileWriter(append = true)(logBacking.file) { writer =>
|
||||||
|
val out = new java.io.PrintWriter(writer)
|
||||||
|
val loggedState = state.copy(globalLogging = logBacking.newLogger(out, logBacking))
|
||||||
|
try run(loggedState) finally out.close()
|
||||||
|
}
|
||||||
|
sealed trait RunNext
|
||||||
|
final class ClearGlobalLog(val state: State) extends RunNext
|
||||||
|
final class KeepGlobalLog(val state: State) extends RunNext
|
||||||
|
final class Return(val result: xsbti.MainResult) extends RunNext
|
||||||
|
|
||||||
|
/** Runs the next sequence of commands that doesn't require global logging changes.*/
|
||||||
|
@tailrec def run(state: State): RunNext =
|
||||||
|
state.next match
|
||||||
|
{
|
||||||
|
case State.Continue => run(next(state))
|
||||||
|
case State.ClearGlobalLog => new ClearGlobalLog(state.continue)
|
||||||
|
case State.KeepLastLog => new KeepGlobalLog(state.continue)
|
||||||
|
case ret: State.Return => new Return(ret.result)
|
||||||
|
}
|
||||||
|
|
||||||
|
def next(state: State): State =
|
||||||
|
ErrorHandling.wideConvert { state.process(Command.process) } match
|
||||||
|
{
|
||||||
|
case Right(s) => s
|
||||||
|
case Left(t: xsbti.FullReload) => throw t
|
||||||
|
case Left(t) => handleException(t, state)
|
||||||
|
}
|
||||||
|
|
||||||
|
def handleException(e: Throwable, s: State): State =
|
||||||
|
handleException(e, s, s.log)
|
||||||
|
def handleException(e: Throwable, s: State, log: Logger): State =
|
||||||
|
{
|
||||||
|
e match
|
||||||
|
{
|
||||||
|
case _: AlreadyHandledException | _: UnprintableException => ()
|
||||||
|
case ite: InvocationTargetException =>
|
||||||
|
val cause = ite.getCause
|
||||||
|
if(cause == null || cause == ite) logFullException(ite, log) else handleException(cause, s, log)
|
||||||
|
case _: MessageOnlyException => log.error(e.toString)
|
||||||
|
case _ => logFullException(e, log)
|
||||||
|
}
|
||||||
|
s.fail
|
||||||
|
}
|
||||||
|
def logFullException(e: Throwable, log: Logger)
|
||||||
|
{
|
||||||
|
log.trace(e)
|
||||||
|
log.error(ErrorHandling reducedToString e)
|
||||||
|
log.error("Use 'last' for the full log.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,7 +5,6 @@ package sbt
|
||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.concurrent.Callable
|
import java.util.concurrent.Callable
|
||||||
import CommandSupport.{FailureWall, logger}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Data structure representing all command execution information.
|
Data structure representing all command execution information.
|
||||||
|
|
@ -27,6 +26,7 @@ final case class State(
|
||||||
remainingCommands: Seq[String],
|
remainingCommands: Seq[String],
|
||||||
history: State.History,
|
history: State.History,
|
||||||
attributes: AttributeMap,
|
attributes: AttributeMap,
|
||||||
|
globalLogging: GlobalLogging,
|
||||||
next: State.Next
|
next: State.Next
|
||||||
) extends Identity {
|
) extends Identity {
|
||||||
lazy val combinedParser = Command.combine(definedCommands)(this)
|
lazy val combinedParser = Command.combine(definedCommands)(this)
|
||||||
|
|
@ -112,6 +112,8 @@ trait StateOps {
|
||||||
|
|
||||||
object State
|
object State
|
||||||
{
|
{
|
||||||
|
final val FailureWall = "---"
|
||||||
|
|
||||||
/** Represents the next action for the command processor.*/
|
/** Represents the next action for the command processor.*/
|
||||||
sealed trait Next
|
sealed trait Next
|
||||||
/** Indicates that the command processor should process the next command.*/
|
/** Indicates that the command processor should process the next command.*/
|
||||||
|
|
@ -175,7 +177,7 @@ object State
|
||||||
def update[T](key: AttributeKey[T])(f: Option[T] => T): State = put(key, f(get(key)))
|
def update[T](key: AttributeKey[T])(f: Option[T] => T): State = put(key, f(get(key)))
|
||||||
def has(key: AttributeKey[_]) = s.attributes contains key
|
def has(key: AttributeKey[_]) = s.attributes contains key
|
||||||
def remove(key: AttributeKey[_]) = s.copy(attributes = s.attributes remove key)
|
def remove(key: AttributeKey[_]) = s.copy(attributes = s.attributes remove key)
|
||||||
def log = CommandSupport.logger(s)
|
def log = s.globalLogging.full
|
||||||
def fail =
|
def fail =
|
||||||
{
|
{
|
||||||
val remaining = s.remainingCommands.dropWhile(_ != FailureWall)
|
val remaining = s.remainingCommands.dropWhile(_ != FailureWall)
|
||||||
|
|
@ -3,7 +3,8 @@
|
||||||
*/
|
*/
|
||||||
package sbt
|
package sbt
|
||||||
|
|
||||||
import CommandSupport.{ClearOnFailure,FailureWall}
|
import BasicCommandStrings.ClearOnFailure
|
||||||
|
import State.FailureWall
|
||||||
import annotation.tailrec
|
import annotation.tailrec
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import Types.const
|
import Types.const
|
||||||
|
|
@ -63,7 +64,7 @@ object Watched
|
||||||
catch { case e: Exception =>
|
catch { case e: Exception =>
|
||||||
val log = s.log
|
val log = s.log
|
||||||
log.error("Error occurred obtaining files to watch. Terminating continuous execution...")
|
log.error("Error occurred obtaining files to watch. Terminating continuous execution...")
|
||||||
BuiltinCommands.handleException(e, s, log)
|
MainLoop.handleException(e, s, log)
|
||||||
(false, watchState, s.fail)
|
(false, watchState, s.fail)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -14,7 +14,7 @@ object Sbt extends Build
|
||||||
{
|
{
|
||||||
override lazy val settings = super.settings ++ buildSettings ++ Status.settings
|
override lazy val settings = super.settings ++ buildSettings ++ Status.settings
|
||||||
def buildSettings = Seq(
|
def buildSettings = Seq(
|
||||||
organization := "org.scala-tools.sbt",
|
organization := "org.scala-sbt",
|
||||||
version := "0.12.0-SNAPSHOT",
|
version := "0.12.0-SNAPSHOT",
|
||||||
publishArtifact in packageDoc := false,
|
publishArtifact in packageDoc := false,
|
||||||
scalaVersion := "2.9.1",
|
scalaVersion := "2.9.1",
|
||||||
|
|
@ -111,8 +111,11 @@ object Sbt extends Build
|
||||||
classfileSub, classpathSub, compileIncrementalSub, compilePersistSub, compilerSub, completeSub, apiSub,
|
classfileSub, classpathSub, compileIncrementalSub, compilePersistSub, compilerSub, completeSub, apiSub,
|
||||||
interfaceSub, ioSub, ivySub, logSub, processSub, runSub, stdTaskSub, taskSub, trackingSub, testingSub)
|
interfaceSub, ioSub, ivySub, logSub, processSub, runSub, stdTaskSub, taskSub, trackingSub, testingSub)
|
||||||
|
|
||||||
|
lazy val commandSub = testedBaseProject(commandPath, "Command") dependsOn(interfaceSub, ioSub, launchInterfaceSub, logSub, completeSub, classpathSub)
|
||||||
|
|
||||||
// The main integration project for sbt. It brings all of the subsystems together, configures them, and provides for overriding conventions.
|
// The main integration project for sbt. It brings all of the subsystems together, configures them, and provides for overriding conventions.
|
||||||
lazy val mainSub = testedBaseProject(mainPath, "Main") dependsOn(actionsSub, interfaceSub, ioSub, ivySub, launchInterfaceSub, logSub, processSub, runSub)
|
lazy val mainSub = testedBaseProject(mainPath, "Main") dependsOn(actionsSub, interfaceSub, ioSub, ivySub, launchInterfaceSub, logSub, processSub, runSub, commandSub)
|
||||||
|
|
||||||
// Strictly for bringing implicits and aliases from subsystems into the top-level sbt namespace through a single package object
|
// Strictly for bringing implicits and aliases from subsystems into the top-level sbt namespace through a single package object
|
||||||
// technically, we need a dependency on all of mainSub's dependencies, but we don't do that since this is strictly an integration project
|
// technically, we need a dependency on all of mainSub's dependencies, but we don't do that since this is strictly an integration project
|
||||||
// with the sole purpose of providing certain identifiers without qualification (with a package object)
|
// with the sole purpose of providing certain identifiers without qualification (with a package object)
|
||||||
|
|
@ -126,6 +129,7 @@ object Sbt extends Build
|
||||||
def utilPath = file("util")
|
def utilPath = file("util")
|
||||||
def compilePath = file("compile")
|
def compilePath = file("compile")
|
||||||
def mainPath = file("main")
|
def mainPath = file("main")
|
||||||
|
def commandPath = mainPath / "command"
|
||||||
def scriptedPath = file("scripted")
|
def scriptedPath = file("scripted")
|
||||||
|
|
||||||
def sbtSettings = Seq(
|
def sbtSettings = Seq(
|
||||||
|
|
@ -137,8 +141,8 @@ object Sbt extends Build
|
||||||
(launcher, scriptedSbtClasspath, scriptedSbtInstance, _, v, sv, ssv, sourcePath, args) =>
|
(launcher, scriptedSbtClasspath, scriptedSbtInstance, _, v, sv, ssv, sourcePath, args) =>
|
||||||
val loader = classpath.ClasspathUtilities.toLoader(scriptedSbtClasspath.files, scriptedSbtInstance.loader)
|
val loader = classpath.ClasspathUtilities.toLoader(scriptedSbtClasspath.files, scriptedSbtInstance.loader)
|
||||||
val m = ModuleUtilities.getObject("sbt.test.ScriptedTests", loader)
|
val m = ModuleUtilities.getObject("sbt.test.ScriptedTests", loader)
|
||||||
val r = m.getClass.getMethod("run", classOf[File], classOf[Boolean], classOf[String], classOf[String], classOf[String], classOf[Array[String]], classOf[File])
|
val r = m.getClass.getMethod("run", classOf[File], classOf[Boolean], classOf[String], classOf[String], classOf[String], classOf[Array[String]], classOf[File], classOf[Array[String]])
|
||||||
try { r.invoke(m, sourcePath, true: java.lang.Boolean, v, sv, ssv, args.toArray[String], launcher) }
|
try { r.invoke(m, sourcePath, true: java.lang.Boolean, v, sv, ssv, args.toArray[String], launcher, Array[String]()) }
|
||||||
catch { case ite: java.lang.reflect.InvocationTargetException => throw ite.getCause }
|
catch { case ite: java.lang.reflect.InvocationTargetException => throw ite.getCause }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,9 @@
|
||||||
package object sbt extends sbt.std.TaskExtra with sbt.Types with sbt.ProcessExtra with sbt.impl.DependencyBuilders
|
package object sbt extends sbt.std.TaskExtra with sbt.Types with sbt.ProcessExtra with sbt.impl.DependencyBuilders
|
||||||
with sbt.PathExtra with sbt.ProjectExtra with sbt.DependencyFilterExtra with sbt.BuildExtra
|
with sbt.PathExtra with sbt.ProjectExtra with sbt.DependencyFilterExtra with sbt.BuildExtra
|
||||||
{
|
{
|
||||||
|
@deprecated("Renamed to CommandStrings.", "0.12.0")
|
||||||
|
val CommandSupport = CommandStrings
|
||||||
|
|
||||||
@deprecated("Use SettingKey, which is a drop-in replacement.", "0.11.1")
|
@deprecated("Use SettingKey, which is a drop-in replacement.", "0.11.1")
|
||||||
type ScopedSetting[T] = SettingKey[T]
|
type ScopedSetting[T] = SettingKey[T]
|
||||||
@deprecated("Use TaskKey, which is a drop-in replacement.", "0.11.1")
|
@deprecated("Use TaskKey, which is a drop-in replacement.", "0.11.1")
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,13 @@ $ absent ran
|
||||||
$ exists ran
|
$ exists ran
|
||||||
$ delete ran
|
$ delete ran
|
||||||
|
|
||||||
# single project, Aggregate = Enabled on Mark
|
# single project, aggregate = true on Mark
|
||||||
> set aggregate in Mark := false
|
> set aggregate in Mark := true
|
||||||
> mark
|
> mark
|
||||||
$ exists ran
|
$ exists ran
|
||||||
$ delete ran
|
$ delete ran
|
||||||
|
|
||||||
# single project, Aggregate = Disabled on Mark
|
# single project, aggregate = false on Mark
|
||||||
> set aggregate in Mark := false
|
> set aggregate in Mark := false
|
||||||
> mark
|
> mark
|
||||||
$ exists ran
|
$ exists ran
|
||||||
|
|
@ -45,7 +45,7 @@ $ absent ran
|
||||||
$ exists sub/ran
|
$ exists sub/ran
|
||||||
$ delete sub/ran
|
$ delete sub/ran
|
||||||
|
|
||||||
# unset the root task. the sub task shouldn't be runnable from root
|
# unset the root task. the sub task shouldn't be runnable from root without aggregation
|
||||||
> session remove 1
|
> session remove 1
|
||||||
-> mark
|
-> mark
|
||||||
$ absent ran sub/ran
|
$ absent ran sub/ran
|
||||||
|
|
@ -80,20 +80,6 @@ $ exists ran sub/ran
|
||||||
$ absent sub/sub/ran
|
$ absent sub/sub/ran
|
||||||
$ delete ran sub/ran
|
$ delete ran sub/ran
|
||||||
|
|
||||||
# check explicit aggregation. running on root should run root/mark and sub2/mark
|
|
||||||
> set aggregate in Mark := Aggregation(sub2 :: Nil)
|
|
||||||
> mark
|
|
||||||
$ exists ran sub/sub/ran
|
|
||||||
$ absent sub/ran
|
|
||||||
$ delete ran sub/sub/ran
|
|
||||||
|
|
||||||
# check intransitive aggregation. running on root should not continue to sub2/mark
|
|
||||||
> set aggregate in Mark := Aggregation(sub :: Nil, false)
|
|
||||||
> mark
|
|
||||||
$ exists ran sub/ran
|
|
||||||
$ absent sub/sub/ran
|
|
||||||
$ delete ran sub/ran
|
|
||||||
|
|
||||||
# the aggregation setting in a leaf shouldn't affect whether it can be run directly
|
# the aggregation setting in a leaf shouldn't affect whether it can be run directly
|
||||||
> set aggregate in (sub2, Mark) := false
|
> set aggregate in (sub2, Mark) := false
|
||||||
> sub2/mark
|
> sub2/mark
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ publishTo <<= baseDirectory { base =>
|
||||||
|
|
||||||
projectID <<= projectID { _.extra("e:color" -> "red") }
|
projectID <<= projectID { _.extra("e:color" -> "red") }
|
||||||
|
|
||||||
organization := "org.scala-tools.sbt"
|
organization := "org.scala-sbt"
|
||||||
|
|
||||||
version := "1.0"
|
version := "1.0"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ resolvers <<= baseDirectory( base =>
|
||||||
|
|
||||||
libraryDependencies <<= baseDirectory { base =>
|
libraryDependencies <<= baseDirectory { base =>
|
||||||
val color = IO.read(base / "color")
|
val color = IO.read(base / "color")
|
||||||
val dep = "org.scala-tools.sbt" %% "define-color" % "1.0" extra("e:color" -> color)
|
val dep = "org.scala-sbt" %% "define-color" % "1.0" extra("e:color" -> color)
|
||||||
dep :: Nil
|
dep :: Nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ object InfoTest extends Build
|
||||||
lazy val root = Project("root", file(".")) settings(
|
lazy val root = Project("root", file(".")) settings(
|
||||||
ivyPaths <<= (baseDirectory, target)( (dir, t) => new IvyPaths(dir, Some(t / "ivy-cache"))),
|
ivyPaths <<= (baseDirectory, target)( (dir, t) => new IvyPaths(dir, Some(t / "ivy-cache"))),
|
||||||
ivyXML <<= (customInfo, organization, moduleName, version) apply inlineXML,
|
ivyXML <<= (customInfo, organization, moduleName, version) apply inlineXML,
|
||||||
|
scalaVersion := "2.9.0",
|
||||||
projectID ~= (_ cross false),
|
projectID ~= (_ cross false),
|
||||||
customInfo <<= baseDirectory{_ / "info" exists },
|
customInfo <<= baseDirectory{_ / "info" exists },
|
||||||
TaskKey[Unit]("check-download") <<= checkDownload,
|
TaskKey[Unit]("check-download") <<= checkDownload,
|
||||||
|
|
@ -24,9 +25,9 @@ object InfoTest extends Build
|
||||||
ScalaQuery is a type-safe database query API for Scala.
|
ScalaQuery is a type-safe database query API for Scala.
|
||||||
</description>
|
</description>
|
||||||
</info>
|
</info>
|
||||||
<dependency org="org.scalacheck" name="scalacheck" rev="1.5"/>)
|
<dependency org="org.scala-tools.testing" name="scalacheck_2.9.0" rev="1.9"/>)
|
||||||
else
|
else
|
||||||
<dependency org="org.scalacheck" name="scalacheck" rev="1.5"/>
|
<dependency org="org.scala-tools.testing" name="scalacheck_2.9.0" rev="1.9"/>
|
||||||
|
|
||||||
def checkDownload = (dependencyClasspath in Compile) map { cp => if(cp.isEmpty) error("Dependency not downloaded"); () }
|
def checkDownload = (dependencyClasspath in Compile) map { cp => if(cp.isEmpty) error("Dependency not downloaded"); () }
|
||||||
def checkInfo = (customInfo, delivered) map { (addInfo, d) =>
|
def checkInfo = (customInfo, delivered) map { (addInfo, d) =>
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
resolvers += ScalaToolsReleases
|
||||||
|
|
||||||
libraryDependencies += "org.scalacheck" % "scalacheck" % "1.5"
|
libraryDependencies += "org.scalacheck" % "scalacheck" % "1.5"
|
||||||
|
|
||||||
ivyPaths <<= baseDirectory( dir => new IvyPaths(dir, Some(dir / "ivy-home")))
|
ivyPaths <<= baseDirectory( dir => new IvyPaths(dir, Some(dir / "ivy-home")))
|
||||||
|
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
#Project properties
|
|
||||||
#Fri Jan 30 20:49:57 EST 2009
|
|
||||||
project.name=Inline Dependency Test A
|
|
||||||
project.version=1.0
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
import sbt._
|
|
||||||
|
|
||||||
class UpdateTestProject(info: ProjectInfo) extends DefaultProject(info)
|
|
||||||
{
|
|
||||||
val sc = "org.scalacheck" % "scalacheck" % "1.5"
|
|
||||||
override def ivyCacheDirectory = Some(outputPath / "ivy-cache")
|
|
||||||
override def disableCrossPaths = true
|
|
||||||
}
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
object MakePomTest extends Build
|
object MakePomTest extends Build
|
||||||
{
|
{
|
||||||
lazy val root = Project("root", file(".")) settings(
|
lazy val root = Project("root", file(".")) settings(
|
||||||
|
resolvers += ScalaToolsReleases,
|
||||||
readPom <<= makePom map XML.loadFile,
|
readPom <<= makePom map XML.loadFile,
|
||||||
TaskKey[Unit]("check-pom") <<= checkPom,
|
TaskKey[Unit]("check-pom") <<= checkPom,
|
||||||
TaskKey[Unit]("check-extra") <<= checkExtra,
|
TaskKey[Unit]("check-extra") <<= checkExtra,
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,6 @@
|
||||||
moduleConfigurations += ModuleConfiguration("org.scala-lang", "*", "2.10.0-.*", scalaSnapshots)
|
moduleConfigurations += ModuleConfiguration("org.scala-lang", "*", "2.10.0-.*", scalaSnapshots)
|
||||||
}
|
}
|
||||||
|
|
||||||
libraryDependencies += "org.scala-lang" % "scala-compiler" % "2.10.0-20111001.020530-165"
|
libraryDependencies += "org.scala-lang" % "scala-compiler" % "2.10.0-20120122.024228-256"
|
||||||
|
|
||||||
resolvers := Nil
|
resolvers := Nil
|
||||||
|
|
@ -4,6 +4,6 @@
|
||||||
moduleConfigurations += ModuleConfiguration("org.not-scala-lang", "*", "2.10.0-.*", scalaSnapshots)
|
moduleConfigurations += ModuleConfiguration("org.not-scala-lang", "*", "2.10.0-.*", scalaSnapshots)
|
||||||
}
|
}
|
||||||
|
|
||||||
libraryDependencies += "org.scala-lang" % "scala-compiler" % "2.10.0-20111001.020530-165"
|
libraryDependencies += "org.scala-lang" % "scala-compiler" % "2.10.0-20120122.024228-256"
|
||||||
|
|
||||||
resolvers := Nil
|
resolvers := Nil
|
||||||
|
|
@ -4,6 +4,6 @@
|
||||||
moduleConfigurations += ModuleConfiguration("org.scala-lang", "*", "2.10.0-.*", scalaSnapshots)
|
moduleConfigurations += ModuleConfiguration("org.scala-lang", "*", "2.10.0-.*", scalaSnapshots)
|
||||||
}
|
}
|
||||||
|
|
||||||
libraryDependencies += "org.scala-lang" % "scala-compiler" % "2.10.0-20111001.020530-165"
|
libraryDependencies += "org.scala-lang" % "scala-compiler" % "2.10.0-20120122.024228-256"
|
||||||
|
|
||||||
resolvers := Nil
|
resolvers := Nil
|
||||||
|
|
@ -4,6 +4,6 @@
|
||||||
moduleConfigurations += ModuleConfiguration("org.scala-lang", "*", "2.10.0-.*", scalaSnapshots)
|
moduleConfigurations += ModuleConfiguration("org.scala-lang", "*", "2.10.0-.*", scalaSnapshots)
|
||||||
}
|
}
|
||||||
|
|
||||||
libraryDependencies += "org.scala-lang" % "scala-compiler" % "2.10.0-20111001.020530-164"
|
libraryDependencies += "org.scala-lang" % "scala-compiler" % "2.10.0-20120122.024228-255"
|
||||||
|
|
||||||
resolvers := Nil
|
resolvers := Nil
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
object ParentTest extends Build
|
object ParentTest extends Build
|
||||||
{
|
{
|
||||||
lazy val parent: Project = Project("Flowmodel", file(".")) aggregate(core, reporters)
|
lazy val parent: Project = Project("Flowmodel", file(".")) aggregate(core, reporters)
|
||||||
lazy val core: Project = Project("Flowmodel core", file("core"), delegates = parent :: Nil)
|
lazy val core: Project = Project("Flowmodel-core", file("core"), delegates = parent :: Nil)
|
||||||
lazy val reporters: Project = Project("Extra reporters", file("reporters"), delegates = parent :: Nil) aggregate(jfreechart) dependsOn(jfreechart)
|
lazy val reporters: Project = Project("Extra-reporters", file("reporters"), delegates = parent :: Nil) aggregate(jfreechart) dependsOn(jfreechart)
|
||||||
lazy val jfreechart: Project = Project("JFreeChart reporters", file("jfreechart")/*, delegates = reporters :: Nil*/) dependsOn(core)
|
lazy val jfreechart: Project = Project("JFreeChart-reporters", file("jfreechart")/*, delegates = reporters :: Nil*/) dependsOn(core)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
object PomRepoTest extends Build
|
object PomRepoTest extends Build
|
||||||
{
|
{
|
||||||
lazy val root = Project("root", file(".")) settings(
|
lazy val root = Project("root", file(".")) settings(
|
||||||
resolvers ++= Seq(local, ScalaToolsSnapshots),
|
resolvers ++= Seq(local, ScalaToolsReleases, ScalaToolsSnapshots),
|
||||||
InputKey[Unit]("check-pom") <<= InputTask(_ => spaceDelimited("<args>")) { result => (makePom, result, streams) map checkPomRepositories },
|
InputKey[Unit]("check-pom") <<= InputTask(_ => spaceDelimited("<args>")) { result => (makePom, result, streams) map checkPomRepositories },
|
||||||
makePomConfiguration <<= (makePomConfiguration, baseDirectory) { (conf, base) =>
|
makePomConfiguration <<= (makePomConfiguration, baseDirectory) { (conf, base) =>
|
||||||
conf.copy(filterRepositories = pomIncludeRepository(base, conf.filterRepositories) )
|
conf.copy(filterRepositories = pomIncludeRepository(base, conf.filterRepositories) )
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@ object PomTest extends Build
|
||||||
{
|
{
|
||||||
override def settings = super.settings :+ (TaskKey[Unit]("check-pom") <<= checkPom)
|
override def settings = super.settings :+ (TaskKey[Unit]("check-pom") <<= checkPom)
|
||||||
|
|
||||||
lazy val subJar = Project("Sub Jar", file("subJar"))
|
lazy val subJar = Project("sub-jar", file("subJar"))
|
||||||
lazy val subWar = Project("Sub War", file("subWar")) settings( warArtifact)
|
lazy val subWar = Project("sub-war", file("subWar")) settings( warArtifact)
|
||||||
lazy val subParent = Project("Sub Parent", file("subParent")) settings( publishArtifact in Compile := false )
|
lazy val subParent = Project("sub-parent", file("subParent")) settings( publishArtifact in Compile := false )
|
||||||
|
|
||||||
def art(p: ProjectReference) = makePom in p
|
def art(p: ProjectReference) = makePom in p
|
||||||
def checkPom = (art(subJar), art(subWar), art(subParent)) map { (jar, war, pom) =>
|
def checkPom = (art(subJar), art(subWar), art(subParent)) map { (jar, war, pom) =>
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,23 @@ import sbt._
|
||||||
import Keys._
|
import Keys._
|
||||||
object P extends Build
|
object P extends Build
|
||||||
{
|
{
|
||||||
override def settings = super.settings ++ Seq( scalaVersion in update := "2.9.0" )
|
override def settings = super.settings ++ Seq(
|
||||||
|
scalaBinaryVersion in update := "2.9.0",
|
||||||
|
resolvers += ScalaToolsReleases
|
||||||
|
)
|
||||||
|
|
||||||
|
def configIvyScala =
|
||||||
|
ivyScala ~= { _.map(_.copy(checkExplicit = false)) }
|
||||||
|
|
||||||
val declared = SettingKey[Boolean]("declared")
|
val declared = SettingKey[Boolean]("declared")
|
||||||
lazy val a = Project("A", file("a")) settings(
|
lazy val a = Project("A", file("a")) settings(
|
||||||
libraryDependencies += "org.scala-tools.sbinary" %% "sbinary" % "0.4.0" % "provided"
|
libraryDependencies += "org.scala-tools.sbinary" %% "sbinary" % "0.4.0" % "provided",
|
||||||
|
configIvyScala
|
||||||
)
|
)
|
||||||
|
|
||||||
lazy val b = Project("B", file("b")) dependsOn(a) settings(
|
lazy val b = Project("B", file("b")) dependsOn(a) settings(
|
||||||
libraryDependencies <<= declared(d => if(d) Seq("org.scala-tools.sbinary" %% "sbinary" % "0.4.0" % "provided") else Nil),
|
libraryDependencies <<= declared(d => if(d) Seq("org.scala-tools.sbinary" %% "sbinary" % "0.4.0" % "provided") else Nil),
|
||||||
declared <<= baseDirectory(_ / "declare.lib" exists)
|
declared <<= baseDirectory(_ / "declare.lib" exists),
|
||||||
|
configIvyScala
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
libraryDependencies <<= (libraryDependencies, appConfiguration) { (deps, conf) =>
|
libraryDependencies <<= (libraryDependencies, appConfiguration) { (deps, conf) =>
|
||||||
deps :+ ("org.scala-tools.sbt" %% "sbt" % conf.provider.id.version)
|
deps :+ ("org.scala-sbt" %% "sbt" % conf.provider.id.version)
|
||||||
}
|
}
|
||||||
|
|
@ -3,6 +3,10 @@ import Keys._
|
||||||
|
|
||||||
object Build extends Build
|
object Build extends Build
|
||||||
{
|
{
|
||||||
|
override def settings = super.settings ++ Seq(
|
||||||
|
sbtBinaryVersion <<= sbtVersion
|
||||||
|
)
|
||||||
|
|
||||||
lazy val root = Project("root", file(".")) aggregate(a,b,c)
|
lazy val root = Project("root", file(".")) aggregate(a,b,c)
|
||||||
lazy val a = Project("a", file("a"))
|
lazy val a = Project("a", file("a"))
|
||||||
lazy val b = Project("b", file("b"))
|
lazy val b = Project("b", file("b"))
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
libraryDependencies += "org.scalatest" % "scalatest" % "1.3"
|
libraryDependencies += "org.scalatest" %% "scalatest" % "1.6.1" % "test"
|
||||||
|
|
||||||
|
|
||||||
testOptions in Configurations.Test ++= {
|
testOptions in Configurations.Test ++= {
|
||||||
def args(path: String, args: String*): Seq[TestOption] = if(file(path).exists) Tests.Argument(args : _*) :: Nil else Nil
|
def args(path: String, args: String*): Seq[TestOption] = if(file(path).exists) Tests.Argument(args : _*) :: Nil else Nil
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import org.specs._
|
import org.specs2.mutable._
|
||||||
|
|
||||||
class B extends Specification
|
class B extends Specification
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import org.specs._
|
import org.specs2.mutable._
|
||||||
|
|
||||||
class B extends Specification
|
class B extends Specification
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import org.specs._
|
import org.specs2.mutable._
|
||||||
|
|
||||||
class B extends Specification
|
class B extends Specification
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import org.specs._
|
import org.specs2.mutable._
|
||||||
|
|
||||||
class B extends Specification
|
class B extends Specification
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,11 @@ object B extends Build
|
||||||
lazy val root =
|
lazy val root =
|
||||||
Project("root", file("."))
|
Project("root", file("."))
|
||||||
.configs( IntegrationTest )
|
.configs( IntegrationTest )
|
||||||
.settings( libraryDependencies += specs )
|
|
||||||
.settings( Defaults.itSettings : _*)
|
.settings( Defaults.itSettings : _*)
|
||||||
|
.settings(
|
||||||
|
libraryDependencies += specs,
|
||||||
|
resolvers += ScalaToolsReleases
|
||||||
|
)
|
||||||
|
|
||||||
lazy val specs = "org.scala-tools.testing" %% "specs" % "1.6.7.2" % "it,test" intransitive()
|
lazy val specs = "org.specs2" %% "specs2" % "1.7.1" % "it,test"
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
resolvers += ScalaToolsReleases
|
||||||
|
|
||||||
|
libraryDependencies += "com.novocode" % "junit-interface" % "0.8" % "test"
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
package com.foo.junit.test.blah
|
||||||
|
|
||||||
|
import org.junit._
|
||||||
|
|
||||||
|
class Failure
|
||||||
|
{
|
||||||
|
@Test def fail() { error("Fail!") }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
package com.foo.junit.test.blah
|
||||||
|
|
||||||
|
import org.junit._
|
||||||
|
|
||||||
|
class Success
|
||||||
|
{
|
||||||
|
@Test def succeed() { }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
> test
|
||||||
|
|
||||||
|
$ copy-file changes/Success.scala src/test/scala/Success.scala
|
||||||
|
> test
|
||||||
|
|
||||||
|
> test-only com.foo.junit.test.blah.Success
|
||||||
|
|
||||||
|
$ copy-file changes/Failure.scala src/test/scala/Failure.scala
|
||||||
|
-> test
|
||||||
|
-> test-only com.foo.junit.test.blah.Failure
|
||||||
|
> test-only com.foo.junit.test.blah.Success
|
||||||
|
|
@ -1 +1,3 @@
|
||||||
libraryDependencies += "org.scala-tools.testing" %% "specs" % "1.6.7.2" intransitive()
|
libraryDependencies += "org.specs2" %% "specs2" % "1.7.1" % "test"
|
||||||
|
|
||||||
|
resolvers += ScalaToolsReleases
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import org.specs._
|
import org.specs2.mutable._
|
||||||
|
|
||||||
object BasicTest extends Specification
|
object BasicTest extends Specification
|
||||||
{
|
{
|
||||||
"Test resource on test classpath" in {
|
"Test resource on test classpath" in {
|
||||||
getClass.getResource("TestResource.txt") mustNotBe null
|
getClass.getResource("TestResource.txt") must not beNull
|
||||||
}
|
}
|
||||||
"Main resource on test classpath" in {
|
"Main resource on test classpath" in {
|
||||||
getClass.getResource("MainResource.txt") mustNotBe null
|
getClass.getResource("MainResource.txt") must not beNull
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1 +1,3 @@
|
||||||
libraryDependencies += "org.scala-tools.testing" %% "specs" % "1.6.7.2" intransitive()
|
libraryDependencies += "org.specs2" %% "specs2" % "1.7.1" % "test"
|
||||||
|
|
||||||
|
resolvers += ScalaToolsReleases
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import org.specs._
|
import org.specs2.mutable._
|
||||||
|
|
||||||
class B extends Specification
|
class B extends Specification
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import org.specs._
|
import org.specs2.mutable._
|
||||||
|
|
||||||
class B extends Specification
|
class B extends Specification
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import org.specs._
|
import org.specs2.mutable._
|
||||||
|
|
||||||
class B extends Specification
|
class B extends Specification
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import org.specs._
|
import org.specs2.mutable._
|
||||||
|
|
||||||
class B extends Specification
|
class B extends Specification
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ object ScriptedPlugin extends Plugin {
|
||||||
ivyConfigurations += scriptedConf,
|
ivyConfigurations += scriptedConf,
|
||||||
scriptedSbt <<= (appConfiguration)(_.provider.id.version),
|
scriptedSbt <<= (appConfiguration)(_.provider.id.version),
|
||||||
scriptedScalas <<= (scalaVersion) { (scala) => ScriptedScalas(scala, scala) },
|
scriptedScalas <<= (scalaVersion) { (scala) => ScriptedScalas(scala, scala) },
|
||||||
libraryDependencies <<= (libraryDependencies, scriptedScalas, scriptedSbt) {(deps, scalas, version) => deps :+ "org.scala-tools.sbt" % ("scripted-sbt_" + scalas.build) % version % scriptedConf.toString },
|
libraryDependencies <<= (libraryDependencies, scriptedScalas, scriptedSbt) {(deps, scalas, version) => deps :+ "org.scala-sbt" % ("scripted-sbt_" + scalas.build) % version % scriptedConf.toString },
|
||||||
sbtLauncher <<= (appConfiguration)(app => IO.classLocationFile(app.provider.scalaProvider.launcher.getClass)),
|
sbtLauncher <<= (appConfiguration)(app => IO.classLocationFile(app.provider.scalaProvider.launcher.getClass)),
|
||||||
sbtTestDirectory <<= sourceDirectory / "sbt-test",
|
sbtTestDirectory <<= sourceDirectory / "sbt-test",
|
||||||
scriptedBufferLog := true,
|
scriptedBufferLog := true,
|
||||||
|
|
|
||||||
|
|
@ -92,12 +92,12 @@ object ScriptedTests
|
||||||
val bootProperties = new File(args(5))
|
val bootProperties = new File(args(5))
|
||||||
val tests = args.drop(6)
|
val tests = args.drop(6)
|
||||||
val logger = ConsoleLogger()
|
val logger = ConsoleLogger()
|
||||||
run(directory, buffer, sbtVersion, defScalaVersion, buildScalaVersions, tests, logger, bootProperties, Seq())
|
run(directory, buffer, sbtVersion, defScalaVersion, buildScalaVersions, tests, logger, bootProperties, Array())
|
||||||
}
|
}
|
||||||
def run(resourceBaseDirectory: File, bufferLog: Boolean, sbtVersion: String, defScalaVersion: String, buildScalaVersions: String, tests: Array[String], bootProperties: File, launchOpts: Seq[String]): Unit =
|
def run(resourceBaseDirectory: File, bufferLog: Boolean, sbtVersion: String, defScalaVersion: String, buildScalaVersions: String, tests: Array[String], bootProperties: File, launchOpts: Array[String]): Unit =
|
||||||
run(resourceBaseDirectory, bufferLog, sbtVersion, defScalaVersion, buildScalaVersions, tests, ConsoleLogger(), bootProperties, launchOpts)//new FullLogger(Logger.xlog2Log(log)))
|
run(resourceBaseDirectory, bufferLog, sbtVersion, defScalaVersion, buildScalaVersions, tests, ConsoleLogger(), bootProperties, launchOpts)//new FullLogger(Logger.xlog2Log(log)))
|
||||||
|
|
||||||
def run(resourceBaseDirectory: File, bufferLog: Boolean, sbtVersion: String, defScalaVersion: String, buildScalaVersions: String, tests: Array[String], logger: AbstractLogger, bootProperties: File, launchOpts: Seq[String])
|
def run(resourceBaseDirectory: File, bufferLog: Boolean, sbtVersion: String, defScalaVersion: String, buildScalaVersions: String, tests: Array[String], logger: AbstractLogger, bootProperties: File, launchOpts: Array[String])
|
||||||
{
|
{
|
||||||
val runner = new ScriptedTests(resourceBaseDirectory, bufferLog, sbtVersion, defScalaVersion, buildScalaVersions, bootProperties, launchOpts)
|
val runner = new ScriptedTests(resourceBaseDirectory, bufferLog, sbtVersion, defScalaVersion, buildScalaVersions, bootProperties, launchOpts)
|
||||||
for( ScriptedTest(group, name) <- get(tests, resourceBaseDirectory, logger) )
|
for( ScriptedTest(group, name) <- get(tests, resourceBaseDirectory, logger) )
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
version: 2.9.1
|
version: 2.9.1
|
||||||
|
|
||||||
[app]
|
[app]
|
||||||
org: org.scala-tools.sbt
|
org: org.scala-sbt
|
||||||
name: sbt
|
name: sbt
|
||||||
version: read(sbt.version)[0.12.0-SNAPSHOT]
|
version: read(sbt.version)[0.12.0-SNAPSHOT]
|
||||||
class: ${sbt.main.class-sbt.xMain}
|
class: ${sbt.main.class-sbt.xMain}
|
||||||
|
|
@ -13,8 +13,6 @@
|
||||||
local
|
local
|
||||||
typesafe-ivy-releases: http://repo.typesafe.com/typesafe/ivy-releases/, [organization]/[module]/[revision]/[type]s/[artifact](-[classifier]).[ext]
|
typesafe-ivy-releases: http://repo.typesafe.com/typesafe/ivy-releases/, [organization]/[module]/[revision]/[type]s/[artifact](-[classifier]).[ext]
|
||||||
maven-central
|
maven-central
|
||||||
scala-tools-releases
|
|
||||||
scala-tools-snapshots
|
|
||||||
|
|
||||||
[ivy]
|
[ivy]
|
||||||
ivy-home: ${sbt.ivy.home-${user.home}/.ivy2/}
|
ivy-home: ${sbt.ivy.home-${user.home}/.ivy2/}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
version: 2.9.1
|
version: 2.9.1
|
||||||
|
|
||||||
[app]
|
[app]
|
||||||
org: org.scala-tools.sbt
|
org: org.scala-sbt
|
||||||
name: sbt
|
name: sbt
|
||||||
version: 0.12.0-SNAPSHOT
|
version: 0.12.0-SNAPSHOT
|
||||||
class: sbt.ScriptMain
|
class: sbt.ScriptMain
|
||||||
|
|
@ -13,5 +13,3 @@
|
||||||
local
|
local
|
||||||
typesafe-ivy-releases: http://repo.typesafe.com/typesafe/ivy-releases/, [organization]/[module]/[revision]/[type]s/[artifact](-[classifier]).[ext]
|
typesafe-ivy-releases: http://repo.typesafe.com/typesafe/ivy-releases/, [organization]/[module]/[revision]/[type]s/[artifact](-[classifier]).[ext]
|
||||||
maven-central
|
maven-central
|
||||||
scala-tools-releases
|
|
||||||
scala-tools-snapshots
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
version: 2.9.1
|
version: 2.9.1
|
||||||
|
|
||||||
[app]
|
[app]
|
||||||
org: org.scala-tools.sbt
|
org: org.scala-sbt
|
||||||
name: sbt
|
name: sbt
|
||||||
version: 0.12.0-SNAPSHOT
|
version: 0.12.0-SNAPSHOT
|
||||||
class: sbt.ConsoleMain
|
class: sbt.ConsoleMain
|
||||||
|
|
@ -13,5 +13,3 @@
|
||||||
local
|
local
|
||||||
typesafe-ivy-releases: http://repo.typesafe.com/typesafe/ivy-releases/, [organization]/[module]/[revision]/[type]s/[artifact](-[classifier]).[ext]
|
typesafe-ivy-releases: http://repo.typesafe.com/typesafe/ivy-releases/, [organization]/[module]/[revision]/[type]s/[artifact](-[classifier]).[ext]
|
||||||
maven-central
|
maven-central
|
||||||
scala-tools-releases
|
|
||||||
scala-tools-snapshots
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import Incomplete.{Error, Value => IValue}
|
||||||
* @param causes a list of incompletions that prevented `node` from completing
|
* @param causes a list of incompletions that prevented `node` from completing
|
||||||
* @param directCause the exception that caused `node` to not complete */
|
* @param directCause the exception that caused `node` to not complete */
|
||||||
final case class Incomplete(node: Option[AnyRef], tpe: IValue = Error, message: Option[String] = None, causes: Seq[Incomplete] = Nil, directCause: Option[Throwable] = None)
|
final case class Incomplete(node: Option[AnyRef], tpe: IValue = Error, message: Option[String] = None, causes: Seq[Incomplete] = Nil, directCause: Option[Throwable] = None)
|
||||||
extends Exception(message.orNull, directCause.orNull) {
|
extends Exception(message.orNull, directCause.orNull) with UnprintableException {
|
||||||
override def toString = "Incomplete(node=" + node + ", tpe=" + tpe + ", msg=" + message + ", causes=" + causes + ", directCause=" + directCause +")"
|
override def toString = "Incomplete(node=" + node + ", tpe=" + tpe + ", msg=" + message + ", causes=" + causes + ", directCause=" + directCause +")"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ class TestFramework(val implClassName: String)
|
||||||
try { Some(Class.forName(implClassName, true, loader).newInstance.asInstanceOf[Framework]) }
|
try { Some(Class.forName(implClassName, true, loader).newInstance.asInstanceOf[Framework]) }
|
||||||
catch { case e: ClassNotFoundException => log.debug("Framework implementation '" + implClassName + "' not present."); None }
|
catch { case e: ClassNotFoundException => log.debug("Framework implementation '" + implClassName + "' not present."); None }
|
||||||
}
|
}
|
||||||
|
override def toString = "TestFramework(" + implClassName + ")"
|
||||||
}
|
}
|
||||||
final class TestDefinition(val name: String, val fingerprint: Fingerprint)
|
final class TestDefinition(val name: String, val fingerprint: Fingerprint)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -177,7 +177,7 @@ trait Init[Scope]
|
||||||
if(dist < 0) None else Some(dist)
|
if(dist < 0) None else Some(dist)
|
||||||
}
|
}
|
||||||
|
|
||||||
final class Uninitialized(val undefined: Seq[Undefined], msg: String) extends Exception(msg)
|
final class Uninitialized(val undefined: Seq[Undefined], override val toString: String) extends Exception(toString)
|
||||||
final class Undefined(val definingKey: ScopedKey[_], val referencedKey: ScopedKey[_])
|
final class Undefined(val definingKey: ScopedKey[_], val referencedKey: ScopedKey[_])
|
||||||
final class RuntimeUndefined(val undefined: Seq[Undefined]) extends RuntimeException("References to undefined settings at runtime.")
|
final class RuntimeUndefined(val undefined: Seq[Undefined]) extends RuntimeException("References to undefined settings at runtime.")
|
||||||
def Undefined(definingKey: ScopedKey[_], referencedKey: ScopedKey[_]): Undefined = new Undefined(definingKey, referencedKey)
|
def Undefined(definingKey: ScopedKey[_], referencedKey: ScopedKey[_]): Undefined = new Undefined(definingKey, referencedKey)
|
||||||
|
|
|
||||||
|
|
@ -4,4 +4,11 @@
|
||||||
package sbt
|
package sbt
|
||||||
|
|
||||||
final class MessageOnlyException(override val toString: String) extends RuntimeException(toString)
|
final class MessageOnlyException(override val toString: String) extends RuntimeException(toString)
|
||||||
final class NoMessageException extends RuntimeException
|
|
||||||
|
/** A dummy exception for the top-level exception handler to know that an exception
|
||||||
|
* has been handled, but is being passed further up to indicate general failure. */
|
||||||
|
final class AlreadyHandledException extends RuntimeException
|
||||||
|
|
||||||
|
/** A marker trait for a top-level exception handler to know that this exception
|
||||||
|
* doesn't make sense to display. */
|
||||||
|
trait UnprintableException extends Throwable
|
||||||
|
|
@ -17,6 +17,7 @@ import scala.collection.mutable.{HashMap,HashSet}
|
||||||
import scala.reflect.{Manifest => SManifest}
|
import scala.reflect.{Manifest => SManifest}
|
||||||
import Function.tupled
|
import Function.tupled
|
||||||
|
|
||||||
|
/** A collection of File, URL, and I/O utility methods.*/
|
||||||
object IO
|
object IO
|
||||||
{
|
{
|
||||||
/** The maximum number of times a unique temporary filename is attempted to be created.*/
|
/** The maximum number of times a unique temporary filename is attempted to be created.*/
|
||||||
|
|
@ -26,21 +27,40 @@ object IO
|
||||||
val temporaryDirectory = new File(System.getProperty("java.io.tmpdir"))
|
val temporaryDirectory = new File(System.getProperty("java.io.tmpdir"))
|
||||||
/** The size of the byte or char buffer used in various methods.*/
|
/** The size of the byte or char buffer used in various methods.*/
|
||||||
private val BufferSize = 8192
|
private val BufferSize = 8192
|
||||||
|
|
||||||
|
/** The newline string for this system, as obtained by the line.separator system property. */
|
||||||
val Newline = System.getProperty("line.separator")
|
val Newline = System.getProperty("line.separator")
|
||||||
|
|
||||||
val utf8 = Charset.forName("UTF-8")
|
val utf8 = Charset.forName("UTF-8")
|
||||||
|
|
||||||
|
/** Returns a URL for the directory or jar containing the the class file `cl`.
|
||||||
|
* If the location cannot be determined, an error is generated.
|
||||||
|
* Note that Java standard library classes typically do not have a location associated with them.*/
|
||||||
def classLocation(cl: Class[_]): URL =
|
def classLocation(cl: Class[_]): URL =
|
||||||
{
|
{
|
||||||
val codeSource = cl.getProtectionDomain.getCodeSource
|
val codeSource = cl.getProtectionDomain.getCodeSource
|
||||||
if(codeSource == null) error("No class location for " + cl)
|
if(codeSource == null) error("No class location for " + cl)
|
||||||
else codeSource.getLocation
|
else codeSource.getLocation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the directory or jar file containing the the class file `cl`.
|
||||||
|
* If the location cannot be determined or it is not a file, an error is generated.
|
||||||
|
* Note that Java standard library classes typically do not have a location associated with them.*/
|
||||||
def classLocationFile(cl: Class[_]): File = toFile(classLocation(cl))
|
def classLocationFile(cl: Class[_]): File = toFile(classLocation(cl))
|
||||||
|
|
||||||
|
/** Returns a URL for the directory or jar containing the class file for type `T` (as determined by an implicit Manifest).
|
||||||
|
* If the location cannot be determined, an error is generated.
|
||||||
|
* Note that Java standard library classes typically do not have a location associated with them.*/
|
||||||
def classLocation[T](implicit mf: SManifest[T]): URL = classLocation(mf.erasure)
|
def classLocation[T](implicit mf: SManifest[T]): URL = classLocation(mf.erasure)
|
||||||
|
|
||||||
|
/** Returns the directory or jar file containing the the class file for type `T` (as determined by an implicit Manifest).
|
||||||
|
* If the location cannot be determined, an error is generated.
|
||||||
|
* Note that Java standard library classes typically do not have a location associated with them.*/
|
||||||
def classLocationFile[T](implicit mf: SManifest[T]): File = classLocationFile(mf.erasure)
|
def classLocationFile[T](implicit mf: SManifest[T]): File = classLocationFile(mf.erasure)
|
||||||
|
|
||||||
def toFile(url: URL) =
|
/** Constructs a File corresponding to `url`, which must have a scheme of `file`.
|
||||||
|
* This method properly works around an issue with a simple conversion to URI and then to a File. */
|
||||||
|
def toFile(url: URL): File =
|
||||||
try { new File(url.toURI) }
|
try { new File(url.toURI) }
|
||||||
catch { case _: URISyntaxException => new File(url.getPath) }
|
catch { case _: URISyntaxException => new File(url.getPath) }
|
||||||
|
|
||||||
|
|
@ -61,6 +81,13 @@ object IO
|
||||||
def assertDirectories(file: File*) { file.foreach(assertDirectory) }
|
def assertDirectories(file: File*) { file.foreach(assertDirectory) }
|
||||||
|
|
||||||
// "base.extension" -> (base, extension)
|
// "base.extension" -> (base, extension)
|
||||||
|
/** Splits the given string into base and extension strings.
|
||||||
|
* If `name` contains no period, the base string is the input string and the extension is the empty string.
|
||||||
|
* Otherwise, the base is the substring up until the last period (exclusive) and
|
||||||
|
* the extension is the substring after the last period.
|
||||||
|
*
|
||||||
|
* For example, `split("Build.scala") == ("Build", "scala")`
|
||||||
|
*/
|
||||||
def split(name: String): (String, String) =
|
def split(name: String): (String, String) =
|
||||||
{
|
{
|
||||||
val lastDot = name.lastIndexOf('.')
|
val lastDot = name.lastIndexOf('.')
|
||||||
|
|
@ -70,8 +97,13 @@ object IO
|
||||||
(name, "")
|
(name, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Each input file in `files` is created if it doesn't exist.
|
||||||
|
* If a file already exists, the last modified time is set to the current time.
|
||||||
|
* It is not guaranteed that all files will have the same last modified time after this call.*/
|
||||||
def touch(files: Traversable[File]): Unit = files.foreach(f => touch(f))
|
def touch(files: Traversable[File]): Unit = files.foreach(f => touch(f))
|
||||||
/** Creates a file at the given location.*/
|
|
||||||
|
/** Creates a file at the given location if it doesn't exist.
|
||||||
|
* If the file already exists and `setModified` is true, this method sets the last modified time to the current time.*/
|
||||||
def touch(file: File, setModified: Boolean = true)
|
def touch(file: File, setModified: Boolean = true)
|
||||||
{
|
{
|
||||||
val absFile = file.getAbsoluteFile
|
val absFile = file.getAbsoluteFile
|
||||||
|
|
@ -178,13 +210,16 @@ object IO
|
||||||
transfer(inputStream, to)
|
transfer(inputStream, to)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Copies the contents of `in` to `out`.*/
|
||||||
def transfer(in: File, out: File): Unit =
|
def transfer(in: File, out: File): Unit =
|
||||||
fileInputStream(in){ in => transfer(in, out) }
|
fileInputStream(in){ in => transfer(in, out) }
|
||||||
|
|
||||||
|
/** Copies the contents of the input file `in` to the `out` stream.
|
||||||
|
* The output stream is not closed by this method.*/
|
||||||
def transfer(in: File, out: OutputStream): Unit =
|
def transfer(in: File, out: OutputStream): Unit =
|
||||||
fileInputStream(in){ in => transfer(in, out) }
|
fileInputStream(in){ in => transfer(in, out) }
|
||||||
|
|
||||||
/** Copies all bytes from the given input stream to the given File.*/
|
/** Copies all bytes from the given input stream to the given File. The input stream is not closed by this method.*/
|
||||||
def transfer(in: InputStream, to: File): Unit =
|
def transfer(in: InputStream, to: File): Unit =
|
||||||
Using.fileOutputStream()(to) { outputStream =>
|
Using.fileOutputStream()(to) { outputStream =>
|
||||||
transfer(in, outputStream)
|
transfer(in, outputStream)
|
||||||
|
|
@ -223,7 +258,11 @@ object IO
|
||||||
try { action(dir) }
|
try { action(dir) }
|
||||||
finally { delete(dir) }
|
finally { delete(dir) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Creates a directory in the default temporary directory with a name generated from a random integer. */
|
||||||
def createTemporaryDirectory: File = createUniqueDirectory(temporaryDirectory)
|
def createTemporaryDirectory: File = createUniqueDirectory(temporaryDirectory)
|
||||||
|
|
||||||
|
/** Creates a directory in `baseDirectory` with a name generated from a random integer */
|
||||||
def createUniqueDirectory(baseDirectory: File): File =
|
def createUniqueDirectory(baseDirectory: File): File =
|
||||||
{
|
{
|
||||||
def create(tries: Int): File =
|
def create(tries: Int): File =
|
||||||
|
|
@ -241,6 +280,8 @@ object IO
|
||||||
}
|
}
|
||||||
create(0)
|
create(0)
|
||||||
}
|
}
|
||||||
|
/** Creates a file in the default temporary directory, calls `action` with the file, deletes the file, and returns the result of calling `action`.
|
||||||
|
* The name of the file will begin with `prefix`, which must be at least three characters long, and end with `postfix`, which has no minimum length. */
|
||||||
def withTemporaryFile[T](prefix: String, postfix: String)(action: File => T): T =
|
def withTemporaryFile[T](prefix: String, postfix: String)(action: File => T): T =
|
||||||
{
|
{
|
||||||
val file = File.createTempFile(prefix, postfix)
|
val file = File.createTempFile(prefix, postfix)
|
||||||
|
|
@ -250,6 +291,7 @@ object IO
|
||||||
|
|
||||||
private[sbt] def jars(dir: File): Iterable[File] = listFiles(dir, GlobFilter("*.jar"))
|
private[sbt] def jars(dir: File): Iterable[File] = listFiles(dir, GlobFilter("*.jar"))
|
||||||
|
|
||||||
|
/** Deletes all empty directories in the set. Any non-empty directories are ignored. */
|
||||||
def deleteIfEmpty(dirs: collection.Set[File]): Unit =
|
def deleteIfEmpty(dirs: collection.Set[File]): Unit =
|
||||||
{
|
{
|
||||||
val isEmpty = new HashMap[File, Boolean]
|
val isEmpty = new HashMap[File, Boolean]
|
||||||
|
|
@ -259,7 +301,10 @@ object IO
|
||||||
for( (f, true) <- isEmpty) f.delete
|
for( (f, true) <- isEmpty) f.delete
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Deletes each file or directory (recursively) in `files`.*/
|
||||||
def delete(files: Iterable[File]): Unit = files.foreach(delete)
|
def delete(files: Iterable[File]): Unit = files.foreach(delete)
|
||||||
|
|
||||||
|
/** Deletes `file`, recursively if it is a directory. */
|
||||||
def delete(file: File)
|
def delete(file: File)
|
||||||
{
|
{
|
||||||
translate("Error deleting file " + file + ": ")
|
translate("Error deleting file " + file + ": ")
|
||||||
|
|
@ -273,26 +318,32 @@ object IO
|
||||||
file.delete
|
file.delete
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the children of directory `dir` that match `filter` in a non-null array.*/
|
||||||
def listFiles(filter: java.io.FileFilter)(dir: File): Array[File] = wrapNull(dir.listFiles(filter))
|
def listFiles(filter: java.io.FileFilter)(dir: File): Array[File] = wrapNull(dir.listFiles(filter))
|
||||||
|
|
||||||
|
/** Returns the children of directory `dir` that match `filter` in a non-null array.*/
|
||||||
def listFiles(dir: File, filter: java.io.FileFilter): Array[File] = wrapNull(dir.listFiles(filter))
|
def listFiles(dir: File, filter: java.io.FileFilter): Array[File] = wrapNull(dir.listFiles(filter))
|
||||||
|
|
||||||
|
/** Returns the children of directory `dir` in a non-null array.*/
|
||||||
def listFiles(dir: File): Array[File] = wrapNull(dir.listFiles())
|
def listFiles(dir: File): Array[File] = wrapNull(dir.listFiles())
|
||||||
|
|
||||||
private[sbt] def wrapNull(a: Array[File]) =
|
private[sbt] def wrapNull(a: Array[File]) =
|
||||||
{
|
|
||||||
if(a == null)
|
if(a == null)
|
||||||
new Array[File](0)
|
new Array[File](0)
|
||||||
else
|
else
|
||||||
a
|
a
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Creates a jar file.
|
/** Creates a jar file.
|
||||||
* @param sources The files to include in the jar file paired with the entry name in the jar.
|
* @param sources The files to include in the jar file paired with the entry name in the jar. Only the pairs explicitly listed are included.
|
||||||
* @param outputJar The file to write the jar to.
|
* @param outputJar The file to write the jar to.
|
||||||
* @param manifest The manifest for the jar.*/
|
* @param manifest The manifest for the jar.*/
|
||||||
def jar(sources: Traversable[(File,String)], outputJar: File, manifest: Manifest): Unit =
|
def jar(sources: Traversable[(File,String)], outputJar: File, manifest: Manifest): Unit =
|
||||||
archive(sources.toSeq, outputJar, Some(manifest))
|
archive(sources.toSeq, outputJar, Some(manifest))
|
||||||
|
|
||||||
/** Creates a zip file.
|
/** Creates a zip file.
|
||||||
* @param sources The files to include in the zip file paired with the entry name in the zip.
|
* @param sources The files to include in the zip file paired with the entry name in the zip. Only the pairs explicitly listed are included.
|
||||||
* @param outputZip The file to write the zip to.*/
|
* @param outputZip The file to write the zip to.*/
|
||||||
def zip(sources: Traversable[(File,String)], outputZip: File): Unit =
|
def zip(sources: Traversable[(File,String)], outputZip: File): Unit =
|
||||||
archive(sources.toSeq, outputZip, None)
|
archive(sources.toSeq, outputZip, None)
|
||||||
|
|
|
||||||
|
|
@ -139,6 +139,13 @@ sealed abstract class PathFinder
|
||||||
final def \ (literal: String): PathFinder = this / literal
|
final def \ (literal: String): PathFinder = this / literal
|
||||||
|
|
||||||
def x_: Traversable[(File,T)] = x(mapper, false)
|
def x_: Traversable[(File,T)] = x(mapper, false)
|
||||||
|
|
||||||
|
/** Applies `mapper` to each path selected by this PathFinder and returns the path paired with the non-empty result.
|
||||||
|
* If the result is empty (None) and `errorIfNone` is true, an exception is thrown.
|
||||||
|
* If `errorIfNone` is false, the path is dropped from the returned Traversable.*/
|
||||||
|
def pair[T](mapper: File => Option[T], errorIfNone: Boolean = true): Seq[(File,T)] =
|
||||||
|
x(mapper, errorIfNone)
|
||||||
|
|
||||||
/** Applies `mapper` to each path selected by this PathFinder and returns the path paired with the non-empty result.
|
/** Applies `mapper` to each path selected by this PathFinder and returns the path paired with the non-empty result.
|
||||||
* If the result is empty (None) and `errorIfNone` is true, an exception is thrown.
|
* If the result is empty (None) and `errorIfNone` is true, an exception is thrown.
|
||||||
* If `errorIfNone` is false, the path is dropped from the returned Traversable.*/
|
* If `errorIfNone` is false, the path is dropped from the returned Traversable.*/
|
||||||
|
|
@ -154,7 +161,7 @@ sealed abstract class PathFinder
|
||||||
* <code>descendantsExcept("*.jar", ".svn")</code>*/
|
* <code>descendantsExcept("*.jar", ".svn")</code>*/
|
||||||
def descendantsExcept(include: FileFilter, intermediateExclude: FileFilter): PathFinder =
|
def descendantsExcept(include: FileFilter, intermediateExclude: FileFilter): PathFinder =
|
||||||
(this ** include) --- (this ** intermediateExclude ** include)
|
(this ** include) --- (this ** intermediateExclude ** include)
|
||||||
@deprecated("Use `descendantsExcept` instead.", "0.11.3")
|
@deprecated("Use `descendantsExcept` instead.", "0.12.0")
|
||||||
def descendentsExcept(include: FileFilter, intermediateExclude: FileFilter): PathFinder =
|
def descendentsExcept(include: FileFilter, intermediateExclude: FileFilter): PathFinder =
|
||||||
descendantsExcept(include, intermediateExclude)
|
descendantsExcept(include, intermediateExclude)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,35 +10,62 @@ trait Mapper
|
||||||
type PathMap = File => Option[String]
|
type PathMap = File => Option[String]
|
||||||
type FileMap = File => Option[File]
|
type FileMap = File => Option[File]
|
||||||
|
|
||||||
|
/** A path mapper that pairs a File with the path returned by calling `getPath` on it.*/
|
||||||
val basic: PathMap = f => Some(f.getPath)
|
val basic: PathMap = f => Some(f.getPath)
|
||||||
|
|
||||||
|
/** A path mapper that pairs a File with its path relative to `base`.
|
||||||
|
* If the File is not a descendant of `base`, it is not handled (None is returned by the mapper). */
|
||||||
def relativeTo(base: File): PathMap = IO.relativize(base, _)
|
def relativeTo(base: File): PathMap = IO.relativize(base, _)
|
||||||
|
|
||||||
def relativeTo(bases: Iterable[File], zero: PathMap = transparent): PathMap = fold(zero, bases)(relativeTo)
|
def relativeTo(bases: Iterable[File], zero: PathMap = transparent): PathMap = fold(zero, bases)(relativeTo)
|
||||||
|
|
||||||
def rebase(oldBase: File, newBase0: String): PathMap =
|
/** A path mapper that pairs a descendent of `oldBase` with `newBase` prepended to the path relative to `oldBase`.
|
||||||
|
* For example, if `oldBase = /old/x/` and `newBase = new/a/`, then `/old/x/y/z.txt` gets paired with `new/a/y/z.txt`. */
|
||||||
|
def rebase(oldBase: File, newBase: String): PathMap =
|
||||||
{
|
{
|
||||||
val newBase = normalizeBase(newBase0)
|
val normNewBase = normalizeBase(newBase)
|
||||||
(file: File) =>
|
(file: File) =>
|
||||||
if(file == oldBase)
|
if(file == oldBase)
|
||||||
Some( if(newBase.isEmpty) "." else newBase )
|
Some( if(normNewBase.isEmpty) "." else normNewBase )
|
||||||
else
|
else
|
||||||
IO.relativize(oldBase, file).map(newBase + _)
|
IO.relativize(oldBase, file).map(normNewBase + _)
|
||||||
}
|
}
|
||||||
|
/** A mapper that throws an exception for any input. This is useful as the last mapper in a pipeline to ensure every input gets mapped.*/
|
||||||
def fail: Any => Nothing = f => error("No mapping for " + f)
|
def fail: Any => Nothing = f => error("No mapping for " + f)
|
||||||
|
|
||||||
|
/** A path mapper that pairs a File with its name. For example, `/x/y/z.txt` gets paired with `z.txt`.*/
|
||||||
val flat: PathMap = f => Some(f.getName)
|
val flat: PathMap = f => Some(f.getName)
|
||||||
def flatRebase(newBase0: String): PathMap =
|
|
||||||
|
/** A path mapper that pairs a File with a path constructed from `newBase` and the file's name.
|
||||||
|
* For example, if `newBase = /new/a/`, then `/old/x/z.txt` gets paired with `/new/a/z.txt`. */
|
||||||
|
def flatRebase(newBase: String): PathMap =
|
||||||
{
|
{
|
||||||
val newBase = normalizeBase(newBase0)
|
val newBase0 = normalizeBase(newBase)
|
||||||
f => Some(newBase + f.getName)
|
f => Some(newBase0 + f.getName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** A mapper that is defined on all inputs by the function `f`.*/
|
||||||
def total[A,B](f: A => B): A => Some[B] = x => Some(f(x))
|
def total[A,B](f: A => B): A => Some[B] = x => Some(f(x))
|
||||||
|
|
||||||
|
/** A mapper that ignores all inputs.*/
|
||||||
def transparent: Any => Option[Nothing] = _ => None
|
def transparent: Any => Option[Nothing] = _ => None
|
||||||
|
|
||||||
def normalizeBase(base: String) = if(!base.isEmpty && !base.endsWith("/")) base + "/" else base
|
def normalizeBase(base: String) = if(!base.isEmpty && !base.endsWith("/")) base + "/" else base
|
||||||
|
|
||||||
|
/** Pairs a File with the absolute File obtained by calling `getAbsoluteFile`.
|
||||||
|
* Note that this usually means that relative files are resolved against the current working directory.*/
|
||||||
def abs: FileMap = f => Some(f.getAbsoluteFile)
|
def abs: FileMap = f => Some(f.getAbsoluteFile)
|
||||||
def resolve(newDirectory: File): FileMap = file => Some(new File(newDirectory, file.getPath))
|
|
||||||
|
/** Returns a File mapper that resolves a relative File against `newDirectory` and pairs the original File with the resolved File.
|
||||||
|
* The mapper ignores absolute files. */
|
||||||
|
def resolve(newDirectory: File): FileMap = file => if(file.isAbsolute) None else Some(new File(newDirectory, file.getPath))
|
||||||
|
|
||||||
def rebase(oldBases: Iterable[File], newBase: File, zero: FileMap = transparent): FileMap =
|
def rebase(oldBases: Iterable[File], newBase: File, zero: FileMap = transparent): FileMap =
|
||||||
fold(zero, oldBases)(old => rebase(old, newBase))
|
fold(zero, oldBases)(old => rebase(old, newBase))
|
||||||
|
|
||||||
|
/** Produces a File mapper that pairs a descendant of `oldBase` with a file in `newBase` that preserving the relative path of the original file against `oldBase`.
|
||||||
|
* For example, if `oldBase` is `/old/x/` and `newBase` is `/new/a/`, `/old/x/y/z.txt` gets paired with `/new/a/y/z.txt`.
|
||||||
|
* */
|
||||||
def rebase(oldBase: File, newBase: File): FileMap =
|
def rebase(oldBase: File, newBase: File): FileMap =
|
||||||
file =>
|
file =>
|
||||||
if(file == oldBase)
|
if(file == oldBase)
|
||||||
|
|
@ -46,9 +73,22 @@ trait Mapper
|
||||||
else
|
else
|
||||||
IO.relativize(oldBase, file) map { r => new File(newBase, r) }
|
IO.relativize(oldBase, file) map { r => new File(newBase, r) }
|
||||||
|
|
||||||
|
/** Constructs a File mapper that pairs a file with a file with the same name in `newDirectory`.
|
||||||
|
* For example, if `newDirectory` is `/a/b`, then `/r/s/t/d.txt` will be paired with `/a/b/d.txt`*/
|
||||||
def flat(newDirectory: File): FileMap = file => Some(new File(newDirectory, file.getName))
|
def flat(newDirectory: File): FileMap = file => Some(new File(newDirectory, file.getName))
|
||||||
|
|
||||||
import Alternatives._
|
import Alternatives._
|
||||||
|
|
||||||
|
/** Selects all descendents of `base` directory and maps them to a path relative to `base`.
|
||||||
|
* `base` itself is not included. */
|
||||||
|
def allSubpaths(base: File): Traversable[(File,String)] =
|
||||||
|
selectSubpaths(base, AllPassFilter)
|
||||||
|
|
||||||
|
/** Selects descendents of `base` directory matching `filter` and maps them to a path relative to `base`.
|
||||||
|
* `base` itself is not included. */
|
||||||
|
def selectSubpaths(base: File, filter: FileFilter): Traversable[(File,String)] =
|
||||||
|
(PathFinder(base) ** filter --- PathFinder(base)) pair (relativeTo(base)|flat)
|
||||||
|
|
||||||
private[this] def fold[A,B,T](zero: A => Option[B], in: Iterable[T])(f: T => A => Option[B]): A => Option[B] =
|
private[this] def fold[A,B,T](zero: A => Option[B], in: Iterable[T])(f: T => A => Option[B]): A => Option[B] =
|
||||||
(zero /: in)( (mapper, base) => f(base) | mapper )
|
(zero /: in)( (mapper, base) => f(base) | mapper )
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
/* sbt -- Simple Build Tool
|
||||||
|
* Copyright 2010 Mark Harrah
|
||||||
|
*/
|
||||||
|
package sbt
|
||||||
|
|
||||||
|
import java.io.{File, PrintWriter}
|
||||||
|
|
||||||
|
final case class GlobalLogging(full: Logger, backed: ConsoleLogger, backing: GlobalLogBacking)
|
||||||
|
final case class GlobalLogBacking(file: File, last: Option[File], newLogger: (PrintWriter, GlobalLogBacking) => GlobalLogging, newBackingFile: () => File)
|
||||||
|
{
|
||||||
|
def shift(newFile: File) = GlobalLogBacking(newFile, Some(file), newLogger, newBackingFile)
|
||||||
|
def shiftNew() = shift(newBackingFile())
|
||||||
|
def unshift = GlobalLogBacking(last getOrElse file, None, newLogger, newBackingFile)
|
||||||
|
}
|
||||||
|
object GlobalLogBacking
|
||||||
|
{
|
||||||
|
def apply(newLogger: (PrintWriter, GlobalLogBacking) => GlobalLogging, newBackingFile: => File): GlobalLogBacking =
|
||||||
|
GlobalLogBacking(newBackingFile, None, newLogger, newBackingFile _)
|
||||||
|
}
|
||||||
|
object GlobalLogging
|
||||||
|
{
|
||||||
|
def initial(newLogger: (PrintWriter, GlobalLogBacking) => GlobalLogging, newBackingFile: => File): GlobalLogging =
|
||||||
|
{
|
||||||
|
val log = ConsoleLogger()
|
||||||
|
GlobalLogging(log, log, GlobalLogBacking(newLogger, newBackingFile))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
package sbt
|
||||||
|
|
||||||
|
import java.io.PrintWriter
|
||||||
|
|
||||||
|
object MainLogging
|
||||||
|
{
|
||||||
|
def multiLogger(config: MultiLoggerConfig): Logger =
|
||||||
|
{
|
||||||
|
import config._
|
||||||
|
val multi = new MultiLogger(console :: backed :: extra)
|
||||||
|
// sets multi to the most verbose for clients that inspect the current level
|
||||||
|
multi setLevel Level.unionAll(backingLevel :: screenLevel :: extra.map(_.getLevel))
|
||||||
|
// set the specific levels
|
||||||
|
console setLevel screenLevel
|
||||||
|
backed setLevel backingLevel
|
||||||
|
console setTrace screenTrace
|
||||||
|
backed setTrace backingTrace
|
||||||
|
multi: Logger
|
||||||
|
}
|
||||||
|
def globalDefault(writer: PrintWriter, backing: GlobalLogBacking): GlobalLogging =
|
||||||
|
{
|
||||||
|
val backed = defaultBacked()(writer)
|
||||||
|
val full = multiLogger(defaultMultiConfig( backed ) )
|
||||||
|
GlobalLogging(full, backed, backing)
|
||||||
|
}
|
||||||
|
|
||||||
|
def defaultMultiConfig(backing: AbstractLogger): MultiLoggerConfig =
|
||||||
|
new MultiLoggerConfig(defaultScreen, backing, Nil, Level.Info, Level.Debug, -1, Int.MaxValue)
|
||||||
|
|
||||||
|
def defaultScreen: AbstractLogger = ConsoleLogger()
|
||||||
|
|
||||||
|
def defaultBacked(useColor: Boolean = ConsoleLogger.formatEnabled): PrintWriter => ConsoleLogger =
|
||||||
|
to => ConsoleLogger(ConsoleLogger.printWriterOut(to), useColor = useColor) // TODO: should probably filter ANSI codes when useColor=false
|
||||||
|
}
|
||||||
|
|
||||||
|
final case class MultiLoggerConfig(console: AbstractLogger, backed: AbstractLogger, extra: List[AbstractLogger], screenLevel: Level.Value, backingLevel: Level.Value, screenTrace: Int, backingTrace: Int)
|
||||||
Loading…
Reference in New Issue