Play 2.1 ConfigFactory.parseFile fails on substitution - sbt

In application.conf (in Play 2.0.4, sbt 0.11.3) I could use following substitutions:
app {
major = 0
minor = 1
revision = 62
date = 0127
version = ${app.major}.${app.minor}.${app.revision}.${app.date}
}
After upgrade to Play 2.1.0 and sbt 0.12.2 and using this suggestion for Build.scala,
val conf = ConfigFactory.parseFile(new File("conf/application.conf"))
I get error when I do play clean:
Caused by: com.typesafe.config.ConfigException$NotResolved: need to call resolve() on root config; tried to get value type on an unresolved substitution: ConfigSubstitution(${app.major}"."${app.minor}"."${app.revision}"."${app.date})
at com.typesafe.config.impl.ConfigSubstitution.valueType(ConfigSubstitution.java:54)
at com.typesafe.config.impl.DefaultTransformer.transform(DefaultTransformer.java:15)
at com.typesafe.config.impl.SimpleConfig.findKey(SimpleConfig.java:118)
at com.typesafe.config.impl.SimpleConfig.find(SimpleConfig.java:135)
at com.typesafe.config.impl.SimpleConfig.find(SimpleConfig.java:140)
at com.typesafe.config.impl.SimpleConfig.find(SimpleConfig.java:108)
at com.typesafe.config.impl.SimpleConfig.find(SimpleConfig.java:146)
at com.typesafe.config.impl.SimpleConfig.getString(SimpleConfig.java:188)
at ApplicationBuild$.<init>(Build.scala:12)
at ApplicationBuild$.<clinit>(Build.scala)
Based on Play Configuration documentation this kind of substitution should be supported:
Implementations must take care, however, to allow objects to refer to
paths within themselves. For example, this must work:
bar : { foo : 42,
baz : ${bar.foo}
} Here, if an implementation resolved all substitutions in bar as part of resolving the substitution ${bar.foo}, there would be a
cycle. The implementation must only resolve the foo field in bar,
rather than recursing the entire bar object.
Any ideas how to fix this?

Your syntax is correct. It seems that you actually need to call resolve() as the error message says, to resolve substitutions. I guess in 2.0.x the play framework did this and provided a config that was already resolved this way. Now that the config API is used directly it needs to be resolved manually.
Add a call to resolve() in this line:
val conf = ConfigFactory.parseFile(new File("conf/application.conf")).resolve()

AFAIK, my understanding of the doc is that you should use something like:
app {
major = 0
minor = 1
revision = 62
date = 0127
version = ${major}.${minor}.${revision}.${date}
}
I did not test it...
And maybe it worked under 2.0.4 because of a bug ?

Related

SysCTypes errors when using NetCDF.chpl?

I have a simple Chapel program to test the NetCDF module:
use NetCDF;
use NetCDF.C_NetCDF;
var f: int = ncopen("ppt2020_08_20.nc", NC_WRITE);
var status: int = nc_close(f);
and when I compile with:
chpl -I/usr/include -L/usr/lib/x86_64-linux-gnu -lnetcdf hello.chpl
it produces a list of errors about SysCTypes:
$CHPL_HOME/modules/packages/NetCDF.chpl:57: error: 'c_int' undeclared (first use this function)
$CHPL_HOME/modules/packages/NetCDF.chpl:77: error: 'c_char' undeclared (first use this function)
...
Would anyone see what my error is? I tried adding use SysCTypes; to my program, but that didn't seem to have an effect.
Sorry for the delayed response and for this bad behavior. This is a bug that's crept into the NetCDF module which seems not to have been caught by Chapel's nightly testing. To work around it, edit $CHPL_HOME/modules/packages/NetCDF.chpl, adding the line:
public use SysCTypes, SysBasic;
within the declaration of the C_NetCDF module (around line 50 in my copy of the sources). If you would consider filing this bug as an issue on the Chapel GitHub issue tracker, that would be great as well, though we'll try to get this fixed in the next release in any case.
With that change, your program almost compiles for me, except that nc_close() takes a c_int argument rather than a Chapel int. You could either lean on Chapel's type inference to cause this to happen:
var f = ncopen("ppt2020_08_20.nc", NC_WRITE);
or explicitly declare f to be of type c_int:
var f: c_int = ncopen("ppt2020_08_20.nc", NC_WRITE);
And then as one final note, I believe you should be able to drop the -lnetcdf from your chpl command-line as using the NetCDF module should cause this requirement to automatically be added.
Thanks for bringing this bug to our attention!

Pass in version number when building in sbt

I have a semi-complicated SBT process because I need to conditionally include a different config file based on what kind of build is needed. I solved this problem through sub-projects:
lazy val app = project
.in(file("."))
.enablePlugins(JavaAppPackaging)
.settings(
commonSettings // Seq() of settings to be shared between projects
,sourceGenerators in Compile += (avroScalaGenerateSpecific in Compile).taskValue
,(avroSpecificSourceDirectory in Compile) := new java.io.File("src/main/resources/com/coolCompany/folderName/avro")
)
lazy val localPackage = project
.in(file("build/local"))
.enablePlugins(JavaAppPackaging)
.settings(
organization := "com.coolCompany",
version := "0.1.0-SNAPSHOT",
scalaVersion := "2.11.8",
name := "my-neat-project",
scalacOptions := compilerOptions, //Seq() of compiler flags
sourceDirectory in Compile := (sourceDirectory in (app, Compile)).value,
mappings in Universal += {
((sourceDirectory in Compile).value / "../../conf/local/config.properties") -> "lib/config.properties"
}
)
.dependsOn(app)
val buildNumber = inputKey[String]("The version number of the artifact.")
lazy val deployedPackage = project
.in(file("build/deployed"))
.enablePlugins(JavaAppPackaging)
.settings(
organization := "com.coolCompany",
buildNumber := {
val args : Seq[String] = spaceDelimited("<arg>").parsed
println(s"Input version number is ${args.head}")
args.head
},
version := buildNumber.inputTaskValue + "-SNAPSHOT", //"0.1.0-SNAPSHOT",
scalaVersion := "2.11.8",
name := "my-cool-project",
scalacOptions := compilerOptions,
sourceDirectory in Compile := (sourceDirectory in (app, Compile)).value,
mappings in Universal += {
((sourceDirectory in Compile).value / "../../conf/deployed/config.properties") -> "lib/config.properties"
}
)
.dependsOn(app)
Now I need to allow the version number to be passed in by a build tool when building. You can see what I've attempted to do already: I created an inputKey task called buildNumber, then tried to access that in the version := definition. I can run the buildNumber task itself just fine:
$ sbt 'deployedPackage/buildNumber 0.1.2'
Input version number is 0.1.2
So I can at least verify that my input task works as expected. The issue is that I can't figure out how I actually get to that input value when running the actual packageBin step that I want.
I've tried the following:
$ sbt 'deployedPackage/universal:packageBin 0.1.2'
[error] Expected key
[error] Expected '::'
[error] Expected end of input.
[error] deployedPackage/universal:packageBin 0.1.2
So it clearly doesn't understand what to do with the version number. I've tried a bunch of different input variations, such as [...]packageBin buildNumber::0.1.2, [...]packageBin -- buildNumber 0.1.2, or [...]packageBin -- 0.1.2, and all of them give that error or something similar indicating it doesn't understand what I'm trying to pass in.
Now, ultimately, these errors make sense. buildNumber, the task, is what knows what to do with the command line values, but packageBin does not. How do I set up this task or these set of tasks to allow the version number to be passed in?
I have seen this question but the answers link to an sbt plugin that seems to do about 100 more things than I want it to do, including quite a few that I would need to find a way to explicitly disable. I only want the version number to be able to be passed in & used in the artifact.
Edit/Update: I resolved this issue by switching back to Maven.
I think you're a bit confused about the way sbt settings work. Settings are set when sbt loads and then cannot be changed until you reload the session. So whatever you set version to, it will be fixed, it cannot be dynamic and depend on user input or a task (which on the contrast is dynamic and is evaluated every time you call it).
This is true. However you can still compute a SettingKey value in the first place. We use environment variables to set our build version.
version := "1." + sys.env.getOrElse("BUILD_NUMBER", "0-SNAPSHOT")
Explanation
1. is the major version. Increment this manually as you like
BUILD_NUMBER is an environment variable that is typically set by a CI, e.g. Jenkins. If not set, use 0-SNAPSHOT as a version suffix.
We use this in our company for our continuous deployment pipeline.
Hope that helps,
Muki
I think you're a bit confused about the way sbt settings work. Settings are set when sbt loads and then cannot be changed until you reload the session. So whatever you set version to, it will be fixed, it cannot be dynamic and depend on user input or a task (which on the contrast is dynamic and is evaluated every time you call it).
You have an input task buildNumber which depends on user input and is evaluated every time you call it:
> show buildNumber 123
Input version number is 123
[info] 123
[success] Total time: 0 s, completed Dec 24, 2017 3:41:43 PM
> show buildNumber 456
Input version number is 456
[info] 456
[success] Total time: 0 s, completed Dec 24, 2017 3:41:45 PM
It returns whatever you give it and doesn't do anything (besides println). More importantly, it doesn't affect version setting anyhow (and couldn't even in theory).
When you use buildNumber.inputTaskValue, you refer to the input task itself, not its value (which is unknown because it depends on the user input). You can see it by checking the version setting value:
> show version
[info] sbt.InputTask#6c996907-SNAPSHOT
So it's definitely not what you want.
I suggest you to review your approach in general and read a bit more sbt docs, for example about Task graph (and the whole Getting started chapter).
If you still really need to set version on sbt load according to your input, you can do it with a command. It would look like this:
commands += Command.single("pkg") { (state0, buildNumber) =>
val state1 = Project.extract(state0).append(Seq(version := buildNumber + "-SNAPSHOT"), state0)
val (state2, result) = Project.extract(state1).runTask(packageBin in (deployedPackage, universal), state1)
state2
}
But you should be really careful dealing with the state manually. Again, I recommend you to review your approach and change it to a more sbt-idiomatic one.
I suggest you just set the version setting only for the project deployedPackage just before you call the task needing the version. This is the simplest way of setting the version, and as settings keys have scopes, this should work as intended.
I used something like this for a big multi module project, where one of the projects had a separate versioning history than the other projects.

Can I use sbt's `apiMappings` setting for managed dependencies?

I'd like the ScalaDoc I generate with sbt to link to external libraries, and in sbt 0.13 we have autoAPIMappings which is supposed to add these links for libraries that declare their apiURL. In practice though, none of the libraries I use provide this in their pom/ivy metadata, and I suspect some of these libraries will never do so.
The apiMappings setting is supposed to help with just that, but it is typed as Map[File, URL] and hence geared towards setting doc urls for unmanaged dependencies. Managed dependencies are declared as instances of sbt.ModuleID and cannot be inserted directly in that map.
Can I somehow populate the apiMappings setting with something that will associate an URL with a managed dependency ?
A related question is: does sbt provide an idiomatic way of getting a File from a ModuleID? I guess I could try to evaluate some classpaths and get back Files to try and map them to ModuleIDs but I hope there is something simpler.
Note: this is related to https://stackoverflow.com/questions/18747265/sbt-scaladoc-configuration-for-the-standard-library/18747266, but that question differs by linking to the scaladoc for the standard library, for which there is a well known File scalaInstance.value.libraryJar, which is not the case in this instance.
I managed to get this working for referencing scalaz and play by doing the following:
apiMappings ++= {
val cp: Seq[Attributed[File]] = (fullClasspath in Compile).value
def findManagedDependency(organization: String, name: String): File = {
( for {
entry <- cp
module <- entry.get(moduleID.key)
if module.organization == organization
if module.name.startsWith(name)
jarFile = entry.data
} yield jarFile
).head
}
Map(
findManagedDependency("org.scalaz", "scalaz-core") -> url("https://scalazproject.ci.cloudbees.com/job/nightly_2.10/ws/target/scala-2.10/unidoc/")
, findManagedDependency("com.typesafe.play", "play-json") -> url("http://www.playframework.com/documentation/2.2.1/api/scala/")
)
}
YMMV of course.
The accepted answer is good, but it'll fail when assumptions about exact project dependencies don't hold. Here's a variation that might prove useful:
apiMappings ++= {
def mappingsFor(organization: String, names: List[String], location: String, revision: (String) => String = identity): Seq[(File, URL)] =
for {
entry: Attributed[File] <- (fullClasspath in Compile).value
module: ModuleID <- entry.get(moduleID.key)
if module.organization == organization
if names.exists(module.name.startsWith)
} yield entry.data -> url(location.format(revision(module.revision)))
val mappings: Seq[(File, URL)] =
mappingsFor("org.scala-lang", List("scala-library"), "http://scala-lang.org/api/%s/") ++
mappingsFor("com.typesafe.akka", List("akka-actor"), "http://doc.akka.io/api/akka/%s/") ++
mappingsFor("com.typesafe.play", List("play-iteratees", "play-json"), "http://playframework.com/documentation/%s/api/scala/index.html", _.replaceAll("[\\d]$", "x"))
mappings.toMap
}
(Including scala-library here is redundant, but useful for illustration purposes.)
If you perform mappings foreach println, you'll get output like (note that I don't have Akka in my dependencies):
(/Users/michaelahlers/.ivy2/cache/org.scala-lang/scala-library/jars/scala-library-2.11.7.jar,http://scala-lang.org/api/2.11.7/)
(/Users/michaelahlers/.ivy2/cache/com.typesafe.play/play-iteratees_2.11/jars/play-iteratees_2.11-2.4.6.jar,http://playframework.com/documentation/2.4.x/api/scala/)
(/Users/michaelahlers/.ivy2/cache/com.typesafe.play/play-json_2.11/jars/play-json_2.11-2.4.6.jar,http://playframework.com/documentation/2.4.x/api/scala/)
This approach:
Allows for none or many matches to the module identifier.
Concisely supports multiple modules to link the same documentation.
Or, with Nil provided to names, all modules for an organization.
Defers to the module as the version authority.
But lets you map over versions as needed.
As in the case with Play's libraries, where x is used for the patch number.
Those improvements allow you to create a separate SBT file (call it scaladocMappings.sbt) that can be maintained in a single location and easily copy and pasted into any project.
Alternatively to my last suggestion, the sbt-api-mappings plugin by ThoughtWorks shows a lot of promise. Long term, that's a far more sustainable route than each project maintaining its own set of mappings.

Scalatra Databinding

I'm playing with command model binding and I looked at the example github project and I have issues when using the dependency:
"org.scalatra" % "scalatra-data-binding" % "2.2.0-RC1"
Taking the example project code i.e.
abstract class TodosCommand[S](implicit mf: Manifest[S]) extends ModelCommand[S] with ParamsOnlyCommand
class CreateTodoCommand extends TodosCommand[Todo] {
val name: Field[String] = asType[String]("name").notBlank.minLength(3)
}
case class Todo(id: Integer, name: String, done: Boolean = false)
I am unable to compile when I use the command[CreateTodoCommand] method from the CommandSupport trait i.e.
scala: type arguments [au.com.xxx.sapi.seo.CreateTodoCommand] do not conform to method command's type parameter bounds [T <: SeoServlet.this.CommandType]
val cmd = command[CreateTodoCommand]
^
I'm not that clued up with Scala but I would assume that as ParamsOnlyCommand extends Command and there is this line in the command support trait, then there should be no issues:
type CommandType <: org.scalatra.databinding.Command
Any ideas why I am getting this issue?
Cheers, Chris.
It's very likely that the reason you're having problems is that we're still linking to an ancient example version, for which the docs no longer apply. I thought I'd caught all of the example projects in the docs and moved them into https://github.com/scalatra/scalatra-website-examples, but apparently I missed this one. Sorry for the hassle!
I'll see if I can fix this today sometime, and provide a compiling example. In the meantime, you might try updating all your Scalatra-related dependencies to the 2.2.0 release - and see if that fixes anything straight away.
The latest stable release of Scalatra is currently 2.2.1, but you'll need to be careful around commands as I remember #casualjim saying that he'd changed the way things worked to some extent between 2.2.0 and 2.2.1.
In Scalatra 2.2.1, "org.scalatra" %% "scalatra-commands" % "2.2.0" I have no issues. but I don't know scalatra-data-binding is also standalone.

Bug in zc.recipe.cmmi?

If I provide a variable with an embedded space in the environment as follows:
environment =
CPPFLAGS="-D_GNU_SOURCE -I${openssl:location}/include"
I get this error:
ValueError: dictionary update sequence element #1 has length 1; 2 is required
Is this a bug? Is there a workaround?
It's a shortcoming in zc.recipe.cmmi; it cannot handle environment variables without spaces. There is a patch available in the bugtracker for the recipe.
I am not currently aware of a workaround for this other than applying the patch. You can apply the patch on existing eggs using the collective.recipe.patch recipe, which should work in this case too (untried):
[buildout]
parts =
patch-z.r.cmmi
yourcmmipart
[patch-z.r.cmmi]
recipe = collective.recipe.patch
egg = zc.recipe.cmmi <= 1.3.4
patch = patches/environ_section_trunk_r101308.patch
This assumes you have a patches suddirectory with the patch from the bug downloaded. The part needs to be listed before your cmmi part to be executed before that part (or you can fabricate a dependency).
An alternative solution is to just abuse the recipe's 'configure-command' like so:
[buildthis]
recipe = zc.recipe.cmmi
...
configure-command =
export CPPFLAGS="-D_GNU_SOURCE -I${openssl:location}/include";
./configure

Resources