How to get Intellij to use dependencies from SBT scala - scala

I am trying to figure out how idea will recognize thrid party dependencies when using SBT. When I use the sbt plugin gen-idea it seems to download all the necessary dependencies which get put into my ~/.ivy/ directory as expected. How can intellij use these deps?
EDIT:
One thing I noticed is if I make a new idea project instead of just a module then this works? Any idea why this would be? I would like to be able to have multiple sbt modules in the same project.

The sbt-idea plugin works with multi-module sbt project. We have been using it since somewhere around sbt-0.10.0, and currently are at sbt-0.11.2. It seems like you have the dependency part of the build file set up ok, so here's an example of how we do the project setup from a full specification Build.scala file:
object Vcaf extends Build {
import Resolvers._
import Dependencies._
import BuildSettings._
lazy val vcafDb = Project(
id = "vcaf-db",
base = file("./vcaf-db"),
dependencies = Seq(),
settings = buildSettings ++ /* proguard */ SbtOneJar.oneJarSettings ++ Seq(libraryDependencies := dbDeps, resolvers := cseResolvers)
)
lazy val vcaf = Project(
"vcaf",
file("."),
dependencies = Seq(vcafDb),
aggregate = Seq(vcafDb),
settings = buildSettings ++ Seq(libraryDependencies := vcafDeps, resolvers := cseResolvers) ++ webSettings
)
}
In the example, the vcaf-db project is in the a folder within the vcaf project folder. The vcaf-db project does not have it's own build.sbt or Build.scala file. You'll notice that we are specifying libraryDependencies for each project, which may or may not be your missing link.
As ChrisJamesC mentioned, you need to do a "reload" from within SBT (or exit sbt and come back in) to pick up changes to your build definition. After the project is reloaded, you should be able to do a "gen-idea no-classifiers no-sbt-classifiers" and get an intellij project that has the main project, modules, and library access as defined in the build file.
Hope it helps!

If you want multiple SBT modules in one IDEA project, you can use sbt multi-project builds (aka subprojects). Just create a master project that refers to the modules as sub-projects, then run gen-idea on the master. To specify dependencies among the modules you have to use Build.scala (not build.sbt), as in jxstanford's answer or like this:
lazy val foo = Project(id = "foo", base = file("foo"))
lazy val bar = Project(id = "bar", base = file("bar")) dependsOn(foo)
One level of subprojects works fine (with the dependencies correctly reflected in the resulting IDEA project), but nested subprojects don't seem to work. Also, it seems to be an sbt restriction that the subprojects must live in subdirectories of the master project (i.e., file("../foo") is not allowed).
See also How to manage multiple interdependent modules with SBT and IntelliJ IDEA?.

Related

Problems with SBT dependencies in Intellij Idea

This is a problem that is really getting on my nerves. I'm writing proofs for the Welder proof assistant. I was doing so without the help of an IDE and following an SBT-based building approach. This is the build file:
name := "proofs"
scalaVersion := "2.11.8"
lazy val welder = RootProject(uri("git://github.com/epfl-lara/welder.git#2b9dd10a7a751777cc9cda543ce888294113c0b1"))
lazy val root = (project in file(".")).dependsOn(welder)
I tried to bring my project into an Intellij Idea project. However, while doing so, the IDE won't recognize the imports of the external library:
import inox._
How can I solve this issue?
Edit
I stress that the compile errors are produced in the files from Welder
Here is the welder project/Build.scala file
import sbt._
object WelderBuild extends Build {
lazy val root = Project("root", file(".")) dependsOn(inoxProject)
lazy val inoxProject = RootProject(uri("git://github.com/epfl-lara/inox.git#53ea4533a957050bd6a968d5a340890bd54998a5"))
}
See my answer to your other question and the issue on the Scala plugin issue tracker.
Renaming the modules and manually adding a dependency from the welder-root to the inox-root module will solve the compile path issue, but the build will still fail because one of the project uses source generators, which are not supported in IDEA directly.
Instead, enable the "use sbt for build and import" option in the sbt preferences:

After migrating library to scalajs, publish-local does not work

Following the hints of the post explaining the basics of migrating to scalajs and this page about cross-compilations, I decided to add cross compilation to my standalone dependency-free scala library by doing the following changes:
I added a file project/plugins.sbt with the content
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.16")
I added scalaVersion in ThisBuild := "2.11.8" in build.sbt because else just scalaVersion was using 2.10
I also added in the build.sbt the following content to ensure that I can keep the same directory structure, since I don't have any particular files for the JVM or for Javascript:
lazy val root = project.in(file(".")).
aggregate(fooJS, fooJVM).
settings(
publish := {},
publishLocal := {}
)
lazy val foo = crossProject.crossType(CrossType.Pure).in(file(".")).
settings(version := "0.1").
jvmSettings(
// Add JVM-specific settings here
).
jsSettings(
// Add JS-specific settings here
)
lazy val fooJVM = foo.jvm
lazy val fooJS = foo.js
But now, after I published the project locally using sbt publish-local the projects depending on this library do not work anymore, i.e. they don't see the classes that this library was offering and raise errors.
I looked into .ivy2/local/.../foo/0.1/jars and the JAR went from 1MB to 1KB, so the errors make sense.
However, how can I make sure the JVM jar file is compiled correctly?
Further informations
The jar time does not change anymore, it looks like there had been some miscompilation. I deleted the .ivy2 cache, but now sbt publish-local always finishes with success but does not regenerate the files.
Ok I found the solution myself.
I needed to remove the publishLocal := {} from the build, and now all the projects depending on my library work fine.

Setting a module project in Scala as an sbt project?

I'd like to know how to convert a regular scala project into an sbt project. I've tried manually creating an sbt file on the root directory, correctly implemented, but Intellij still doesn't recognize this as a sbt project, i.e, it won't show me in the "View -> Tool Windows" the "SBT" option.
How should I go about this? What I'm actually attempting to do is to create an empty project with multiple (independent) modules.
From what I've gathered there seems to be no way to add a module directly with sbt support, am I right?
Thanks
Here is an example of a multi-project build. The root project "aggregates" them all in case you want to compile them all together or package them all together, etc. The "coreLibrary" project depends on the code of "coreA" and "coreB".
import sbt.Keys._
import sbt._
name := "MultiProject"
lazy val root = project.in(file(".")).aggregate(coreA, coreB, coreLibrary)
lazy val coreA = Project("CoreA", file("core-a")).settings(
organization := "org.me",
version := "0.1-SNAPSHOT"
)
lazy val coreB = Project("CoreB", file("core-b")).settings(
organization := "org.me",
libraryDependencies += "org.apache.kafka" %% "kafka" % "0.8.2-beta",
version := "0.3-SNAPSHOT"
)
lazy val coreLibrary = Project("UberCore", file("core-main")).dependsOn(coreA, coreB).settings(
organization := "org.me",
version := "0.2-SNAPSHOT"
)
You can (for example) compile each project from the command line:
>sbt CoreB/compile
Or you can do this interactively:
>sbt
>project CoreB
>compile
I recommend you to use a single multiple-module SBT project. sbt is a great build tool for scala, you can do a lot of things with sbt, including checking out from the repository one module and built it.
sbt
projects
project <helloProject>
Actually, this feature allows multiple people to work on the same project in parallel. Please take a look at this: http://www.scala-sbt.org/0.13.5/docs/Getting-Started/Multi-Project.html.

Using a custom sbt plugin

I've created a new scala project and written an AutoPlugin underneath it in a src/main/scala/com/company/plugin directory and a corresponding namespace. The plugin code is a cut and paste of HelloPlugin3 from [1], however I have changed the names.
Then, in a second sbt project I've updated the project/plugins.sbt file to include my new Hello World plugin. This second project has other 'business code' in. When I run sbt in that second project, the plugin is resolved and I've tested that by deleting the jar from underneath the ~/.ivy/local/... and then reloading the project and witnessing sbt complain that it can't find the plugin. When I publishLocal my plugin project again, that error goes away.
So I'm happy that the plugin is resolved and the jar file is not empty because I have checked its contents.
However, when I do an sbt> about my custom plugin isn't listed and the command I was expecting to be available isn't. ("[error] Not a valid command: hello"). But the other plugin I list in plugins.sbt (io.spray sbt-revolver) does appear in the output.
Both the plugin project and the second project have scalaVersion := "2.10.3" specified in their build.sbt files.
I'm using sbt 0.13.6. Interestingly, and perhaps related, is the sbt command plugins is not apparently valid in this project either, although it works just fine in the plugin project.
What extra step am I missing to make the command available to my second project? How do I check to see if I've got some particularly messed up sbt config happening?
For convenience, the plugin code is below, but as mentioned, it's a copy from the link underneath it.
package com.company.plugin
import sbt._
import Keys._
object HelloPlugin extends AutoPlugin {
object autoImport {
val greeting = settingKey[String]("greeting")
}
import autoImport._
override def trigger = allRequirements
override lazy val buildSettings = Seq(
greeting := "Hi",
commands += helloCommand)
lazy val helloCommand =
Command.command("hello") { (state: State) =>
println("fred")
state
}
}
Edit:
The build.sbt for the plugin project as as follows;
sbtPlugin := true
scalaVersion := "2.10.3"
organization := "com.company"
name := "name"
version := "0.0.1-SNAPSHOT"
The only other file I've created in this project is the .scala file for the plugin itself.
[1] http://www.scala-sbt.org/release/docs/Plugins.html
The problem ended up being with the project/build.properties of the project trying to use the plugin. This file set the sbt version to 0.13.1, which for some reason cases both my plugin and the sbt plugins command to not work.
Changing the value to 0.13.6 made all the problems go away.

sbt-onejar and multi-project build

When using oneJar to package a multi project sbt build, project dependencies are not bundled into the jar. My setting is the following:
foo/build.sbt (top-level build.sbt)
foo/src/ (sources of the root project)
foo/gui/build.sbt (project 'build' definition)
foo/gui/src (sources of the 'gui' project)
The build definitions are:
// foo/build.sbt
name := "foo"
version := "0.0.1"
scalaVersion := "2.10.4"
lazy val root = project.in( file(".") )
lazy val gui = project.in( file("gui") ).dependsOn( root )
[...]
//foo/gui/build.sbt
name := "foo-gui"
seq(com.github.retronym.SbtOneJar.oneJarSettings: _*)
[...]
When calling oneJar on the gui project everything seems to run fine, but the classes of the root project are not included in the jar (although the library dependencies are). Is there any fix ?
I never tried a light configuration as you but shouldn't you put the oneJar settings in the root sbt file? You want to package the root and include guy right?
I tried something similar for the first time today and started with oneJar but when using a full sbt configuration the compiler complained that settings were a Seq(_) and sbt expected a single setting or something like that. I switched to sbt-assembly and it worked.
sbt-oneJar has not been updated for 2 years while sbt-assembly was recently updated. I'm not sure which one is preferred but I'd rather use an active tool.