How can I create a separate sbt Configuration or Task to compile with WartRemover?
Asked Answered
P

1

9

WartRemover is a scalac plugin. Typically it is configured via an sbt plugin.

I'd like to be able to run WartRemover on my sbt project as a separate configuration or task without affecting the usual run of compile.

After adding Wartremover to my plugins.sbt I tried quite a few variations on the following.

lazy val Lint = config("lint").extend(Compile)

project("foo").
  configs(Lint)
  settings(inConfig(Lint)(Defaults.compileSettings): _*).
  settings(inConfig(Linting)(wartremover.wartremoverSettings):_*).
  settings(inConfig(Linting)(wartremover.wartremoverErrors := wartremover.Warts.all))

Afterward scalacOptions contained roughly what I expected inside my new lint configuration and in the compile configuration. However, when I ran lint:compile and compile with sbt in debug mode so I could see the command line arguments to scalac, either both or neither commands would result in pass the -P:wartremover:... switches. That was surprising because only lint:scalacOptions showed the -P:wartremover:... switches.

How can I create a separate sbt Configuration or Task to compile with WartRemover without affecting compile:compile?

Psychopathology answered 19/12, 2014 at 23:6 Comment(2)
Do you mean a custom command? scala-sbt.org/0.12.2/docs/Extending/…Janeenjanek
@gangstead, I'm not opposed to a custom command. I simply don't understand well enough how to make it execute 'compile' with the necessary configuration.Psychopathology
A
11

I think you came really close. Here are some of the details:

  1. sbt downloads library dependencies and compiler plugins all using Compile configuration's update task, which uses libraryDependencies setting. addCompilerPlugin is a shorthand for libraryDependencies with CompilerPlugin configuration.
  2. Compiler plugin requires scalaOptions on the configuration that you're interested in.
  3. You need to grab sources from Compile to use them in Lint.

If you see the implementation of wartremoverSettings it's doing both addCompilerPlugin and scalacOptions. You have two options to disable wartremover on Compile:

  1. Use auto plugin (requires sbt 0.13.5+) to inject wartremoverSettings, then manually remove wartremover compiler plugin from Compile.
  2. Disable auto plugin, then manually add wart remover into libraryDependencies.

Here's the first option.

project/build.properties

sbt.version=0.13.7

project/wart.sbt

addSbtPlugin("org.brianmckenna" % "sbt-wartremover" % "0.11")

build.sbt

lazy val Lint = config("lint") extend Compile

lazy val foo = project.
  configs(Lint).
  settings(inConfig(Lint) {
    Defaults.compileSettings ++ wartremover.wartremoverSettings ++
    Seq(
      sources in Lint := {
        val old = (sources in Lint).value
        old ++ (sources in Compile).value 
      },
      wartremover.wartremoverErrors := wartremover.Warts.all
    ) }: _*).
  settings(
    scalacOptions in Compile := (scalacOptions in Compile).value filterNot { _ contains "wartremover" }
  )

foo/src/main/scala/Foo.scala

package foo

object Foo extends App {
  // Won't compile: Inferred type containing Any
  val any = List(1, true, "three")
  println("hi")
}

sample output

foo> clean
[success] Total time: 0 s, completed Dec 23, 2014 9:43:30 PM
foo> compile
[info] Updating {file:/quick-test/wart/}foo...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[info] Done updating.
[info] Compiling 1 Scala source to /quick-test/wart/foo/target/scala-2.10/classes...
[success] Total time: 1 s, completed Dec 23, 2014 9:43:33 PM
foo> run
[info] Running foo.Foo 
hi
[success] Total time: 0 s, completed Dec 23, 2014 9:43:37 PM
foo> lint:compile
[info] Compiling 1 Scala source to /quick-test/wart/foo/target/scala-2.10/lint-classes...
[error] /quick-test/wart/foo/src/main/scala/Foo.scala:5: Inferred type containing Any
[error]   val any = List(1, true, "three")
[error]       ^
[error] /quick-test/wart/foo/src/main/scala/Foo.scala:5: Inferred type containing Any
[error]   val any = List(1, true, "three")
[error]             ^
Achernar answered 24/12, 2014 at 2:45 Comment(3)
Thanks for your help! Your suggested worked exactly as I'd hoped. I didn't seem to need to remove the AutoPlugin added configuration from Compile, which I'm guessing is because my build is specified in .scala files.Psychopathology
I was wrong: As Eugene said I needed the filter on scalac's options to remove the wartremover switch from being passed to in the Compile configuration. It wasn't noticing any effect from the switch being passed because by default the WartRemover plugin disables all warts. However, the WartRemover plugin was still being loaded by the compiler during compile:compile which isn't what I intended.Psychopathology
What does adding Defaults.compileSettings do? It causes some issues in our build; taking it out fixes them and seems to have no side-effects. (Our settings are all defined in lazy vals that are passed into projects's settings blocks, there's nothing on the 'top level' except name, version and organization.Worth

© 2022 - 2024 — McMap. All rights reserved.