scala sbt-launch.jar - multiple projects ihe same directory? - scala

I'm sure this is simple, but I haven't figured it out yet...
I've installed sbt-launch.jar and a shell script to execute it (named sbt).
How do I put multiple projects in the same directory?
When I run sbt the directories project and target get created and populated, and the current project is default-XXXXX. The compile command picks up source files in the top-level directory and jar files in the top-level 'lib' directory.
How do I add another project under the same directory? Every time I run sbt in an empty directory it creates a 20+ MB project directory.
Note 1: when I run sbt I an not getting asked "Create new project?" or any other questions.
Note 2: I am using sbt-launch.jar from this url: http://typesafe.artifactoryonline.com/typesafe/ivy-releases/org.scala-tools.sbt/sbt-launch/0.10.1/sbt-launch.jar
and I'm following the instructions at: http://code.google.com/p/simple-build-tool/wiki/Setup

Found the answer (for sbt 0.10.1):
Create the file project/Build.scala that looks like this:
import sbt._
object MyBuild extends Build
{
lazy val root = Project("root", file("."))
lazy val sub1: Project = Project("proj1", file("dir1"));
lazy val sub2 = Project("proj2", file("dir2"))
}
This creates three projects 'root' (in the top-level directory), 'proj1' (in the sub-directory 'dir1') and 'proj2' (in the sub-directory 'dir2')
For more info, see https://github.com/harrah/xsbt/wiki/Full-Configuration

Related

Reuse Scalafmt Config File Across Projects

I have a set of Scala projects and for all of those projects, I would like to introduce some scala source code formatting for which purpose, I'm using the scamafmt sbt pliugin. I have compiled the config file and this config file is in a separate project repo. I would now like to reuse this in all of the other Scala projects. I see two possibilities:
Use the repo where the conf file is located as a git submodule in all the other 10 projects where I want to run the scala formatter
Do not do anything, just add a README documentation that every user who is working on the codebase should download the scalafmt conf file to the project (I will pre add a .gitignore to all projects to ignore the local conf file)
Is there any other approach? I definitely do not want the conf file to diverge if I leave it as is in all the projects.
As per the documentation, one option is to build (and publish in your org) a SBT plugin with your configuration:
https://scalameta.org/scalafmt/docs/installation.html#share-configuration-between-builds
To share configuration across different sbt builds, create a custom sbt plugin that generates .scalafmt-common.conf on build reload, then include the generated file from .scalafmt.conf
// project/MyScalafmtPlugin.scala
import sbt._
object MyScalafmtPlugin extends AutoPlugin {
override def trigger = allRequirements
override def requires = plugins.JvmPlugin
override def buildSettings: Seq[Def.Setting[_]] = {
SettingKey[Unit]("scalafmtGenerateConfig") :=
IO.write(
// writes to file once when build is loaded
file(".scalafmt-common.conf"),
"maxColumn = 100".stripMargin.getBytes("UTF-8")
)
}
}
// .scalafmt.conf
include ".scalafmt-common.conf"

Scala Standalone JAR with a conf Folder

I'm using the sbt assembly jar plugin to create a standalone jar file. My project folder structure would look like this:
MyProject
-src
- main
- scala
- mypackages and source files
- conf // contains application.conf, application.test.conf and so on
- test
-project // contains all the build related files
- README.md
I now want to be able to run the fat jar that I produce against a version of the application.conf that I specify as a System property!
So here is what I do in my unit test!
System.setProperty("environment", "test")
And this is how I load the config in one of the files in my src folder:
val someEnv = Option(System.getProperty("environment", "")).filter(_.nonEmpty) // gives me some(test)
val name = s"application.${someEnv.get}.conf"
I can see that the environment variable is set and I get the environment passed it. But later on I load the application.test.conf as below:
ConfigFactory.load(name).resolve()
It however loads just the edfault application.conf and not the one that I specify!
What is wrong in my case? Where should I put the conf folder? I'm trying to run it against my unit test which is inside the test folder!
I believe you need to specify the full name of the configuration file. The .conf is optional. Try
ConfigFactory.load(s"application.${someEnv.get}").resolve()
The docs for ConfigFactory.load(String) indicate you need to supply
name (optionally without extension) of a resource on classpath
Ok! Here is what I had to do! Change the name of the folder where the config file is located. I originally had it as conf and I had to rename it to resources and bang it worked!

how to get the sub project path in sbt multi project build

I am trying to get the location of sub project in multi-project build in sbt. But I am able to get only the root project directory.
lazy val copyToResources = taskKey[Unit]("copies the assembly jar.")
private val rootLocation: File = file(".").getAbsoluteFile
private val subProjectLocation: File = file("sub_project").getAbsoluteFile.getParentFile
lazy val settings = Seq(copyToResources := {
val absPath = subProjectLocation.getAbsolutePath
println(s"rootLocation:$subProjectLocation $absPath, sub-proj-location: ${rootLocation.getAbsolutePath}")
})
Output:
rootLocation:/home/user/projects/workarea/repo /home/vdinakaran/projects/workarea/repo, sub-proj-location: /home/vdinakaran/projects/workarea/repo
rootLocation:/home/user/projects/workarea/repo /home/vdinakaran/projects/workarea/repo, sub-proj-location: /home/vdinakaran/projects/workarea/repo
directory structure:
repo
|-- sub_project
As a work around , I have added the sub_project folder using the rootLocation. But why the file("sub_project") is not returning the path ?
If you define your subproject like this
lazy val subProject = project in file("sub_project") // ...
then you can get its path using the scoped baseDirectory setting:
(outdated syntax, pre sbt 1)
baseDirectory.in(subProject).value.getAbsolutePath
(new unified syntax)
(subProject / baseDirectory).value.getAbsolutePath
And in the sbt console:
> show subProject/baseDirectory
About the problem with your code (beside that you mixed up root and sub-project in the output) is the usage of relative paths. Sbt documentation on Paths explicitly says
Relative files should only be used when defining the base directory of a Project, where they will be resolved properly.
Elsewhere, files should be absolute or be built up from an absolute base File. The baseDirectory setting defines the base directory of the build or project depending on the scope.

Using DependsOn between two ScalaJS SBT projects

(Long question ahead. Simplified tl;dr at the bottom).
I have two ScalaJS projects built with SBT - "myapp" and "mylib", in the following directory structure
root/build.sbt
root/myapp/build.sbt
root/myapp/jvm/
root/myapp/js/
root/myapp/shared/
root/mylib/build.sbt
root/mylib/jvm
root/mylib/js
root/mylib/shared
lib exports an artifact named "com.example:mylib:0.1", which as used as a libraryDependency for myapp.
myapp and mylib are in separate repositories, contain their own build files, and should be able to be build completely separately (i.e. they must contain their own individual build config).
In production, they will be built separately with mylib being first published as a maven artifact before building myapp separately.
In development however, I want to be able to merge these into a parent SBT project so that both can be developed in parallel without needing to use publishLocal after each change.
In a traditional (not scalajs) project this would be quite easy
$ROOT/build.sbt:
lazy val mylib = project
lazy val myapp = project.dependsOn(mylib)
However in ScalaJS, we actually have two projects inside each module - appJVM, appJS, libJVM and libJS. As such, the above configuration only finds the aggregate root project and does not correctly apply the dependsOn configuration to the actual JVM and JS projects.
(i.e. myapp and mylib build.sbt each contains two projects, and an aggregate root project)
Ideally I'd like to be able to do something like the following
lazy val mylibJVM = project
lazy val myappJVM = project.dependsOn(mylibJVM)
lazy val mylibJS = project
lazy val myappJS = project.dependsOn(myappJS)
Unfortunately this just creates new projects within the root instead of importing the subprojects themselves.
I've also tried various combinations of paths (such as)
lazy val mylibJVM = project.in(file("mylib/jvm"))
But this doesn't see configuration in build.sbt file in mylib
Ultimately I keep running up against the same problem - when importing an existing multi-project SBT project into a parent sbt file, it imports the root project, but does not seem to provide a way to import a subproject from an existing multimodule SBT file in a way that lets me add dependsOn configuration to it.
tl;dr
If I have
root/mylib/build.sbt with multiple projects defined and
root/myapp/build.sbt with multiple projects defined
Is it possible to import individual subprojects into root/build.sbt instead of the root project from the submodule?
i.e. Can I have two layers of multiproject builds.
After spending a lot of time digging through SBT source code, I managed to figure out a solution. This isn't clean, but it works. (For bonus points, it imports correctly into IntelliJ).
// Add this function to your root build.sbt file.
// It can be used to define a dependency between any
// `ProjectRef` without needing a full project definition.
def addDep(from:String, to:String) = {
buildDependencies in Global <<= (
buildDependencies in Global,
thisProjectRef in from,
thisProjectRef in to) {
(deps, fromref, toref) =>
deps.addClasspath(fromref, ResolvedClasspathDependency(toref, None))
}
}
// `project` will import the `build.sbt` file
// in the subdirectory of the same name as the `lazy val`
// (performed by an SBT macro). i.e. `./mylib/build.sbt`
//
// This won't reference the actual subprojects directly,
// will but import them into the namespace such that they
// can be referenced as "ProjectRefs", which are implicitly
// converted to from strings.
//
// We then aggregate the JVM and JS ScalaJS projects
// into the new root project we've defined. (Which unfortunately
// won't inherit anything from the child build.sbt)
lazy val mylib = project.aggregate("mylibJVM","mylibJS")
lazy val myapp = project.aggregate("myappJVM","myappJS")
// Define a root project to aggregate everything
lazy val root = project.in(file(".")).aggregate(mylib,myapp)
// We now call our custom function to define a ClassPath dependency
// between `myapp` -> `mylib` for both JVM and JS subprojects.
// In particular, this will correctly find exported artifacts
// so that `myapp` can refer to `mylib` in libraryDependencies
// without needing to use `publishLocal`.
addDep("myappJVM", "mylibJVM")
addDep("myappJS","mylibJS")

PlayFramework2 Scala File Map

I'm just starting with Scala and have run into a problem that has me stumped, but I'm guessing that I'm missing something easy.
I was following instructions to use the Clapper ClassFinder:
http://thoughts.inphina.com/2011/09/15/building-a-plugin-based-architecture-in-scala/
val classpath = List("./plugins").map(new File(_))
val finder = ClassFinder(classpath)
val classes = finder.getClasses
val classMap = ClassFinder.classInfoMap(classes)
After executing the first line, I see that classpath is set simply to
List(.\plugins)
I'm running this on windows, so the swapping of the slash seems to be OK.
But I expected to see a list of File objects, although I am not sure about this Scala syntax, and perhaps I'm missing something in the Scala IDE. The value for classes shows an "empty iterator".
It seems not to be finding any files in the path that I specified. I tried using an absolute path, but I had the same results. I have a single jar file in the plugins directory that I'm hoping it will find. The plugins directory is at the root of the Play2 project I'm using.
Edit ---
I did find that when I explicitly list the path to one jar that it is able to find it:
val classpath = List("./plugins/myPlugin.jar").map(new File(_))
But I want to find all jar files in the directory.
The following didn't work:
val classpath = List("./plugins/*").map(new File(_))
Nor did this:
val classpath = List("./plugins/*.jar").map(new File(_))
Judging by this issue on the ClassFinder repo on Github it may be a bug.
I think you need to create an explicit list of jar files or to list the ones contained in your folder like:
val classpath =(new File("./plugins")).listFiles.filter(_.getName.endsWith(".jar"))
EDIT: from a cursory glance at ClassFinder's source on GitHub I think it's not a bug. ClassFinder searches for .class files either in jars or in zip files or directly in folders but it looks like it does not mix these things recursively (i.e. if you give it a folder it will look for classes directly in the folder but it won't look for classes in jars in the folder)
if you objective is to list all jar files, you can use following code:
val classpath = List("./plugins").map(path => Option(new File(path).listFiles).getOrElse(Array.empty[java.io.File]) filter(file => file.isFile && file.getName.endsWith(".jar"))).flatten