Skip to content

Commit

Permalink
Fix sbt#319: Add a filtered compiler reporter
Browse files Browse the repository at this point in the history
As explained in the issue and discussions [here](sbt#304 (comment)).
  • Loading branch information
jvican committed Jun 28, 2017
1 parent cbad640 commit 5e5297f
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 7 deletions.
4 changes: 3 additions & 1 deletion internal/zinc-compile-core/src/main/contraband/reporter.json
Expand Up @@ -9,7 +9,9 @@
{ "name": "loggerName", "type": "String" },
{ "name": "maximumErrors", "type": "int" },
{ "name": "useColor", "type": "boolean" },
{ "name": "logLevel", "type": "java.util.logging.Level" },
{ "name": "msgFilters", "type": "java.util.regex.Pattern*" },
{ "name": "fileFilters", "type": "java.util.regex.Pattern*" },
{ "name": "logLevel", "type": "java.util.logging.Level" },
{ "name": "positionMapper", "type": "java.util.function.Function<Position, Position>" }
]
}
Expand Down
@@ -0,0 +1,45 @@
package sbt.internal.inc

import sbt.internal.util.ManagedLogger
import xsbti.{ Position, Problem, Severity }

import scala.util.matching.Regex

/**
* Defines a filtered reporter as Pants Zinc's fork does letting users control which messages
* are reported or not. This implementation has been adapted from the Pants repository.
*
* @link https://github.com/pantsbuild/pants/blob/master/src/scala/org/pantsbuild/zinc/logging/Reporters.scala#L28
*
* This reporter may be useful to companies that have domain-specific knowledge
* about compile messages that are not relevant and can be filtered out, or users
* that hold similar knowledge about the piece of code that they compile.
*/
class FilteredReporter(
fileFilters: Array[Regex],
msgFilters: Array[Regex],
maximumErrors: Int,
logger: ManagedLogger,
positionMapper: Position => Position
) extends LoggerReporter(maximumErrors, logger, positionMapper) {
private final def isFiltered(filters: Seq[Regex], str: String): Boolean =
filters.exists(_.findFirstIn(str).isDefined)

private final def isFiltered(pos: Position, msg: String, severity: Severity): Boolean = {
severity != Severity.Error && (
(pos.sourceFile.isPresent && isFiltered(fileFilters, pos.sourceFile.get.getPath)) ||
(isFiltered(msgFilters, msg))
)
}

/**
* Redefines display so that non-error messages whose paths match a regex in `fileFilters`
* or whose messages' content match `msgFilters` are not reported to the user.
*/
override def display(problem: Problem): Unit = {
val severity = problem.severity()
val dontShow = isFiltered(problem.position(), problem.message(), severity)
if (dontShow) inc(severity)
else super.display(problem)
}
}
Expand Up @@ -103,7 +103,7 @@ class LoggerReporter(
logger.error(countElementsAsString(errors, "error") + " found")
}

private def inc(sev: Severity) = count.put(sev, count.get(sev) + 1)
protected def inc(sev: Severity) = count.put(sev, count.get(sev) + 1)

// this is used by sbt
private[sbt] def display(p: Problem): Unit = {
Expand Down
Expand Up @@ -5,14 +5,16 @@ import java.nio.charset.StandardCharsets
import java.util.logging.Level

import sbt.internal.util.{ ConsoleAppender, MainAppender }
import sbt.util.{ LogExchange }
import sbt.util.LogExchange
import sbt.util.{ Level => SbtLevel }
import xsbti.{ Position, Reporter, ReporterConfig }

import scala.util.matching.Regex

object ReporterManager {
import java.util.concurrent.atomic.AtomicInteger
private val idGenerator: AtomicInteger = new AtomicInteger
private val DefaultReporterName = "zinc-out"
private val DefaultName = "zinc-out"
private def generateZincReporterId(name: String): String =
s"$name-${idGenerator.incrementAndGet}"

Expand Down Expand Up @@ -45,7 +47,7 @@ object ReporterManager {
}
}

private val FallbackUseColor = ConsoleAppender.formatEnabled
private val UseColor = ConsoleAppender.formatEnabled
private val NoPositionMapper = java.util.function.Function.identity[Position]()

import java.util.function.{ Function => JavaFunction }
Expand All @@ -56,7 +58,7 @@ object ReporterManager {

/** Returns sane defaults with a long tradition in sbt. */
def getDefaultReporterConfig: ReporterConfig =
new ReporterConfig(DefaultReporterName, 100, FallbackUseColor, Level.INFO, NoPositionMapper)
new ReporterConfig(DefaultName, 100, UseColor, Array(), Array(), Level.INFO, NoPositionMapper)

def getReporter(toOutput: PrintWriter, config: ReporterConfig): Reporter = {
val printWriterToAppender = MainAppender.defaultBacked(config.useColor())
Expand All @@ -69,7 +71,16 @@ object ReporterManager {
val sbtLogLevel = fromJavaLogLevel(config.logLevel())
val toAppend = List(appender -> sbtLogLevel)
LogExchange.bindLoggerAppenders(loggerName, toAppend)
new LoggerReporter(config.maximumErrors(), logger, config.positionMapper().toScala)

val maxErrors = config.maximumErrors()
val posMapper = config.positionMapper().toScala
if (config.fileFilters().isEmpty && config.msgFilters.isEmpty)
new LoggerReporter(maxErrors, logger, posMapper)
else {
implicit def scalaPatterns(patterns: Array[java.util.regex.Pattern]): Array[Regex] =
patterns.map(_.pattern().r)
new FilteredReporter(config.fileFilters, config.msgFilters, maxErrors, logger, posMapper)
}
}

def getReporter(toOutput: PrintStream, config: ReporterConfig): Reporter = {
Expand Down

0 comments on commit 5e5297f

Please sign in to comment.