135 lines
4.7 KiB
Scala
135 lines
4.7 KiB
Scala
package org.broadinstitute.sting.queue
|
|
|
|
import scala.tools.nsc.{Global, Settings}
|
|
import scala.tools.nsc.io.PlainFile
|
|
import org.broadinstitute.sting.queue.util.Logging
|
|
import collection.JavaConversions._
|
|
import java.io.File
|
|
import scala.tools.nsc.reporters.AbstractReporter
|
|
import java.lang.String
|
|
import org.apache.log4j.Level
|
|
import scala.tools.nsc.util.{FakePos, NoPosition, Position}
|
|
import org.broadinstitute.sting.queue.util.TextFormatUtils._
|
|
import org.broadinstitute.sting.utils.classloader.JVMUtils
|
|
|
|
/**
|
|
* Plugin manager for QScripts which loads QScripts into the current class loader.
|
|
*/
|
|
class QScriptManager() extends Logging {
|
|
/**
|
|
* Compiles and loads the scripts in the files into the current classloader.
|
|
* Heavily based on scala/src/compiler/scala/tools/ant/Scalac.scala
|
|
*/
|
|
def loadScripts(scripts: List[File], tempDir: File) {
|
|
if (scripts.size > 0) {
|
|
val settings = new Settings((error: String) => logger.error(error))
|
|
settings.deprecation.value = true
|
|
settings.outdir.value = tempDir.getPath
|
|
|
|
// Set the classpath to the current class path.
|
|
JVMUtils.getClasspathURLs.foreach(url => settings.classpath.append(url.getPath))
|
|
|
|
val reporter = new QScriptManager.Log4JReporter(settings)
|
|
|
|
val compiler = new Global(settings, reporter)
|
|
val run = new compiler.Run
|
|
|
|
logger.info("Compiling %s QScript%s".format(scripts.size, plural(scripts.size)))
|
|
logger.debug("Compilation directory: " + settings.outdir.value)
|
|
run.compileFiles(scripts.map(new PlainFile(_)))
|
|
|
|
reporter.printSummary()
|
|
if (reporter.hasErrors) {
|
|
val msg = "Compile of %s failed with %d error%s".format(
|
|
scripts.mkString(", "), reporter.ERROR.count, plural(reporter.ERROR.count))
|
|
throw new QException(msg)
|
|
}
|
|
else if (reporter.WARNING.count > 0)
|
|
logger.warn("Compile succeeded with %d warning%s".format(
|
|
reporter.WARNING.count, plural(reporter.WARNING.count)))
|
|
else
|
|
logger.info("Compilation complete")
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Plugin manager for QScripts which loads QScripts into the current classloader.
|
|
*/
|
|
object QScriptManager extends Logging {
|
|
|
|
/**
|
|
* NSC (New Scala Compiler) reporter which logs to Log4J.
|
|
* Heavily based on scala/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala
|
|
*/
|
|
private class Log4JReporter(val settings: Settings) extends AbstractReporter {
|
|
def displayPrompt { throw new UnsupportedOperationException("Unable to prompt the user. Prompting should be off.") }
|
|
|
|
/**
|
|
* Displays the message at position with severity.
|
|
* @param posIn Position of the event in the file that generated the message.
|
|
* @param msg Message to display.
|
|
* @param severity Severity of the event.
|
|
*/
|
|
def display(posIn: Position, msg: String, severity: Severity) {
|
|
severity.count += 1
|
|
val level = severity match {
|
|
case INFO => Level.INFO
|
|
case WARNING => Level.WARN
|
|
case ERROR => Level.ERROR
|
|
}
|
|
val pos = if (posIn eq null) NoPosition
|
|
else if (posIn.isDefined) posIn.inUltimateSource(posIn.source)
|
|
else posIn
|
|
pos match {
|
|
case FakePos(fmsg) =>
|
|
printMessage(level, fmsg+" "+msg)
|
|
case NoPosition =>
|
|
printMessage(level, msg)
|
|
case _ =>
|
|
val file = pos.source.file
|
|
printMessage(level, file.name+":"+pos.line+": "+msg)
|
|
printSourceLine(level, pos)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Prints a summary count of warnings and errors.
|
|
*/
|
|
def printSummary() {
|
|
if (WARNING.count > 0)
|
|
printMessage(Level.WARN, countElementsAsString(WARNING.count, "warning") + " found")
|
|
if (ERROR.count > 0)
|
|
printMessage(Level.ERROR, countElementsAsString(ERROR.count, "error") + " found")
|
|
}
|
|
|
|
/**
|
|
* Prints the source code line of an event followed by a pointer within the line to the error.
|
|
* @param level Severity level.
|
|
* @param pos Position in the file of the event.
|
|
*/
|
|
private def printSourceLine(level: Level, pos: Position) {
|
|
printMessage(level, pos.lineContent.stripLineEnd)
|
|
printColumnMarker(level, pos)
|
|
}
|
|
|
|
/**
|
|
* Prints the column marker of the given position.
|
|
* @param level Severity level.
|
|
* @param pos Position in the file of the event.
|
|
*/
|
|
private def printColumnMarker(level: Level, pos: Position) {
|
|
if (pos.isDefined) { printMessage(level, " " * (pos.column - 1) + "^") }
|
|
}
|
|
|
|
/**
|
|
* Prints the message at the severity level.
|
|
* @param level Severity level.
|
|
* @param message Message content.
|
|
*/
|
|
private def printMessage(level: Level, message: String) {
|
|
logger.log(level, message)
|
|
}
|
|
}
|
|
}
|