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:
Mark Harrah 2010-10-23 16:34:22 -04:00
parent 5ed8f3c042
commit a76d75bca6
17 changed files with 405 additions and 138 deletions

View File

@ -4,7 +4,7 @@
package sbt package sbt
package compile package compile
import xsbti.{AnalysisCallback, Logger => xLogger} import xsbti.{AnalysisCallback, Logger => xLogger, Reporter}
import java.io.File import java.io.File
import java.net.{URL, URLClassLoader} 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 * 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 * 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.*/ * 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 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) 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) val arguments = (new CompilerArguments(scalaInstance, cp))(sources, classpath, outputDirectory, options)
compile(arguments, callback, maximumErrors, log) 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)( call("xsbt.CompilerInterface", log)(
classOf[Array[String]], classOf[AnalysisCallback], classOf[Int], classOf[xLogger] ) ( classOf[Array[String]], classOf[AnalysisCallback], classOf[xLogger], classOf[Reporter] ) (
arguments.toArray[String] : Array[String], callback, maximumErrors: java.lang.Integer, log ) 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 = 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) 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 = def console(classpath: Seq[File], options: Seq[String], initialCommands: String, log: Logger)(loader: Option[ClassLoader] = None, bindings: Seq[(String, Any)] = Nil): Unit =
{ {

View File

@ -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
}
}
}
}

View File

@ -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 class CompileFailed(val arguments: Array[String], override val toString: String) extends xsbti.CompileFailed
{ {
def problems = Array()
override def fillInStackTrace = this override def fillInStackTrace = this
} }

View File

@ -3,13 +3,13 @@
*/ */
package xsbt package xsbt
import xsbti.{AnalysisCallback,Logger} import xsbti.{AnalysisCallback,Logger,Problem,Reporter}
import scala.tools.nsc.{Phase, SubComponent} import scala.tools.nsc.{Phase, SubComponent}
import Log.debug import Log.debug
class CompilerInterface 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} import scala.tools.nsc.{Global, Settings}
@ -17,7 +17,7 @@ class CompilerInterface
val settings = new Settings(Log.settingsError(log)) val settings = new Settings(Log.settingsError(log))
val command = Command(args.toList, settings) val command = Command(args.toList, settings)
val reporter = LoggerReporter(settings, maximumErrors, log) val reporter = DelegatingReporter(settings, delegate)
def noErrors = !reporter.hasErrors && command.ok def noErrors = !reporter.hasErrors && command.ok
val phasesSet = new scala.collection.mutable.HashSet[Any] // 2.7 compatibility val phasesSet = new scala.collection.mutable.HashSet[Any] // 2.7 compatibility
@ -84,8 +84,8 @@ class CompilerInterface
if(!noErrors) if(!noErrors)
{ {
debug(log, "Compilation failed (CompilerInterface)") 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

View File

@ -59,6 +59,6 @@ object MakeSettings
if(command.ok) if(command.ok)
command.settings command.settings
else else
throw new InterfaceCompileFailed(Array(), command.usageMsg) throw new InterfaceCompileFailed(Array(), Array(), command.usageMsg)
} }
} }

View File

@ -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) }
}

View File

@ -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
}
}
}

View File

@ -3,19 +3,20 @@
*/ */
package xsbt package xsbt
import xsbti.Logger import xsbti.Logger
import Log.debug import Log.debug
class ScaladocInterface 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 docSettings: doc.Settings = new doc.Settings(Log.settingsError(log))
val command = Command(args.toList, docSettings) val command = Command(args.toList, docSettings)
val reporter = LoggerReporter(docSettings, maximumErrors, log) val reporter = DelegatingReporter(docSettings, delegate)
def noErrors = !reporter.hasErrors && command.ok def noErrors = !reporter.hasErrors && command.ok
import forScope._ import forScope._
@ -29,12 +30,12 @@ private class Runner(args: Array[String], maximumErrors: Int, log: Logger)
processor.document(command.files) processor.document(command.files)
} }
reporter.printSummary() reporter.printSummary()
if(!noErrors) throw new InterfaceCompileFailed(args, "Scaladoc generation failed") if(!noErrors) throw new InterfaceCompileFailed(args, reporter.problems, "Scaladoc generation failed")
} }
object forScope 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) object compiler extends Global(command.settings, reporter)
{ {

View File

@ -3,4 +3,5 @@ package xsbti;
public abstract class CompileFailed extends RuntimeException public abstract class CompileFailed extends RuntimeException
{ {
public abstract String[] arguments(); public abstract String[] arguments();
public abstract Problem[] problems();
} }

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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);
}

View File

@ -0,0 +1,9 @@
/* sbt -- Simple Build Tool
* Copyright 2008, 2009, 2010 Mark Harrah
*/
package xsbti;
public enum Severity
{
Info, Warn, Error
}

View File

@ -12,6 +12,16 @@ object Compile
{ {
val DefaultMaxErrors = 100 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 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 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) final class IncSetup(val javaSrcBases: Seq[File], val analysisMap: Map[File, Analysis], val cacheDirectory: File)

View 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 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 type File = java.io.File
implicit def maybeToOption[S](m: xsbti.Maybe[S]): Option[S] =
if(m.isDefined) Some(m.get) else None
} }

View File

@ -16,6 +16,9 @@ object Incomplete extends Enumeration {
val causeStr = if(i.causes.isEmpty) "" else (i.causes.length + " cause(s)") val causeStr = if(i.causes.isEmpty) "" else (i.causes.length + " cause(s)")
"Incomplete (" + show(i.tpe) + ") " + i.message.getOrElse("") + causeStr + "\n" + traces "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] = def allExceptions(i: Incomplete): Iterable[Throwable] =
{ {
val exceptions = IDSet.create[Throwable] val exceptions = IDSet.create[Throwable]