How to exclude unmanaged resources from Compile scope only (not from Test) - scala

In one of my sub projects, I am trying to exclude *.conf and *.groovy files from my list of unmanaged resources:
excludeFilter in Compile in unmanagedResources := "*.conf" || "*.groovy"
Now, this works but has the unintended effect of removing the *.conf files from Test.
I tried to add the following includeFilter setting :
includeFilter in Test in unmanagedResources := "*.conf"
However, this does not work.
I figure that there is a relationship between Test and Compile that may be causing this issue.
Any suggestions would be helpful.
Thanks.

There are two issues here and you've identified the main one, which is the relationship between Test and Compile. The other is that a file must both be included by includeFilter and not be excluded by excludeFilter.
Test gets its settings from Compile if none are specified for Test explicitly. When you define excludeFilter in Compile, it applies to Test as well. So, you can define excludeFilter in Test to be the default, which is to ignore hidden files:
excludeFilter in Test := HiddenFileFilter
(Or, you can use NoFilter to not have any exclusions.)

Related

How to create a custom package task to jar a subset of classes in SBT

I am trying to define a separate package task without modifying the original task in compile configuration. This new task will package only a subset of classes conforming an API which we need to be able to share with other teams so they can write plugins for our application. So the end result will be two jars, one with the full application and a second one with a subset of the classes.
I approached this problem by creating a different configuration which I called pluginApi and would redefine the packageBin task within this new configuration so it does not change the original definition of packageBin. This idea was taken from here:
How to create custom "package" task to jar up only specific package in SBT?
In my build.stb I have:
lazy val PluginApi = config("pluginApi") extend(Compile) describedAs("Custom plugin api configuration")
lazy val root = project in file(".") overrideConfigs (PluginApi)
This effectively creates my new configuration and I can call
sbt pluginApi:packageBin
Which generates the complete jar in the same way as compile:packageBin would do. I then try to modify the mappings in the new packageBin task with:
mappings in (PluginApi, packageBin) ~= { (ms: Seq[(File, String)]) =>
ms filter { case (file, toPath) =>
toPath.startsWith("some/path/defining/api")
}
}
but this has no effect. I think the reason is because the call to pluginApi:packageBin is delegated to compile:packageBin rather than it being a cloned task.
I can redefine a new packageBin within the new scope like:
packageBin in PluginApi := {
}
However I would have to rewrite all packageBin functionality instead of reusing existing code. Also, in case that rewriting is unavoidable I am not sure how that implementation would be.
Could somebody provide an example about how to achieve this?
You could have it done as follows
lazy val PluginApi = config("pluginApi").extend(Compile)
inConfig(PluginApi)(Defaults.compileSettings) // you have to have standard
mappings in (PluginApi, packageBin) := {
val original = (mappings in (PluginApi, packageBin)).value
original.filter { case (file, toPath) => toPath.startsWith("some/path/defining/api") }
}
unmanagedSourceDirectories in PluginApi := (unmanagedSourceDirectories in Compile).value
Note that, if you keep your sources in src/main/scala you'll have to override unmanagedSourceDirectories in the newly created configuration.
Normally the unmanagedSourceDirectories contains the configuration name. E.g. src/pluginApi/scala or src/pluginApi/java.
I have had similar problems (with more than one jar per project). Our project uses ant - here you can do it, you just will repeat yourself a lot.
However, I have come to the conclusion that this scenario (2 JARs for one project) actually can be simplified by splitting the project - i.e. making 2 modules out of it.
This way, I don't have to "fight" tools which assume project==artifact (like sbt, maybe maven?, IDEA's default setting,...).
As a bonus point the compiler helps me to verify that my dependencies are correct, i.e. that I did not accidentally make my API package depend on the implementation package - when compiling everything together and only splitting classes apart in the JAR step, you do run the risk of getting an invalid dependency in your setup which you would only see when testing, because during compile time everything is compiled together.

Filtering packages from unmanagedSources in SBT

This should be very easy, but I am missing something. I apologize for the too-basic question.
I am reorganizing some code. I'd like to get the main package fixed, and then I'll have to modify code in some packages that depend upon the main package. Temporarily, I'd like for those dependent packages not to try to compile in my sbt ~compile world.
I know there exists a setting, excludeFilter in Compile in unmanagedSources, but I don't know what syntax I should use to keep whatever default exclusions are there but to add an new exclusions for (deeply nested) source directories that correspond to dependent packages.
Many thanks for any help!
Here's a working example that excludes anything with any parent directory named foo:
Compile / unmanagedSources / excludeFilter ~= { _ ||
new FileFilter {
def accept(f: File) = f.getPath.containsSlice("/foo/")
} }
(Updated to use sbt 1 style syntax.)

Explain SBT syntax like compile:compile

Although SBT is called simple build tools, it's far from being simple. I still can't get this syntax in sbt session like compile:compile? What's the difference between this and just compile?
The main trick in here is in scopes. If you want really understand how SBT works then always use three commands:
show <setting> - Displays the value of the specified setting.
show <task> - Evaluates the specified task and display the value returned by the task.
inspect <key> - shows info about setting
inspect tree <key> - displays key and its dependencies in a tree structure.
There are many other good commands, but this will help you most to understand the basics of SBT.
As for the syntax. Each build consists of settings, tasks, projects and scopes. There are too much to tell about them, there is a good explanation given on the official site. And the syntax you gave is all about this terms, for example let's take a look at:
compile:scalaSource::sourceDirectory
1 2 3
1 - it is a Compile scope
2 - it is a dependant Setting
3 - dependency Setting
If you type inspect scalaSource you'll see that, if you type just scalaSource in the SBT session this will call scalaSource in the compile scope(compile:scalaSource), this explains the difference between compile:compile and compile, this are the same (call inspect on compile). The second thing you should take a look at in inspect scalaSource is the Dependencies: part: compile:sourceDirectory, so scalaSource depends on the sourceDirectory setting in compile:sourceDirectory and if you've seen some build on github, in *.sbt or *.scala build files it's written like:
sourceDirectory in (Compile, scalaSource) := ....
Just for the exercise, call:
show compile:scalaSource::sourceDirectory
and you'll see the output like this: <project-dir>/src/main and then call:
set sourceDirectory in (Compile, scalaSource) <<= baseDirectory(_ / "src" / "sc")
and then again:
show compile:scalaSource::sourceDirectory

Scala SBT CoffeeScripted, correctly override compile target

Groping in the dark, I just resorted to a pathetic hack (note the path backtracking):
(resourceManaged in (Compile, CoffeeKeys.coffee)) <<=
(crossTarget in Compile)(_ / "../../../apache/static" / "js")
Is there any way to specify the absolute target write path with coffeescripted-sbt? The intro/overview states
You can override this behavior by overriding the resourceManaged
setting scoped to your configration and the CoffeeKeys.coffee task.
Below is an example you can append to your build definition which will
copy generated javascript to target/:scala-version/your_preference/js
That's great, but I'd like to write directly to apache statics directory, and not 4 levels deep in my sbt-eclipse project
Should note: I'm getting the Unicorn is Angry quite often on GitHub these days, so issue tracker isn't much help.
Thanks for any clues, what I have works, but I'd like to know how to set the absolute path properly
(resourceManaged in (Compile, CoffeeKeys.coffee)) <<=
(crossTarget in Compile)(_ / "pref" / "js")
Sets compile target relative to the default, which is "project_root/target/scala-version/"
The solution is refreshingly simple:
resourceManaged in (Compile, CoffeeKeys.coffee) :=
file("/absolute/path/to/apache/static/js")
SBT user group thread

Filtering resources in SBT

I am trying to setup SBT to compile an existing project which does not use the maven directory structure. I am using the full configuration and have set my javaSource & resourceDirectory settings as follows:
def settings = Defaults.defaultSettings ++ Seq(
resourceDirectory in Compile <<= baseDirectory( _ / "java" ),
javaSource in Compile <<= baseDirectory( _ / "java" )
)
Now I want to be able to filter the resources we include in the jar artifact, as we currently do with ant, plus exclude .java files as our resources are mixed in with source code. For example:
<fileset dir="java" includes="**/*.txt, **/*.csv" excludes="**/*.java" />
Is there any way to do this?
Use defaultExcludes scoped for the unmanagedResources task and optionally the configuration. For example, this setting excludes .java files from the main resources:
defaultExcludes in Compile in unmanagedResources := "*.java"
in Compile restricts this setting to only apply to main resources. By using in Test instead, it would apply only to test resources. By omitting a configuration (that is, no in Compile or in Test), the setting would apply to both main and test resources.
in unmanagedResources applies these excludes for resources only. To apply excludes to sources, for example, the scope would be in unmanagedSources. The reason for the unmanaged part is to emphasize that these apply to unmanaged (or manually edited) sources only.
The defaultExcludes key has type sbt.FileFilter, so the setting value must be of this type. In the example above, "*.java" is implicitly converted to a FileFilter. * is interpreted as a wildcard and so the filter accepts files with a name that ends in '.java'. To combine filters, you use || and &&. For example, if .scala files needed to be excluded as well, the argument to := would be:
"*.java" || "*.scala"
In the original Ant fileset, the include and exclude filters select mutually exclusive sets of files, so only one is necessary.
It is also possible to directly build the Seq[File] for unmanagedResources. For example:
unmanagedResources in Compile <<=
unmanagedResourceDirectories in Compile map { (dirs: Seq[File]) =>
( dirs ** ("*.txt" || "*.csv" -- "*.java") ).get
}
The ** method selects all descendents that match the FileFilter argument. You can verify that the files are selected as you expect by running show unmanaged-resources.
For sbt 1.48 I needed this style:
.settings(
Compile / sources := Seq(file("/path/to/your/file"))
)