Play! dist throws Exception - scala

I m trying to create a standalone version of my Play! application , when I do play run it works fine , but after doing play dist
I get following error when I run the start command
I m using play2.1 and Scala 2.10.0
Oops, cannot start the server.
#6e25l921m: Cannot init the Global object
at play.api.WithDefaultGlobal$$anonfun$play$api$WithDefaultGlobal$$globalInstance$1.apply(Application.scala:57)
at play.api.WithDefaultGlobal$$anonfun$play$api$WithDefaultGlobal$$globalInstance$1.apply(Application.scala:51)
at play.utils.Threads$.withContextClassLoader(Threads.scala:18)
at play.api.WithDefaultGlobal$class.play$api$WithDefaultGlobal$$globalInstance(Application.scala:50)
at play.api.DefaultApplication.play$api$WithDefaultGlobal$$globalInstance$lzycompute(Application.scala:383)
at play.api.DefaultApplication.play$api$WithDefaultGlobal$$globalInstance(Application.scala:383)
at play.api.WithDefaultGlobal$class.global(Application.scala:66)
at play.api.DefaultApplication.global(Application.scala:383)
at play.api.WithDefaultConfiguration$class.play$api$WithDefaultConfiguration$$fullConfiguration(Application.scala:80)
at play.api.DefaultApplication.play$api$WithDefaultConfiguration$$fullConfiguration$lzycompute(Application.scala:383)
at play.api.DefaultApplication.play$api$WithDefaultConfiguration$$fullConfiguration(Application.scala:383)
at play.api.WithDefaultConfiguration$class.configuration(Application.scala:82)
at play.api.DefaultApplication.configuration(Application.scala:383)
at play.api.Application$class.$init$(Application.scala:268)
at play.api.DefaultApplication.(Application.scala:383)
at play.core.StaticApplication.(ApplicationProvider.scala:52)
at play.core.server.NettyServer$.createServer(NettyServer.scala:228)
at play.core.server.NettyServer$$anonfun$main$5.apply(NettyServer.scala:259)
at play.core.server.NettyServer$$anonfun$main$5.apply(NettyServer.scala:258)
at scala.Option.map(Option.scala:145)
at play.core.server.NettyServer$.main(NettyServer.scala:258)
at play.core.server.NettyServer.main(NettyServer.scala)
Caused by: java.lang.NoSuchMethodError: com.typesafe.config.ConfigFactory.load(Lcom/typesafe/config/ConfigParseOptions;)Lcom/typesafe/config/Config;
at play.api.Configuration$.dontAllowMissingConfig$lzycompute(Configuration.scala:25)
at play.api.Configuration$.dontAllowMissingConfig(Configuration.scala:25)
at play.api.Configuration$.load(Configuration.scala:59)
at play.api.WithDefaultConfiguration$$anonfun$initialConfiguration$1.apply(Application.scala:74)
at play.api.WithDefaultConfiguration$$anonfun$initialConfiguration$1.apply(Application.scala:74)
at play.utils.Threads$.withContextClassLoader(Threads.scala:18)
at play.api.WithDefaultConfiguration$class.initialConfiguration(Application.scala:73)
at play.api.DefaultApplication.initialConfiguration$lzycompute(Application.scala:383)
at play.api.DefaultApplication.initialConfiguration(Application.scala:383)
at play.api.WithDefaultGlobal$class.play$api$WithDefaultGlobal$$globalClass(Application.scala:24)
at play.api.DefaultApplication.play$api$WithDefaultGlobal$$globalClass$lzycompute(Application.scala:383)
at play.api.DefaultApplication.play$api$WithDefaultGlobal$$globalClass(Application.scala:383)
at play.api.WithDefaultGlobal$class.play$api$WithDefaultGlobal$$javaGlobal(Application.scala:30)
at play.api.DefaultApplication.play$api$WithDefaultGlobal$$javaGlobal$lzycompute(Application.scala:383)
at play.api.DefaultApplication.play$api$WithDefaultGlobal$$javaGlobal(Application.scala:383)
at play.api.WithDefaultGlobal$$anonfun$play$api$WithDefaultGlobal$$globalInstance$1.apply(Application.scala:52)
... 21 more

I ran into the same issue. The exact fix was to change a dependency from
"org.skife.com.typesafe.config" % "typesafe-config" % "0.3.0"
to
"com.typesafe" % "config" % "1.0.0"

I figured out that I was using "org.skife.com.typesafe.config" % "typesafe-config" % "0.3.0" in the build.sbt , and the play start was using com.typesafe.config-1.0.0, removing the dependency for skife config 0.3.0 solved the problem.
seems like these 2 dependencies conflict with each other.

Related

SLF4J : simplelogger.properties in the project not detected

I am using Grizzled-SLF4J (a wrapper around SLF4J) for my Spark/Scala/SBT Project. The property file simplelogger.properties has been placed in the src/main/resources. But the property file is not getting detected when I run the Application using spark-submit. Whatever the change I make to property file is not getting reflected and seems like some default values for the properties are used(In my case only WARN / ERROR messages are displayed).
Here is my build.sbt
lazy val root = (project in file(".")).
settings(
name := "myprojectname",
...,
libraryDependencies ++= Seq(
"org.clapper" %% "grizzled-slf4j" % "1.3.0",
"org.slf4j" % "slf4j-simple" % "1.7.22",
"org.slf4j" % "slf4j-api" % "1.7.22",
)
)
simplelogger.properties
org.slf4j.simpleLogger.logFile = System.err
org.slf4j.simpleLogger.defaultLogLevel = debug
org.slf4j.simpleLogger.showDateTime = false
org.slf4j.simpleLogger.dateTimeFormat = yyyy'/'MM'/'dd' 'HH':'mm':'ss'-'S
org.slf4j.simpleLogger.showThreadName = true
org.slf4j.simpleLogger.showLogName = true
org.slf4j.simpleLogger.showShortLogName= false
org.slf4j.simpleLogger.levelInBrackets = true
Am I missing something here?
PS : I did checked the Jar and simplelogger.properties is available in the root directory
Instead of adding it to the root, add it under resources, next to scala code folder:
/
src
main
resources
simplelogger.properties
scala
Obviously this is not only valid for simplelogger.properties but for any other kind of file that you want in the classpath at runtime.
I had the same struggle until I tried to set the properties manually using System.setProperty(org.slf4j.simpleLogger.defaultLogLevel,"DEBUG");
and I noticed that these properties were not present in the slf4j-simple-1.6.1.jar
Make sure to get at least slf4j-simple-1.7.25.jar . The prior versions don't support properties
org.slf4j.simpleLogger.logFile
or
org.slf4j.simpleLogger.defaultLogLevel
Upgrading to 1.7.25 picked up the simple logger config from simplelogger.properties

ensime server fails to start from emacs

I am starting a new project in scala. I use emacs as editor.
So far it cannot be more simple. This is the build.sbt
name := "Sampler"
version := "1.0"
scalaVersion := "2.11.8"
I have run the ensimeConfig command in sbt (0.13 version)
When I start ensime on Emacs (M-ensime) I get the following error:
13:34:52.511 ERROR None Server - There was a problem parsing /home/jeronimo/prog/coursera/progfun2/circuits/.ensime
java.lang.NoSuchMethodError: shapeless.DataT$.genTraversableDataT(Lshapeless/Lazy;Lscala/collection/generic/CanBuildFrom;)Lshapeless/DataT;
at org.ensime.config.EnsimeConfigProtocol$anon$default$macro$337$1.inst$macro$320$lzycompute(EnsimeConfigProtocol.scala:61)
at org.ensime.config.EnsimeConfigProtocol$anon$default$macro$337$1.inst$macro$320(EnsimeConfigProtocol.scala:61)
at org.ensime.config.EnsimeConfigProtocol$anon$default$macro$337$1$$anonfun$inst$macro$319$1.apply(EnsimeConfigProtocol.scala:61)
at org.ensime.config.EnsimeConfigProtocol$anon$default$macro$337$1$$anonfun$inst$macro$319$1.apply(EnsimeConfigProtocol.scala:61)
at shapeless.Lazy$$anon$1.value$lzycompute(lazy.scala:121)
at shapeless.Lazy$$anon$1.value(lazy.scala:121)
at shapeless.EverywhereAux$$anonfun$default$2.apply(sybclass.scala:184)
at shapeless.Cases$Case1$$anon$1$$anonfun$1.apply(cases.scala:40)
at shapeless.Cases$Case1$$anon$1$$anonfun$1.apply(cases.scala:38)
at shapeless.PolyDefns$Case.apply(poly.scala:37)
at shapeless.DataT$$anon$12.gmapT(sybclass.scala:144)
at shapeless.DataT$$anon$12.gmapT(sybclass.scala:142)
at shapeless.DataT$$anon$12.gmapT(sybclass.scala:144)
at shapeless.DataT$$anon$12.gmapT(sybclass.scala:142)
at shapeless.DataT1$$anon$9.gmapT(sybclass.scala:116)
at shapeless.EverywhereAux$$anonfun$default$2.apply(sybclass.scala:184)
at shapeless.Cases$Case1$$anon$1$$anonfun$1.apply(cases.scala:40)
at shapeless.Cases$Case1$$anon$1$$anonfun$1.apply(cases.scala:38)
at shapeless.PolyDefns$Case.apply(poly.scala:39)
at org.ensime.core.Canonised$.apply(Canon.scala:19)
at org.ensime.config.EnsimeConfigProtocol$.validated(EnsimeConfigProtocol.scala:61)
at org.ensime.config.EnsimeConfigProtocol$$anonfun$3.apply(EnsimeConfigProtocol.scala:44)
at org.ensime.config.EnsimeConfigProtocol$$anonfun$3.apply(EnsimeConfigProtocol.scala:44)
at scala.collection.immutable.List.map(List.scala:273)
at org.ensime.config.EnsimeConfigProtocol$.validated(EnsimeConfigProtocol.scala:44)
at org.ensime.config.EnsimeConfigProtocol$.parse(EnsimeConfigProtocol.scala:32)
at org.ensime.server.Server$.main(Server.scala:120)
at org.ensime.server.Server.main(Server.scala)
Exception in thread "main" java.lang.NoSuchMethodError: shapeless.DataT$.genTraversableDataT(Lshapeless/Lazy;Lscala/collection/generic/CanBuildFrom;)Lshapeless/DataT;
at org.ensime.config.EnsimeConfigProtocol$anon$default$macro$337$1.inst$macro$320$lzycompute(EnsimeConfigProtocol.scala:61)
at org.ensime.config.EnsimeConfigProtocol$anon$default$macro$337$1.inst$macro$320(EnsimeConfigProtocol.scala:61)
at org.ensime.config.EnsimeConfigProtocol$anon$default$macro$337$1$$anonfun$inst$macro$319$1.apply(EnsimeConfigProtocol.scala:61)
at org.ensime.config.EnsimeConfigProtocol$anon$default$macro$337$1$$anonfun$inst$macro$319$1.apply(EnsimeConfigProtocol.scala:61)
at shapeless.Lazy$$anon$1.value$lzycompute(lazy.scala:121)
at shapeless.Lazy$$anon$1.value(lazy.scala:121)
at shapeless.EverywhereAux$$anonfun$default$2.apply(sybclass.scala:184)
at shapeless.Cases$Case1$$anon$1$$anonfun$1.apply(cases.scala:40)
at shapeless.Cases$Case1$$anon$1$$anonfun$1.apply(cases.scala:38)
at shapeless.PolyDefns$Case.apply(poly.scala:37)
at shapeless.DataT$$anon$12.gmapT(sybclass.scala:144)
at shapeless.DataT$$anon$12.gmapT(sybclass.scala:142)
at shapeless.DataT$$anon$12.gmapT(sybclass.scala:144)
at shapeless.DataT$$anon$12.gmapT(sybclass.scala:142)
at shapeless.DataT1$$anon$9.gmapT(sybclass.scala:116)
at shapeless.EverywhereAux$$anonfun$default$2.apply(sybclass.scala:184)
at shapeless.Cases$Case1$$anon$1$$anonfun$1.apply(cases.scala:40)
at shapeless.Cases$Case1$$anon$1$$anonfun$1.apply(cases.scala:38)
at shapeless.PolyDefns$Case.apply(poly.scala:39)
at org.ensime.core.Canonised$.apply(Canon.scala:19)
at org.ensime.config.EnsimeConfigProtocol$.validated(EnsimeConfigProtocol.scala:61)
at org.ensime.config.EnsimeConfigProtocol$$anonfun$3.apply(EnsimeConfigProtocol.scala:44)
at org.ensime.config.EnsimeConfigProtocol$$anonfun$3.apply(EnsimeConfigProtocol.scala:44)
at scala.collection.immutable.List.map(List.scala:273)
at org.ensime.config.EnsimeConfigProtocol$.validated(EnsimeConfigProtocol.scala:44)
at org.ensime.config.EnsimeConfigProtocol$.parse(EnsimeConfigProtocol.scala:32)
at org.ensime.server.Server$.main(Server.scala:120)
at org.ensime.server.Server.main(Server.scala)
Process *inferior-ensime-server-circuits* exited abnormally with code 1
After trying to delete the .ivy2 cache without success I fixed the issue re-installing the EMACS ensime plugin.

SBT run fails when I'm launching it

I have a little problem when I'm running the command sbt run :
$ sbt run
java.lang.NoSuchMethodError: com.typesafe.config.ConfigFactory.defaultApplication(Lcom/typesafe/config/ConfigParseOptions;)Lcom/typesafe/config/Config;
at play.api.Configuration$$anonfun$3.apply(Configuration.scala:75)
at play.api.Configuration$$anonfun$3.apply(Configuration.scala:71)
at scala.Option.getOrElse(Option.scala:121)
at play.api.Configuration$.load(Configuration.scala:71)
at play.core.server.DevServerStart$$anonfun$mainDev$1.apply(DevServerStart.scala:203)
at play.core.server.DevServerStart$$anonfun$mainDev$1.apply(DevServerStart.scala:61)
at play.utils.Threads$.withContextClassLoader(Threads.scala:21)
at play.core.server.DevServerStart$.mainDev(DevServerStart.scala:60)
at play.core.server.DevServerStart$.mainDevHttpMode(DevServerStart.scala:50)
at play.core.server.DevServerStart.mainDevHttpMode(DevServerStart.scala)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at play.runsupport.Reloader$.startDevMode(Reloader.scala:207)
at play.sbt.run.PlayRun$$anonfun$playRunTask$1$$anonfun$apply$2$$anonfun$apply$3.devModeServer$lzycompute$1(PlayRun.scala:73)
at play.sbt.run.PlayRun$$anonfun$playRunTask$1$$anonfun$apply$2$$anonfun$apply$3.play$sbt$run$PlayRun$$anonfun$$anonfun$$anonfun$$devModeServer$1(PlayRun.scala:73)
at play.sbt.run.PlayRun$$anonfun$playRunTask$1$$anonfun$apply$2$$anonfun$apply$3.apply(PlayRun.scala:99)
at play.sbt.run.PlayRun$$anonfun$playRunTask$1$$anonfun$apply$2$$anonfun$apply$3.apply(PlayRun.scala:52)
at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
Most of errors that I met with sbt have one issue when I google it but for this kind of error, no idea how to fix that.
My file build.sbt:
import play.routes.compiler.InjectedRoutesGenerator
import play.sbt.PlayScala
version := "1.0-SNAPSHOT"
lazy val root = (project in file(".")).enablePlugins(PlayScala)
scalaVersion := "2.11.6"
libraryDependencies ++= Seq(
cache,
ws,
filters,
"com.typesafe" % "config" % "1.0.0",
"org.reactivemongo" %% "play2-reactivemongo" % "0.11.7.play24",
"com.amazonaws" % "aws-java-sdk" % "1.10.12",
"org.webjars" %% "webjars-play" % "2.4.0-1",
"org.webjars" % "bootstrap" % "3.3.5",
"org.webjars" % "angularjs" % "1.4.7",
"org.webjars" % "angular-ui-bootstrap" % "0.14.3",
"org.webjars" % "angular-ui-router" % "0.2.15"
)
resolvers += "Sonatype Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots/"
resolvers += "scalaz-bintray" at "http://dl.bintray.com/scalaz/releases"
resolvers += "Typesafe Releases" at "http://repo.typesafe.com/typesafe/releases/"
// Play provides two styles of routers, one expects its actions to be injected, the
// other, legacy style, accesses its actions statically.
routesGenerator := InjectedRoutesGenerator
Anybody see one issue for this problem ?
Update with application.conf :
# This is the main configuration file for the application.
# ~~~~~
# Secret key
# ~~~~~
# The secret key is used to secure cryptographics functions.
#
# This must be changed for production, but we recommend not changing it in this file.
#
# See http://www.playframework.com/documentation/latest/ApplicationSecret for more details.
play.crypto.secret = "changeme"
# The application languages
# ~~~~~
play.i18n.langs = [ "en" ]
# Router
# ~~~~~
# Define the Router object to use for this application.
# This router will be looked up first when the application is starting up,
# so make sure this is the entry point.
# Furthermore, it's assumed your route file is named properly.
# So for an application router like `my.application.Router`,
# you may need to define a router file `conf/my.application.routes`.
# Default to Routes in the root package (and conf/routes)
# play.http.router = my.application.Routes
# Database configuration
# ~~~~~
# You can declare as many datasources as you want.
# By convention, the default datasource is named `default`
#
# db.default.driver=org.h2.Driver
# db.default.url="jdbc:h2:mem:play"
# db.default.username=sa
# db.default.password=""
# Evolutions
# ~~~~~
# You can disable evolutions if needed
# play.evolutions.enabled=false
# You can disable evolutions for a specific datasource if necessary
# play.evolutions.db.default.enabled=false
play.modules.enabled += "play.modules.reactivemongo.ReactiveMongoModule"
project/plugins.sbt:
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.4.0")
Update "com.typesafe" % "config" % "1.0.0", to 1.3.0
According to github, missed method appears in 1.3.0 version of ConfigFactory
https://github.com/typesafehub/config/blob/master/config/src/main/java/com/typesafe/config/ConfigFactory.java
* #since 1.3.0
*
* #param options the options
* #return the default application configuration
*/
public static Config defaultApplication(ConfigParseOptions options) {
return parseApplicationConfig(ensureClassLoader(options, "defaultApplication"));
}
For the people meeting this problem, The way to solve it was to put the config-1.3.0.jar into the lib folder.
The same error can happen if you put some play libraries into a provided environment classpath (as with an assembled fat jar). For example, Flink 1.3.2 has an older com.typesafe.config library, not compatible with Play 2.5 or further.
The way to solve is this is by shading the libraries as explained in sbt-assembly.

Forking and ordering tests in Sbt 0.13.x

Here is how it was configured for Sbt 0.12.x:
parallelExecution in test := false
testGrouping in Test <<= definedTests in Test map { tests =>
tests.map { test =>
import Tests._
import scala.collection.JavaConversions._
new Group(
name = test.name,
tests = Seq(test),
runPolicy = SubProcess(javaOptions = Seq(
"-server", "-Xms4096m", "-Xms4096m", "-XX:NewSize=3584m",
"-Xss256k", "-XX:+UseG1GC", "-XX:+TieredCompilation",
"-XX:+UseNUMA", "-XX:+UseCondCardMark",
"-XX:-UseBiasedLocking", "-XX:+AlwaysPreTouch") ++
System.getProperties.toMap.map {
case (k, v) => "-D" + k + "=" + v
}))
}.sortWith(_.name < _.name)
}
During migration to Sbt 0.13.x I get the following error:
[error] Could not accept connection from test agent: class java.net.SocketException: socket closed
java.net.SocketException: socket closed
at java.net.DualStackPlainSocketImpl.accept0(Native Method)
at java.net.DualStackPlainSocketImpl.socketAccept(DualStackPlainSocketImpl.java:131)
at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:398)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:199)
at java.net.ServerSocket.implAccept(ServerSocket.java:530)
at java.net.ServerSocket.accept(ServerSocket.java:498)
at sbt.ForkTests$$anonfun$mainTestTask$1$Acceptor$2$.run(ForkTests.scala:48)
at java.lang.Thread.run(Thread.java:745)
Migration changes are just updates in sbt & plugin versions.
Are there any other approaches to forking and ordering of tests in Sbt 0.13.x to overcome that exception?
Works fine on Linux and Mac OS.
Got error on Windows because of limit of classpath length that prevents launching of test agent instance with following error in System.err:
Error: Could not find or load main class sbt.ForkMain
I also got this error when moving to Scala repo to sbt version sbt.version = 1.3.8 (previously 1.2.8 was ok). Strangely worked fine on my mac, but failed on teamcity linux build agents.
Fix for me was to set
fork := false,
in build.sbt.
Not sure why repo had it previously set to fork := true (guess it was cut/paste from somewhere else as no strong reason for this in this repo), but this change resolved the issue. Locally on my mac also runs a few seconds faster now.
See here for background
https://www.scala-sbt.org/1.0/docs/Forking.html

How can I get automatic dependency resolution in my scala scripts?

I'm just learning scala coming out of the groovy/java world. My first script requires a 3rd party library TagSoup for XML/HTML parsing, and I'm loath to have to add it the old school way: that is, downloading TagSoup from its developer website, and then adding it to the class path.
Is there a way to resolve third party libraries in my scala scripts? I'm thinking Ivy, I'm thinking Grape.
Ideas?
The answer that worked best for me was to install n8:
curl https://raw.github.com/n8han/conscript/master/setup.sh | sh
cs harrah/xsbt --branch v0.11.0
Then I could import tagsoup fairly easily example.scala
/***
libraryDependencies ++= Seq(
"org.ccil.cowan.tagsoup" % "tagsoup" % "1.2.1"
)
*/
def getLocation(address:String) = {
...
}
And run using scalas:
scalas example.scala
Thanks for the help!
While the answer is SBT, it could have been more helpful where scripts are regarded. See, SBT has a special thing for scripts, as described here. Once you get scalas installed, either by installing conscript and then running cs harrah/xsbt --branch v0.11.0, or simply by writing it yourself more or less like this:
#!/bin/sh
java -Dsbt.main.class=sbt.ScriptMain \
-Dsbt.boot.directory=/home/user/.sbt/boot \
-jar sbt-launch.jar "$#"
Then you can write your script like this:
#!/usr/bin/env scalas
!#
/***
scalaVersion := "2.9.1"
libraryDependencies ++= Seq(
"net.databinder" %% "dispatch-twitter" % "0.8.3",
"net.databinder" %% "dispatch-http" % "0.8.3"
)
*/
import dispatch.{ json, Http, Request }
import dispatch.twitter.Search
import json.{ Js, JsObject }
def process(param: JsObject) = {
val Search.text(txt) = param
val Search.from_user(usr) = param
val Search.created_at(time) = param
"(" + time + ")" + usr + ": " + txt
}
Http.x((Search("#scala") lang "en") ~> (_ map process foreach println))
You may also be interested in paulp's xsbtscript, which creates an xsbtscript shell that has the same thing as scalas (I guess the latter was based on the former), with the advantage that, without either conscript or sbt installed, you can get it ready with this:
curl https://raw.github.com/paulp/xsbtscript/master/setup.sh | sh
Note that it installs sbt and conscript.
And there's also paulp's sbt-extras, which is an alternative "sbt" command line, with more options. Note that it's still sbt, just the shell script that starts it is more intelligent.
SBT (Simple Build Tool) seems to be the build tool of choice in the Scala world. It supports a number of different dependency resolution mechanisms: https://github.com/harrah/xsbt/wiki/Library-Management
Placed as an answer cause it doesn't fit in comment length constraint.
In addition to #Chris answer, I would like to recommend you some commons for sbt (which I personally think is absolutely superb). Although sbt denote Simple Build Tool, sometimes it is not so easy for first-timers to setup project with sbt (all this things with layouts, configs, and so on).
Use giter (g8) to create new project with predefined template (which g8 fetches from github.com). There are templates for Android app, unfiltered and more. Sometimes they are include some of the dependencies by default.
To create layout just type:
g8 gseitz/android-sbt-project
(An example for Android app)
Alternatively, use np pluggin for sbt, which provides interactive type-through way to create new project and basic layout.
A corrected and simplified version of the current main answer: use scalas.
You have to compose your script of 3 parts. One would be sbt, another would be a very simple wrapper around SBT called scalas, the last one is your custom script. Note that the first two scripts can be installed either globally (/usr/bin/, ~/bin/) or locally (in the same directory).
the first part is sbt. If you already have it installed then good. If not, you can either install it, or use a very cool script from paulp: https://github.com/paulp/sbt-extras/blob/master/sbt BTW, that thing is a charming way to use sbt on Unix. Although not available on windows. Anyways...
the second part is scalas. It's just an entrypoint to SBT.
#!/bin/sh
exec /path/to/sbt -Dsbt.main.class=sbt.ScriptMain -sbt-create \
-Dsbt.boot.directory=$HOME/.sbt/boot \
"$#"
the last part is your custom script. Example:
#!/usr/bin/env scalas
/***
scalaVersion := "2.11.0"
libraryDependencies ++= Seq(
"org.joda" % "joda-convert" % "1.5",
"joda-time" % "joda-time" % "2.3"
)
*/
import org.joda.time._
println(DateTime.now())
//println(DateTime.now().minusHours(12).dayOfMonth())
What Daniel said. Although it's worth mentioning that the sbt docs carefully label this functionality "experimental".
Indeed, if you try to run the embedded script with scalaVersion := "2.10.3", you'll get not found: value !#
Luckily, the !# script header-closer is unnecessary here, so you can leave it out.
Under scalaVersion := "2.10.3", the script will need to have the file extension ".scala"; using the bash shell script file extension, ".sh", won't work.
Also, it isn't clear to me that the latest version of Dispatch (0.11.0) supports dispatch-twitter, which is used in the example.
For more about header-closers in this context, see Alvin Alexander's blog post on Scala scripting, or section 14.10 of his Scala Cookbook.
I have a build.gradle file with the following task:
task classpath(dependsOn: jar) << {
println "CLASSPATH=${tasks.jar.archivePath}:${configurations.runtime.asPath}"
}
Then, in my Scala script:
#!
script_dir=$(cd $(dirname "$0") >/dev/null; pwd -P)
classpath=$(cd ${script_dir} && ./gradlew classpath | grep '^CLASSPATH=' | sed -e 's|^CLASSPATH=||')
PATH=${SCALA_HOME}/bin:${PATH}
JAVA_OPTS="-Xmx4g -XX:MaxPermSize=1g" exec scala -classpath ${classpath} "$0" "$0" "$#"
!#
Note that we don't need a separate scalas executable in our PATH, since we can use the self-executing shell script trick.
Here's an example script, which reads its own content (via the $0 variable), chops off everything before an arbitrary marker (__BEGIN_SCRIPT__) and runs sbt on the result. We use process substitution to pretend this calculated content is a real file. One problem with this approach is that sbt will seek within the given file, i.e. it doesn't read it sequentially. That stops it working with the <(foo) form of process substitution, as found in bash; however zsh has a =(foo) form which is seekable.
#!/usr/bin/env zsh
set -e
# Find the line # in this file ($0) after the line beginning __BEGIN_SCRIPT__
LINENUM=$(awk '/^__BEGIN_SCRIPT__/ {print NR + 1; exit 0; }' "$0")
sbtRun() {
# Run the sbt command, such that it will fetch dependencies and execute a
# script
sbt -Dsbt.main.class=sbt.ScriptMain \
-sbt-create \
-Dsbt.boot.directory="$HOME/.sbt/boot" \
"$#"
}
# Run SBT on the contents of this file, starting at LINENUM
sbtRun =(tail -n+"$LINENUM" "$0")
exit 0
__BEGIN_SCRIPT__
/***
scalaVersion := "2.11.0"
libraryDependencies ++= Seq(
"org.joda" % "joda-convert" % "1.5",
"joda-time" % "joda-time" % "2.3"
)
*/
import org.joda.time._
println(DateTime.now())