mirror of https://github.com/sbt/sbt.git
more flexible scalac logging
the custom scalac Reporter now delegates to an instance of an sbt interface called xsbti.Reporter handling compilation logging is now mainly done on the sbt-side of the compiler interface the xsbti.Reporter interface provides access to richer information about errors and warnings, including source file, line, and offset xsbti.Reporter can be implemented by users to get access to detailed information without needing to parse the logging output the CompileFailed exception that is thrown when compilation fails now includes an array of the problems, providing detailed error and warning information that can, for example, be consumed by doing a mapFailure on 'compile' and using 'Compile.allProblems'
This commit is contained in:
parent
5ed8f3c042
commit
a76d75bca6
|
|
@ -4,7 +4,7 @@
|
|||
package sbt
|
||||
package compile
|
||||
|
||||
import xsbti.{AnalysisCallback, Logger => xLogger}
|
||||
import xsbti.{AnalysisCallback, Logger => xLogger, Reporter}
|
||||
import java.io.File
|
||||
import java.net.{URL, URLClassLoader}
|
||||
|
||||
|
|
@ -12,7 +12,7 @@ package compile
|
|||
* provided by scalaInstance. This class requires a ComponentManager in order to obtain the interface code to scalac and
|
||||
* the analysis plugin. Because these call Scala code for a different Scala version than the one used for this class, they must
|
||||
* be compiled for the version of Scala being used.*/
|
||||
class AnalyzingCompiler(val scalaInstance: ScalaInstance, val manager: ComponentManager, val cp: ClasspathOptions, log: Logger) extends NotNull
|
||||
class AnalyzingCompiler(val scalaInstance: ScalaInstance, val manager: ComponentManager, val cp: ClasspathOptions, log: Logger)
|
||||
{
|
||||
def this(scalaInstance: ScalaInstance, manager: ComponentManager, log: Logger) = this(scalaInstance, manager, ClasspathOptions.auto, log)
|
||||
def apply(sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String], callback: AnalysisCallback, maximumErrors: Int, log: Logger)
|
||||
|
|
@ -20,16 +20,23 @@ class AnalyzingCompiler(val scalaInstance: ScalaInstance, val manager: Component
|
|||
val arguments = (new CompilerArguments(scalaInstance, cp))(sources, classpath, outputDirectory, options)
|
||||
compile(arguments, callback, maximumErrors, log)
|
||||
}
|
||||
def compile(arguments: Seq[String], callback: AnalysisCallback, maximumErrors: Int, log: Logger)
|
||||
|
||||
def compile(arguments: Seq[String], callback: AnalysisCallback, maximumErrors: Int, log: Logger): Unit =
|
||||
compile(arguments, callback, log, new LoggerReporter(maximumErrors, log))
|
||||
def compile(arguments: Seq[String], callback: AnalysisCallback, log: Logger, reporter: Reporter)
|
||||
{
|
||||
call("xsbt.CompilerInterface", log)(
|
||||
classOf[Array[String]], classOf[AnalysisCallback], classOf[Int], classOf[xLogger] ) (
|
||||
arguments.toArray[String] : Array[String], callback, maximumErrors: java.lang.Integer, log )
|
||||
classOf[Array[String]], classOf[AnalysisCallback], classOf[xLogger], classOf[Reporter] ) (
|
||||
arguments.toArray[String] : Array[String], callback, log, reporter )
|
||||
}
|
||||
|
||||
def doc(sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String], maximumErrors: Int, log: Logger): Unit =
|
||||
doc(sources, classpath, outputDirectory, options, log, new LoggerReporter(maximumErrors, log))
|
||||
def doc(sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String], log: Logger, reporter: Reporter): Unit =
|
||||
{
|
||||
val arguments = (new CompilerArguments(scalaInstance, cp))(sources, classpath, outputDirectory, options)
|
||||
call("xsbt.ScaladocInterface", log) (classOf[Array[String]], classOf[Int], classOf[xLogger]) (arguments.toArray[String] : Array[String], maximumErrors: java.lang.Integer, log)
|
||||
call("xsbt.ScaladocInterface", log) (classOf[Array[String]], classOf[xLogger], classOf[Reporter]) (
|
||||
arguments.toArray[String] : Array[String], log, reporter)
|
||||
}
|
||||
def console(classpath: Seq[File], options: Seq[String], initialCommands: String, log: Logger)(loader: Option[ClassLoader] = None, bindings: Seq[(String, Any)] = Nil): Unit =
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,153 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2008, 2009, 2010 Mark Harrah
|
||||
*/
|
||||
package sbt
|
||||
|
||||
// The following code is based on scala.tools.nsc.reporters.{AbstractReporter, ConsoleReporter, Reporter}
|
||||
// Copyright 2002-2009 LAMP/EPFL
|
||||
// see licenses/LICENSE_Scala
|
||||
// Original author: Martin Odersky
|
||||
|
||||
import xsbti.{Maybe,Position,Problem,Reporter,Severity}
|
||||
import java.util.EnumMap
|
||||
import scala.collection.mutable
|
||||
import LoggerReporter._
|
||||
import Severity.{Error,Info,Warn}
|
||||
|
||||
object LoggerReporter
|
||||
{
|
||||
def m2o[S](m: Maybe[S]): Option[S] = if(m.isDefined) Some(m.get) else None
|
||||
|
||||
final class PositionKey(pos: Position)
|
||||
{
|
||||
def offset = pos.offset
|
||||
def sourceFile = pos.sourceFile
|
||||
|
||||
override def equals(o: Any) =
|
||||
o match { case pk: PositionKey => equalsKey(pk); case _ => false }
|
||||
|
||||
def equalsKey(o: PositionKey) =
|
||||
m2o(pos.offset) == m2o(o.offset) &&
|
||||
m2o(pos.sourceFile) == m2o(o.sourceFile)
|
||||
override def hashCode =
|
||||
m2o(pos.offset).hashCode * 31
|
||||
m2o(pos.sourceFile).hashCode
|
||||
}
|
||||
|
||||
def countElementsAsString(n: Int, elements: String): String =
|
||||
n match {
|
||||
case 0 => "no " + elements + "s"
|
||||
case 1 => "one " + elements
|
||||
case 2 => "two " + elements + "s"
|
||||
case 3 => "three " + elements + "s"
|
||||
case 4 => "four " + elements + "s"
|
||||
case _ => "" + n + " " + elements + "s"
|
||||
}
|
||||
}
|
||||
|
||||
class LoggerReporter(maximumErrors: Int, log: Logger) extends xsbti.Reporter
|
||||
{
|
||||
val positions = new mutable.HashMap[PositionKey, Severity]
|
||||
val count = new EnumMap[Severity, Int](classOf[Severity])
|
||||
private val allProblems = new mutable.ListBuffer[Problem]
|
||||
|
||||
reset()
|
||||
|
||||
def reset()
|
||||
{
|
||||
count.put(Warn, 0)
|
||||
count.put(Info, 0)
|
||||
count.put(Error, 0)
|
||||
positions.clear()
|
||||
allProblems.clear()
|
||||
}
|
||||
def hasWarnings = count.get(Warn) > 0
|
||||
def hasErrors = count.get(Error) > 0
|
||||
def problems = allProblems.toArray
|
||||
|
||||
def printSummary()
|
||||
{
|
||||
val warnings = count.get(Severity.Warn)
|
||||
if(warnings > 0)
|
||||
log.warn(countElementsAsString(warnings, "warning") + " found")
|
||||
val errors = count.get(Severity.Error)
|
||||
if(errors > 0)
|
||||
log.error(countElementsAsString(errors, "error") + " found")
|
||||
}
|
||||
|
||||
def inc(sev: Severity) = count.put(sev, count.get(sev) + 1)
|
||||
|
||||
def display(pos: Position, msg: String, severity: Severity)
|
||||
{
|
||||
inc(severity)
|
||||
if(severity != Warn || maximumErrors <= 0 || count.get(severity) <= maximumErrors)
|
||||
print(severityLogger(severity), pos, msg)
|
||||
}
|
||||
def severityLogger(severity: Severity): (=> String) => Unit =
|
||||
m =>
|
||||
{
|
||||
(severity match
|
||||
{
|
||||
case Error => log.error(m)
|
||||
case Warn => log.warn(m)
|
||||
case Info => log.info(m)
|
||||
})
|
||||
}
|
||||
|
||||
def print(log: (=> String) => Unit, pos: Position, msg: String)
|
||||
{
|
||||
if(pos.sourcePath.isEmpty && pos.line.isEmpty)
|
||||
log(msg)
|
||||
else
|
||||
{
|
||||
val sourcePrefix = m2o(pos.sourcePath).getOrElse("")
|
||||
val lineNumberString = m2o(pos.line).map(":" + _ + ":").getOrElse(":") + " "
|
||||
log(sourcePrefix + lineNumberString + msg)
|
||||
val lineContent = pos.lineContent
|
||||
if(!lineContent.isEmpty)
|
||||
{
|
||||
log(lineContent)
|
||||
for(space <- m2o(pos.pointerSpace))
|
||||
log(space + "^") // pointer to the column position of the error/warning
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def log(pos: Position, msg: String, severity: Severity): Unit =
|
||||
{
|
||||
allProblems += problem(pos, msg, severity)
|
||||
severity match
|
||||
{
|
||||
case Warn | Error =>
|
||||
{
|
||||
if(!testAndLog(pos, severity))
|
||||
display(pos, msg, severity)
|
||||
}
|
||||
case _ => display(pos, msg, severity)
|
||||
}
|
||||
}
|
||||
def problem(pos: Position, msg: String, sev: Severity): Problem =
|
||||
new Problem
|
||||
{
|
||||
val position = pos
|
||||
val message = msg
|
||||
val severity = sev
|
||||
}
|
||||
|
||||
def testAndLog(pos: Position, severity: Severity): Boolean =
|
||||
{
|
||||
if(pos.offset.isEmpty || pos.sourceFile.isEmpty)
|
||||
false
|
||||
else
|
||||
{
|
||||
val key = new PositionKey(pos)
|
||||
if(positions.get(key).map(_.ordinal >= severity.ordinal).getOrElse(false))
|
||||
true
|
||||
else
|
||||
{
|
||||
positions(key) = severity
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -36,5 +36,6 @@ class RawCompiler(val scalaInstance: ScalaInstance, cp: ClasspathOptions, log: L
|
|||
}
|
||||
class CompileFailed(val arguments: Array[String], override val toString: String) extends xsbti.CompileFailed
|
||||
{
|
||||
def problems = Array()
|
||||
override def fillInStackTrace = this
|
||||
}
|
||||
|
|
@ -3,13 +3,13 @@
|
|||
*/
|
||||
package xsbt
|
||||
|
||||
import xsbti.{AnalysisCallback,Logger}
|
||||
import xsbti.{AnalysisCallback,Logger,Problem,Reporter}
|
||||
import scala.tools.nsc.{Phase, SubComponent}
|
||||
import Log.debug
|
||||
|
||||
class CompilerInterface
|
||||
{
|
||||
def run(args: Array[String], callback: AnalysisCallback, maximumErrors: Int, log: Logger)
|
||||
def run(args: Array[String], callback: AnalysisCallback, log: Logger, delegate: Reporter)
|
||||
{
|
||||
import scala.tools.nsc.{Global, Settings}
|
||||
|
||||
|
|
@ -17,7 +17,7 @@ class CompilerInterface
|
|||
|
||||
val settings = new Settings(Log.settingsError(log))
|
||||
val command = Command(args.toList, settings)
|
||||
val reporter = LoggerReporter(settings, maximumErrors, log)
|
||||
val reporter = DelegatingReporter(settings, delegate)
|
||||
def noErrors = !reporter.hasErrors && command.ok
|
||||
|
||||
val phasesSet = new scala.collection.mutable.HashSet[Any] // 2.7 compatibility
|
||||
|
|
@ -84,8 +84,8 @@ class CompilerInterface
|
|||
if(!noErrors)
|
||||
{
|
||||
debug(log, "Compilation failed (CompilerInterface)")
|
||||
throw new InterfaceCompileFailed(args, "Compilation failed")
|
||||
throw new InterfaceCompileFailed(args, reporter.problems, "Compilation failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
class InterfaceCompileFailed(val arguments: Array[String], override val toString: String) extends xsbti.CompileFailed
|
||||
class InterfaceCompileFailed(val arguments: Array[String], val problems: Array[Problem], override val toString: String) extends xsbti.CompileFailed
|
||||
|
|
@ -59,6 +59,6 @@ object MakeSettings
|
|||
if(command.ok)
|
||||
command.settings
|
||||
else
|
||||
throw new InterfaceCompileFailed(Array(), command.usageMsg)
|
||||
throw new InterfaceCompileFailed(Array(), Array(), command.usageMsg)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,119 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2008, 2009, 2010 Mark Harrah
|
||||
*/
|
||||
package xsbt
|
||||
|
||||
import xsbti.{F0,Logger,Maybe}
|
||||
import java.io.File
|
||||
|
||||
private object DelegatingReporter
|
||||
{
|
||||
def apply(settings: scala.tools.nsc.Settings, delegate: xsbti.Reporter): DelegatingReporter =
|
||||
new DelegatingReporter(Command.getWarnFatal(settings), delegate)
|
||||
}
|
||||
|
||||
private trait ReporterCompat27 {
|
||||
// this method is not in 2.7.7, so we need to have a dummy interface or scalac complains nothing is overridden
|
||||
def hasWarnings: Boolean
|
||||
}
|
||||
// The following code is based on scala.tools.nsc.reporters.{AbstractReporter, ConsoleReporter}
|
||||
// Copyright 2002-2009 LAMP/EPFL
|
||||
// Original author: Martin Odersky
|
||||
private final class DelegatingReporter(warnFatal: Boolean, delegate: xsbti.Reporter) extends scala.tools.nsc.reporters.Reporter with ReporterCompat27
|
||||
{
|
||||
import scala.tools.nsc.util.{FakePos,NoPosition,Position}
|
||||
|
||||
def error(msg: String) { error(FakePos("scalac"), msg) }
|
||||
|
||||
def printSummary() = delegate.printSummary()
|
||||
|
||||
// this helps keep source compatibility with the changes in 2.8 : Position.{source,line,column} are no longer Option[X]s, just plain Xs
|
||||
// so, we normalize to Option[X]
|
||||
private def o[T](t: Option[T]): Option[T] = t
|
||||
private def o[T](t: T): Option[T] = Some(t)
|
||||
|
||||
override def hasErrors = delegate.hasErrors
|
||||
override def hasWarnings = delegate.hasWarnings
|
||||
def problems = delegate.problems
|
||||
|
||||
override def reset =
|
||||
{
|
||||
super.reset
|
||||
delegate.reset
|
||||
}
|
||||
protected def info0(pos: Position, msg: String, rawSeverity: Severity, force: Boolean)
|
||||
{
|
||||
val severity = if(warnFatal && rawSeverity == WARNING) ERROR else rawSeverity
|
||||
delegate.log(convert(pos), msg, convert(rawSeverity))
|
||||
}
|
||||
private[this] def convert(posIn: Position): xsbti.Position =
|
||||
{
|
||||
val pos =
|
||||
posIn match
|
||||
{
|
||||
case null | NoPosition => NoPosition
|
||||
case x: FakePos => x
|
||||
case x =>
|
||||
posIn.inUltimateSource(o(posIn.source).get)
|
||||
}
|
||||
pos match
|
||||
{
|
||||
case NoPosition | FakePos(_) => position(None, None, None, "", None, None, None)
|
||||
case _ => makePosition(pos)
|
||||
}
|
||||
}
|
||||
private[this] def makePosition(pos: Position): xsbti.Position =
|
||||
{
|
||||
val srcO = o(pos.source)
|
||||
val opt(sourcePath, sourceFile) = for(src <- srcO) yield (src.file.path, src.file.file)
|
||||
val line = o(pos.line)
|
||||
if(!line.isEmpty)
|
||||
{
|
||||
val lineContent = pos.lineContent.stripLineEnd
|
||||
val offsetO = o(pos.offset)
|
||||
val opt(pointer, pointerSpace) =
|
||||
for(offset <- offsetO; src <- srcO) yield
|
||||
{
|
||||
val pointer = offset - src.lineToOffset(src.offsetToLine(offset))
|
||||
val pointerSpace = ((lineContent: Seq[Char]).take(pointer).map { case '\t' => '\t'; case x => ' ' }).mkString
|
||||
(pointer, pointerSpace)
|
||||
}
|
||||
position(sourcePath, sourceFile, line, lineContent, offsetO, pointer, pointerSpace)
|
||||
}
|
||||
else
|
||||
position(sourcePath, sourceFile, line, "", None, None, None)
|
||||
}
|
||||
private[this] object opt
|
||||
{
|
||||
def unapply[A,B](o: Option[(A,B)]): Some[(Option[A], Option[B])] =
|
||||
Some(o match
|
||||
{
|
||||
case Some((a,b)) => (Some(a), Some(b))
|
||||
case None => (None, None)
|
||||
})
|
||||
}
|
||||
private[this] def position(sourcePath0: Option[String], sourceFile0: Option[File], line0: Option[Int], lineContent0: String, offset0: Option[Int], pointer0: Option[Int], pointerSpace0: Option[String]) =
|
||||
new xsbti.Position
|
||||
{
|
||||
val line = o2mi(line0)
|
||||
val lineContent = lineContent0
|
||||
val offset = o2mi(offset0)
|
||||
val sourcePath = o2m(sourcePath0)
|
||||
val sourceFile = o2m(sourceFile0)
|
||||
val pointer = o2mi(pointer0)
|
||||
val pointerSpace = o2m(pointerSpace0)
|
||||
}
|
||||
|
||||
import xsbti.Severity.{Info, Warn, Error}
|
||||
private[this] def convert(sev: Severity): xsbti.Severity =
|
||||
sev match
|
||||
{
|
||||
case INFO => Info
|
||||
case WARNING => Warn
|
||||
case ERROR => Error
|
||||
}
|
||||
|
||||
import java.lang.{Integer => I}
|
||||
private[this] def o2mi(opt: Option[Int]): Maybe[I] = opt match { case None => Maybe.nothing[I]; case Some(s) => Maybe.just[I](s) }
|
||||
private[this] def o2m[S](opt: Option[S]): Maybe[S] = opt match { case None => Maybe.nothing[S]; case Some(s) => Maybe.just(s) }
|
||||
}
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2008, 2009 Mark Harrah
|
||||
*/
|
||||
package xsbt
|
||||
|
||||
import xsbti.{F0,Logger}
|
||||
|
||||
private object LoggerReporter
|
||||
{
|
||||
def apply(settings: scala.tools.nsc.Settings, maximumErrors: Int, log: Logger): LoggerReporter =
|
||||
new LoggerReporter(Command.getWarnFatal(settings), maximumErrors, log)
|
||||
}
|
||||
|
||||
// The following code is based on scala.tools.nsc.reporters.{AbstractReporter, ConsoleReporter}
|
||||
// Copyright 2002-2009 LAMP/EPFL
|
||||
// Original author: Martin Odersky
|
||||
private final class LoggerReporter(warnFatal: Boolean, maximumErrors: Int, log: Logger) extends scala.tools.nsc.reporters.Reporter
|
||||
{
|
||||
import scala.tools.nsc.util.{FakePos,NoPosition,Position}
|
||||
private val positions = new scala.collection.mutable.HashMap[Position, Severity]
|
||||
|
||||
def error(msg: String) { error(FakePos("scalac"), msg) }
|
||||
|
||||
def printSummary()
|
||||
{
|
||||
if(WARNING.count > 0)
|
||||
log.warn(Message(countElementsAsString(WARNING.count, "warning") + " found"))
|
||||
if(ERROR.count > 0)
|
||||
log.error(Message(countElementsAsString(ERROR.count, "error") + " found"))
|
||||
}
|
||||
|
||||
def display(pos: Position, msg: String, severity: Severity)
|
||||
{
|
||||
severity.count += 1
|
||||
if(severity != ERROR || maximumErrors < 0 || severity.count <= maximumErrors)
|
||||
print(severityLogger(severity), pos, msg)
|
||||
}
|
||||
private def severityLogger(severity: Severity) =
|
||||
(m: F0[String]) =>
|
||||
{
|
||||
(severity match
|
||||
{
|
||||
case ERROR => log.error(m)
|
||||
case WARNING => log.warn(m)
|
||||
case INFO => log.info(m)
|
||||
})
|
||||
}
|
||||
|
||||
// this helps keep source compatibility with the changes in 2.8 : Position.{source,line,column} are no longer Option[X]s, just plain Xs
|
||||
// so, we normalize to Option[X]
|
||||
private def o[T](t: Option[T]): Option[T] = t
|
||||
private def o[T](t: T): Option[T] = Some(t)
|
||||
private def print(logger: F0[String] => Unit, posIn: Position, msg: String)
|
||||
{
|
||||
def log(s: => String) = logger(Message(s))
|
||||
val pos =
|
||||
posIn match
|
||||
{
|
||||
case null | NoPosition => NoPosition
|
||||
case x: FakePos => x
|
||||
case x =>
|
||||
posIn.inUltimateSource(o(posIn.source).get)
|
||||
}
|
||||
pos match
|
||||
{
|
||||
case NoPosition => log(msg)
|
||||
case FakePos(fmsg) => log(fmsg+" "+msg)
|
||||
case _ =>
|
||||
val sourcePrefix = o(pos.source).map(_.file.path).getOrElse("")
|
||||
val lineNumberString = o(pos.line).map(line => ":" + line + ":").getOrElse(":") + " "
|
||||
log(sourcePrefix + lineNumberString + msg)
|
||||
if (!o(pos.line).isEmpty)
|
||||
{
|
||||
val lineContent = pos.lineContent.stripLineEnd
|
||||
log(lineContent) // source line with error/warning
|
||||
for(offset <- o(pos.offset); src <- o(pos.source))
|
||||
{
|
||||
val pointer = offset - src.lineToOffset(src.offsetToLine(offset))
|
||||
val pointerSpace = (lineContent: Seq[Char]).take(pointer).map { case '\t' => '\t'; case x => ' ' }
|
||||
log(pointerSpace.mkString + "^") // pointer to the column position of the error/warning
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
override def reset =
|
||||
{
|
||||
super.reset
|
||||
positions.clear
|
||||
}
|
||||
|
||||
|
||||
protected def info0(pos: Position, msg: String, rawSeverity: Severity, force: Boolean)
|
||||
{
|
||||
val severity = if(warnFatal && rawSeverity == WARNING) ERROR else rawSeverity
|
||||
severity match
|
||||
{
|
||||
case WARNING | ERROR =>
|
||||
{
|
||||
if(!testAndLog(pos, severity))
|
||||
display(pos, msg, severity)
|
||||
}
|
||||
case _ => display(pos, msg, severity)
|
||||
}
|
||||
}
|
||||
|
||||
private def testAndLog(pos: Position, severity: Severity): Boolean =
|
||||
{
|
||||
if(pos == null || pos.offset.isEmpty)
|
||||
false
|
||||
else if(positions.get(pos).map(_ >= severity).getOrElse(false))
|
||||
true
|
||||
else
|
||||
{
|
||||
positions(pos) = severity
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,14 +8,15 @@ import Log.debug
|
|||
|
||||
class ScaladocInterface
|
||||
{
|
||||
def run(args: Array[String], maximumErrors: Int, log: Logger) = (new Runner(args, maximumErrors, log)).run
|
||||
def run(args: Array[String], log: Logger, delegate: xsbti.Reporter) = (new Runner(args, log, delegate)).run
|
||||
}
|
||||
private class Runner(args: Array[String], maximumErrors: Int, log: Logger)
|
||||
private class Runner(args: Array[String], log: Logger, delegate: xsbti.Reporter)
|
||||
{
|
||||
import scala.tools.nsc.{doc, Global}
|
||||
import scala.tools.nsc.{doc, Global, reporters}
|
||||
import reporters.Reporter
|
||||
val docSettings: doc.Settings = new doc.Settings(Log.settingsError(log))
|
||||
val command = Command(args.toList, docSettings)
|
||||
val reporter = LoggerReporter(docSettings, maximumErrors, log)
|
||||
val reporter = DelegatingReporter(docSettings, delegate)
|
||||
def noErrors = !reporter.hasErrors && command.ok
|
||||
|
||||
import forScope._
|
||||
|
|
@ -29,12 +30,12 @@ private class Runner(args: Array[String], maximumErrors: Int, log: Logger)
|
|||
processor.document(command.files)
|
||||
}
|
||||
reporter.printSummary()
|
||||
if(!noErrors) throw new InterfaceCompileFailed(args, "Scaladoc generation failed")
|
||||
if(!noErrors) throw new InterfaceCompileFailed(args, reporter.problems, "Scaladoc generation failed")
|
||||
}
|
||||
|
||||
object forScope
|
||||
{
|
||||
class DocFactory(reporter: LoggerReporter, docSettings: doc.Settings) // 2.7 compatibility
|
||||
class DocFactory(reporter: Reporter, docSettings: doc.Settings) // 2.7 compatibility
|
||||
{
|
||||
object compiler extends Global(command.settings, reporter)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,4 +3,5 @@ package xsbti;
|
|||
public abstract class CompileFailed extends RuntimeException
|
||||
{
|
||||
public abstract String[] arguments();
|
||||
public abstract Problem[] problems();
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2008, 2009, 2010 Mark Harrah
|
||||
*/
|
||||
package xsbti;
|
||||
|
||||
/** Intended as a lightweight carrier for scala.Option. */
|
||||
public abstract class Maybe<t>
|
||||
{
|
||||
// private pending Scala bug #3642
|
||||
protected Maybe() {}
|
||||
|
||||
public static <s> Maybe<s> just(final s v)
|
||||
{
|
||||
return new Maybe<s>() {
|
||||
public boolean isDefined() { return true; }
|
||||
public s get() { return v; }
|
||||
};
|
||||
}
|
||||
public static <s> Maybe<s> nothing()
|
||||
{
|
||||
return new Maybe<s>() {
|
||||
public boolean isDefined() { return false; }
|
||||
public s get() { throw new UnsupportedOperationException("nothing.get"); }
|
||||
};
|
||||
}
|
||||
|
||||
public final boolean isEmpty() { return !isDefined(); }
|
||||
public abstract boolean isDefined();
|
||||
public abstract t get();
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2008, 2009, 2010 Mark Harrah
|
||||
*/
|
||||
package xsbti;
|
||||
|
||||
public interface Position
|
||||
{
|
||||
Maybe<Integer> line();
|
||||
String lineContent();
|
||||
Maybe<Integer> offset();
|
||||
|
||||
// pointer to the column position of the error/warning
|
||||
Maybe<Integer> pointer();
|
||||
Maybe<String> pointerSpace();
|
||||
|
||||
Maybe<String> sourcePath();
|
||||
Maybe<java.io.File> sourceFile();
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2008, 2009, 2010 Mark Harrah
|
||||
*/
|
||||
package xsbti;
|
||||
|
||||
public interface Problem
|
||||
{
|
||||
Severity severity();
|
||||
String message();
|
||||
Position position();
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2008, 2009, 2010 Mark Harrah
|
||||
*/
|
||||
package xsbti;
|
||||
|
||||
public interface Reporter
|
||||
{
|
||||
/** Resets logging, including any accumulated errors, warnings, messages, and counts.*/
|
||||
public void reset();
|
||||
/** Returns true if this logger has seen any errors since the last call to reset.*/
|
||||
public boolean hasErrors();
|
||||
/** Returns true if this logger has seen any warnings since the last call to reset.*/
|
||||
public boolean hasWarnings();
|
||||
/** Logs a summary of logging since the last reset.*/
|
||||
public void printSummary();
|
||||
/** Returns a list of warnings and errors since the last reset.*/
|
||||
public Problem[] problems();
|
||||
/** Logs a message.*/
|
||||
public void log(Position pos, String msg, Severity sev);
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2008, 2009, 2010 Mark Harrah
|
||||
*/
|
||||
package xsbti;
|
||||
|
||||
public enum Severity
|
||||
{
|
||||
Info, Warn, Error
|
||||
}
|
||||
|
|
@ -12,6 +12,16 @@ object Compile
|
|||
{
|
||||
val DefaultMaxErrors = 100
|
||||
|
||||
def allProblems(inc: Incomplete): Seq[Problem] =
|
||||
allProblems(inc :: Nil)
|
||||
def allProblems(incs: Seq[Incomplete]): Seq[Problem] =
|
||||
problems(Incomplete.allExceptions(incs).toSeq)
|
||||
def problems(es: Seq[Throwable]): Seq[Problem] =
|
||||
es flatMap {
|
||||
case cf: xsbti.CompileFailed => cf.problems
|
||||
case _ => Nil
|
||||
}
|
||||
|
||||
final class Inputs(val compilers: Compilers, val config: Options, val incSetup: IncSetup, val log: Logger)
|
||||
final class Options(val classpath: Seq[File], val sources: Seq[File], val classesDirectory: File, val options: Seq[String], val javacOptions: Seq[String], val maxErrors: Int)
|
||||
final class IncSetup(val javaSrcBases: Seq[File], val analysisMap: Map[File, Analysis], val cacheDirectory: File)
|
||||
|
|
|
|||
|
|
@ -4,4 +4,6 @@
|
|||
package object sbt extends sbt.std.TaskExtra with sbt.Types with sbt.ProcessExtra with sbt.impl.DependencyBuilders with sbt.PathExtra
|
||||
{
|
||||
type File = java.io.File
|
||||
implicit def maybeToOption[S](m: xsbti.Maybe[S]): Option[S] =
|
||||
if(m.isDefined) Some(m.get) else None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@ object Incomplete extends Enumeration {
|
|||
val causeStr = if(i.causes.isEmpty) "" else (i.causes.length + " cause(s)")
|
||||
"Incomplete (" + show(i.tpe) + ") " + i.message.getOrElse("") + causeStr + "\n" + traces
|
||||
}
|
||||
|
||||
def allExceptions(is: Seq[Incomplete]): Iterable[Throwable] =
|
||||
allExceptions(new Incomplete(causes = is))
|
||||
def allExceptions(i: Incomplete): Iterable[Throwable] =
|
||||
{
|
||||
val exceptions = IDSet.create[Throwable]
|
||||
|
|
|
|||
Loading…
Reference in New Issue