What is the correct way of using static assets in a Scala SBT project? - scala

What is the best way of using static resources in an SBT based Scala project with a packaging plugin such as sbt-assembly or sbt-native-packager.
We know that by using TypeSafe-Config with sbt-native-packager's universal plugin, we can just put the configuration file in the resources directory under sources. However, what if I wanted my application to have other static sources such as JSON files containing mappings, and models?
I understand that I can just reference the resources directory and read from the file, but would that still work after packaging the application with plugins (assuming the universal or docker plugin in this case)?
If not, what is the correct way to achieve this?

You could use
unmanagedResourceDirectories += (baseDirectory in <project>).value / some / path
to add more directories that are later mapped into the jar as static resources.

Put it into the resources directory, but don't "reference the resources directory and read from the file": use ClassLoader.getResourceAsStream() (or getResources, depending on your requirements) instead. This is the same technique TypeSafe Config and innumerable other libraries use. For this it doesn't matter if you use sbt-native-packager or not.
This approach runs into problems if you need to make these resources available specifically as files (e.g. to feed them to an external process). In this case add them to mappings as shown here:
mappings in Universal in packageBin += file("README") -> "README"
(obviously replacing "README" with the file(s) you need).

Related

How to share .proto (protobuf) files using a shared scala library using sbt

I have a few apps using shared .proto files. Each app's repo currently contains a copy of the files, which is not ideal and has recently created a problem when they accidentally diverged.
I would like to store the .proto files in a shared library which is already a common dependency for these apps. We're using sbt-protoc which has documentation for including .proto files from external libraries, but I can't find any information on how to package libraries that include them.
The .proto files are located in src/main/protobuf, but do not appear in the generated jar, which is presumably standard behaviour. I know you can tell sbt to include specific resource files, but I don't know if I've missed how to do it using sbt-protoc
To get protos included in the JAR, you can rely on standard sbt functionality, by adding a setting such as:
Compile / unmanagedResourceDirectories += sourceDirectory.value / "protobuf"

Using external conf folder as resource folder with sbt-native-packager

I'm pretty new to sbt-native-packager. What I want is using external conf folder like a resource folder and configure the files inside it differently on each environment such as production, dev and etc.
Project has src/universal/conf and bunch of configuration files under this directory used by libraries at runtime.
I exclude src/universal/conf during build so final jar does not has these conf files as resources. I checked bin/start.sh and only lib/ folder set as classpath.
How can I accomplish it? What's the best practices? I don't think that JavaServerPackaging is more convenient because final jar has several main methods to be used as separate applications on same node. So one dameon application looks like doesn't fit.
There are already a few questions with proper solutions for this
SBT using sbt-native-packager how to create different build files?
What is the recommended way to set JVM options...

Scala SBT Project Application Configuration File

I come from the C# .NET world and as I build my Scala project I noticed how many different ways there are to do things in the open source community. Anyways in .Net C# project we have the Web.config or the App.config file which is very useful to specify app keys that are used globally and it is also helpful for transformation for different environments and such.
What would be the equivalent for a Scala SBT project? Do you know a place to store your connection strings and other app settings?
There is no universal configuration file name. The basic way is to use Properties, see e.g. how to read properties file in scala, and call the file your-application-name.properties. But there is a popular library called simply Config which I'd recommend; as https://github.com/typesafehub/config#standard-behavior says, its standard names for config files are
The convenience method ConfigFactory.load() loads the following (first-listed are higher priority):
system properties
application.conf (all resources on classpath with this name)
application.json (all resources on classpath with this name)
application.properties (all resources on classpath with this name)
reference.conf (all resources on classpath with this name)
The idea is that libraries and frameworks should ship with a reference.conf in their jar. Applications should provide an application.conf , or if they want to create multiple configurations in a single JVM, they could use ConfigFactory.load("myapp") to load their own myapp.conf . (Applications can provide a reference.conf also if they want, but you may not find it necessary to separate it from application.conf .)
As #ashalynd's answer says, in order for any such library to see your configuration files, they should go into src/{main,test}/resources.
I think you are talking about application.conf. It can be found in /src/main/resources or in /src/test/resources (affecting main and test settings, respectively). If application.conf is not present in /src/test/resources, the main application.conf will be used for the tests.

Is there any way to use SBT's resolver only for subset of artifacts?

Is there any way to define custom resolver that would be used only for subset of artifacts, more specifically to fetch artifacts only with predefined groupId?
For example, project defines a custom FooResolver that should be used only for artifacts with groupId org.foo but all other artifacts should be resolved using the default resolver.
To add unmanaged dependencies to an SBT project, the simplest solution is to just put the jars in the lib folder in your project. All libraries in the lib folder will be in the classpath by default.
If you want to use another folder instead of lib, you can redefine it:
unmanagedBase := // provide a java.io.File here.
If you want to do something more complex: SBT retrieves unmanaged libraries with the unmanagedJars task, so you can always redefine that task (but that would probably be a sign that you're trying to do something too complicated to reasonably use unmanaged dependencies...).

External configuration for Play 2 Framework

I have a custom configuration file for my database, and I want to externalize it when my Play project is packaged into a war.
I tried javaOptions in build.sbt with the -DConfig.file java command, but my file is not detected...
my line : javaOptions in run += "-Dconfig.file=conf/database.conf"
and my deployed war on a Tomcat server is :
/mywar/META-INF/MANIFEST.MF
/mywar/WEB-INF/lib/myplayproject.jar (with other dependencies)
I put my conf file in lib directory : /lib/conf/database.conf
Where am I doing wrong ?
(based on this link : http://www.scala-sbt.org/0.12.3/docs/Detailed-Topics/Forking.html)
If you deploy your war on Tomcat, I don't see how sbt is involved, which may explain why your option is ignored.
Play is not really meant to be deployed as a war. I think the easiest thing for you would be to manually load the config file in your code via the typesafe config library.
When deploying to a container you aren't in control of the JVM process so you can't specify command line options to set system properties.
Your easiest approach here is probably to just rename your config file to reference.conf or application.conf. Those two names are auto-loaded by the configuration library from the classpath.
You could also edit reference.conf or application.conf to add include "database.conf" if you want to keep a separate file.
Otherwise you could manually load a config file, e.g. with ConfigFactory.parseResource to search the classpath.
In addition to including classpath resources you can include files and urls out of the box. Use the include url("http://example.com") or include file("foo.conf") syntax. By hand (in code) ConfigFactory can of course also parse urls and files.
If that isn't flexible enough, it's also possible to customize includes in two ways.
One is to create a custom ConfigIncluder http://typesafehub.github.io/config/latest/api/com/typesafe/config/ConfigIncluder.html
The other is to create a custom URL protocol in the usual Java way, see Creating custom URI scheme using URI class and http://www.cooljeff.co.uk/2009/12/12/custom-url-protocols-and-multiple-classloaders/ for example. Then use include url("myproto:foobar")