Sbt dist cause no access to unmanaged resources? - scala

With my sbt - play/scala application, I have been using sbt run while developing.
Almost finished my project, and now I want to sbt dist for production purposes.
(Correct me if this is a bad idea.)
My question is here.
With my sbt run, I had the access to unmanaged resources by adding
unmanagedResourceDirectories in Assets += baseDirectory.value / "works"
to my build.sbt
However, after sbt dist the same url no longer works and sends me 404 not found error.
Not Found For request 'GET /assets/RAW/abc.png'
This "works" folder includes files that will be generated during the service, which is separate directory from the usual "public" folder.
And This is my routes FYI.
GET /assets/*file controllers.Assets.at(path="/public", file)
GET /works/*file controllers.Assets.at(path="/works/", file)
Does sbt-dist requires any additional code in build.sbt or should I fix anything?

Additional asset directories specified via unmanagedResourceDirectories
unmanagedResourceDirectories in Assets += baseDirectory.value / "works"
will also be served from public according to docs:
A nuance with sbt-web is that all assets are served from the public
folder... note that the files there will be aggregated into the target public folder
This means you need to change GET /works route from
GET /works/*file controllers.Assets.at(path="/works/", file)
to
GET /works/*file controllers.Assets.at(path="/public", file)
Additional assets should now be accessible at both
http://example.com/assets/RAW/abc.png
http://example.com/works/RAW/abc.png
You can confirm that additional assets end up under public after sbt dist by unzipping the generated package at .../target/universal, and then listing the contents of a jar under lib directory ending with -assets.jar, for example:
jar tf target/universal/play-scala-starter-example-1.0-SNAPSHOT/play-scala-starter-example.play-scala-starter-example-1.0-SNAPSHOT-assets.jar

Ok, so here is how I solved my problem.
After hours(probably days) of research, I was able to get an access to external files by adding a new function in controllers, sendfile(new file(filename), inline=true)
I also had to set routes. In my case,
GET /download/:id/:name controllers.DownloadTask.download(id: String, name: String)
After adding this url/routes info in the client, it worked well.

Related

SBT, include entire external directory (with the dir itself) in jar built

I need to include entire static directory from external location in my SBT-generated JAR file (with optional folder renaming).
Adding it's path to unmanagedResourceDirectories adds its content only, not the entire directory which results in static content in the JAR root. I was playing with mappings of various sorts but with no luck.
Does anyone had similar use-case and could point me to the right direction on how to do that?
I can't modify the process that generates the static dir and can't use it's parent as it has other files/dirs I don't want inside.
Ok, I sorted it out with a little hint I got on sbt's gitter channel. So mappings is what I needed:
mappings in (Compile, packageBin) := {
val statics = contentOf(baseDirectory.value / "static").map {
case (file, dest) => file -> s"webapp/$dest"
}
(mappings in (Compile, packageBin)).value ++ statics
}
This will take all the content from static directory and place it in the webapp directory of the resulting JAR file

Working with two assets directories in Scala Play framework 2.4

I am trying to use 2 public assets routes. One for development version and the other one for production version. But this routes config does not work: for both pathes I receive 404 error.
GET /assets/*file controllers.Assets.at(path="/public", file)
GET /us/*file controllers.Assets.at(path="/us", file)
For the old play 2.0 I have to config extra assets directories in build.sbt
playAssetsDirectories <+= baseDirectory / "us"
to publish all files in copiled target. But now this property does not exists.
This has been changed in Play 2.3 and there's a migration guide for this issue. Instead:
playAssetsDirectories <+= baseDirectory / "us"
you should now use the following construction:
unmanagedResourceDirectories in Assets += baseDirectory.value / "us"
However, this will copy the content of us directory into public in the target distribution, so make sure you don't override something important. You can find more details in the given docs.

Scala.js compilation destination

I'm working on a Scala.js cross project where the jvm folder represents my server application and jsrepresents my scala.js code.
Whenever i compile my scala.js code via sbt crossJS/fastOptJS the compiled JS ends up in ./js/target/scala-2.11/web-fastopt.js.
I need to have this compiled JS file accessible in the resources of the server project in the jvm folder, so i can server it through my web application. I think i have to do something with artifactPath but i can't seem to get any results from my experiments thus far.
You can simply set the artifactPath of the fastOptJS task (or the fullOptJS task) to the (managed) resources directory of your JVM project:
// In the JS project's settings
artifactPath in fastOptJS in Compile :=
(resourceManaged in jvm in Compile).value /
((moduleName in fastOptJS).value + "-fastopt.js"))
This will put it in the directory, if the you run the fastOptJS task. However, it will not be included in sbt's resources task and it will not automatically be triggered, if you launch your server. Therefore:
// In the JVM project's settings
resources in Compile += (fastOptJS in js).value.data
A couple of notes:
The first step is only necessary, if your web-server does only serve specific directories. Otherwise the second one is enough, as this adds the file to the resources already; where it lies is secondary.
Setting the crossTarget, as in #ochrons' answer will also output all the .class and .sjsir files in the resource directory.
Have a look at Vincent Munier's sbt-play-scalajs for out-of-the-box sbt-web / Scala.js integration (it follows a slightly different approach: It copies the file from the js project, rather than directly placing it in the JVM project. Useful if you have multiple JVM projects).
You can configure the Scala.js SBT plugin to output the JavaScript file in folder of your choosing. For example like this:
// configure a specific directory for scalajs output
val scalajsOutputDir = Def.settingKey[File]("directory for javascript files output by scalajs")
// make all JS builds use the output dir defined later
lazy val js2jvmSettings = Seq(fastOptJS, fullOptJS, packageJSDependencies) map { packageJSKey =>
crossTarget in(js, Compile, packageJSKey) := scalajsOutputDir.value
}
// instantiate the JVM project for SBT with some additional settings
lazy val jvm: Project = sharedProject.jvm.settings(js2jvmSettings: _*).settings(
// scala.js output is directed under "web/js" dir in the jvm project
scalajsOutputDir := (classDirectory in Compile).value / "web" / "js",
This will also store -jsdeps.js and .js.map files in the same folder, in case you want to use those in your web app.
For a more complete example, check out this tutorial which addresses many other issues of creating a more complex Scala.js application.

How to add some local maven repo url to global sbt, and make them be tried first?

I want to add some fast local maven repository url to sbt, say:
http://maven.example.com/public
I want to add it to "global", so that I don't need to add them to each of sbt project. And also want to be tried first when sbt downloading some jars.
But I can't find useful information to do this, how to do it?
(My sbt version is 0.13.1)
With the help of a friend, finally I found the solution:
create a new file ~/.sbt/repositories
add content like this:
[repositories]
local
my-maven-repo: http://example.org/repo
my-ivy-repo: http://example.org/ivy-repo/, [organization]/[module]/[revision]/[type]s/[artifact](-[classifier]).[ext]
See official doc: http://www.scala-sbt.org/0.13.2/docs/Detailed-Topics/Library-Management.html#override-all-resolvers-for-all-builds
Modify your global configuration file, which is normally located in ~/.sbt/0.13/global.sbt, if it's not there you can create it.
In the file add following line:
externalResolvers := { ("Fast Repo" at "http://maven.example.com/public") +: externalResolvers.value }
You can confirm it's working by executing show externalResolvers in any project to see the list of resolvers. Your newly added resolver should be first.

Custom deployment with sbt

I have a Scala application and i want to setup a deployment process result similar to one Akka sbt plugin gives, but i it requires project to be a microkernel. Sbt-assembly is a very cool plugin, but i want to have a free access to my config files, basically i want to have the following app structure:
/app/bin - start script bash file
/config - all my application .conf files
/deploy - my project .jar with classes
/lib - all my dependencies .jar files
/logs - log files
I we checked typesafe sbt-native-packager, it's better, but it could place my .conf file and logs out of jars. All those settings in SBT looks confusing to me, what can i do to with this?
Actually this is not hard to update akka-sbt-plugin to make it work in general, add this file to your project folder and somewhere in your build the following settings:
.settings(Distribution.distSettings: _*)
.settings(mappings in Compile in packageBin ~= { _.filter(!_._1.getName.endsWith(".conf")) })
The first line adds all dist settings to your project and the second one excludes all .conf files from your .jar and reads them from config folder.
Now you have to commands: dist - creates a folder with a structure you've discribed and zipDist which packs it all into .zip file, later you can add this to you publish setting:
addArtifact(Artifact(someName, "zip", "zip"), zipDist)