how to share vals between build.sbt and assembly.sbt - scala

I'm using two files for my build: build.sbt and assembly.sbt (for building fat jars using sbt-assembly plugin). I have some vals defined in build.sbt. Let's just say I'm doing some custom tasks that depend on them. However, I noticed that vals defined in build.sbt are not visible in assembly.sbt. So I end up duplicating code in those two files. How do I configure it such that assembly.sbt can see the vals in build.sbt?
Thanks!

Currently, val in *.sbt files are meant to be namespace separated. We've debated the merits of having a global namespace or not, but in the end keeping them separate makes things a lot more consistent.
The "sbt" way to share vals and settings between build.sbt is to either:
Create a plugin which does so.
Create a "library" in the project/ directory which does so.
For option #2, you can do the following:
project/lib.scala
package mylib
object MyStuff {
val foo = "hi"
}
build.sbt
import mylib.MyStuff
// Just reference .scala code from the project/ directory.
name := MyStuff.foo
Hope that helps!

Related

How to use sbt-assembly in sbt-plugin?

I am writing an sbt-plugin to abstract away some boilerplate.
Let's call it sbt-redux
then there is one more plugin sbt-assembly.
In this quest, my plugin(sbt-redux) needs to know about where the project ( Project which is using sbt-redux ) will create Uber jar using sbt-assembly and what will be the name of jar.
I tried adding sbt-assembly in plugins of sbt-redux, but for the obvious reasons it will not add dependencies in my src folder as it has limitations only in build.sbt.
I tried using .dependsOn(assembly) but still no luck.
So, How can I use other plugins into src?
P.S. Please let me know if the question is not clear.
There I found a solution and it is working for me.
If you want to read assembly's settings, you have to make sure your plugins depend on it. In your build.sbt file, you can add:
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.7").
And then in your AutoPlugin implementation, you should override requires this way:
override def requires = super.requires && sbtassembly.AssemblyPlugin
After that, you'll have access to assembly settings and tasks.
Thanks to gpoirier.
To expand on the correct answer from #arglee, when you have a multi-module project, the addSbtPlugin line needs to be part of the .settings entries for the module that needs the dependency, like:
lazy val mod = (project in file("mod"))
.settings(
...,
addSbtPlugin( ... ),
libraryDependencies ++= Seq( ... ),
...
)

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

Mixing build.sbt with project *.scala files: should all be unified in build.sbt?

Using SBT 0.13.13, our build definition is inherited from an older project. Currently there are a build.sbt and some project/*.scala files. These scala files follow the same pattern. Here is an example:
import sbt._
import sbt.Keys._
object Docs {
lazy val docTask = TaskKey[Unit]("docPackage", "Generate Scaladoc")
lazy val settings = Seq(
docTask := {
val docs = (doc in Compile).value
IO.copyDirectory(docs, new java.io.File("src/main/resources/myapp-scaladoc"), overwrite = true)
},
docTask := (docTask.dependsOn(doc in Compile)).value
)
}
Appendix: .scala build definition says
In the previous versions of sbt, .scala was the only way to create
multi-project build definition
Question: I suppose this mean the use of separate project/*.scala files is discouraged. If so, is it OK to move the code of these *.scala file and put them all in build.sbt?
There is little functional difference between having code in project/ and code in build.sbt.
The advantage to putting code in a .scala file in project/ is that all symbols in it are imported into the namespace of all build.sbt files in all subprojects of your build. This means that helper methods, constants, plugins, or other Scala code can live in a single location, but be called from anywhere.
Ultimately, whether to use this features comes down to whether you want shared items configured in a single location, or in multiple locations.
If you prefer to have your project settings configured entirely in separate build.sbt files in their subproject directories, putting shared settings in the project/ folder is the way to do that.
If you're OK with having shared settings configured in the root build.sbt file (or if you don't use any subproject build.sbt files), you can consolidate all of your shared configuration into it.

How to load/include projects from submodule Build.scala

If I want to to combine two (or more) sbt projects (e.g. include one in the other)
without publish-local.
folder structure:
/ComboProject
build.sbt
/project
Build.scala
/Project1
build.sbt
/project
Build.scala #this includes lazy val p1
/Project2
build.sbt
/project
Build.scala #this includes lazy val p21, p22, p23, p24
The nested Build.scala gets ignored by sbt, however do they contain the project description and more importantly the build settings.
How can I import/make them visible at the ComboProject level without copy-pasting them into the top-level Build.sbt.
The same problem appears when including once project inside the other one.
/Project1 #make Project2 modules visible here
build.sbt
/project
Build.scala #this includes lazy val p1
/Project2
build.sbt
/project
Build.scala #this includes lazy val p21, p22, p23, p24
Thanks a lot,
this would make it a lot easier to depend on fast evolving dependencies.

What is the difference between build.sbt and build.scala?

I started to learn Scala and almost in every tutorial I see a build.sbt file which describes project settings. But now I have installed giter8 and created a project from template. And generated project from template missed build.sbt file, but it have build.scala (which seems used for same purposes, but it is more flexible).
So what is the difference between build.sbt and build.scala?
Which is more preferred and why?
To give a brief example, this build.sbt:
name := "hello"
version := "1.0"
is a shorthand notation roughly equivalent to this project/Build.scala:
import sbt._
import Keys._
object Build extends Build {
lazy val root = Project(id = "root", base = file(".")).settings(
name := "hello",
version := "1.0"
)
}
The .sbt file can also include vals, lazy vals, and defs (but not objects and classes).
See the SBT document called ".scala build definition", particularly the section "Relating build.sbt to Build.scala".
Consider a .scala build definition if you're doing something complicated where you want the full expressiveness of Scala.
Update July 2016 (3 years later)
Build.scala is officially deprecated in sbt 0.13.12
The Build trait is deprecated in favor of the .sbt format
PR 2530 implements that deprecation.
"Appendix: .scala build definition" has been updated.
When .sbts are being compiled, they are before that sort of merged with the .scala files inside project directory. They can't be used in recursive tasks, that is, you can't customize sbt from sbt, for example. For more detailed information, consider reading related section is sbt documentation: http://www.scala-sbt.org/release/docs/Getting-Started/Basic-Def.html#sbt-vs-scala-definition