Play Framework and scala.tools.nsc - scala

I have to use scala parser inside Play Framework application.
import scala.tools.nsc._
trait Foo
class Parser {
def parse(code: String) = {
val settings = new Settings
settings.embeddedDefaults[Foo]
val interpreter = new Interpreter(settings)
interpreter.parse(code)
}
}
I have following dependency in Build.scala
"org.scala-lang" % "scala-compiler" % "2.9.1"
This code works when build using SBT. In Play it ends with NullPointerException and:
Failed to initialize compiler: object scala not found.
** Note that as of 2.8 scala does not assume use of the java classpath.
** For the old behavior pass -usejavacp to scala, or if using a Settings
** object programatically, settings.usejavacp.value = true.
Build.scala
import sbt._
import Keys._
import PlayProject._
object ApplicationBuild extends Build {
val appName = "com.qwerty.utils"
val appVersion = "1.0-SNAPSHOT"
val scalaVersion = "2.9.1"
val appDependencies = Seq(
"org.scala-lang" % "scala-compiler" % "2.9.1"
)
val main = PlayProject(appName, appVersion, appDependencies, mainLang = SCALA).settings(
// Add your own project settings here
)
}

For background on embeddedDefaults, see the original proposal.
The container (Play) must define the 'app.class.path' and 'boot.class.path' resources and then embeddedDefaults will use them to configure the interpreter properly for the environment. So, this is an enhancement for Play.
If you can pass the necessary classpaths into your application, you can configure classpaths and classloaders explicitly yourself with something like:
val settings = new Settings
settings.classpath.value = "<classpath>"
settings.bootclasspath.value =
settings.bootclasspath.value + File.pathSeparator +
"<extra-bootclasspath>"
val interpreter = new Interpreter(settings) {
override def parentClassLoader = classOf[Foo].getClassLoader
}
interpreter.parse(code)
The bootclasspath should generally contain scala-library.jar and the classpath should contain the application jars.

Related

Migrating from Play 2.1 to 2.5: Build.scala configuration issues

I am upgrading from Play 2.1.3 to Play 2.5.4. I resolved multiple issues but I am now stuck at one last step I guess:
My project/Build.scala:
import sbt._
import Keys._
import play.sbt._
import Play.autoImport._
import PlayKeys._
object ApplicationBuild extends Build {
val appName = "dashboard"
val appVersion = "1.0-SNAPSHOT"
val appDependencies = Seq(
// Add your project dependencies here,
javaCore,
javaJdbc,
javaEbean
)
val main = play.Project(appName, appVersion, appDependencies).settings(
// Add your own project settings here
)
}
When I do activator run on my project, I get the following error:
[error] \project\Build.scala:19: object Project is not a member of package play
[error] val main = play.Project(appName, appVersion, apDependencies).settings(
[error] ^
[error] one error found
[debug] Compilation failed (CompilerInterface)
[error] (compile:compileIncremental) Compilation failed
Project loading failed: (r)etry, (q)uit, (l)ast, or (i)gnore?
Can someone please help?
play.Project was replaced by native sbt Project support at version 2.3:. From this version migration docs:
If you were previously using play.Project, for example a Scala project:
object ApplicationBuild extends Build {
val appName = "myproject"
val appVersion = "1.0-SNAPSHOT"
val appDependencies = Seq()
val main = play.Project(appName, appVersion, appDependencies).settings(
)
}
...then you can continue to use a similar approach via native sbt:
object ApplicationBuild extends Build {
val appName = "myproject"
val appVersion = "1.0-SNAPSHOT"
val appDependencies = Seq()
val main = Project(appName, file(".")).enablePlugins(play.PlayScala).settings(
version := appVersion,
libraryDependencies ++= appDependencies
)
}
But, since you are migrating from a very old version (Play 2.1 last release was in Sep 2013), I truly recommend you to use build.sbt instead of project/Build.scala. The migration would be something like:
name := """dashboard"""
version := "1.0-SNAPSHOT"
lazy val root = (project in file(".")).enablePlugins(PlayJava)
scalaVersion := "2.11.8"
libraryDependencies ++= Seq(
javaJdbc,
cache,
javaWs
)
And, instead of adding javaEbean, you will need to use play-ebean instead. To do so, just add the following line to your project/plugins.sbt file (this was changed at Play 2.4 and you have to use the updated version as documented for Play 2.5):
addSbtPlugin("com.typesafe.sbt" % "sbt-play-ebean" % "3.0.0")
After that, change your root project definition to something like this:
lazy val myProject = (project in file(".")).enablePlugins(PlayJava, PlayEbean)
This will automatically add Ebean dependencies. Finally, I can't recommend enough that you read all the migration guides for version between 2.1 and 2.5.

How do you share a custom task in a SBT multi-project

I have a project set up as a SBT multi-build. That looks like this:
- project
Dependencies.scala
- core
build.sbt
- server
build.sbt
build.sbt
I want to use Dependencies.scala as a container for version numbers of libraries that are shared between the sub-projects.
sealed trait Dependencies {
val commonsIo = "2.4"
}
object DependencyVersions extends Dependencies
In the root build.sbt I added a Setting that is given to each sub-project.
lazy val dependencies = settingKey[Dependencies]("versions")
val defaultSettings = Defaults.coreDefaultSettings ++ Seq(
dependencies := DependencyVersions)
def projectFolder(name: String, theSettings: Seq[Def.Setting[_]] = Nil) = Project(name, file(name), settings = theSettings)
lazy val core = projectFolder("core", defaultSettings)
I can't access the dependencies setting in core/build.sbt.
"commons-io" % "commons-io" % dependencies.value.commonsIo, <-- doesn't work
How can I get this to work?
You can define common settings (dependencies) in an object Common extends AutoPlugin (in project/Common.scala), and then use .enablePlugin(Common) on sub-project descriptor (see it in Anorm).
Thanks #cchantep got it working now using the AutoPlugin below
import sbt._
sealed trait Dependencies {
val commonsIo = "2.4"
}
object DependencyVersions extends Dependencies
object DependencyVersionsPlugin extends AutoPlugin {
override def trigger = allRequirements
object autoImport {
lazy val dependencies = settingKey[Dependencies]("Bundles dependency versions")
}
import autoImport._
override def projectSettings = Seq(
dependencies := DependencyVersions
)
}

How to use SBT IntegrationTest configuration from Scala objects

To make our multi-project build more manageable we split up our Build.scala file into several files, e.g. Dependencies.scala contains all dependencies:
import sbt._
object Dependencies {
val slf4j_api = "org.slf4j" % "slf4j-api" % "1.7.7"
...
}
We want to add integration tests to our build. Following the SBT documentation we added
object Build extends sbt.Build {
import Dependencies._
import BuildSettings._
import Version._
import MergeStrategies.custom
lazy val root = Project(
id = "root",
base = file("."),
settings = buildSettings ++ Seq(Git.checkNoLocalChanges, TestReport.testReport)
).configs(IntegrationTest).settings(Defaults.itSettings: _*)
...
}
where Dependencies, BuildSettings, Version and MergeStrategies are custom Scala objects definied in their own files.
Following the documentation we want to add some dependencies for the IntegrationTest configuration in Dependencies.scala:
import sbt._
object Dependencies {
val slf4j_api = "org.slf4j" % "slf4j-api" % "1.7.7"
val junit = "junit" % "junit" % "4.11" % "test,it"
...
}
Unfortunately this breaks the build:
java.lang.IllegalArgumentException: Cannot add dependency
'junit#junit;4.11' to configuration 'it' of module ... because this configuration doesn't exist!
I guess I need to import the IntegrationTest configuration. I tried importing the IntegrationTest configuration in Dependencies.scala:
import sbt.Configurations.IntegrationTest
IntegrationTest is a lazy val defined in the Configurations object:
object Configurations {
...
lazy val IntegrationTest = config("it") extend (Runtime)
...
}
But that did not solve the problem.
Does someone has an idea how to solve this?
You need to add the config to the Project object before you add the dependency to the Project object.
Your code quotes show you doing the former, but you don't show where you are doing the latter in your quoted code.
Please could you post the full config, or try moving those two around each other?
Here is where the config is added to the Project object in the SBT docs you linked to:
lazy val root = (project in file(".")).
configs(IntegrationTest).
Your quoted code above which declares a lazy val but does not use it is not sufficient to get the "it" config into use:
lazy val IntegrationTest = config("it") extend (Runtime)

Why does sbt report "not found: value PlayScala" with Build.scala while build.sbt works?

I am creating a multi-module sbt project, with following structure:
<root>
----build.sbt
----project
----Build.scala
----plugins.sbt
----common
----LoggingModule
LoggingModule is a Play Framework project, while common is a simple Scala project.
In plugins.sbt:
resolvers += "Typesafe repo" at "http://repo.typesafe.com/typesafe/releases/"
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.3.3")
While I have this in build.sbt, all works fine and it recognises PlayScala:
name := "Multi-Build"
lazy val root = project.in(file(".")).aggregate(common, LoggingModule).dependsOn(common, LoggingModule)
lazy val common = project in file("common")
lazy val LoggingModule = (project in file("LoggingModule")).enablePlugins(PlayScala)
However as soon I put this in project/Build.scala instead of `build.sbt' as follows:
object RootBuild extends Build {
lazy val root = project.in(file("."))
.aggregate(common, LoggingModule)
.dependsOn(common, LoggingModule)
lazy val common = project in file("common")
lazy val LoggingModule = (project in file("LoggingModule")).enablePlugins(PlayScala)
...//other settings
}
it generates error as:
not found: value PlayScala
lazy val LoggingModule = (project in file("LoggingModule")).enablePlugins(PlayScala)
^
How to solve the issue?
It's just a missing import.
In .sbt files, some things are automatically imported by default: contents of objects extending Plugin, and (>= 0.13.5) autoImport fields in AutoPlugins. This is the case of PlayScala.
In a Build.scala file, normal Scala import rules apply. So you have to import things a bit more explicitly. In this case, you need to import play.PlayScala (or use .enabledPlugins(play.PlayScala) directly).

Adding multiple subprojects to Play 2 framework

am using play 2 framework with java
I have added a project dependency as a sub-project
by following the tutorials
Now I want a second sub-project.
But kind of new to the scala codes in the build.scala file
can some one tell me how to ass a second sub-project.
below is my code for the build.scala file and the sub-project.
import sbt._
import Keys._
import PlayProject._
object ApplicationBuild extends Build {
val appName = "Rub_Server"
val appVersion = "1.0-SNAPSHOT"
val appDependencies = Seq(
// These are the project dependencies
"mysql" % "mysql-connector-java" % "5.1.18",
)
val subProject = Project("Com-RubineEngine-GesturePoints", file("modules/Com-RubineEngine-GesturePoints"))
val main = PlayProject(appName, appVersion, appDependencies, mainLang = JAVA).settings(
// Add your own project settings here
).dependsOn(subProject)
}
now I want add a second project to the build.scala file
how do I do tht
thanks.
.dependsOn(subProject, anotherProject)