sbt 0.13.16 - How do I customize triggered execution (file watch) - scala

Right now, most of the changes that I am making are to config files and build.sbt files. That being said, I still want to trigger execution (ex. compile, test, reload, etc) when I touch these files. How do I customize sbt triggered execution to execute when any file in the project is modified?
https://www.scala-sbt.org/0.13/docs/Howto-Triggered.html

https://www.scala-sbt.org/0.13/docs/Howto-Triggered.html
https://www.scala-sbt.org/1.0/docs/Howto-Triggered.html
watchSources += baseDirectory.value
I just do this to watch the entire base directory:
watchSources := Seq(file("."))

Related

SBT how to publish an artifact generated from the run command

I'm attempting to compile and run scala code that generates a file in SBT (in this case its a swagger file).
the following sbt executes fine. The jar is built and executed and the swagger.zip file the execution creates is in the target directory. I can't, however, seem to get the zip file to get published to my artifactory repo like my standard jar files would.
Any idea on what I'm missing?
publishArtifact in (Compile, packageBin) := false
publishArtifact in run := true
val myZipTask = taskKey[File]("swagger-zip")
myZipTask := {
file("swagger.zip")
}
addArtifact(Artifact("swagger", "zip", "zip"), myZipTask )
The run command doesn't trigger any publishing tasks, as that's not what it's for. I think you have tried to turn on publishing when run is called with "publishArtifact in run := true", but that code is not sufficient to achieve that; you'd need to attach many other Tasks to that command. That's not what you want anyway.
Your case fits entirely within the expected usage of the addArtifact helper (see the docs, and the code)
As you need to run code to generate artefacts, you should provide that code as a Task argument to the addArtifact helper, i.e.
val myZipTask = taskKey[File]("return the swagger-zip file")
val runZipCodeTask = taskKey[Unit]("run the swagger-zip code")
// See http://www.scala-sbt.org/0.13.2/docs/faq.html, “How can I create a custom run task, in addition to run?”
// and https://stackoverflow.com/questions/23409993/defining-sbt-task-that-invokes-method-from-project-code
fullRunTask(runZipCodeTask, Compile, "ZipGeneratorMainClass")
myZipTask := {
runZipCodeTask.value
file("target/swagger/swagger.zip")
}
addArtifact(Artifact("swagger", "zip", "zip"), myZipTask)
Then run "sbt publish"
Working demo
See https://gist.github.com/RichardBradley/5384a5e0da2427df237f42fe512b30b8 for a working demo.
Note about scopes - consider generating this file in a meta-project, not the main project
See https://stackoverflow.com/a/23416018/8261

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.

Play Framework : how to not watch a folder for changes in Play Framework

I am using Play 2.2.3.
I am new to Play and SBT. I want to make Play not watch a folder during development. In this case, a node_modules folder under public folder.
I tried these below but it did not seems to work. Also, I dont' know what is the difference between watchSources and playMonitoredFiles.
.settings(
playMonitoredFiles <<= playMonitoredFiles map { (files: Seq[String]) =>
files.filterNot(file => file.contains("node_modules"))
}
)
.settings(
watchSources <<= watchSources map { (sources: Seq[java.io.File]) =>
sources
.filterNot(source => source.isFile && source.getPath.contains("node_modules") )
.filterNot(source => source.isDirectory && source.getPath.contains("node_modules"))
}
)
.settings(
watchSources := watchSources.value.filter { !_.getPath.contains("node_modules") }
)
Note: The original question was about a legacy release (2.2.3), however I found useful the same question for modern versions.
So basically watchSources is a SBT key used for the triggered-execution functionality.
On the contrary, playMonitoredFiles is a TaskKey defined by the PlayFramework sbt-plugin, which controls a set of directories to watch by
the development server (sbt run) for the auto-reloading functionality.
When launching an sbt run, for EVERY REQUEST, there is a check of the directories defined by playMonitoredFiles and if any change is found,
a silent re-compilation is triggered. This means shutting down the server, recompiling and starting again.
The default values for playMonitoredFiles are calculated in playMonitoredFilesTask.
So for example, we have a certain version file added to our resources, computed in each compilation. We needed PlayFramework to avoid checking changes on this file
on development, because on every-request, the auto-recompiling regenerated this file and play marked the sources to be recompiled again, however no java files were recompiled and
nothing is printed out, so we had to debug the application in order to find the issue.
This setting only applies to development server (sbt run).
Within a project settings in build.sbt, the task can be overridden to exclude a directory (in the example, target/version directory):
.settings(
...,
playMonitoredFiles := playMonitoredFiles.value.filterNot {
_.getPath() endsWith String.format("target%sversion", File.separator)
}
...,
)
The value is of type File and only contains directories.

CoffeeScript and sbt-concat

I'm having trouble concatenating and fingerprinting all the CoffeeScript files in Play application. Everything works fine for JavaScript files with build.sbt like this one
pipelineStages := Seq(concat, digest)
Concat.groups := Seq(
"javascripts/app.js" -> group(((sourceDirectory in Assets).value / "javascripts") * "*.js")
)
But when sourceDirectory is changed to resourcesManaged that supposedly contains compiled CoffeeScript files sbt-concat doesn't pick them up.
sbt-coffeescript, and all other official source task plugins, don't put their files in resourcesManaged in Assets, but instead their own sub-directory in target/web/<taskname>. They scope the resourcesManaged setting to their main task, in this case this means resourcesManaged in (Assets, coffeescript) and resourcesManaged in (TestAssets, coffeescript).
When you run sbt coffeescript you can see the files are output to target/web/coffeescript/main. You can verify this by running show web-assets:coffeescript::resourceManaged from the sbt console.

Publish zip created by sbt-native-packager

I am trying to publish to a repository the zip file generated by the sbt-native-packager plugin through universal:packageBin task.
I configured my project like this:
publishTo := Some("Repo" at "http://repo")
publishMavenStyle := true
packagerSettings
packageArchetype.java_application
I am struggling trying to create a new sbt task (named publishZip) using publish task and packageBin task to publish the zip file. How can I achieve this ?
Add the following line to your sbt build (around packagerSettings should be fine)
deploymentSettings
Depending on what you want to do you may not need to define the publishZip task you could run
sbt universal:publish which should only publish the zip
redefine publish so it depends on universal:publish which would publish all the projects artifacts
publish <<= publish.dependsOn(publish in config("universal"))
Then run sbt publish.
For completeness sake deploymentSettings (and packagerSettings) come from com.typesafe.sbt.SbtNativePackager which is useful to know if you use a scala build :)
The deploymentSettings worked however I wanted to refine the settings. It seems there were several issues going on. I and finally came up with the following solution:
//--use sbt-native-packager default java application
packageArchetype.java_application
//--a dummy task to hold the result of the universal:packageBin to stop the circular dependency issue
val packageZip = taskKey[File]("package-zip")
//--hard coded result of "universal:packageBin"
packageZip := (baseDirectory in Compile).value / "target" / "universal" / (name.value + "-" + version.value + ".zip")
//--label the zip artifact as a zip instead of the default jar
artifact in (Universal, packageZip) ~= { (art:Artifact) => art.copy(`type` = "zip", extension = "zip") }
//--add the artifact so it is included in the publishing tasks
addArtifact(artifact in (Universal, packageZip), packageZip in Universal)
//--make sure the zip gets made before the publishing commands for the added artifacts
publish := (publish dependsOn (packageBin in Universal)).value
publishM2 := (publishM2 dependsOn (packageBin in Universal)).value
publishLocal := (publishLocal dependsOn (packageBin in Universal)).value
The key pieces of this solution came from a comment from yanns and dgrandes