cleanup logging paths, allow logger to be customized

This commit is contained in:
Mark Harrah 2011-04-12 20:33:29 -04:00
parent ada8e42ef5
commit 43f0212092
3 changed files with 53 additions and 23 deletions

View File

@ -10,6 +10,7 @@ package sbt
import Compiler.Compilers
import Project.{ScopedKey, Setting}
import Keys.Streams
import Scope.GlobalScope
import scala.annotation.tailrec
// name is more like BuildDefinition, but that is too long
@ -127,20 +128,19 @@ object BuildStreams
import Load.{BuildStructure, LoadedBuildUnit}
import Project.display
import std.{TaskExtra,Transform}
import Path._
import BuildPaths.outputDirectory
val GlobalPath = "$global"
val BuildUnitPath = "$build"
final val GlobalPath = "$global"
final val BuildUnitPath = "$build"
final val StreamsDirectory = "streams"
def mkStreams(units: Map[URI, LoadedBuildUnit], root: URI, data: Settings[Scope], logRelativePath: Seq[String] = defaultLogPath): Streams =
std.Streams( path(units, root, logRelativePath), display, LogManager.construct(data) )
def mkStreams(units: Map[URI, LoadedBuildUnit], root: URI, data: Settings[Scope]): Streams =
std.Streams( path(units, root, data), display, LogManager.construct(data) )
def defaultLogPath = "target" :: "streams" :: Nil
def path(units: Map[URI, LoadedBuildUnit], root: URI, data: Settings[Scope])(scoped: ScopedKey[_]): File =
resolvePath( projectPath(units, root, scoped, data), nonProjectPath(scoped) )
def path(units: Map[URI, LoadedBuildUnit], root: URI, sep: Seq[String])(scoped: ScopedKey[_]): File =
{
val (base, sub) = projectPath(units, root, scoped)
resolvePath(base, sep ++ sub ++ nonProjectPath(scoped) )
}
def resolvePath(base: File, components: Seq[String]): File =
(base /: components)( (b,p) => new File(b,p) )
@ -159,34 +159,39 @@ object BuildStreams
pathComponent(scope.extra, scoped, "extra")(_ => error("Unimplemented")) ::
Nil
}
def projectPath(units: Map[URI, LoadedBuildUnit], root: URI, scoped: ScopedKey[_]): (File, Seq[String]) =
def projectPath(units: Map[URI, LoadedBuildUnit], root: URI, scoped: ScopedKey[_], data: Settings[Scope]): File =
scoped.scope.project match
{
case Global => (units(root).localBase, GlobalPath :: Nil)
case Select(BuildRef(uri)) => (units(uri).localBase, BuildUnitPath :: Nil)
case Select(ProjectRef(uri, id)) => (units(uri).defined(id).base, Nil)
case Global => refTarget(GlobalScope, units(root).localBase, data) / GlobalPath
case Select(br @ BuildRef(uri)) => refTarget(br, units(uri).localBase, data) / BuildUnitPath
case Select(pr @ ProjectRef(uri, id)) => refTarget(pr, units(uri).defined(id).base, data)
case Select(pr) => error("Unresolved project reference (" + pr + ") in " + display(scoped))
case This => error("Unresolved project reference (This) in " + display(scoped))
}
def refTarget(ref: ResolvedReference, fallbackBase: File, data: Settings[Scope]): File =
refTarget(GlobalScope.copy(project = Select(ref)), fallbackBase, data)
def refTarget(scope: Scope, fallbackBase: File, data: Settings[Scope]): File =
(Keys.target in scope get data getOrElse outputDirectory(fallbackBase).asFile ) / StreamsDirectory
}
object BuildPaths
{
import Path._
import GlobFilter._
def defaultStaging = Path.userHome / ".sbt" / "staging"
def defaultGlobalPlugins = Path.userHome / ".sbt" / "plugins"
def defaultStaging = Path.userHome / ConfigDirectoryName / "staging"
def defaultGlobalPlugins = Path.userHome / ConfigDirectoryName / PluginsDirectoryName
def definitionSources(base: File): Seq[File] = (base * "*.scala").getFiles
def configurationSources(base: File): Seq[File] = (base * "*.sbt").getFiles
def pluginDirectory(definitionBase: Path) = definitionBase / "plugins"
def pluginDirectory(definitionBase: Path) = definitionBase / PluginsDirectoryName
def evalOutputDirectory(base: Path) = outputDirectory(base) / "config-classes"
def outputDirectory(base: Path) = base / "target"
def outputDirectory(base: Path) = base / DefaultTargetName
def buildOutputDirectory(base: Path, compilers: Compilers) = crossPath(outputDirectory(base), compilers.scalac.scalaInstance)
def projectStandard(base: Path) = base / "project"
def projectHidden(base: Path) = base / ".sbt"
def projectHidden(base: Path) = base / ConfigDirectoryName
def selectProjectDir(base: Path) =
{
val a = projectHidden(base)
@ -194,5 +199,9 @@ object BuildPaths
if(a.exists) a else b
}
final val PluginsDirectoryName = "plugins"
final val DefaultTargetName = "target"
final val ConfigDirectoryName = ".sbt"
def crossPath(base: File, instance: ScalaInstance): File = base / ("scala_" + instance.version)
}

View File

@ -23,6 +23,7 @@ object Keys
val showSuccess = SettingKey[Boolean]("show-success")
val showTiming = SettingKey[Boolean]("show-timing")
val timingFormat = SettingKey[java.text.DateFormat]("timing-format")
val logManager = SettingKey[LogManager]("log-manager")
// Project keys
val projectCommand = AttributeKey[Boolean]("project-command")

View File

@ -7,11 +7,30 @@ package sbt
import LogManager._
import std.Transform
import Project.ScopedKey
import Keys.{logLevel, persistLogLevel, persistTraceLevel, traceLevel}
import Keys.{logLevel, logManager, persistLogLevel, persistTraceLevel, traceLevel}
object LogManager
{
def construct(data: Settings[Scope]) = (task: ScopedKey[_], to: PrintWriter) =>
{
val manager = logManager in task.scope get data getOrElse default
manager(data, task, to)
}
lazy val default: LogManager = withLoggers()
def defaultScreen: AbstractLogger = ConsoleLogger()
def defaultBacked(useColor: Boolean): PrintWriter => AbstractLogger =
to => ConsoleLogger(ConsoleLogger.printWriterOut(to), useColor = useColor) // TODO: should probably filter ANSI codes when useColor=false
def withScreenLogger(mk: => AbstractLogger): LogManager = withLoggers(mk)
def withLoggers(screen: => AbstractLogger = defaultScreen, backed: PrintWriter => AbstractLogger = defaultBacked(false)): LogManager =
new LogManager {
def apply(data: Settings[Scope], task: ScopedKey[_], to: PrintWriter): Logger =
defaultLogger(data, task, screen, backed(to))
}
def defaultLogger(data: Settings[Scope], task: ScopedKey[_], console: AbstractLogger, backed: AbstractLogger): Logger =
{
val scope = task.scope
def getOr[T](key: AttributeKey[T], default: T): T = data.get(scope, key) getOrElse default
@ -20,9 +39,6 @@ object LogManager
val screenTrace = getOr(traceLevel.key, -1)
val backingTrace = getOr(persistTraceLevel.key, Int.MaxValue)
val console = ConsoleLogger()
val backed = ConsoleLogger(ConsoleLogger.printWriterOut(to), useColor = false) // TODO: wrap this with a filter that strips ANSI codes
val multi = new MultiLogger(console :: backed :: Nil)
// sets multi to the most verbose for clients that inspect the current level
multi setLevel Level.union(backingLevel, screenLevel)
@ -33,4 +49,8 @@ object LogManager
backed setTrace backingTrace
multi: Logger
}
}
trait LogManager
{
def apply(data: Settings[Scope], task: ScopedKey[_], writer: PrintWriter): Logger
}