Skip to content

Commit

Permalink
Filter zinc compilation warnings at the Reporter level
Browse files Browse the repository at this point in the history
The existing impl did not include the severity in its match, so it's possible that errors could be filtered.

- Only filter non-errors
- Filter zinc compilation at the Reporter level, rather than in the logger
- Split between message filters and filename filters

Testing Done:
Used:

    ./pants --config-override=pants.ini.isolated publish.jar --no-dryrun --local=~/.m2/repository --named-snapshot=$USER-`date +%s` src/scala/org/pantsbuild/zinc::

...to do a local publish, then tested that:

    ./pants --config-override=pants.ini.isolated compile testprojects/src/java/org/pantsbuild/testproject/dummies::

properly applied both `-msg-filter` and `-file-filter`.

----

Can add a pants integration test once this release goes out.

Reviewed at https://rbcommons.com/s/twitter/r/2656/
  • Loading branch information
stuhood committed Aug 18, 2015
1 parent 17712e3 commit 085bcac
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 40 deletions.
3 changes: 1 addition & 2 deletions src/scala/org/pantsbuild/zinc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -168,14 +168,13 @@ object Compiler {
*/
class Compiler(scalac: AnalyzingCompiler, javac: JavaCompiler, setup: Setup) {

def compile(inputs: Inputs, cwd: Option[File])(log: Logger): Unit = {
def compile(inputs: Inputs, cwd: Option[File], reporter: xsbti.Reporter)(log: Logger): Unit = {
val progress =
new SimpleCompileProgress(
setup.consoleLog.logPhases,
setup.consoleLog.printProgress,
setup.consoleLog.heartbeatSecs
)(log)
val reporter = new LoggerReporter(maximumErrors = 100, log, identity)
compile(inputs, cwd, reporter, Some(progress))(log)
}

Expand Down
11 changes: 8 additions & 3 deletions src/scala/org/pantsbuild/zinc/Main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ package org.pantsbuild.zinc
import java.io.File
import sbt.Level
import xsbti.CompileFailed
import org.pantsbuild.zinc.logging.Loggers
import org.pantsbuild.zinc.logging.{ Loggers, Reporters }

/**
* Command-line main class.
Expand All @@ -33,10 +33,15 @@ object Main {
Loggers.create(
settings.consoleLog.logLevel,
settings.consoleLog.color,
settings.consoleLog.logFilters,
captureLog = settings.captureLog
)
val isDebug = settings.consoleLog.logLevel == Level.Debug
val reporter =
Reporters.create(
log,
settings.consoleLog.fileFilters,
settings.consoleLog.msgFilters
)

// bail out on any command-line option errors
if (errors.nonEmpty) {
Expand Down Expand Up @@ -88,7 +93,7 @@ object Main {
try {
val compiler = Compiler(setup, log)
log.debug("Zinc compiler = %s [%s]" format (compiler, compiler.hashCode.toHexString))
compiler.compile(vinputs, cwd)(log)
compiler.compile(vinputs, cwd, reporter)(log)
log.info("Compile success " + Util.timing(startTime))
} catch {
case e: CompileFailed =>
Expand Down
9 changes: 6 additions & 3 deletions src/scala/org/pantsbuild/zinc/Settings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ case class ConsoleOptions(
logPhases: Boolean = false,
printProgress: Boolean = false,
heartbeatSecs: Int = 0,
logFilters: Seq[Regex] = Seq.empty
fileFilters: Seq[Regex] = Seq.empty,
msgFilters: Seq[Regex] = Seq.empty
)

/**
Expand Down Expand Up @@ -197,8 +198,10 @@ object Settings {
(s: Settings) => s.copy(consoleLog = s.consoleLog.copy(printProgress = true))),
int( "-heartbeat", "interval (sec)", "Print '.' to stdout every n seconds while compiling",
(s: Settings, b: Int) => s.copy(consoleLog = s.consoleLog.copy(heartbeatSecs = b))),
string( "-log-filter", "regex", "Filter log messages matching the regex from stdout",
(s: Settings, re: String) => s.copy(consoleLog = s.consoleLog.copy(logFilters = s.consoleLog.logFilters :+ re.r))),
string( "-msg-filter", "regex", "Filter warning messages matching the given regex",
(s: Settings, re: String) => s.copy(consoleLog = s.consoleLog.copy(msgFilters = s.consoleLog.msgFilters :+ re.r))),
string( "-file-filter", "regex", "Filter warning messages from filenames matching the given regex",
(s: Settings, re: String) => s.copy(consoleLog = s.consoleLog.copy(fileFilters = s.consoleLog.fileFilters :+ re.r))),
file( "-capture-log", "file", "Captures all logging (unfiltered) to the given file",
(s: Settings, f: File) => s.copy(captureLog = Some(f))),

Expand Down
35 changes: 4 additions & 31 deletions src/scala/org/pantsbuild/zinc/logging/Loggers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,16 @@ package org.pantsbuild.zinc.logging

import java.io.{ BufferedOutputStream, File, FileOutputStream, PrintWriter }
import sbt.{ AbstractLogger, ConsoleLogger, FullLogger, ConsoleOut, Level, Logger, MultiLogger }
import scala.util.matching.Regex

object Loggers {
/**
* Create a new console logger based on level, color, and filter settings. If captureLog is
* Create a new console logger based on level and color settings. If captureLog is
* specified, a compound logger is created that will additionally log all output (unfiltered)
* to a file.
*/
def create(
level: Level.Value,
color: Boolean,
filters: Seq[Regex],
out: ConsoleOut = ConsoleOut.systemOut,
captureLog: Option[File] = None
): Logger = {
Expand All @@ -29,24 +27,17 @@ object Loggers {
cl.setLevel(level)
cl
}
// add filtering if defined
val filteredLogger =
if (filters.nonEmpty) {
new FullLogger(new RegexFilterLogger(consoleLogger, filters))
} else {
consoleLogger
}
// if a capture log was specified, add it as an additional unfiltered destination
// if a capture log was specified, add it as an additional destination
captureLog.map { captureLogFile =>
// NB: we append to the capture log, in order to record the complete history of a compile
val fileLogger = {
val fl = new FullLogger(new FileLogger(captureLogFile, true))
fl.setLevel(Level.Debug)
fl
}
new MultiLogger(List(filteredLogger, fileLogger))
new MultiLogger(List(consoleLogger, fileLogger))
}.getOrElse {
filteredLogger
consoleLogger
}
}
}
Expand All @@ -70,21 +61,3 @@ class FileLogger(file: File, append: Boolean) extends Logger {

def trace(t: => Throwable): Unit = ()
}

class RegexFilterLogger(underlying: AbstractLogger, filters: Seq[Regex]) extends Logger {
override def log(level: Level.Value, msg: => String): Unit = {
// only apply filters if there is a chance that the underlying logger will try to log this
if (level.id >= underlying.getLevel.id) {
val message = msg
if (!filters.exists(_.findFirstIn(message).isDefined)) {
underlying.log(level, message)
}
}
}

def success(message: => String): Unit =
underlying.success(message)

def trace(t: => Throwable): Unit =
underlying.trace(t)
}
57 changes: 57 additions & 0 deletions src/scala/org/pantsbuild/zinc/logging/Reporters.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* Copyright (C) 2015 Pants project contributors (see CONTRIBUTORS.md).
* Licensed under the Apache License, Version 2.0 (see LICENSE).
*/

package org.pantsbuild.zinc.logging

import xsbti.{ Position, Reporter, Severity }
import sbt.{ Logger, LoggerReporter }

import scala.util.matching.Regex

object Reporters {
def create(
log: Logger,
fileFilters: Seq[Regex],
msgFilters: Seq[Regex],
maximumErrors: Int = 100
): Reporter =
if (fileFilters.isEmpty && msgFilters.isEmpty) {
new LoggerReporter(maximumErrors, log)
} else {
new RegexFilterReporter(fileFilters, msgFilters, maximumErrors, log)
}
}

/**
* Extends LoggerReporter to filter compile warnings that match various patterns.
*/
class RegexFilterReporter(
fileFilters: Seq[Regex],
msgFilters: Seq[Regex],
maximumErrors: Int,
log: Logger
) extends LoggerReporter(
maximumErrors,
log
) {

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.isEmpty && isFiltered(fileFilters, pos.sourceFile.get.getPath)) || (
isFiltered(msgFilters, msg)
)
)

override def display(pos: Position, msg: String, severity: Severity): Unit =
if (isFiltered(pos, msg, severity)) {
// the only side-effecting operation in the superclass
inc(severity)
} else {
super.display(pos, msg, severity)
}
}
1 change: 0 additions & 1 deletion tests/scala/org/pantsbuild/zinc/logging/LoggersSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ class LoggersSpec extends WordSpec with MustMatchers {
Loggers.create(
Level.Debug,
false,
Seq(),
ConsoleOut.printWriterOut(new PrintWriter(stdout)),
Some(captureFile)
)
Expand Down

0 comments on commit 085bcac

Please sign in to comment.