SBT Build Setup for Library and Multiple Command Line Tools - sbt

I'm trying to set up a Scala project, built using SBT, that will consist of a library and several command-line tools to do various things using that library. The library and tools are going to depend on another Scala project which I've installed into my local Ivy cache with sbt publish-local.
I've never used SBT before, so I'm a bit lost as to how to set this up. I would like several Linux executables or shell scripts in my top-level project directory, each of which executes a main() methods defined in a Scala file, and all of which depend on a single library. How do I get that sort of setup with an SBT project?
The way I'm thinking this will have to work is as an SBT configuration with multiple projects, and a bunch of wrapper shell scripts that execute sbt run in the appropriate project. However, when I run sbt run in my current single-project setup, I get, in addition to my program's intended output, a bunch of SBT noise:
Loading /pod/home/anovak/build/sbt/bin/sbt-launch-lib.bash
[info] Loading project definition from /pod/home/anovak/sequence-graphs/project
[info] Set current project to Sequence Graph API (in build file:/pod/home/anovak/sequence-graphs/)
[info] Running SequenceGraphs
Sequence Graphs are great!
[success] Total time: 2 s, completed Jan 6, 2014 6:01:17 PM
I would like my wrapper scripts to be able to run my command-line tools without seeing anything from SBT on screen at all. I think the [info] and [success] messages can be suppressed by messing about with the project's log level settings, but would that eliminate the "Loading..." line as well? If not, is there some other way to run an SBT project "on its own", without much/any interference from SBT?

I think what you need is one root project - sequence-graphs - with two submodules - library and cmd-tools.
project/build.properties would be as follows:
sbt.version=0.13.1
build.sbt for the root project would be as follows:
lazy val root = project in file(".") aggregate (library, `cmd-tools`)
lazy val library = project
lazy val `cmd-tools` = project dependsOn library
With only these two files you can run sbt and do projects to see the projects available.
[root]> projects
[info] In file:/Users/jacek/sandbox/so/sequence-graphs/
[info] cmd-tools
[info] library
[info] * root
At the same time SBT will create necessary subdirectories for the submodules.
With the project layout you start developing your own command-line tools in cmd-tools submodule.
To make things simple, I assume that a simple App-extending applications are enough.
cmd-tools/Hello1.scala
object Hello1 extends App {
println("Hello1")
}
cmd-tools/Hello2.scala
object Hello2 extends App {
println("Hello2")
}
With these two Hellos you can run cmd-tools/run from SBT shell in the root project.
[root]> cmd-tools/run
[info] Compiling 2 Scala sources to /Users/jacek/sandbox/so/sequence-graphs/cmd-tools/target/scala-2.10/classes...
Multiple main classes detected, select one to run:
[1] Hello2
[2] Hello1
Enter number:
The same could be run from the command line as sbt cmd-tools/run:
jacek:~/sandbox/so/sequence-graphs
$ sbt cmd-tools/run
[info] Loading global plugins from /Users/jacek/.sbt/0.13/plugins
[info] Loading project definition from /Users/jacek/sandbox/so/sequence-graphs/project
[info] Set current project to root (in build file:/Users/jacek/sandbox/so/sequence-graphs/)
Multiple main classes detected, select one to run:
[1] Hello1
[2] Hello2
Enter number: 1
[info] Running Hello1
Hello1
[success] Total time: 4 s, completed Jan 9, 2014 9:44:39 PM
Let's start it over as well as disable infos and [success]es messages.
jacek:~/sandbox/so/sequence-graphs
$ sbt --error 'set showSuccess := false' cmd-tools/run
Multiple main classes detected, select one to run:
[1] Hello1
[2] Hello2
Enter number: 1
Hello1
There's also the runMain command that Runs the main class selected by the first argument, passing the remaining arguments to the main method.
With that and the other examples you could have a sample command-line script to execute Hello1 as follows:
sbt --error 'set showSuccess := false' 'cmd-tools/runMain Hello1'
It could be even simpler when you use the sbt-onejar plugin that can Package your project using One-JAR™ With the plugin you don't have to use SBT after you distribute your command-line tools.
Quoting the plugin's documentation:
sbt-onejar is a simple-build-tool plugin for building a single executable JAR containing all your code and dependencies as nested JARs.
Please note that the Officially supported packages of SBT add some additional checks and printouts, i.e. tgz comes with bin/sbt script that does the following (amongst the other things):
echo "Loading $(dirname "$(realpath "$0")")/sbt-launch-lib.bash"
It's not an integral part of SBT itself, but the script itself that wants to do as much as possible so an end user is, say, happy. In your case, you are not necessarily happy, so either remove the line from the script or follow the steps as described in Manual Installation.

Related

SBT asks for credentials when creating a project

I am completely new to Scala and SBT. I have downloaded the .tgz archive for SBT 1.3.2, extracted it and added its bin directory to my PATH on Ubuntu 18.04.
I am following the official Getting Started guide, which gives a command to create a simple project. It is supposed to run like that:
$ sbt new sbt/scala-seed.g8
....
Minimum Scala build.
name [My Something Project]: hello
Template applied in ./hello
Instead, it asks me for credentials:
$ sbt new sbt/scala_seed.g8
[info] Set current project to code (in build file:/home/user/code/)
[info] Set current project to code (in build file:/home/user/code/)
Username:
I have no idea what to enter. I can't even try to guess, since I can only enter one character before it asks for a password. If I enter one character again, I get the username prompt again. This is the output after pressing two keys:
$ sbt new sbt/scala_seed.g8
[info] Set current project to code (in build file:/home/user/code/)
[info] Set current project to code (in build file:/home/user/code/)
Username: Password:
Username:
I just want to setup a basic project. What am I doing wrong?
If you get sbt new user/some.g8 asking for the Username: then you know that you have typed the template path e.g. user/some.g8 incorrectly so it doesn't exist as a g8 template.
Please check that you have to correct template path and try again.
Even I got the same error when I tried to create a new project following the instruction from https://docs.scala-lang.org/getting-started/sbt-track/getting-started-with-scala-and-sbt-on-the-command-line.html using sbt cli.
I ran the command as below,
sbt new hw/hello-world.g8
Following the above command I was prompted for suername and password. Then I ran it again as
sbt new scala/hello-world.g8
This time the project was successfully created.
Output:
hello-world.g8
[info] welcome to sbt 1.3.13 (Oracle Corporation Java 1.8.0_261)
[info] set current project to scala (in build file:/C:/scala/)
[info] set current project to scala (in build file:/C:/scala/)
A template to demonstrate a minimal Scala application
name [Hello World template]: hello-world
Template applied in C:\scala\.\hello-world
So the hw in the command "sbt new hw/hello-world.g8" is not correct and it has to be only "sbt new scala/hello-world.g8".
In the first, working example you have scala hyphen seed.
$ sbt new sbt/scala-seed.g8
....
In the second non-working example you have scala underscore seed.
$ sbt new sbt/scala_seed.g8
[info] Set current project to code (in build file:/home/user/code/)
[info] Set current project to code (in build file:/home/user/code/)
Username:

sbteclipse: create build.sbt and plugins.sbt

I have downloaded sbt and to resolve the proxy maven repository errors, I have created repositories files with my-maven-proxy-releases: under ~/.sbt
When I do a sbt about, I get the below details:
"~\.sbt\preloaded\org.scala-sbt\sbt\"1.0.4"\jars\sbt.jar"
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=256m; support was removed in 8.0
[warn] No sbt.version set in project/build.properties, base directory: C:\
[info] Set current project to root (in build file:/C:/)
[info] This is sbt 1.0.4
[info] The current project is {file:/C:/}root 0.1-SNAPSHOT
[info] The current project is built against Scala 2.12.4
[info] Available Plugins: sbt.plugins.IvyPlugin, sbt.plugins.JvmPlugin, sbt.plugins.CorePlugin, sbt.plugins.JUnitXmlReportPlugin, sbt.plugins.Giter8TemplatePlugin
[info] sbt, sbt plugins, and build definitions are using Scala 2.12.4
Now, I wanted to import a project in eclipse and I googled. This is the details I found.
1. ~/.sbt/<sbt-version>/plugins/plugins.sbt
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "5.2.4")
sbteclipse
2. ~/.sbt/<sbt-version>/plugins/build.sbt
for scala versions and dependencies.
But I am confused on where to create the build.sbt and plugins.sbt as my folder structure is like this:
~/.sbt/1.0
~/.sbt/1.3
and I do not see ~/.sbt/1.0.4 which is displayed in sbt about.
Please guide if my understanding wrong.
First, you need to understand sbt project structure and the difference between project-local and global plugins.
As you would usually use eclipse plugin globally you should put it in
~/.sbt/<sbt-version>/plugins/plugins.sbt
(as you wrote correctly), where <sbt-version> is
0.13 for any sbt 0.13.*
1.0 for any sbt 1.*.* (this may seem unintuitive, but it's okay)
I guess, ~/.sbt/1.3 is just a typo and is meant to be ~/.sbt/0.13.
Also you normally don't put anything in ~/.sbt/<sbt-version>/plugins/build.sbt. If you need to have some global settings (including those for the global plugins), you should put them in
~/.sbt/<sbt-version>/global.sbt
Read about global settings here.
With non-global plugins and settings it's all the same minus the ~/.sbt/<sbt-version>/ part:
use <your-project>/plugins/plugins.sbt for plugins
and <your-project>/build.sbt for project settings

managed resource available only for freshly cleaned project

I created a SBT AutoPlugin that generates resources:
https://github.com/sphereio/json-schema-inliner/
(Thx to Why doesn't a custom resourceGenerator get executed upon compile?, I could fix my first problem.)
There is a test project that generates "test/inline/category.schema.json" for example.
The test project is in GIT as well: https://github.com/sphereio/json-schema-inliner/tree/master/testProject
This generated resource is available with a freshly cleaned project:
cd testProject
▶ sbt clean run
[...]
[info] Running Main
url from test/category.schema.json: file:/Users/yannsimon/projects/json-schema/testProject/target/scala-2.10/classes/test/category.schema.json
url from test/inline/category.schema.json: file:/Users/yannsimon/projects/json-schema/testProject/target/scala-2.10/classes/test/inline/category.schema.json
When running again, the managed resource disappears from "testProject/target/scala-2.10/classes/test/inline"
▶ sbt run
[...]
[info] Running Main
url from test/category.schema.json: file:/Users/yannsimon/projects/json-schema/testProject/target/scala-2.10/classes/test/category.schema.json
url from test/inline/category.schema.json: null
Any help would be appreciated.
Thanks, Yann
Answered in sbt issue: https://github.com/sbt/sbt/issues/2168#issuecomment-144133794
The fix was this is very simple: https://github.com/sphereio/json-schema-inliner/commit/eeb490189781e93c8c6eb15b504a158ce425b653

SBT Plugin to modify compile and test tasks

I am in the process of creating a plugin that will modify both the compile:compile and test:test tasks. My ultimate aim is to be able to do sbt monkjack or sbt monkjack:test (either is fine). In the compile:compile scope I need to add a compiler plugin, and in the test:test scope I need to run some code after the tests have finished.
My first attempts were around trying to create a custom configuration but which to extend, compile or test, was unclear as both are needed (At the moment I have two, and I copy the CustomTest into the CustomCompile and then run monkjack:test). My second attempts were focusing on a custom task that in turn invoked (compile in Compile).value and (test in Test).value after setting various options.
I realize my knowledge of SBT tasks and how they are related/inherited/scoped is not great.
Q1. Is there a chain of tasks like in maven? In maven if you execute test, it will execute the other phases in order. So mvn clean test will automatically run prepare-sources, compile, etc etc. So in SBT if I run sbt test how are the other tasks automatically executed.
Q2. If you execute a task with a custom config, eg sbt millertime:test will that config propagate to the other tasks that run. Eg, is this the same as sbt monkjack:compile monkjack:test or the same as sbt compile monkjack:test or neither :)
Q3. How do tasks know which is their default config? If I do sbt compile how does SBT know that means sbt compile:compile?
Q4. Which is the best way to go here, a custom configuration or a new task.

How to execute tests in a single project only in multi-module build?

I have a multi-module build, and would like to run tests for different sub-projects independently.
Is there a way to do this in sbt, e.g. if my multi-project build has a core and commons projects, I'd like to only run test in the commons project.
Run sbt commons/test. See detailed explanation in Scopes.
You may also use the combination of two commands from sbt - changing the current project using project and executing test afterwards.
sbt "project commons" test
You can also use
sbt "; project commons; test"
It you are running sbt in interactive mode:
> project commons
> test
You can switch back to core with:
> project core
Never mind, I came across this:
How to execute package for one submodule only on Jenkins?
sbt "project core" test
Another way to do this.
Get into SBT interactive mode
> sbt
sbt:core> commons / test
No need to switch between projects.
to run sbt test only for ONLY the submodules having added, modified on deleted files, if you use git:
while read -r proj ; do sbt "project $proj" test ; \
done < <(git status --porcelain | cut -c 3- | cut -d/ -f1
There is another way to have sbt open for a particular module.
Go to the location of the module directory and type in the "sbt" command.
sbt will then open in interactive mode for that module only

Resources