SBT how to use classes from Build.sbt inside plugin Task execution - scala

Any classes defined in project/*.scala files are made available for use by SBT inside the build definition code.
I would like those classes to be available during the execution of an SBT plugin task, but they do not appear to be available.
Why is that, and how can I fix it?
The specific problem I am trying to solve is adding custom rules for Scalastyle. The project does not currently support writing your own rules, but I thought I might be able to add a rule to the project/*.sbt files and then use it inside Scalastyle.
If I define a rule in project/MyRule.scala, then it is available in the project/Build.scala settings:
object MyBuild extends Build {
lazy val project = Project("MyProject", file("."))
.settings(ScalastylePlugin.Settings: _*)
// my rule is available in this classloader:
val test = classOf[MyRule].getName
...
}
... but when the ScalastylePlugin Task runs, the classloader it is using cannot see that class:
java.lang.NoClassDefFoundError: MyRule
java.net.URLClassLoader$1.run(URLClassLoader.java:202)
java.security.AccessController.doPrivileged(Native Method)
java.net.URLClassLoader.findClass(URLClassLoader.java:190)
java.lang.ClassLoader.loadClass(ClassLoader.java:307)
java.lang.ClassLoader.loadClass(ClassLoader.java:248)
java.lang.Class.forName0(Native Method)
java.lang.Class.forName(Class.java:169)
org.scalastyle.Checker$.newInstance(Checker.scala:194)
org.scalastyle.Checker$$anonfun$verifySource0$1.apply(Checker.scala:116)
org.scalastyle.Checker$$anonfun$verifySource0$1.apply(Checker.scala:116)
...
org.scalastyle.ScalastyleChecker.checkFiles(Checker.scala:64)
org.scalastyle.sbt.Tasks$.runScalastyle(Plugin.scala:121)
org.scalastyle.sbt.Tasks$.doScalastyle(Plugin.scala:90)
org.scalastyle.sbt.ScalastylePlugin$$anonfun$4$$anonfun$apply$1.apply(Plugin.scala:63)
org.scalastyle.sbt.ScalastylePlugin$$anonfun$4$$anonfun$apply$1.apply(Plugin.scala:63)
scala.Function6$$anonfun$tupled$1.apply(Function6.scala:35)
scala.Function6$$anonfun$tupled$1.apply(Function6.scala:34)
scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
sbt.$tilde$greater$$anonfun$$u2219$1.apply(TypeFunctions.scala:42)
sbt.std.Transform$$anon$4.work(System.scala:64)
sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:18)
sbt.Execute.work(Execute.scala:244)
sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:160)
sbt.CompletionService$$anon$2.call(CompletionService.scala:30)
java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
...
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
java.lang.Thread.run(Thread.java:619)
I have inspected the classloader in use during the Scalastyle task, and it has all the SBT librarydependency jars on its classpath, but no classes from the SBT project.
How can I add these classes to its classpath?

I don't think it is possible, as documented in the SBT documentation
Note: At runtime, all plugins for all builds are loaded in a separate,
parent class loader of the class loaders for builds. This means that
plugins will not see classes or resources from build definitions.
Edited
Based on the comments, I think maybe this solution may work. In the project/ create extra project called scala-style-defs. There place your rules. In the same project create build.sbt with the build definition e.g.
libraryDependencies += "org.scalastyle" %% "scalastyle" % "0.4.0"
resolvers += "sonatype-releases" at "https://oss.sonatype.org/content/repositories/releases/"
Then in the project/ create build.sbt with following content
lazy val root = project.in(file(".")) dependsOn(scalastyleDefs)
lazy val scalastyleDefs = Project(id="scalastyleDefs", base=file("scala-style-defs"))
and of course plugins.sbt with
addSbtPlugin("org.scalastyle" %% "scalastyle-sbt-plugin" % "0.4.0")
resolvers += "sonatype-releases" at "https://oss.sonatype.org/content/repositories/releases/"
Now in your main project create build.sbt and there include scalastyle settings
org.scalastyle.sbt.ScalastylePlugin.Settings

Related

Why is the message "Akka version is not supported by Typesafe Console: 2.3.4"?

I'm getting this exception when I do a sbt compile
My build.sbt contains the following entries.
scalaVersion := "2.10.3"
val akkaVersion = "2.3.4"
libraryDependencies ++= Seq(
"com.typesafe.akka" %% "akka-actor" % akkaVersion,
"com.typesafe.akka" %% "akka-testkit" % akkaVersion,
"com.typesafe.akka" %% "akka-persistence-experimental" % akkaVersion)
Any idea what's causing this ?
java.lang.RuntimeException: Akka version is not supported by Typesafe Console: 2.3.4
at scala.sys.package$.error(package.scala:27)
at com.typesafe.sbt.atmos.AtmosRun$.supportedAkkaVersion(AtmosRun.scala:65)
at com.typesafe.sbt.atmos.AtmosRun$$anonfun$selectAkkaVersion$1.apply(AtmosRun.scala:58)
at com.typesafe.sbt.atmos.AtmosRun$$anonfun$selectAkkaVersion$1.apply(AtmosRun.scala:58)
at scala.Option.map(Option.scala:145)
at com.typesafe.sbt.atmos.AtmosRun$.selectAkkaVersion(AtmosRun.scala:58)
at com.typesafe.sbt.SbtAtmos$$anonfun$atmosDefaultSettings$26.apply(SbtAtmos.scala:159)
at com.typesafe.sbt.SbtAtmos$$anonfun$atmosDefaultSettings$26.apply(SbtAtmos.scala:159)
at sbt.Scoped$RichInitialize$$anonfun$map$1$$anonfun$apply$3.apply(Structure.scala:130)
at sbt.std.Transform$$anon$3$$anonfun$apply$2.apply(System.scala:45)
at sbt.std.Transform$$anon$3$$anonfun$apply$2.apply(System.scala:45)
at sbt.std.Transform$$anon$4.work(System.scala:64)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:18)
at sbt.Execute.work(Execute.scala:244)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:160)
at sbt.CompletionService$$anon$2.call(CompletionService.scala:30)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
[error] (atmos:traceAkkaVersion) Akka version is not supported by Typesafe Console: 2.3.4
[error] Total time: 0 s, completed Aug 4, 2014 8:04:08 AM
Did you by chance use Activator to create the application? Typesafe Activator contains the Inspect tab, which basically is what is left of the console (and uses sbt-atmos which is the project where the AtmosRun class is located). I had similar problems when running Akka 2.3.4 with the Activator. Not sure if it is fixed already in the current version. You might need to deactivate the inspect feature of activator in that case.
The Typesafe Console (which you seem to be using) has been discontinued. As the exception states: Akka version is not supported by Typesafe Console: 2.3.4.
The Typesafe Console has been discontinued. Please use the latest Activator https://typesafe.com/platform/getstarted or one of the other Akka monitoring solutions:
http://kamon.io – open source, host yourself
http://www.appdynamics.com – cloud or host yourself
http://newrelic.com – cloud
I had this problem. It seems an earlier version of console or activator (or something) installed an "atmos shim" in my project. Deleting both of these files solved the problem:
activator-sbt-atmos-akka-shim.sbt
project/activator-sbt-atmos-akka-shim.sbt

Using Typesafe Config's ConfigFactory to set key setting in build.sbt?

sbt.version=0.13.1
In build.sbt I am assigning a setting key by calling a piece of my project dependency's code that in turn configures itself via Typesafe Config's ConfigFactory. My dependency has a reference.conf in the root of the jar, and my project itself contains an overriding application.conf in src/main/resources.
The lib/dependency is also my code, btw.
import com.mylib.Finders
import com.myproj.sbt.Keys._
projKeyColorSetting in Compile := Finders.findColor // this calls ConfigFactory.load
seq(projSettings:_*)
The build doesn't even load because it can't find the first conf key I attempt to reference in my lib code.
I've tried a number of combinations of scoping and Classpath manipulation in my build file, but to no avail. I assumed that the jar's reference.conf would have been on the Compile scope's classpath but it doesn't work as I expect.
I spent the majority of yesterday poring over SBT documentation on Classpath, Scopes, Keys, Tasks, and ResourceGenerators - my intention is to execute a custom plugin that relies on the projKeyColorSetting setting in build.sbt as follows:
lazy val projSettings = inConfig(Compile) {
Seq(
resourceGenerators in Compile <+= Def.task {
val fileCreated = createColorFile(projKeyColorSetting.value)
Seq(fileCreated)
}
)
}
If you are getting a class from foo.jar, then ConfigFactory.load() should get a reference.conf found in the same jar. If it doesn't, then something is wrong but it's hard to guess what. It could be that reference.conf has some invalid syntax in it possibly; it could be that reference.conf isn't in the jar; it could be that reference.conf is in a subdirectory instead of root of the jar; hard to guess. I'd try -Dconfig.trace=loads to look for problems in there (it should tell you whether config tries to load the reference.conf for example). You could also do your own classLoader.getResources and see if you can find the file without config involved.
You could also try ConfigFactory.parseResourcesAnySyntax("reference") and see if your reference settings are in there, and try calling ConfigFactory.load directly and see if your settings are in there. Just in general, double-check all assumptions and see where it goes wrong.
As for how to add src/main/resources, the two basic strategies would be 1) to get it on the classpath somehow (which is probably difficult in this case; you would need it before even launching sbt or would need to do some kind of custom ClassLoader fun) or probably more practical 2) load it manually with ConfigFactory.parseFile().
I would probably grab the resourceDirectory key as a dependency of your task and then do something like (untested):
myTask := {
val resourceDir = (resourceDirectory in Compile).value
val appConfig = ConfigFactory.parseFile(resourceDir / "application.conf")
val config = ConfigFactory.load(appConfig) // puts reference.conf underneath
Finders.findColor(config)
}
Note that this involves changing findColor to take a Config parameter, or maybe you would prefer to make Finders a non-singleton that can be constructed with a Config; see the example at https://github.com/typesafehub/config/blob/master/examples/scala/simple-lib/src/main/scala/simplelib/SimpleLib.scala#L22 where I was trying to illustrate that when using a Config usually a library should both default to ConfigFactory.load but also have a constructor that allows a custom Config for situations like this.
I think it's a bug in sbt.
Here's my understanding of your use case and how sbt ultimately behaved.
project/build.properties
sbt.version=0.13.5-M2
The folder config-only-project is for a project with the following two files - build.sbt and src/main/resources/application.conf. This is to simulate an external dependency on a project with application.conf inside.
build.sbt in config-only-project
libraryDependencies += "com.typesafe" % "config" % "1.2.0"
src/main/resources/application.conf in config-only-project
app-name {
hello = "Hello from Typesafe Config"
}
The following files configure the default plugins project as well as the build configuration itself (and hence the build for the project under investigation).
project/build.sbt
lazy val configOnlyProject = uri("../config-only-project")
lazy val plugins = project in file(".") dependsOn (configOnlyProject)
project/build.scala
import sbt._
import Keys._
import com.typesafe.config._
object build extends Build {
lazy val mySetting = taskKey[String]("Setting using Typesafe Config")
lazy val myS = mySetting := {
// Compiler issue Config conf???
println((fullClasspath in Compile).value)
val conf = ConfigFactory.load()
conf getString "app-name.hello"
}
lazy val configOnlyProject = uri("config-only-project")
lazy val root = project in file(".") settings (myS) dependsOn (configOnlyProject)
}
This gives the following directory structure:
jacek:~/sandbox/so/setting-typesafe-config
$ tree
.
├── config-only-project
│   ├── build.sbt
│   ├── project
│   └── src
│   └── main
│   └── resources
│   └── application.conf
└── project
├── application.conf
├── build.properties
├── build.sbt
└── build.scala
6 directories, 6 files
What I couldn't understand was that the setting itself didn't work - neither for the main project nor for the plugins project.
> mySetting
List(Attributed(/Users/jacek/sandbox/so/setting-typesafe-config/target/scala-2.10/classes), Attributed(/Users/jacek/sandbox/so/setting-typesafe-config/config-only-project/target/scala-2.10/classes), Attributed(/Users/jacek/.sbt/boot/scala-2.10.4/lib/scala-library.jar), Attributed(/Users/jacek/.ivy2/cache/com.typesafe/config/bundles/config-1.2.0.jar))
[trace] Stack trace suppressed: run last root/*:mySetting for the full output.
[error] (root/*:mySetting) com.typesafe.config.ConfigException$Missing: No configuration setting found for key 'app-name'
[error] Total time: 0 s, completed Mar 31, 2014 10:24:12 PM
The error was as follows:
> last root/*:mySetting
com.typesafe.config.ConfigException$Missing: No configuration setting found for key 'app-name'
at com.typesafe.config.impl.SimpleConfig.findKey(SimpleConfig.java:124)
at com.typesafe.config.impl.SimpleConfig.find(SimpleConfig.java:147)
at com.typesafe.config.impl.SimpleConfig.find(SimpleConfig.java:159)
at com.typesafe.config.impl.SimpleConfig.find(SimpleConfig.java:164)
at com.typesafe.config.impl.SimpleConfig.getString(SimpleConfig.java:206)
at build$$anonfun$myS$1.apply(build.scala:11)
at build$$anonfun$myS$1.apply(build.scala:7)
at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
at sbt.$tilde$greater$$anonfun$$u2219$1.apply(TypeFunctions.scala:42)
at sbt.std.Transform$$anon$4.work(System.scala:64)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:18)
at sbt.Execute.work(Execute.scala:244)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:160)
at sbt.CompletionService$$anon$2.call(CompletionService.scala:30)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:744)
[error] (root/*:mySetting) com.typesafe.config.ConfigException$Missing: No configuration setting found for key 'app-name'
It did work when I executed the same code in the Scala console:
> console
[info] Starting scala interpreter...
[info]
Welcome to Scala version 2.10.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import com.typesafe.config._
import com.typesafe.config._
scala> ConfigFactory.load()
res0: com.typesafe.config.Config = ...
scala> res0 getString "app-name.hello"
res1: String = Hello from Typesafe Config
When I switched to the plugins project it worked fine, too:
> reload plugins
[info] Loading project definition from /Users/jacek/sandbox/so/setting-typesafe-config/project
> console
[info] Starting scala interpreter...
[info]
Welcome to Scala version 2.10.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import com.typesafe.config._
import com.typesafe.config._
scala> ConfigFactory.load()
res0: com.typesafe.config.Config = ...
scala> res0 getString "app-name.hello"
res1: String = Hello from Typesafe Config
I wish I could explain it, but it seems too much cognitive load for me :(
Same issue with a Play project, solved by adding a ClassLoader parameter to ConfigFactory.parseResourcesAnySyntax() in the task definition:
import com.typesafe.config.ConfigFactory
lazy val root = (project in file(".")).
settings(
myTask := {
val cl = new java.net.URLClassLoader(Array((resourceDirectory
in Compile).value.toURI.toURL))
// load ./conf/foo.conf
val config = ConfigFactory.parseResourcesAnySyntax(cl, "foo.conf")
}
)
The problem that I had with sbt 1.4.4 is that I was trying to add a dependency in my meta-build (project/build.sbt) so that I could use it in my main build.
The library was using ConfigFactory.load() which uses the ClassLoader from the current thread which ended up being SbtMetaClassLoader which did not have the loaders for the meta-build dependencies.
The fix was to change the library to use ConfigFactory.load(getClass.getClassLoader) so that it was using the class loader that loaded the class from the library and presumably the rest of the JAR including the reference.conf file.

How to make sure only one Akka JAR makes it on the classpath?

I'm running into a akka.ConfigurationException: Akka JAR version [2.1.0] does not match the provided config version [2.2.3]. My speculation is that, somehow, $SCALA_HOME/lib/akka-actors.jar is making it onto the classpath along with the Akka JAR managed by SBT.
I created a simple standalone SBT project to demonstrate the issue (see below). My $SCALA_HOME points to Scala 2.10.3. In Build.scala I'm explicitly setting scalaHome to $SCALA_HOME
project/Build.scala
import sbt._
import sbt.Keys._
object ApplicationBuild extends Build {
val appName = "akka-version-problem"
val appVersion = "0.1-SNAPSHOT"
val getJars = TaskKey[Unit]("get-jars")
val getJarsTask = getJars <<= (target, fullClasspath in Compile) map { (target, cp) =>
println(cp map { _.data } filter { _.getAbsolutePath.contains("lib") } mkString "\n")
println(cp map { _.data } filter { _.getAbsolutePath.contains("akka") } mkString "\n")
}
lazy val root = Project("root", file(".")).settings(
scalaVersion := "2.10.3",
scalaHome := Some(file(System.getenv("SCALA_HOME"))),
autoScalaLibrary := false,
libraryDependencies ++= Seq(
"com.typesafe.akka" %% "akka-actor" % "2.2.3"
),
getJarsTask
)
}
src/main/scala/com/example/Main.scala
package com.example
import akka.actor.ActorSystem
object Main extends App {
val system = ActorSystem("AkkaDemoSystem")
system.shutdown()
}
When I run sbt get-jars I don't see $SCALA_HOME/lib/akka-actors.jar in the output
When I run sbt run I get:
[error] (run-main) 44c2d48a-8899-43f9-804b-55cbf739b08bakka.ConfigurationException: Akka JAR version [2.1.0] does not match the provided config version [2.2.3]
44c2d48a-8899-43f9-804b-55cbf739b08bakka.ConfigurationException: Akka JAR version [2.1.0] does not match the provided config version [2.2.3]
at akka.actor.ActorSystem$Settings.<init>(ActorSystem.scala:172)
at akka.actor.ActorSystemImpl.<init>(ActorSystem.scala:465)
at akka.actor.ActorSystem$.apply(ActorSystem.scala:111)
at akka.actor.ActorSystem$.apply(ActorSystem.scala:93)
at com.example.Main$delayedInit$body.apply(Main.scala:6)
at scala.Function0$class.apply$mcV$sp(Function0.scala:40)
at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
at scala.App$$anonfun$main$1.apply(App.scala:71)
at scala.App$$anonfun$main$1.apply(App.scala:71)
at scala.collection.immutable.List.foreach(List.scala:318)
at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:32)
at scala.App$class.main(App.scala:71)
at com.example.Main$.main(Main.scala:5)
at com.example.Main.main(Main.scala)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
Am I missing something obvious? Has anyone else run into this?
The issue here is that akka-actors.jar is part of the scala distribution. Sbt, by default, includes all these jars on your classpath. SO, you wind up with the Akka version from the scala distribution and the one you depend on directly.
Not only that, you're including scala-actors, scala-reflect, etc. If this is what you want, great.
If you'd like to prevent yourself from using more jars than you want, you should create the scalaInstance you use directly. See http://www.scala-sbt.org/release/api/index.html#sbt.ScalaInstance$ for the construction methods (You can see one of these uses the scalaHome).
I'd recommend doing something like (note: sbt 0.13 code):
scalaInstance := {
val homeDir = file("/path/to/scala-home")
val jars = (homeDir ** ".jar").get
val notAkka = jars filterNot (_ contains "akka")
val scalaLib = ScalaInstance.scalaJar(homeDir, "scala-library.jar")
val compilerLib = ScalaInstance.scalaJar(homeDir, "scala-compiler.jar")
ScalaInstance(scalaLib, compilerLib, notAkka:_*)(state.classLoaderCache.apply _)
}
This will fire you a deprecated warning. This is because we assume that if you're using scalaHome you want all those default modules from scala. Since this isn't the case, you can ignore that.
As Viktor says, I'd recommend just using sbt's resolution mechanism for Scala. The caching is of classloaders is done by default if you do this, and it will only download the artifact once. The reality is, that sbt has to download a version of scala anyway to compile your build before it knows you've configured a scalaHome for the project (since you specify this using scala itself).
Hope that helps!

cannot launch findbugs appropriately through sbt

I am trying to run findbugs-sbt plugin (https://bitbucket.org/jmhofer/findbugs4sbt/wiki/Home) for my project. However I got this error when trying to run findbugs in sbt console
[error] Exception in thread "main" java.lang.NoClassDefFoundError: edu/umd/cs/findbugs/LaunchAppropriateUI
[error] Caused by: java.lang.ClassNotFoundException: edu.umd.cs.findbugs.LaunchAppropriateUI
[error] at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
[error] at java.security.AccessController.doPrivileged(Native Method)
[error] at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
[error] at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
[error] at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
[error] at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
[error] Could not find the main class: edu.umd.cs.findbugs.LaunchAppropriateUI. Program will exit.
in project/Build.scala, I just include this as described in their wiki
import de.johoop.findbugs4sbt.FindBugs._
lazy val foo = Project(..., settings = ... ++ findbugsSettings)
in project/plugins.sbt, I added this
addSbtPlugin("de.johoop" % "findbugs4sbt" % "1.2.0") // because I am using sbt 0.12
I tried to add the findbugs dependency in project/plugins.sbt
libraryDependencies ++= Seq(
"com.google.code.findbugs" % "findbugs" % "2.0.1")
but still no go.
After looking at the source code of this plugin, I found out I had to specify the findbugs classpath to make the sbt action work. For those who run into the same problem, here is the solution.
findbugsClasspath := IO.listFiles(file(<your findbugs lib location>)).filter(_.getName.endsWith("jar")).toSeq.classpath
This should've been pointed out clearly in the wiki.
BTW - I believe this could also solve the similar issue by the cpd sbt plugin.

sbt unmanagedClasspath entry for lift compiles but not found at runtime

I have an unmanagedClasspath entry in my lift sbt file that points to the classes for an external java project. It compiles fine but I get a NoClassDefError when it runs. Below is the sbt entry followed by some of the trace of the NoClassDefError.
Any help much appreciated
Des
unmanagedClasspath in Compile += file("[Path to my project]/classes")
ERROR n.liftweb.http.provider.HTTPProvider - Failed to Boot! Your application may not run properly
java.lang.NoClassDefFoundError: com/myproject/MyClass
at bootstrap.liftweb.Boot.boot(Boot.scala:70) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.7.0_21]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[na:1.7.0_21]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.7.0_21]
at java.lang.reflect.Method.invoke(Method.java:601) ~[na:1.7.0_21]
at net.liftweb.util.ClassHelpers$$anonfun$createInvoker$1.apply(ClassHelpers.scala:364) ~[lift-util_2.9.1-2.5-RC2.jar:2.5-RC2]
at net.liftweb.util.ClassHelpers$$anonfun$createInvoker$1.apply(ClassHelpers.scala:362) ~[lift-util_2.9.1-2.5-RC2.jar:2.5-RC2]
at net.liftweb.http.DefaultBootstrap$$anonfun$boot$1.apply(LiftRules.scala:1999) ~[lift-webkit_2.9.1-2.5-RC2.jar:2.5-RC2]
at net.liftweb.http.DefaultBootstrap$$anonfun$boot$1.apply(LiftRules.scala:1999) ~[lift-webkit_2.9.1-2.5-RC2.jar:2.5-RC2]
at net.liftweb.common.Full.map(Box.scala:553) ~[lift-common_2.9.1-2.5-RC2.jar:2.5-RC2]
unmanagedJars in Compile is used as base for the same key in Runtime and Test, so its content is inherited by Runtime, but this is not the case for unmanagedClasspath. That's why you should prefer unmanagedJars when possible.
You can explicitly add your folder to both configurations:
val additionalClasses = file("[Path to my project]/classes")
unmanagedClasspath in Compile += additionalClasses
unmanagedClasspath in Runtime += additionalClasses
Note: sbt < 0.13 doesn't support val in build.sbt, so you have to duplicate its content in both settings, or switch to a full Build.scala.
See the Classpaths docs and this anwser for more details on what the classpath settings do and how they are inherited between configurations.
I could not think of a way to add it to both at the same time though...