4

I have added this to build.sbt

libraryDependencies += "com.typesafe.slick" %% "slick-codegen" % "2.1.0"

lazy val slickGenerate = TaskKey[Seq[File]]("slick code generation")

slickGenerate <<= slickGenerateTask 

lazy val slickGenerateTask = {
    (sourceManaged in Compile, dependencyClasspath in Compile, runner in Compile, streams) map { (dir, cp, r, s) =>
      val dbName = "dbname"
      val userName = "user"
      val password = "password"
      val url = s"jdbc:mysql://server:port/$dbName" 
      val jdbcDriver = "com.mysql.jdbc.Driver"
      val slickDriver = "scala.slick.driver.MySQLDriver"
      val targetPackageName = "models"
      val outputDir = (dir / dbName).getPath // place generated files in sbt's managed sources folder
      val fname = outputDir + s"/$targetPackageName/Tables.scala"
      println(s"\nauto-generating slick source for database schema at $url...")
      println(s"output source file file: file://$fname\n")
      r.run("scala.slick.codegen.SourceCodeGenerator", cp.files, Array(slickDriver, jdbcDriver, url, outputDir, targetPackageName, userName, password), s.log)
      Seq(file(fname))
    }
}

The task's code itself isn't very exciting. It just needs to create an auto-generated scala source file. Problem is, sbt starts fine, yet this new task is evidently not recognized by sbt and cannot be run in the sbt prompt. I have also had very little luck with the := syntax for task definition. Existing documentation has been just confounding.

How can this new task be made available in the sbt prompt?

matanster
  • 15,072
  • 19
  • 88
  • 167
  • so, did my answer help you, or there is some another problem? – dk14 Mar 12 '15 at 09:53
  • It's in my stack to implement (and thus verify) this... should I accept it for the bounty to materialize? – matanster Mar 12 '15 at 10:50
  • i'm more interested in problem solving, but the bounty also would be great :) - I through you'd opened it to quickly solve the issue – dk14 Mar 12 '15 at 11:01
  • No, I opened it to have a solution once I context switch back, as it was inconceivable leaving it indefinitely broken. Since I assume it worked for you, let me "accept" it now :) and thanks again, this will really help! – matanster Mar 12 '15 at 13:51

1 Answers1

8

This works

libraryDependencies += "com.typesafe.slick" %% "slick-codegen" % "2.1.0"

lazy val slickGenerate = taskKey[Seq[File]]("slick code generation")

slickGenerate := {
  val dbName = "dbname"
  val userName = "user"
  val password = "password"
  val url = s"jdbc:mysql://server:port/$dbName"
  val jdbcDriver = "com.mysql.jdbc.Driver"
  val slickDriver = "scala.slick.driver.MySQLDriver"
  val targetPackageName = "models"
  val outputDir = ((sourceManaged in Compile).value / dbName).getPath // place generated files in sbt's managed sources folder
  val fname = outputDir + s"/$targetPackageName/Tables.scala"
  println(s"\nauto-generating slick source for database schema at $url...")
  println(s"output source file file: file://$fname\n")
  (runner in Compile).value.run("scala.slick.codegen.SourceCodeGenerator", (dependencyClasspath in Compile).value.files, Array(slickDriver, jdbcDriver, url, outputDir, targetPackageName, userName, password), streams.value.log)
  Seq(file(fname))
}

In sbt 0.13.x you don't need all those blabla map sameblabla boilerplates. Just access value as is (runner in Compile).value - macro will do everything else for you.

> slickGenerate
[info] Updating {file:/Users/user/slick/}slick...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[info] Done updating.

auto-generating slick source for database schema at jdbc:mysql://server:port/dbname...
output source file file: file:///Users/user/slick/target/scala-2.10/src_managed/main/dbname/models/Tables.scala

> help slickGenerate
slick code generation

Talking about <<= - your TaskKey is incorrect, see the definition:

def apply[T](label : scala.Predef.String, description : scala.Predef.String // not description

So, the old definition <<= uses "generate slick code" as label, while the new := uses the code-given name for command (new style), so it uses your "generate slick code" as a doc. Which looks strange and inconsistent, but that's a fact and it's partially reasoned by backward-compatibility.

So, correct old-style version is:

import sbt.Keys._

lazy val slickGenerate = TaskKey[Seq[File]]("slick-generate", "generate slick code")

slickGenerate <<= slickGenerateTask

def slickGenerateTask =
  (sourceManaged in Compile, dependencyClasspath in Compile, runner in Compile, streams) map { (dir, cp, r, s) =>
    ...
  }

It works in the same way as previous. Note, that you have to use "slickGenerate", not "slick-generate", the last one doesn't work for "help" command.

By the way, you're using Bare build definition now - you may want to switch to Multi-project .sbt definition as it's recommended by sbt docs, see also.

Community
  • 1
  • 1
dk14
  • 22,206
  • 4
  • 51
  • 88
  • 1
    Thanks again. Works indeed and thanks for the related comments! I wonder what should I do to switch my build definition to multi-project build definition. The documentation is quite a clump of narrative, not sure what is the practical series of steps for making that transition, or why it is actually better. – matanster Mar 20 '15 at 10:34