lazy val buildDb = taskKey[Unit]("Initializes the database")
buildDb := {
(compile in Compile).value
val s: TaskStreams = streams.value
s.log.info("Building database")
try {
...
} catch {
case e: Throwable =>
sys.error("Failed to initialize the database: " + e.getMessage)
}
s.log.info("Finished building database")
}
This produces the following error
C:\work\server\build.sbt:98: error: type mismatch;
found : Unit
required: T
s.log.info("Finished building database")
^
[error] Type error in expression
But if I define it like this lazy val buildDb = taskKey[String]("Initializes the database") and then add to the last line in the task "Happy end!" string everything seem to work. Am I to blame, or something wrong with the macro?
The same happened to me. I was able to fix the issue e.g. by adding a : TaskKey[Unit] to the taskKey definition. Here are my findings for sbt 0.13.5:
The following definition is OK (it seems that it is pure luck that this is OK):
lazy val collectJars = taskKey[Unit]("collects JARs")
collectJars := {
println("these are my JARs:")
(externalDependencyClasspath in Runtime).value foreach println
}
The following definition (the same as above without the first println) yields the same error "found: Unit, required: T":
lazy val collectJars = taskKey[Unit]("collects JARs")
collectJars := {
(externalDependencyClasspath in Runtime).value foreach println
}
My findings are that this is definitely something magical: For example, if I indent the line lazy val collectJars = ... by one blank, then it compiles. I would expect (but have not checked) that .sbt and .scala build definitions also behave differently.
However, if you add the type signature, it seems to always compile:
lazy val collectJars: TaskKey[Unit] = taskKey[Unit]("collects JARs")
collectJars := {
(externalDependencyClasspath in Runtime).value foreach println
}
Last but not least: The issue seems to be specific for TaskKey[Unit]. Unit tasks are not a good idea - in your example, you could at least return Boolean (true for success / false for failure).
Related
I need find filename in folder (in build.sbt), and add in artifact list.
//in build.sbt
val myZipTask = taskKey[File]("return the bundle:dist-zip file")
myZipTask := {
val filesArray = new java.io.File("/target/bundle").listFiles()
//here need to find the file name by coincidence and convert to a string
file(fileName)
}; addArtifact( Artifact("bundle", "zip", "zip"), myZipTask)
I tried this option
//in build.sbt
val myZipTask = taskKey[File]("return the bundle:dist-zip file")
myZipTask := {
import java.io.File
def getListOfFiles(dir: String): List[String] = {
val file = new File(dir)
file.listFiles.filter(_.isFile)
.filter(_.getName.startsWith("startName"))
.map(_.getPath).toList
}
getListOfFiles("/target/bundle")
}; addArtifact( Artifact("bundle", "zip", "zip"), myZipTask)
And sbt return me error:
build.sbt: error: type mismatch;
found : List[String]
required: sbt.File
(which expands to) java.io.File
getListOfFiles("/target/bundle")
^
Check the documentation on Path Finders:
val finder: PathFinder = target.value / "bundle"
You can add * "startName*" if you want to filter by prefix. If you call finder.get, it will return you a Seq[File], so this is what you wanted from your getListOfFiles.
But the problem with your code is that you need to return one file, not a list. You could either output an error if the file doesn't exist:
finder.get.headOption.getOrElse {
sys.error("Couldn't find bundle dist-zip file")
}
or change you task type to Option[File], return finder.get.headOption and add the artifact only if the file is there:
myZipTask.value.foreach { zipFile =>
addArtifact(Artifact("bundle", "zip", "zip"), zipFile)
}
This foreach could work even for multiple files if that's an option in your usecase.
For the following straightforward regex that works fine in the repl :
val tsecs = """[^\d]+([\d]+)*""".r
tsecs: scala.util.matching.Regex = [^\d]+([\d]+)*
Why would it not compile - either in Intellij or on the commandline via mvn compile ?
val tsecs = """[^\d]+([\d]+)*""".r
error: value r is not a member of String
[ERROR] val tsecs = """[^\d]+([\d]+)*""".r
The version is scala 2.10.5 in all cases.
There are a few ways to disable Predef.
import scala.Predef.{wrapString => _, augmentString => _, _}
object Test extends App {
def r = "x".r
}
Or
object Test extends App {
val wrapString, augmentString = 42
def r = "x".r
}
Or compile with -Yno-imports.
In sbt 0.13.9, I want to be able to run a task which takes in arguments from the command line and then passes those arguments on to two other tasks.
My initial attempt was something along the lines of:
lazy val logTask = InputKey[Unit](...)
lazy val runTask = InputKey[Unit](...)
lazy val TestCase = config("testCase") extend Test
runTask in TestCase := Def.inputTaskDyn {
val args: Seq[String] = spaceDelimited("<arg>").parsed
runReg(args)
}.evaluated
logTask in TestCase := Def.inputTaskDyn {
val args: Seq[String] = spaceDelimited("<arg>").parsed
log(args)
}.evaluated
def runReg(args: Seq[String]) = Def.taskDyn {
val argString = args.mkString(" ")
(logTask in TestCase).toTask(argString).value
(testOnly in TestCase).toTask(s" $argString")
}
def log(args: Seq[String]) {
(runMain in TestCase).toTask(s" LoggingClass $args.mkString(" ")")
}
But then it complains of an Illegal Dynamic Reference argString in (logTask in TestCase).toTask(argsString).value
I've also tried something like:
runTask in TestCase := {
val args: Seq[String] = spaceDelimited("<arg>").parsed
log(args).value
runReg(args).value
}
which also has an Illegal Dynamic Reference for args.
Is there any way of passing in parsed arguments into two tasks and run one after the other?
Thanks for any help.
Instead of assigning args.mkString(" ") to a variable, just pass it without assigning to any variable like below:
(logTask in TestCase).toTask(args.mkString(" ")).value
Update 1:
This kind of issues can also be sorted out with lazy initialization in sbt. So, try something like below:
lazy val argString = args.mkString(" ")
(logTask in TestCase).toTask(argString).value
I'm trying to play with Scala's PlayFramework and am running into an issue with my build.sbt file. Specifically:
Pattern matching in val statements is not supported
Which is from the obvious:
val env = sys.props.getOrElse("ENV", default = "local")
val (someVal, otherVal) = env match {
case "local" => ("x","a")
case _ => //etc
}
Is there a way to use a match statement in the build.sbt file at all? The error says that it's not supported in val statements. Where is it actually supported?
Edit:
I've tried adding a method to a build.scala object as well, but even when I use plain if statements I still get the same "Pattern matching in val statements is not supported"
Build.scala:
import sbt._
import Keys._
object ExampleBuild extends Build {
def getEnvData(env: String) = {
if(env == "local") {
("c","q")
} else if (env == "other") {
("b","v")
} else {
("x","a")
}
}
}
And updated build.sbt:
val env = sys.props.getOrElse("ENV", default = "local")
val (someVar, otherVar) = ExampleBuild.getEnvData(env)
But to no avail.
The error is not caused by the match statement, but from this:
val (someVar, otherVar) = ...
which is a form of pattern matching (on tuples) not supported by sbt.
Here's a relevant comment from the SbtParser implementation
// Check No val (a,b) = foo or val a,b = foo as these are problematic to range positions and the WHOLE architecture.
You can work around this limitation by using a case class instead of a tuple.
in Build.scala
case class EnvData(someVar: String, otherVar: String)
in build.sbt
val envData = env match {
case "local" => EnvData("x", "a")
case _ => //etc
}
and then use it like envData.someVar, envData.otherVar and so on.
I remember there is switch somewhere to suppress the printing of return types in the Scala REPL, but I cannot find it. I am particularly interested in adding this switch to an sbt build file. Something like returnTypes in console := false.
E.g. now I have
scala> within( Span( 0, 33 ))
res7: scala.collection.immutable.IndexedSeq[(de.sciss.lucre.expr.SpanLike, scala.collection.immutable.IndexedSeq[(de.sciss.lucre.expr.Expr[de.sciss.lucre.stm.InMemory,de.sciss.lucre.expr.SpanLike], de.sciss.lucre.expr.Expr[de.sciss.lucre.stm.InMemory,Long])])] = Vector()
and for obvious reasons I want
scala> within( Span( 0, 33 ))
res7: Vector()
My question is basically mirrored by this mailing-list question. Based on Rex Kerr's idea, the following could go into build.sbt:
initialCommands in console := """// helper method to disable type printing
def shortresults[T](t: => T) = {
val s = t.toString
val name = s.takeWhile(_ != ':')
val idx = s.indexOf(" = ")
val full = if (idx >= 0) name + s.substring(idx) else s
val short = if (full.length>799) full.substring(0,796)+"..." else full
print(short)
t
}
"""
But unfortunately, still the following three REPL escape commands need to be manually executed after the console is up and running:
:power
:wrap shortresults
:silent