Logging from custom SBT plugin not working - scala

At work we've created this plugin, and from one of its inputKey it's suppose to log an exception (whenever that occurs). For demonstration purposes I've only used the relevant stuff, so have a look at the following code:
theTask := {
streams.value.log
val args: Seq[String] = spaceDelimited("<arg>").parsed
args.foreach { arg =>
val env = SomeLogicThatPotentiallyThrowsException(arg)
}
}
object SomeLogicThatPotentiallyThrowsException {
def apply(arg: String): String = {
if(arg==throwexception) throw Exception("Boom!")
else arg
}
}
so whenever I'm trying to use the plugin and execute the task as follows:
sbt theTask throwexception
The error is only logged whenever I've added streams.value.log as a statement in the theTask task..
So yeah.. am I doing anything wrong here or is this a bug in sbt?
Thanks for reading people

Related

How to generate an [error] instead of an [info] upon seeing a wrong value in expect()

Consider the following code:
import chisel3._
import chisel3.util._
import chisel3.iotesters._
class Inverter extends Module {
val io = IO(new Bundle {
val a = Input(UInt(4.W))
val s = Output(UInt(4.W))
})
io.s := ~io.a
}
class InverterTester(c: Inverter) extends PeekPokeTester(c) {
poke(c.io.a, 8)
step(1)
expect(c.io.s, 8) // Should be 7 here
}
object TestMain extends App {
chisel3.iotesters.Driver.execute(args, () => new Inverter()) {
c => new InverterTester(c)
}
}
Now I run sbt 'test:runMain TestMain' and got this line (info is in purple):
[info] [0.002] EXPECT AT 1 io_s got 7 expected 8 FAIL
And the exit value of sbt is zero.
I need that line to be an error (with red color):
[error] [0.002] EXPECT AT 1 io_s got 7 expected 8 FAIL
As well as making the above sbt command exit with a non-zero value.
How can I achieve it with minimal change to existing code?
First the easy part. You can get a non-zero result code by using the result of chisel.execute like this.
val result = chisel3.iotesters.Driver.execute(args, () => new Inverter()) {
c => new InverterTester(c)
}
System.exit(if(result) 0 else 1)
Changing the logging level, unfortunately requires changing each of the separate backends in the chisel-testers repo. The following is an example of changing the TreadleBackend.scala, one of the three.
def expect(signal: InstanceId, expected: BigInt, msg: => String)
(implicit logger: TestErrorLog, verbose: Boolean, base: Int) : Boolean = {
signal match {
case port: Element =>
val name = portNames(port)
val got = treadleTester.peek(name)
val good = got == expected
if (!good) {
logger error
s"""EXPECT AT $stepNumber $msg $name got ${bigIntToStr(got, base)} expected ${bigIntToStr(expected, base)}""" +
s""" ${if (good) "PASS" else "FAIL"}"""
}
else if (verbose) {
logger info
s"""EXPECT AT $stepNumber $msg $name got ${bigIntToStr(got, base)} expected ${bigIntToStr(expected, base)}""" +
s""" ${if (good) "PASS" else "FAIL"}"""
}
if(good) treadleTester.expectationsMet += 1
good
case _ => false
}
}
This would not be an unreasonable issue to file, I think a logger.error would make more sense on an expect failure. There is some concern that changing this could have unexpected consequences for existing users, who are looking for that string.
But I'd like to encourage you to take a look at freechipsproject/chisel-testers2 repo. It's where the team is putting most of their testing development time. It would be easier to change, it has a lot of other nice features for building unit tests, and we are looking at ways we can make it better than chisel-testers.

Can you access a SBT SettingKey inside a Command?

I am writing a Command and want to use the Logger in TaskStreams but this is not possible since you cannot access .value of a SettingKey in a Command. Is there some way?
def myCommand = Command.single("myCommand") {
case (currentState, userInput) =>
val extracted = Project.extract(currentState)
val log = streams.value.log <--- not allowed
log.info("Some logging")
currentState
}
streams is intended for tasks, not commands.
So one way is to create a "holder" TaskKey and get a stream of that, for instance sbt-pgp creates and uses pgpCmdContext - see the definition of pgp-cmd.
Another way is using sLog, but I'm not sure if sLog should be used here:
val myCommand = Command.single("myCommand") { case (s, arg) =>
val extracted = Project extract s
val log = extracted get sLog
log info "Some logging"
currentState
}

Symbol value does not exist in someMethod

This is my source code for testing:
import org.openqa.selenium.firefox.FirefoxDriver
import org.scalatest.FlatSpec
import org.scalatest.Matchers
import play.api.test.FakeApplication
import play.api.test.WithApplication
class FunctionalSpec extends FlatSpec with Matchers {
def withDriver(f: FirefoxDriver => Unit) = {
val driver = new FirefoxDriver
try {
new WithApplication(
new FakeApplication(additionalConfiguration = Map("application.secret" -> "secret"))) {
f(driver)
}
} finally {
driver.quit
}
}
}
It doesn't show any compile-error in Eclipse. But when I execute the test command it shows a very long error message. This is the first line of the errors:
symbol value f$1 does not exist in test.FunctionalSpec$$anon$1$delayedInit$body.apply
I tried to play around a bit by modifying the code as shown below:
def withDriver(f: FirefoxDriver => Unit) = {
val driver = new FirefoxDriver
try {
val g = f
val driver2 = driver
new WithApplication(
new FakeApplication(additionalConfiguration = Map("application.secret" -> "secret"))) {
val h = g
val driver3 = driver2
h(driver3)
}
} finally {
driver.quit
}
}
There are no errors thrown when I executed the test command. Any idea what's happening? Is there any limit of how deep a block of code can go in order to keep the identifiers recognised?
EDIT:
Using my modified code above results in runtime-error. I added the code below:
"The admin" should "be able to login and logout correctly" in withDriver { implicit driver =>
// Don't do anything yet.
}
This one is displayed in one line of the runtime-error messages:
Cause: java.lang.NoSuchFieldError: g$1
Any suggestion for a workaround?
ADDITIONAL NOTE:
All the codes above compile just fine. Neither Eclipse or scalac complain. All the errors above happen only when I do the test command from the Play command shell.
This doesn't directly answer your question, but I would do two things:
Use Specs2 instead of ScalaTest
Rewrite your tests as described here: http://www.playframework.com/documentation/2.2.x/ScalaFunctionalTest

NPE when accessing val that is not lazy

EDIT2:
So another heads up on this:
I still have no idea why this happens, but I have now a similar problem with jOOQ and the Dialect I have to it. My code here looks like this:
object MyDB {
private lazy val dialect = SQLDialect.POSTGRES
def withSession[T](f: DSLContext => T) = f(DSL.using(getConnectionPool, dialect))
}
if I remove the "lazy" it blows up when I try to execute jOOQ queries in line 552 of https://github.com/jOOQ/jOOQ/blob/version-3.2.0/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java
That happens to be a line where the dialect is evaluated. After I added the lazy everything works as expected.
Maybe this is an issue with the threading of LiftWeb and the executing thread does not see the correct value of the val? I have no idea...
EDIT:
I have found a way to do what I want simply by adding a lazy to the values in the first, broken version. So with lazy vals it all works well.
However I'll let this stay open, as I have no idea how to explain this behavior.
Original Post:
So I am trying to use Parameterized Queries in Slick.
My code is below, my problem is that I get an NPE (see comments) when I try to run this from within the webapplication (liftweb, container started with sbt) (the application creates an object of the class PlayerListCollector that is given the string "cola")
When I execute the object as App from within Eclipse the println at the bottom works just fine.
class PlayerListCollector(term: String) {
import PlayerListCollector._
val searchResult = executeSearch(term)
}
object PlayerListCollector extends Loggable with App{
private val searchNameCurrent = Parameters[String].flatMap {
case (term) => {
for {
p <- Players if p.uberName.isNotNull
n <- p.displayName if (n.displayName.toLowerCase.like(term))
} yield (p.id, n.displayName)
}
}
private def executeSearch(term: String) = {
val lowerTerm = "%"+term.toLowerCase()+"%"
logger info "HELLO " +lowerTerm // prints HELLO %cola%
val foo = searchNameCurrent(lowerTerm) // NPE right in this line
logger info foo // never executed from here on ...
val byCurrent = foo.list
logger info byCurrent
[...]
}
// this works if run directly from within eclipse!
println(DB withSession {
searchNameCurrent("%cola%").list
})
}
The problem vanishes when I change the code to look like this:
[...]
object PlayerListCollector extends Loggable with App{
private def executeSearch(term: String) = {
val searchNameCurrent = Parameters[String].flatMap {
case (term) => {
for {
p <- Players if p.uberName.isNotNull
n <- p.displayName if (n.displayName.toLowerCase.like(term))
} yield (p.id, n.displayName)
}
}
val lowerTerm = "%"+term.toLowerCase()+"%"
logger info "HELLO " +lowerTerm // prints HELLO %cola%
val foo = searchNameCurrent(lowerTerm) // executes just fine when the query is in a local val
logger info foo
val byCurrent = foo.list
logger info byCurrent // prints expected output
[...]
}
[...]
}
I have no idea whatsoever why this happens.
Isn't the whole point of a paramterized query to put it in a val that is only once filled with a value so it does not need to be compiled multiple times?
So it turns out I used the App-Trait (http://www.scala-lang.org/api/current/index.html#scala.App) on these objects.
Reading the big fat caveat tells us what is happening I guess.

Ostrich can't compile configuration file

I'm trying to use ostrich as configuration library in my new application (previously I had a positive experience using it for runtime statistics). But I can't get it work using the code snippet from the readme.
Here is my code:
class Boot {
val bootLogger = LoggerFactory.getLogger(this.getClass)//slf4j
val confPath = Option(System.getenv("CONF_FILE"))
//living inside akka-kernel, so there is no access to real args
val args: Array[String] = confPath match {
case Some(path) => Array("-f", path)
case None => Array()
}
bootLogger.info(Class.forName("la.myproject.Config").toString)
val runtime = RuntimeEnvironment(this, args)
val server = runtime.loadRuntimeConfig[Server]()
try {
server.start()
} catch {
case e: Exception =>
bootLogger.error("Server start failed", e)
}
}
And this is my config:
new la.myproject.Config {
//use the defaults
}
The program successfully loads the configuration class and fails with the following eror:
Error in config file: ../../src/main/conf/myproject.scala
com.twitter.util.Eval$CompilerException: Compiler exception error: line 3: not found: value la
new la.myproject.Config {
I guess that it is a class loading problem. But digging through sources gave me no clue why it happens. Ostrich as well as Eval utility don't touch classloading at all.
In your config file:
import la.myproject.Config