Copying resources using SBT - scala

I have a Scala project, using SBT. I have a directory html inside my project which needs to be copied when the project is being run with sbt run, or when I package it into a Jar using sbt-assembly. Either way, I'll expect to have the html directory copied to target/scala-2.11/classes/html.
I have tried:
resourceDirectory in Compile := file("html")
...which moves each of the files inside html to target/scala-2.11/classes without the intermediate html directory.
and:
unmanagedResources in Compile := Seq(file("html"))
...which copies the directory, but none of the files inside it!

Maybe not so nice, but working:
val html = "html"
lazy val compileCopyTask = taskKey[Unit](s"Copy $html.")
compileCopyTask := {
println(s"Start copying $html")
val mainVersion = scalaVersion.value.split("""\.""").take(2).mkString(".")
val to = target.value / ("scala-" + mainVersion) / html / "classes"
to.mkdirs()
val from = baseDirectory.value / html
IO.copyDirectory(from,to)
println(s"$from -> $to...done.")
}
compile in Compile := {
compileCopyTask.value
(compile in Compile).value
}

if you run sbt copy-resourcesafter you sbt compile
you might have some luck. Ran into this recently.
your html folder will have to be in scr/main/resources or wherever your resourceDirectory is set in your build....

Related

How do I make sbt include non-Java sources to published artifact?

How do I make sbt include non-Java sources to published artifact ?
I'm using Kotlin plugin and can't figure out how to force sbt to include .kt file into published source jar. It only includes .java files.
A lot of people online suggest adding following code to sbt script but it doesn't help
mappings in (Compile, packageSrc) ++= {
val base = (sourceManaged in Compile).value
val files = (managedSources in Compile).value
files.map { f => (f, f.relativeTo(base).get.getPath) }
},
I also tried
includeFilter in (Compile, packageSrc) := "*.scala" || "*.java" || "*.kt",
Here is output of some variables in sbt console
sbt:collections> show unmanagedSourceDirectories
[info] * /home/expert/work/sideprojects/unoexperto/extensions-collections/src/main/scala
[info] * /home/expert/work/sideprojects/unoexperto/extensions-collections/src/main/java
[info] * /home/expert/work/sideprojects/unoexperto/extensions-collections/src/main/kotlin
sbt:collections> show unmanagedSources
[info] * /home/expert/work/sideprojects/unoexperto/extensions-collections/src/main/java/com/walkmind/extensions/collections/TestSomething.java
which plugin you use for kotlin?
https://github.com/pfn/kotlin-plugin has the option kotlinSource to configure where the source directory is located.
sbt packageBin compiled kotlin files and include them to output jar.
build.sbt
// define kotlin source directory
kotlinSource in Compile := baseDirectory.value / "src/main/kotlin",
src/main/kotlin/org.test
package org.test
fun main(args: Array<String>) {
println("Hello World!")
}
console
sbt compile
sbt packageBin
target/scala-2.13
jar include MainKt.class
and folder org/test contains MainKt.class too.
would this solve your problem?
I found a workaround for this in my project https://github.com/makiftutuncu/e. I made following: https://github.com/makiftutuncu/e/blob/master/project/Settings.scala#L105
Basically, I added following setting in SBT to properly generate sources artifact:
// Include Kotlin files in sources
packageConfiguration in Compile := {
val old = (packageConfiguration in Compile in packageSrc).value
val newSources = (sourceDirectories in Compile).value.flatMap(_ ** "*.kt" get)
new Package.Configuration(
old.sources ++ newSources.map(f => f -> f.getName),
old.jar,
old.options
)
}
For the documentation artifact, I added Gradle build to my Kotlin module. I set it up as shown here https://github.com/makiftutuncu/e/blob/master/e-kotlin/build.gradle.kts. This way, I make Gradle build generate the Dokka documentation. And finally, added following setting in SBT to run Gradle while building docs:
// Delegate doc generation to Gradle and Dokka
doc in Compile := {
import sys.process._
Process(Seq("./gradlew", "dokkaJavadoc"), baseDirectory.value).!
target.value / "api"
}
I admit, this is a lot of work just to get 2 artifacts but it did the trick for me. 🤷🏻 Hope this helps.

IntelliJ repeatedly forgets that target src_managed is a source directory

I am using IntelliJ 2017.1 Ultimate edition. I am working on a scala project where I generate some code using SBT.
The code is copied into target/scala-2.11/src_managed folder.
Time and again, my compilation fails and I see that IntelliJ has forgotten that src_managed is a source dir
If i right click on the src_managed folder and say mark directory as source root then compilation succeeds. But its very irritating that IntelliJ forgets time and again, that this is a source directory.
Stumbled upon this question as I had the same problem. Though this question is old, I'll answer with my solution for others that may have the same problem.
Add the directory as managed source directory in your build.sbt:
Compile / managedSourceDirectories += baseDirectory.value / "target/scala-2.13/src_managed"
// or if you have your scala version in a value/variable
lazy val scalaVersion = "2.13.3"
Compile / managedSourceDirectories += baseDirectory.value / s"target/scala-${"""[\d]*[\.][\d]*""".r.findFirstIn(scalaVersion).get}/src_managed"
For some reason when you add "main" to the source path and it creates the sources in src_managed/main then Intellj picks it up:
.settings(
(sourceGenerators in Compile) += (codeGen in Compile),
(codeGen in Compile) := {
val r = (runner in Compile).value
val s = streams.value.log
// This is [basedir]/target/scala-2.11/src_managed
val sourcePath = sourceManaged.value
val classPath = (fullClasspath in Test in `generator`).value.map(_.data)
// This is [basedir]/target/scala-2.11/src_managed/main
val fileDir = new File(sourcePath, "main").getAbsoluteFile
r.run(
"com.github.integration.CodeGeneratorRunner",
classPath, Seq(fileDir.getAbsolutePath), s
)
)
)
... and then intellj picks it up!
I don't know how, I don't know why but it does. SBT works either way. Maybe there's some SBT convention we don't know about, maybe there's a bug with Intellij.

webappResources in package := Seq(baseDirectory.value ....) throws Error parsing expression

I try to configure sbt (version 0.9.0) to use webapp/dist as the webappResource directory when running package task in sbt, and webapp/app as the webappResource directory when running the container:start command, following this description:
How to have different webapp resources for container:start and package tasks in SBT
But it throws the following error:
error: eof expected but 'package' found.
webappResources in package := Seq(baseDirectory.value / "webapp" / "dist")
^
[error] Error parsing expression.
I guess that package is a reserved word also in sbt conf file, any other way to override setting in package task?
The reason for doing this is that I use gulp to manage webclient. Gulp runs the project from app folder, and compiles (minification etc.) the webclient project into dist folder. When I develop, I use the webapp/app folder as declared below:
webappResources in Compile := Seq(baseDirectory.value / "webapp" / "app")
When I create a release, I first build (minification etc.) the webapp client into webapp/dist using gulp. Then I want to package webapp/dist content into the final war.
But I am not able to override the setting above to use webapp/dist, when using the package task.
I have also tried to create my own configuration like this:
webappResources in Compile := Seq(baseDirectory.value / "src" / "main" / "webapp" / "app")
lazy val ReleaseWarConfig = config("release-war") extend (Compile)
val root = (project in file(".")).
configs(ReleaseWarConfig).
settings(inConfig(ReleaseWarConfig)(webSettings): _*).
settings(
webappResources in Compile := Seq(baseDirectory.value/"src"/"main"/"webapp"/"dist")
)
// I have also tried webappResources in ReleaseConfig instead of Compile ..
But it still uses the webapp/app directory instead of webapp/dist directory.
Any help would be very much appreciated !!!!
What is the directory layout of your project? It sounds like you have your Web application resources directory at [myproject]/webapp/dist/, meaning you have WEB-INF/ and WEB-INF/web.xml (and various other optional resources) under [myproject]/webapp/dist/ as well. Is this correct?
To set the location of your Web application resources directory to [myproject]/webapp/dist/, add the following setting to your sbt configuration:
build.sbt:
webappSrc in webapp <<= (baseDirectory in Compile) map { _ / "webapp" / "dist" }
You can read more about this setting in the readme.

Changing Scala sources directory in SBT

I'm having quite a few troubles pointing at a custom directory for Scala source-files in SBT.
I would like sbt to compile scala-files from a given directory instead of the regular src/main/scala directory.
I have tried both defining a .sbt and .scala project files, setting baseDirectory, scalaSource (and scalaSource s in the .scala file). I've also toyed around with everything from system-absolute to relative paths but nothing seems to work. It cannot locate any .scala file under the specified directory.
What are the proper ways to handle this?
Try this in build.sbt:
scalaSource in Compile <<= (sourceDirectory in Compile)(_ / "foo")
This will result in a directory src/main/foo for Scala sources. If you want to use some arbitrary directory, go for this:
scalaSource in Compile := file("/Users/heiko/tmp")
Update answer for SBT 0.13.13 ->
sourceDirectory in Compile := (baseDirectory( _ / "foo" )).value
And to add a source directory (instead of just replacing it) also for SBT 0.13.13 ->
unmanagedSourceDirectories in Compile += (baseDirectory( _ / "foo" )).value

How to configure sbt to load resources when running application?

My code (Java) reads an image from jar:
Main.class.getResourceAsStream("/res/logo.png")
Everything runs fine (if I start the app after packaging it into a jar). But when I run it using sbt's run task, it returns me null instead of needed stream.
Running this from sbt console also gives null:
getClass.getResourceAsStream("/res/logo.png")
Is there a way to tell sbt to put my resources on classpath?
EDIT:
I set the resources dir to be same as source dir:
build.sbt:
resourceDirectory <<= baseDirectory { _ / "src" }
When I loaded sbt's `console' and ran the following:
classOf[Main].getProtectionDomain().getCodeSource()
I got the location of my classes, but it does not contain neither res folder nor any of my resource files.
Seems that sbt copies resources only to the resulting jar, and does not copy them to classes dir. Should I modify compile task to move these resources files to classes dir?
EDIT2:
Yes, when I manually copy the resource file to classes dir, I can easily access it from console. So, how should I automate this process?
EDIT3:
It seems that sbt is just unable to see my resource folder - it does not add files to resulting jar file, actually!
Solution:
resourceDirectory in Compile <<= baseDirectory { _ / "src" }
I can't give you a full solution right now, but there is a setting called resourceDirectories to which you could add the res folder.
[EDIT]
For me it didn't work also if the resource was in the standard resource folder. Please try it that way:
Main.class.getClassLoader().getResourceAsStream("icon.png")
[EDIT2] This is the full build script (build.scala) which works if your resource is in src/main/java:
import sbt._
import Keys._
object TestBuild extends Build {
lazy val buildSettings = Seq(
organization := "com.test",
version := "1.0-SNAPSHOT",
scalaVersion := "2.9.1"
)
lazy val test = Project(
id = "test",
base = file("test"),
settings = Defaults.defaultSettings ++ Seq(resourceDirectory in Compile <<= javaSource in Compile)
)
}