sbt: set the base-directory of a remote RootProject - scala

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.

Related

scala create and use local library

I am trying to create a local library which contains a class
myproject.scala:
object test {
def info(message: String): Unit = println(s"INFO: $message")
}
build.sbt:
name := "MyProject"
version := "0.1"
organization := "MyCorp"
scalaVersion := "2.11.0"
sbtVersion := "0.13"
I ran sbt clean compile publishLocal and I see the jar in my local ivy2 directory. What I'm unsure about is how to now use that library in another project.
do I added libraryDependencies += "MyCorp"%"myproject_2.11"%"0.1"
to the second project's sbt, and I see it in the classPath when I print it out in the repl. The problem is when I try
import MyCorp.myproject
I get an error not found. I'm sure I'm missing something simple, but it's driving me nuts.
I ran sbt clean compile and I see the jar in my local ivy2 directory.
That's weird. sbt clean compile does not publish the artifact in the local repository. (Have you copied it manually there?) That should have been done with publishLocal command and the artifact should become available at {path_to_.ivy2}/local/MyCorp/MyProject/0.1/jars/MyProject.jar.
Now in your second project, it can be added as
libraryDependencies += "MyCorp" % "MyProject" % "0.1"
// or in libraryDependencies ++= Seq(...)
Please notice that the _2.11 suffix that you have used in the name depends on how the first project was built, whether its build was differentiated by Scala versions. If it was, the suffix would be usually present in the artifact .jar file name. And it is preferable to avoid including the suffix in the library dependency declaration, but rather use %% for built-in support.
After checking it, also try to restart the SBT CLI, because unfortunately sometimes changes in build.sbt are not taken into account on-the-fly.
Update
I assume its mycorp.myproject.test , but I tried every possible combination. #Brian
Following the comments, I think that there still should be something misconfigured in the project and/or missing in the description.
Assuming there is a file {path/to/project}/src/main/scala/mycorp/myproject/Test.scala, with the following contents:
package mycorp.myproject
object Test {
def info(message: String): Unit = println(s"INFO: $message")
}
When the artifact is published, the .jar file should contain the folders mycorp/myproject with Test.class and Test$.class files.
After adding the .jar to the dependencies of the second project, importing Test into another class should look like:
package mycorp.myproject2
import mycorp.myproject.Test
object AnotherTest extends App {
Test.info("hello")
}
I hope this helps.
End-of-update

Why can't sbt find my local package

Searching for examples of library use I downloaded this project.
https://github.com/marcusatbang/Hooks
I then moved the build.bat up one directory. Commented out the xsbt-gpg dependency lines in build.sbt and Build.scala since sbt couldn't find the package. I checked the source to comment out any imports of xsbt-gpg -- there were none. ( Surprise! )
So I managed to compile the project. I then did sbt publish-local. find ~/.ivy2 -iname "\*hooks*jar" generated the following line: .ivy2/local/cc.minotaur/hooks_2.9.0/0.1/jars/hooks_2.9.0.jar.
I then entered the examples folder and tried to build the example project.
The build.scala contains the line: libraryDependencies += "cc.minotaur" %% "hooks" % "0.1", and it generates the error: unresolved dependency: cc.minotaur#hooks_2.9.1;0.1: not found
So how do I fix this error? It seems to me it should be finding the hooks jar/
That could be that your resolver doesn't see local directory. Try something like:
val ivyLocal = Resolver.file("local", file(Path.userHome.absolutePath +
"/.ivy2/local"))(Resolver.ivyStylePatterns)
externalResolvers += ivyLocal
It seems to me that you are using two versions of Scala. The one you are generating the jar is 2.9.0 while the one you are using in the example project is 2.9.1. Probably will solve the problem setting the same version in both projects.
I think your scala version is 2.9.1, u have generated jar for version 2.9.0
change your library dependency as mentioned below.
libraryDependencies += "cc.minotaur" % "hooks_2.9.0" % "0.1"
or add scalaVersion := "2.9.0" in your build.sbt file

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.

How to add a github java dependency in sbt config?

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>")

What's the Scala + sbt workflow equivalent of Ruby + Bundler with a Gemfile?

I'm having a good time learning Scala, but I'm having the hardest time grasping how to set up a development environment.
In Ruby
File hierarchy
my_app/
|
+-- Gemfile
+-- app.rb
Gemfile
source :rubygems
gem "mechanize"
app.rb
require "mechanize"
agent = Mechanize.new
page = agent.get("http://google.com")
Install dependencies and run it
$ bundle install
$ ruby app.rb
What's the Scala equivalent with sbt?
I'm reading about sbt and how packages/imports/jar dependencies work in Java/Scala, but I can't seem to filter out the bare bones necessities.
What's the minimal file hierarchy to replicate the above with Scala?
Here's the Java Mechanize lib available on Maven: http://search.maven.org/#search|ga|1|mechanize
Once you run sbt and download the Mechanize dependencies, how to you discern the necessary import statements you need to get this to work?
val agent = new MechanizeAgent
val page: HtmlDocument = agent.get("http://www.google.com")
I got the above working in Eclipse by manually importing the .jars and then importing packages from the libraries until the compiler/runtime errors stopped and the agent worked. But that experience was discouraging and I've come here to repent.
Intent of this question: The Java ecosystem/workflow is overwhelming to me as someone that's used to Ruby's effortless, IDEless workflow. I think a bare bones equivalent would give me a place to start building upon.
Ideally, I'd like to get Scala development working with just Vim and the command line before becoming dependent on Eclipse.
sbt uses a library called ivy to import projects from the main maven repository. There are a few repositories sbt is preconfigured to work with, including the main maven repository.
Once these libraries are "resolved" (downloaded to your computer and hooked up to your project), the eclipse plugin will create dependencies to each jar in the eclipse project generated.
Here is how you configure it.
sbt Managed Dependencies
http://www.scala-sbt.org/release/docs/Getting-Started/Basic-Def.html#adding-library-dependencies
Add a dependency in your project's build.sbt file. If you add a dependency that depends on a specific version of scala, use two %% between the group and artifact name. Don't forget to add an empty line between each command in your build.sbt file.
libraryDependencies += "com.gistlabs" % "mechanize" % "0.11.0"
libraryDependencies += "org.scalatest" %% "scalatest" % "1.6.1" % "test"
Update the dependencies by running the update command:
$ sbt update
sbt Eclipse Plugin
https://github.com/typesafehub/sbteclipse/wiki/Installing-sbteclipse
You can install the sbt eclipse plugin globally by creating a file at ~/.sbt/plugins/plugins.sbt and putting this line into it:
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.1.0")
Whenever you add or update a dependency, run the following command and refresh your eclipse project:
$ sbt eclipse
I'd like to go a step farther than ffk's answer, do much more hand-holding, and actually provide the direct translation of the Ruby example to Scala + sbt.
File hierarchy
Crawler/
+- build.sbt
+- src/
+- main/
+- scala/
+- Crawler.scala
build.sbt
libraryDependencies += "com.gistlabs" % "mechanize" % "0.11.0"
Crawler.scala
import com.gistlabs.mechanize.MechanizeAgent
import com.gistlabs.mechanize.document.Document
object Crawler extends App {
val agent = new MechanizeAgent
val page: Document = agent.get("http://google.com")
}
Install dependencies and run it
$ sbt run
To make the project importable into Eclipse or IntelliJ, you need the sbteclipse-plugin or sbt-idea plugin. But rather than having to declare these plugins in every build.sbt for every new project, you can declare them in a global build.sbt:
// in ~/.sbt/plugins/build.sbt
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.1.0")
addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.2.0")
Then, back in your Scala app's root directory:
$ sbt eclipse
or
$ gen-idea
Afterwards, you should be able to open it in the respective IDE.
Note: Whenever you add dependencies in your build.sbt, you'll need to rerun the sbt eclipse/gen-idea command so the IDE can pick it up.