PlayFramework: adding assets on compiling - scala

in our Scala project we're using Play Framework with some static assets in the public directory, linked in the normal way:
via "routes":
GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset)
and in the "index.scala.hml":
<script type="text/javascript" src="#routes.Assets.versioned("javascripts/main.js")">
Now we want to use a submodule written in nodejs, which should create other js files on compiling, and put them to the assets folder.
We were able to run npm commands in the "build.sbt" file:
buildSubmodules := {
val s: TaskStreams = streams.value
val shell: Seq[String] = if (sys.props("os.name").contains("Windows")) Seq("cmd", "/c") else Seq("bash", "-c")
val npmInstall: Seq[String] = shell :+ "npm --prefix submodules/ install"
val npmBuild: Seq[String] = shell :+ "npm --prefix submodules/ run build"
s.log.info("building submodules...")
if((npmInstall #&& npmBuild !) == 0) {
s.log.success("submodules build successful!")
} else {
throw new IllegalStateException("submodules build failed!")
}
}
(Compile / compile) := ((Compile / compile) dependsOn buildSubmodules).value
and also included in the "index.scala.html":
<link rel="stylesheet" href="#routes.Assets.versioned("submodules/main.css")" />
but new created files still cannot be found in the "public/assets" folder after compilation finished.
Is there any way to add these assets to compiled project?
Thank you

Related

A simple console while loop that captures the console input and prints to console not working

Why does the below code when run in sbt just print out continuously...
[Info] command:null
[Info] command:null
[Info] command:null
[Info] command:null
I thought readline will block until I enter something in the console.
def main(args: Array[String]): Unit = {
var command = ""
while (command != "exit") {
command = scala.io.StdIn.readLine()
println(s"command: $command")
}
}
If I paste this into ammonite it works as expected, it waits for my input that outputs it to the console. Typing "exit" exits the application.
SBT docs (https://www.scala-sbt.org/1.x/docs/Forking.html) describe the issue of input handling when forking:
By default, the standard input of the sbt process is not forwarded to
the forked process. To enable this, configure the connectInput
setting:
run / connectInput := true
To disable forking use something like this:
Compile / run / fork := false
or:
fork := false

What is the preferred way in mill to point to the directory where build.sc file is located?

What is the preferred way in mill to point to the directory where build.sc file is located?
In the mill documentation os.pwd is used e.g. here, but if it is possible to start/run mill from elsewhere, then os.pwd points to incorrect location.
import mill._, mill.modules.Jvm
def sourceRoot = T.sources { os.pwd / "src" }
def resourceRoot = T.sources { os.pwd / "resources" }
The root location of each defined module is defined in def millSourcePath: os.Path, and it's the preferred way to access the module path.
Example:
import mill._, mill.scalalib._
object mymodule extends JavaModule {
def sources = T.sources(millSourcePath / "src")
}
$ mill show __.sources
No mill version specified.
You should provide a version via '.mill-version' file or --mill-version option.
Using mill version 0.9.9
Compiling /tmp/stackoverflow/build.sc
[1/1] show
[1/1] show > [1/1] mymodule.sources
[
"ref:c984eca8:/tmp/stackoverflow/mymodule/src"
]
If you need to access the path of project itself, notice, that it's a mill.define.Module itself and you can access it via the variable build. The project directory is therefore accessible via build.millSourcePath.
Example:
import mill._, mill.scalalib._
val baseDir = build.millSourcePath
object mymodule extends JavaModule {
def sources = T.sources {
super.sources() ++ Seq(PathRef(baseDir / "src"))
}
}
$ mill show __.sources
No mill version specified.
You should provide a version via '.mill-version' file or --mill-version option.
Using mill version 0.9.9
Compiling /tmp/stackoverflow/build.sc
[1/1] show
[1/1] show > [2/2] mymodule.sources
[
"ref:c984eca8:/tmp/stackoverflow/mymodule/src",
"ref:c984eca8:/tmp/stackoverflow/src"
]

error: object Service is not a member of package com.twitter.finagle - Defining Bazel dependencies in Build file, Scala finagle

Im trying to add the finagle-http library to my new bazel project as an external maven dependency. But getting the following error. I assume im doing something wrong in creating the build without fully understanding it. Trying to learning. Appreciate any help on this.
error: object Service is not a member of package com.twitter.finagle
error: object util is not a member of package com.twitter
error: type Request is not a member of package com.twitter.finagle.http
error: object Response is not a member of package com.twitter.finagle.http
error: Symbol 'type com.twitter.finagle.Client' is missing from the classpath. This symbol is required by 'object com.twitter.finagle.Http'.
error: not found: value Await
The same code is working using sbt. Below is the code.
import com.twitter.finagle.{Http, Service}
import com.twitter.finagle.http
import com.twitter.util.{Await, Future}
object HelloWorld extends App {
val service = new Service[http.Request, http.Response] {
def apply(req: http.Request): Future[http.Response] =
Future.value(http.Response(req.version, http.Status.Ok))
}
val server = Http.serve(":8080", service)
Await.ready(server)
}
WORKSPACE file
maven_install(
artifacts = [
"org.apache.spark:spark-core_2.11:2.4.4",
"org.apache.spark:spark-sql_2.11:2.4.1",
"org.apache.spark:spark-unsafe_2.11:2.4.1",
"org.apache.spark:spark-tags_2.11:2.4.1",
"org.apache.spark:spark-catalyst_2.11:2.4.1",
"com.twitter:finagle-http_2.12:21.8.0",
],
repositories = [
"https://repo.maven.apache.org/maven2/",
"https://repo1.maven.org/maven2/",
]
)
BUILD file
load("#io_bazel_rules_scala//scala:scala.bzl", "scala_binary")
package(default_visibility = ["//visibility:public"])
scala_binary(
name="helloworld",
main_class="microservices.HelloWorld",
srcs=[
"Main.scala",
],
deps = ["spark],
)
java_library(
name = "spark",
exports = [
"#maven//:com_twitter_finagle_http_2_12_21_8_0",
],
)
Working SBT dependency that was working in my initial sbt project
libraryDependencies += "com.twitter" %% "finagle-http" % "21.8.0"
Figured out the issue, unlike in sbt, in bazel i had induvidualy add the related dependencies. I modified the workspace as below.
maven_install(
artifacts = [
"com.twitter:finagle-http_2.12:21.8.0",
"com.twitter:util-core_2.12:21.8.0",
"com.twitter:finagle-core_2.12:21.8.0",
"com.twitter:finagle-base-http_2.12:21.8.0",
"com.fasterxml.jackson.module:jackson-module-scala_2.12:2.11.2",
"com.fasterxml.jackson.core:jackson-databind:2.11.2",
],
repositories = [
"https://repo.maven.apache.org/maven2/",
"https://repo1.maven.org/maven2/",
]
Build file --
java_library(
name = "finagletrial",
exports = [
"#maven//:com_twitter_finagle_http_2_12_21_8_0",
"#maven//:com_twitter_util_core_2_12_21_8_0",
"#maven//:com_twitter_finagle_core_2_12_21_8_0",
"#maven//:com_twitter_finagle_base_http_2_12_21_8_0",
"#maven//:com_fasterxml_jackson_module_jackson_module_scala_2_12_2_11_2",
"#maven//:com_fasterxml_jackson_core_jackson_databind_2_11_2"
],

How to publish to multiple repositories in SBT?

I am in the middle of upgrading Nexus version. As part of the process I've set up a new Nexus instance which will run in parallel with the older Nexus instance.
While migrating to the new instance I want to thoroughly test and vet the new instance before pulling the plug on older instance. This requires me to temporarily modify the publish workflow in such a way that sbt publishes the artifacts to both the Nexus instances.
I highly doubt the following code will actually work:
publishTo <<= (version) {
version: String =>
if (version.trim.endsWith("SNAPSHOT")) Some("snapshots" at "http://maven1.dev.net:8081/nexus/content/" + "repositories/snapshots/")
else Some("releases" at "http://maven1.dev.net:8081/nexus/content/" + "repositories/releases/")
},
credentials += Credentials("Sonatype Nexus Repository Manager", "maven1.dev.net", "release-eng", "release"),
publishTo <<= (version) {
version: String =>
if (version.trim.endsWith("SNAPSHOT")) Some("snapshots" at "http://maven2.dev.net:8081/nexus/content/" + "repositories/snapshots/")
else Some("releases" at "http://maven2.dev.net:8081/nexus/content/" + "repositories/releases/")
},
credentials += Credentials("Sonatype Nexus Repository Manager", "maven2.dev.net", "release-eng", "release"),
I also tried looking into a plugin called sbt-multi-publish but I couldn't compile and use it, either.
With Commands and How to change a version setting inside a single sbt command? I could define a new command - myPublishTo - that changes publishTo setting before executing the original publish task:
def myPublishTo = Command.command("myPublishTo") { state =>
val extracted = Project.extract(state)
Project.runTask(
publish in Compile,
extracted.append(List(publishTo := Some(Resolver.file("file", target.value / "xxx"))), state),
true
)
Project.runTask(
publish in Compile,
extracted.append(List(publishTo := Some(Resolver.file("file", target.value / "yyy"))), state),
true
)
state
}
commands += myPublishTo
With this, execute myPublishTo as any other command/task.
You could also define a couple of aliases - pxxx, pyyy and pxy - in build.sbt that would execute a series of commands using ;.
addCommandAlias("pxxx", "; set publishTo := Some(Resolver.file(\"file\", target.value / \"xxx\")) ; publish") ++
addCommandAlias("pyyy", "; set publishTo := Some(Resolver.file(\"file\", target.value / \"yyy\")) ; publish") ++
addCommandAlias("pxy", "; pxxx ; pyyy")
In sbt console you can execute them as any other commands/tasks.
[sbt-0-13-1]> alias
pxxx = ; set publishTo := Some(Resolver.file("file", target.value / "xxx")) ; publish
pyyy = ; set publishTo := Some(Resolver.file("file", target.value / "yyy")) ; publish
pxy = ; pxxx ; pyyy
[sbt-0-13-1]> pxy
[info] Defining *:publishTo
[info] The new value will be used by *:otherResolvers, *:publishConfiguration
[info] Reapplying settings...
[info] Set current project to sbt-0-13-1 (in build file:/Users/jacek/sandbox/so/sbt-0.13.1/)
...
[info] published sbt-0-13-1_2.10 to /Users/jacek/sandbox/so/sbt-0.13.1/target/xxx/default/sbt-0-13-1_2.10/0.1-SNAPSHOT/sbt-0-13-1_2.10-0.1-SNAPSHOT-javadoc.jar
[success] Total time: 1 s, completed Jan 9, 2014 11:20:48 PM
[info] Defining *:publishTo
[info] The new value will be used by *:otherResolvers, *:publishConfiguration
[info] Reapplying settings...
...
[info] published sbt-0-13-1_2.10 to /Users/jacek/sandbox/so/sbt-0.13.1/target/yyy/default/sbt-0-13-1_2.10/0.1-SNAPSHOT/sbt-0-13-1_2.10-0.1-SNAPSHOT-javadoc.jar
[success] Total time: 0 s, completed Jan 9, 2014 11:20:49 PM
This is an old question, but the problem persists. I tried to revive sbt-multi-publish, but it's really old (sbt-0.12) and uses some sbt internals that are hard to deal with. So I took another approach and wrote a new plugin: sbt-publish-more.
It doesn't involve any on-the-fly settings changing or custom commands like the other answer.
After you add the plugin, just set resolvers you want to publish to (taking your code as an example):
publishResolvers := {
val suffix = if (isSnapshot.value) "shapshots" else "releases"
Seq(
s"Maven1 ${suffix}" at s"http://maven1.dev.net:8081/nexus/content/repositories/${suffix}/",
s"Maven2 ${suffix}" at s"http://maven2.dev.net:8081/nexus/content/repositories/${suffix}/"
)
}
And call publishAll task, it will publish to both repositories.
You can also publish to different repositories with different configurations. Check usage docs for details.

Building paths in SBT for the packageMappings of the sbt-native-packager

I am very new to SBT and need to create a RPM package for one of my project. The RPM contains only 1 file, which is a one-jar created by the sbt-onejar plugin). I want to use sbt-native-packager plugin and have created a Packagin.scala file under the /project directory like this:
object Packaging {
val settings: Seq[Setting[_]] = packagerSettings ++ deploymentSettings ++ mapGenericFilesToLinux ++ Seq(
maintainer := "Team",
packageSummary := "Summary",
packageDescription := """Description""",
mappings in Universal += {
file("target/scala-2.10/projectname_2.10-0.1-one-jar.jar") -> "/opt/projectname/projectname-0.1.jar"
},
linuxPackageMappings in Rpm <+= (baseDirectory) map { _:File =>
(packageMapping(file("target/scala-2.10/projectname_2.10-0.1-one-jar.jar") -> "/opt/projectname/projectname-0.1.jar")
withUser "someusr" withGroup "somegroup" withPerms "0755")
},
name in Rpm := "projectname",
version in Rpm <<= version apply { sv => sv split "[^\\d]" filterNot (_.isEmpty) mkString "." },
rpmRelease := "1",
rpmVendor := "Vendor",
rpmUrl := Some("url"),
rpmGroup := Some("group"),
rpmLicense := Some("BSD")
)
}
1) I don't want to hardcode the file names. Instead of having "target/scala-2.10/projectname_2.10-0.1-one-jar.jar" I need a way to use existing SettingKey's, i.e. target + "scala-" + scalaVersion + "/" + name + "_" + scalaVersion + "-" + version + "-one-jar.jar" - how do you do this=
2) For the value rpmRelease := "1" I want to use a System property, i.e. in Maven I would do ${rpm.buildNumber}, how does that work in SBT?
3) Is there anything I should do better in regards to the sbt-native-packager plugin?
1) You should always use task output in sbt rather than raw filesystem lookups. Because sbt has parallel execution, if you don't put an explicit dependency on the output of a task, then you have no guarantee that a file will be created before you run your task.
In that vein you want to change your package mappings line to be something like this:
mappings in Universal += {
oneJar.value -> "/opt/projectname/projectname-0.1.jar"
},
Where the oneJar key is defined in the onejar plugin.
2) Sbt just uses scala for the build language, so you can grab system properties similarly (but please also provide a default):
rpmRelease := Option(sys.props("rpm.buildNumber")) getOrElse "1"
3) Right now you're defining a generic package and redefining the same file in the Rpm with a different user. The mapGenericFilesToLinux settings still lack a few customizations, but if you're not creating universal distributions, you should be able to drop that bit of settings and instead directly configure your linux package:
linuxPackageMappings in Rpm <+= (oneJar) map { jar:File =>
(packageMapping(jar -> "/opt/projectname/projectname-0.1.jar")
withUser "someusr" withGroup "somegroup" withPerms "0755")
},