* fix buffered logging

* script tasks
This commit is contained in:
Mark Harrah 2010-03-26 08:22:06 -04:00
parent 259c73e98c
commit 0685320bd5
6 changed files with 129 additions and 102 deletions

View File

@ -1,96 +0,0 @@
/* sbt -- Simple Build Tool
* Copyright 2009 Mark Harrah
*/
/*import sbt._
import java.io.File
trait ReleaseProject extends ExecProject
{ self: SbtProject =>
def info: ProjectInfo
lazy val releaseChecks = javaVersionCheck && projectVersionCheck && fullyCheckedOut
lazy val fullyCheckedOut =
task
{
if(svnArtifactsPath.exists) None
else Some("You need a fully checked out sbt repository with commit rights to do a release.")
}
lazy val javaVersionCheck =
task
{
val javaVersion = System.getProperty("java.version")
if(!javaVersion.startsWith("1.5."))
Some("Java version must be 1.5.x (was " + javaVersion + ")")
else
None
}
lazy val projectVersionCheck =
task
{
def value(a: Option[Int]) = a.getOrElse(0)
def lessThan(a: Option[Int], b: Option[Int]) = value(a) < value(b)
version match
{
case BasicVersion(major, minor, micro, None) =>
Version.fromString(sbtVersion.value) match
{
case Right(BasicVersion(builderMajor, builderMinor, builderMicro, None))
if (builderMajor < major || ( builderMajor == major &&
lessThan(builderMinor, minor) || (builderMinor == minor &&
lessThan(builderMicro, micro ) ))) =>
None
case _ => Some("Invalid builder sbt version. Must be a release version older than the project version. (was: " + sbtVersion.value + ")")
}
case _ => Some("Invalid project version. Should be of the form #.#.# (was: " + version + ")")
}
}
def svnURL = "https://simple-build-tool.googlecode.com/svn/"
def latestURL = svnURL + "artifacts/latest"
def svnArtifactsPath = Path.fromFile(info.projectPath.asFile.getParentFile) / "artifacts"
def svnArtifactPath = svnArtifactsPath / version.toString
def ivyLocalPath = Path.userHome / ".ivy2" / "local" / "sbt" / "simple-build-tool" / version.toString
def manualTasks =
("Upload launcher jar: " + boot.outputJar.absolutePath) ::
"Update, build, check and commit Hello Lift example" ::
Nil
lazy val copyDocs = main.copyTask ( (main.mainDocPath ##) ** "*", svnArtifactPath / "api") dependsOn(main.doc, releaseChecks)
lazy val copyIvysJars = main.copyTask( (ivyLocalPath ##) ** "*", svnArtifactPath) dependsOn(main.crossPublishLocal, releaseChecks)
lazy val release = manualTaskMessage dependsOn(commitDocs, releaseArtifacts, releaseChecks)
lazy val releaseArtifacts = nextVersion dependsOn(tag, latestLink, boot.proguard, releaseChecks)
lazy val manualTaskMessage = task { println("The following tasks must be done manually:\n\t" + manualTasks.mkString("\n\t")); None }
import sbt.ProcessXML._
lazy val addArtifacts = execTask {<o> svn add {svnArtifactPath} </o>} dependsOn ( copyIvysJars, copyDocs, releaseChecks )
lazy val commitArtifacts = execTask {<o> svn commit -m "Jars, Ivys, and API Docs for {version.toString}" {svnArtifactPath} </o>} dependsOn(addArtifacts, releaseChecks)
lazy val tag = execTask {<o> svn copy -m "Tagging {version.toString}" {svnURL}/trunk/ {svnURL}/tags/{version.toString} </o>} dependsOn(releaseChecks)
lazy val latestLink = (deleteLatestLink && makeLatestLink) dependsOn(commitArtifacts, releaseChecks)
lazy val makeLatestLink = execTask {<o> svn copy -m "Creating new latest link" {svnURL}/artifacts/{version.toString}/ {latestURL} </o>} dependsOn(releaseChecks)
lazy val deleteLatestLink = execTask {<o> svn del -m "Deleting old latest link" {latestURL} </o>} dependsOn(releaseChecks)
lazy val commitProperties = execTask {<o> svn commit -m "Bumping versions" project/build.properties </o>} dependsOn(releaseChecks)
lazy val commitDocs = execTask {<o> svn commit -m "Updated documentation for {version.toString}" ../wiki/ </o>} dependsOn(releaseChecks)
lazy val nextVersion = (incrementVersions && commitProperties) dependsOn(releaseChecks)
lazy val incrementVersions = task { incrementVersionNumbers(); None }
def incrementVersionNumbers(): Unit =
for( v <- projectVersion)
{
sbtVersion() = v.toString
val incremented = v.asInstanceOf[BasicVersion].incrementMicro // BasicVersion checked by releaseChecks
import incremented._
val newVersion = BasicVersion(major, minor, micro, Some("SNAPSHOT"))
log.info("Changing version to " + newVersion)
projectVersion() = newVersion
saveEnvironment
}
}
package sbt {
object ProcessXML {
implicit def elemToPB(command: scala.xml.Elem): ProcessBuilder =
impl.CommandParser.parse(command.text.trim).fold(error, Function.tupled(Process.apply))
}
}*/

View File

@ -137,7 +137,7 @@ final class FilterLogger(delegate: Logger) extends BasicLogger
if(atLevel(Level.Info))
delegate.control(event, message)
}
def logAll(events: Seq[LogEvent]): Unit = events.foreach(delegate.log)
def logAll(events: Seq[LogEvent]): Unit = delegate.logAll(events)
}
/** A logger that can buffer the logging done on it by currently executing Thread and
@ -354,4 +354,11 @@ object Level extends Enumeration with NotNull
def apply(s: String) = levels.find(s == _.toString)
/** Same as apply, defined for use in pattern matching. */
private[sbt] def unapply(s: String) = apply(s)
}
final class LoggerWriter(delegate: Logger, level: Level.Value) extends java.io.Writer
{
override def flush() {}
override def close() {}
override def write(content: Array[Char], offset: Int, length: Int): Unit =
delegate.log(level, new String(content, offset, length))
}

View File

@ -55,6 +55,19 @@ sealed abstract class Path extends PathFinder with NotNull
def absolutePath: String = asFile.getAbsolutePath
private[sbt] def prependTo(s: String): String
/** The last component of this path.*/
def name = asFile.getName
/** The extension part of the name of this path. This is the part of the name after the last period, or the empty string if there is no period.*/
def ext = baseAndExt._2
/** The base of the name of this path. This is the part of the name before the last period, or the full name if there is no period.*/
def base = baseAndExt._1
def baseAndExt: (String, String) =
{
val nme = name
val dot = nme.lastIndexOf('.')
if(dot < 0) (nme, "") else (nme.substring(0, dot), nme.substring(dot+1))
}
/** Equality of Paths is defined in terms of the underlying <code>File</code>.*/
override final def equals(other: Any) =
other match

View File

@ -17,7 +17,7 @@ trait Project extends TaskManager with Dag[Project] with BasicEnvironment
final val log: Logger = logImpl
protected def logImpl: Logger =
{
val lg = new FilterLogger(new BufferedLogger(info.logger))
val lg = new BufferedLogger(new FilterLogger(info.logger))
lg.setLevel(defaultLoggingLevel)
lg
}
@ -388,6 +388,7 @@ object Project
/** Checks the project's dependencies, initializes its environment, and possibly its directories.*/
private def initialize[P <: Project](p: P, setupInfo: Option[SetupInfo], log: Logger): P =
{
def save() = p.saveEnvironment() foreach { errorMsg => log.error(errorMsg) }
setupInfo match
{
case Some(setup) =>
@ -399,8 +400,7 @@ object Project
p.projectOrganization() = org
if(!setup.initializeDirectories)
p.setEnvironmentModified(false)
for(errorMessage <- p.saveEnvironment())
log.error(errorMessage)
save()
if(setup.initializeDirectories)
p.initializeDirectories()
}
@ -409,8 +409,7 @@ object Project
{
p.initializeDirectories()
p.projectInitialize() = false
for(errorMessage <- p.saveEnvironment())
log.error(errorMessage)
save()
}
}
val useName = p.projectName.get.getOrElse("at " + p.info.projectDirectory.getAbsolutePath)

View File

@ -0,0 +1,69 @@
package sbt.script
import java.io.PrintWriter
import javax.script.{ScriptContext, ScriptEngine, ScriptEngineManager, SimpleScriptContext}
import xsbt.OpenResource.fileReader
import xsbt.FileUtilities.defaultCharset
object Run
{
def apply(file: Path, project: Project): AnyRef =
apply(file, defaultContext(project)_, project)
def apply(file: Path, ctx: ScriptContext => Unit, project: Project): AnyRef =
apply(file, ctx, defaultLoaders(project))
def apply(script: String, language: String, project: Project): AnyRef =
apply(script, language, defaultContext(project)_, project)
def apply(script: String, language: String, ctx: ScriptContext => Unit, project: Project): AnyRef =
apply(script, language, ctx, defaultLoaders(project))
def apply(file: Path, ctx: ScriptContext => Unit, loaders: Stream[ClassLoader]): AnyRef =
{
val engine = getEngineByExt(loaders, file.ext)
ctx(engine.getContext)
apply(file, engine)
}
def apply(script: String, language: String, ctx: ScriptContext => Unit, loaders: Stream[ClassLoader]): AnyRef =
{
val engine = getEngineByName(loaders, language)
ctx(engine.getContext)
engine.eval(script)
}
def defaultContext(project: Project)(ctx: ScriptContext)
{
ctx.setAttribute("project", project, ScriptContext.ENGINE_SCOPE)
// JavaScript implementation in 1.6 depends on this being a PrintWriter
ctx.setErrorWriter(new PrintWriter(new LoggerWriter(project.log, Level.Error)))
ctx.setWriter(new PrintWriter(new LoggerWriter(project.log, Level.Info)))
}
def apply(file: Path, engine: ScriptEngine): AnyRef =
xsbt.OpenResource.fileReader(defaultCharset)(file asFile)( engine.eval )
def bind(engine: ScriptEngine, bindings: Map[String, AnyRef]): Unit =
for( (k, v) <- bindings ) engine.put(k, v)
def defaultLoaders(project: Project) = Stream(project.getClass.getClassLoader, launcherLoader(project))
def launcherLoader(project: Project) = project.info.launcher.topLoader.getParent
def defaultBindings(project: Project) = Map("project" -> project)
def getEngine(loaders: Stream[ClassLoader], get: ScriptEngineManager => ScriptEngine, label: String): ScriptEngine =
firstEngine( engines(managers(loaders), get), label)
def getEngineByName(loaders: Stream[ClassLoader], lang: String): ScriptEngine =
getEngine(loaders, _.getEngineByName(lang), "name '" + lang + "'")
def getEngineByExt(loaders: Stream[ClassLoader], ext: String): ScriptEngine =
getEngine(loaders, _.getEngineByExtension(ext), "extension '" + ext + "'")
def managers(loaders: Stream[ClassLoader]): Stream[ScriptEngineManager] =
loaders.map(new ScriptEngineManager(_))
def engines(managers: Stream[ScriptEngineManager], get: ScriptEngineManager => ScriptEngine) =
managers.flatMap(getEngine(get))
def firstEngine(engines: Stream[ScriptEngine], label: String) =
engines.headOption.getOrElse(error("Could not find script engine for " + label))
def getEngine(get: ScriptEngineManager => ScriptEngine)(manager: ScriptEngineManager) =
{
val engine = get(manager)
if(engine == null) Nil else engine :: Nil
}
}

View File

@ -0,0 +1,35 @@
package sbt.script
import scala.collection.Set
import Scripts.{checkName, runScript}
trait Scripts extends Project
{
abstract override def tasks = if(scriptedTasks.isEmpty) super.tasks else Map() ++ super.tasks ++ scriptedTasks
def scriptSources: PathFinder = info.builderPath / "scripts" * "*.*"
lazy val scriptedTasks: Map[String, Task] = makeScripted(scriptSources.get)
def makeScripted(files: Set[Path]): Map[String, Task] = Map() ++ (files map makeScripted)
def makeScripted(file: Path): (String, Task) =
{
val t = scriptedTask(file) named(checkName(file.base))
(t.name, t)
}
def scriptedTask(file: Path): Task = task { runScript(file, this) }
def scriptedTask(script: String, language: String): Task = task { runScript(script, language, this) }
}
object Scripts
{
def runScript(file: Path, project: Project): Option[String] = getError( Run(file, project) )
def runScript(script: String, language: String, project: Project): Option[String] = getError( Run(script, language, project) )
def getError(result: AnyRef): Option[String] =
result match
{
case Some(v: String) => Some(v)
case _ => None
}
def checkName(base: String) = base.find(c => !legalID(c)) match { case Some(c) => error("Illegal character in scripted task name '" + base + "': '" + c + "'"); case None => base }
def legalID(c: Char) = java.lang.Character.isJavaIdentifierPart(c) || c == '-'
}