How to use ForkOptions in SBT to change working directory for test within subproject? - scala

I currently have a multiproject SBT build with 2 projects under it, one of which has a dependency on the other. The dependent one has a test in which it needs to load a file from a certain directory structure underneath its working directory. It uses a relative path in a configuration file to designate this directory structure.
The issue is that depending on whether I am running this test through my IDE (with working directory at the subproject level) or at the SBT umbrella project level (with working directory at the umbrella level) makes a difference in the ability of my test to load this file via its relative path and succeed.
I need to use a relative path so that other developers working on this project may use the checked-in code out of the box, and duplicating the directory structure and contained files at two levels in the project is out of the question. What I really need to do is direct SBT to move the working directory into the subproject when doing tests, so that the directory structure can remain the same regardless of where the test is initiated from.
SBT offers a ForkOptions class (http://www.scala-sbt.org/0.13.0/api/index.html#sbt.ForkOptions), further described here: http://www.scala-sbt.org/0.13/docs/Forking.html at the bottom of the page, through which it seems one can supply a working directory for the forked JVM to be started in but gives no good examples on how to set up the configuration in a root build.sbt or supply a ForkOptions instance to a test task.
Does anyone have any experience using this class, and/or can anyone offer some guidance on getting this functionality out of a multiproject build in SBT?

The solution is to provide the following settings to the project definition in the root build.sbt.
lazy val yourProject = project.settings(
fork := true,
baseDirectory in test := file("yourProject")
)
These cause the JVM to fork for the tests in that subproject and changes the working directory to the base of that subproject.

Related

Organizing files in a SBT-based scala project

Newcomer to the Intellij IDE here, with no Java background. I've looked at Build Definition to get a brief idea on how should I organize my scala files, but their example doesn't cover the full structure of an SBT-based project shown attached.
Can you advise what each folder should be used for (e.g. where my source files should go, etc.) and also point me to sources where I can go read up more.
Thanks so much
It is described pretty well here:
http://www.scala-sbt.org/0.13.5/docs/Getting-Started/Directories.html
But to sum up.
.idea:
This contains the project files for your idea project, and has nothing directly to do with sbt itself. However idea (if auto refresh is enabled) updates its own project, each time the sbt build files change.
project:
This contains the sbt project files, except for the main build file (files ending in .sbt). Sbt build is itself based on scala, and if you need to have some scala code included in your build (e.g., code-generation/meta-programming, pre-compiler macros), then you can place scala source files in this directory. The code of these files can be used in your build system, and is not part of your project itself. To really understand how a build is made, then you will need to understand the difference in how sbt files and scala files for the build should be placed. When you run sbt, then it will search for .sbt files in the directory your are standing in, when these are found, it will search for scala files in the project directory. These files together are the source of the build system, but because these are source files, they need to be built before they can be used. To build this build system, sbt uses sbt. So a build system to build the build system is needed. It therefore looks for sbt files inside the project directory, and scala files for this build inside project/project and build these files to get a build system, that can build the build system (that can build your project). Actually it can continue recursive down to any project/project/project... directory, until it finds a project folder containing no scala files, and therefore needs no building before use.
The target folder inside project, is the target folder for the sbt build of your build definition. See below what a target folder is.
Normally you would not need to be concerned about this; just remember that build.sbt in your root directory is the build script for your project. project/plugins.sbt defines plugins activated for your build system, and project/build.properties contains special sbt properties. Currently the only sbt property I now of, is what version of sbt should be used.
src:
This is where your place the source files of your project. You should place any java sources in src/main/java, scala sources in src/main/scala. Resources are placed in src/main/resources.
The src/main/scala_2.11 folder is typically used, if you have some code that it not binary compatible with different versions of scala. In such cases you would be able to configure sbt to use different source files when building for different versions of scala. You probably do not need this, so I would advise to just delete the src/main/scala_2.11 folder.
Test sources are placed inside src/test/java and source/test/scala, and test resources are placed in src/test/resources.
target
This folder is the target folder for sbt. All compiled files, generated packages and so on are placed somewhere inside this dir.
Most things in this dir are not so interesting, as most of it is just internal sbt things. However if your build a jar file by calling sbt package, then it will be placed inside target/scala-x (where x is the scala version). There are also a lot of different plugins, that can package your application in different ways, and they will normally also place the package files somewhere inside the target dir.

sbt multi project: create resource in another sub-project

I have an sbt project with two sub-projects, A and B. A produces a standalone scala-based executable exe. When exe is run, it will produce a file out.xml. I want this file to be part of resources for project B. I do not want B to include any references to A's code, all I want is the out.xml file to be part of it. I suspect that http://www.scala-sbt.org/0.13.5/docs/Howto/generatefiles.html should be a good starting point, but I can't get my head around on how to split it between two projects. Any takers?
Since A is a dependency of the build process, which needs to run the executable to generate your xml file you would list it as a libraryDepencency in project/[something].sbt or project/project/[something].scala. This would make it available to code you put in build.sbt or project/[something].scala but not make it a transitive dependency of the resulting artifact of project B.
(Or you could of course make project A a sbt-plugin itself, or create yet another project which is a plugin depending on A that runs the executable.)

How do I get sbt to not try to compile a directory whose name ends in .scala as a Scala source file?

I am trying to convert an existing Maven multi-module project over to use sbt instead. One of the module subdirectories has .scala at the end of its name (because it's a pure Scala implementation of a library that was originally written in Java). Maven had no problem with this. However, sbt sees the .scala and thinks that the directory is a Scala source file and tries to compile it, which fails, of course.
How can I configure sbt so that it doesn't try to compile a directory as a source file? Note that the top-level (root) project doesn't contain any source code itself, so disabling compilation altogether at that level would be an acceptable solution (as long as it doesn't prevent the submodules from being compiled).
Yes, I have considered simply renaming the submodule directory so that it doesn't contain .scala, but I would prefer to avoid restructuring my build tree if possible.
Let's say the name of your directory is ./directory.scala (located in the root of the project). Then this should do the trick:
excludeFilter in Compile := "directory.scala"

Sbt's gen-idea always creates two IntelliJ projects

I am new to SBT. Just be curious that why does sbt's gen-idea always generate two IntelliJ projects:
.idea
.idea_modules
When I open the generated project, the "project" directory is always there as a separate project different with the top level project. The name is "myproject-build".
Just wondering whether this is normal?
Thanks.
Yes this is normal, this is the default behavior. You can change it by excluding some folders (see the doc available here : https://github.com/mpeltonen/sbt-idea at Exclude some folders)
So what is the difference between .idea and .idea_modules?
.idea_module generates an IDEA module while .idea generates an IDEA project.
In short a project can be multi-module or single-module and also contains IntelliJ libraries.
In longer version from the doc (http://confluence.jetbrains.com/display/IDEADEV/Structure+of+IntelliJ+IDEA+Project)
Project
In IntelliJ IDEA, a project encapsulates all your source code,
libraries, build instructions into a single organizational unit.
Everything you do in IntelliJ IDEA, is done within the context of a
project. A project defines some collections referred to as modules and
libraries. Depending on the logical and functional requirements to the
project, you can create a single-module or a multi-module project.
Module
A module is a discrete unit of functionality that can be run, tested,
and debugged independently. Modules includes such things as source
code, build scripts, unit tests, deployment descriptors, etc. In the
project, each module can use a specific SDK or inherit SDK defined on
the project level (see the SDK section later in this document). A
module can depend on other modules of the project.
Yes, it is ok for that SBT plugin for IDEA.
Usually IDEA project consists of top-level .idea directory (which contains configuration common to the project) and several *.iml files, one for each module in the project (module-specific configuration, like facets, excluded directories, custom dependencies). These files are usually located in the top-level directories of corresponding modules.
On the other hand, SBT plugin does something unusual. It creates standard .idea directory, but it stores all project modules in one location, namely .idea_modules directory in the top-level directory of the project. This is fully supported by IDEA project structure, which is a set of XMLs after all.
As for project directory/module, it is a standard feature of SBT builds. It contains your build configuration. See SBT manual on this.
The foregoing was about SBT plugin which is currently present in plugins repo. There is an official SBT plugin in active development which keeps familiar modules structure (no .idea_modules directory) and has higher integration with SBT. The latter is most prominent in dependency management - official plugin extracts dependencies, even unmanaged, and makes them available for the IDE; current SBT plugin cannot do that.

Transforming build definition in sbt plugin

Is it possible for an sbt plugin to hook into sbt's project loading mechanism, and alter the properties of the current root project further after it is processed?
In other words, automatically:
Take the root project
Transform it in some way. For example, with a call to dependsOn.
Make the transformed project the new root project
An application for this would be to automatically check for a "checkouts" directory inside any loaded project's base directory, and call dependsOn for each directory inside it that is symlinked. (Similar to Leiningen's checkouts feature).
See Setting up sbt environment to hack on multiple libraries at once
I would like to write (or consume) a plugin that does this automatically, but first need to know if this is viable.
Build Loaders are what provide the most flexibility in transforming builds, but are more advanced.