I'm trying out sbt's direct dependsOn feature with a git repository ("project A") hosted at Github. I am using a stable tag reference, and in my test project ("project B"), sbt does clone project A from source and starts compiling. However compilation fails with project A's own dependencies seemingly missing (i.e. it doesn't seem to pick up anything defined in project A's build.sbt).
Is this a different from maven/ivy managed dependencies? Do I need to include all the transitive dependencies in my child project B? Sounds a bit weird to me. That would kind of kill off the whole effort, as I'm having like a dozen libraries on which project A depends.
To illustrate:
Project A (online on Github as source):
// build.sbt:
version := "1.2.3"
libraryDependencies += "org.foo" %% "bar" % "1.0"
Project B (local):
// project/Build.scala
import sbt._
import Keys._
object Build extends sbt.Build {
lazy val projA = RootProject(uri("git://github.com/me/projA.git#v1.2.3"))
lazy val projB = Project(id = "project-B", base = file(".").dependsOn(projA)
}
This goes:
[info] Compiling 678 Scala sources to /Users/me/.sbt/staging/
5666eafa865fdf605be3/target/scala-2.10/classes...
[error] /Users/me/.sbt/staging/5666eafa865fdf605be3/src/main/scala/com/me/
BarKeeper.scala:3: not found: object bar
[error] import org.foo.bar
[error] ^
So do I have to re-declare the library dependency on "org.foo" %% "bar" % "1.0"? I hope not!
This was purely my own fault, not sbt's. I had overseen an unmanaged library (folder lib) in project A. After exchanging it for a Maven managed version (folder lib_managed), project A now correctly compiles from source in the staging for project B.
Related
I am using Intellij UE 2017.3. The steps that I undertook were:
Create a new project from Lightbend templates
Check import sbt sources (tried without as well)
Try the suggested solutions from this thread
As a result in my build.sbt nothing seems to be imported, regardless of whether before or after trying the suggested fixes, (even the Dependencies object in /project folder).
Here is Dependencies object contents:
import sbt._
object Dependencies {
lazy val scalaTest = "org.scalatest" %% "scalatest" % "3.0.5"
}
I attach below screenshot with the errors and project structure. Note that in External Libraries scalatest version is different from scalaVersion, but former is correctly imported in Dependencies object.
The errors that appear are:
for Dependencies: Cannot resolve symbol
for settings: Cannot resolve reference settings with such signature, Cannot resolve symbol settings
for List: Type mismatch: expected: Def.SettingsDefinition,
actual Seq[Def.Setting[_]]
for name and libraryDependencies: too many
arguments for method settings
sbt.version is 1.1.1
Disclaimer: I am new to sbt and Scala so I might be missing obvious things.
My objective here is to use the Scala compiler as a library from my main project. I was initially doing that by manually placing the scala jars in a libs directory in my project and then including that dir in my classpath. Note that at the time I wasn't using sbt. Now, I want to use sbt and also download the scala sources from github, build the scala jars and then build my project. I start by creating 2 directories: myProject and myProject/project. I then create the following 4 files:
The sbt version file:
// File 1: project/build.properties
sbt.version=0.13.17
The plugins file (not relevant to this question):
// File 2: project/plugins.sbt
addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.7.0")
The build.sbt file:
// File 3: build.sbt
lazy val root = (project in file(".")).
settings(
inThisBuild(List(
organization := "me",
scalaVersion := "2.11.12",
version := "0.1.0-SNAPSHOT"
)),
name := "a name"
).dependsOn(ScalaDep)
lazy val ScalaDep = RootProject(uri("https://github.com/scala/scala.git"))
My source file:
// File 4: Test.scala
import scala.tools.nsc.MainClass
object Test extends App {
println("Hello World !")
}
If I run sbt inside myProject then sbt will download the scala sources from github and then try to compile them. The problem is that the base-directory is still myProject. This means that if the scala sbt source files refer to something that is in the scala base-directory they won't find it. For example, the scala/project/VersionUtil.scala file tries to open the scala/versions.properties file that lies in the scala base-directory.
Question: How can I set sbt to download a github repo and then build it using that project's base-directory instead of mine's (by that I mean the base-directory of myProject in the above example) ??
Hope that makes sense.
I would really appreciate any feedback on this.
Thanks in advance !
In the Scala ecosystem you usually depend on binary artifacts (libraries) that are published in Maven or Ivy repositories. Virtually all Scala projects publish binaries, including the compiler. So all you have to do is add the line below to your project settings:
libraryDependencies += "org.scala-lang" % "scala-compiler" % scalaVersion.value
dependsOn is used for dependencies between sub-projects in the same build.
For browsing sources you could use an IDE. IntelliJ IDEA can readily import Sbt projects and download/attach sources for library dependencies. Eclipse has an Sbt plugin that does the same. Ensime also, etc. Or just git clone the repository.
I'm trying to create an SBT plugin that provides common plugins and settings for my organization's projects (something like a Maven parent POM).
Since most of these settings should also be present in the commons project itself, I'm adding the sources as unmanagedSourceDirectories in plugins.sbt so the autoplugins I define for the proper project are also present on the meta-project (a neat trick I took from sbt-release plugin).
Things work just fine, except I still need to duplicate the addSbtPlugin entries when I want a plugin for booth my proper project and meta-project. If I don't do this, my proper-project won't compile since the plugins' classes are not loaded.
I tried moving all the shared plugin dependencies to a separate autoplugin assuming SBT would compile it and add the library dependencies to the meta-project so they would be there when my common plugin is compiled, but it doesn't work.
I would like to understand why this fails and if there is some way to thinker with the compilation order to somehow make it work. If not, I would gladly hear any alternatives you guys know to avoid having to maintain duplicate versions of all my shared plugins.
Here is a simplified version of my code:
project structure
/common
|-build.sbt
|-/project
| |-plugins.sbt
|-/src/main/scala/package
|-Dependencies.scala
|-MyCommonPlugin.scala
build.sbt
sbtPlugin := true
name := "common"
plugins.sbt
unmanagedSourceDirectories in Compile += baseDirectory.value.getParentFile / "src" / "main" / "scala"
Dependencies.scala
import sbt._
import sbt.Keys._
//Plugins I intend to share between build.sbt and plugins.sbt
object Dependencies extends AutoPlugin {
override def trigger = allRequirements
override lazy val projectSettings = super.projectSettings ++ Seq(
addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "0.8.5")
)
}
MyCommonPlugin.scala
import sbt._
import sbt.Keys._
//this import fails! object sbt is not a member of package com.typesafe
import com.typesafe.sbt.GitBranchPrompt.{ projectSettings => gitBranchPromptSettings }
object MyCommonPlugin extends AutoPlugin {
override def trigger = allRequirements
override lazy val projectSettings =
super.projectSettings ++
gitBranchPromptSettings ++
Seq(
// My common settings
)
}
To make this code work I would need to repeat the addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "0.8.5") on plugins.sbt.
I've added this code to my Build.scala.
lazy val root = Project("root", file(".")) dependsOn(jbcrypt)
lazy val jbcrypt = RootProject(uri("https://github.com/jeremyh/jBCrypt.git"))
But sbt fails with the error:
[error] (root/*:update) sbt.ResolveException: unresolved dependency: default#jbcrypt_2.11;0.1-SNAPSHOT: not found
How to tell sbt that it is Java not Scala?
How to reference to a specific branch or tag?
Thank you.
Building a project from source is only possible if the referenced project is a sbt project. sbt doesn't know of all the different build systems out there, so how is it supposed to know how to build a non sbt project?
It is possible to add support for other build systems through a sbt plugin but this may be a lot of work.
Your referenced project is a simple Maven project, which means that you can easily create a sbt project from it. Just fork the repo and create a build.sbt with the following content:
scalaVersion := "2.11.5"
projectDependencies += "junit" % "junit" % "3.8.1" % "test"
publishTo := {
val nexus = "https://oss.sonatype.org/"
if (isSnapshot.value) Some("snapshots" at nexus + "content/repositories/snapshots")
else Some("releases" at nexus + "service/local/staging/deploy/maven2")
}
This is the minimal code that was necessary to get it up and running. sbt seems to require that a publish repo is specified, it also seems to require an explicit Scala version. The dependency is already specified by your linked Maven project.
Of course, you know need to change the URI of RootProject to point to the location of your fork.
To your second question: You can reference a commit/tag/branch by appending it to the URI, separated with a # sign:
uri("git://github.com/your/repo#<commit-hash/tag/branch>")
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?.