为什么sbt run会使用Slick的代码生成器抛出重叠输出目录?

时间:2014-06-08 19:26:16

标签: playframework-2.0 sbt slick

我正在尝试将the computer-database example from Play 2.3anorm迁移到Slick 2.我想使用Slick's code generator

这是我的project/build.scala

import sbt._
import Keys._

object build extends Build {

  lazy val mainProject = Project(
    id = "main",
    base = file("."),
    settings = Defaults.coreDefaultSettings ++ Seq(
      scalaVersion := "2.10.4",
      libraryDependencies ++= List(
        "com.typesafe.slick" %% "slick" % "2.0.2",
        "org.slf4j" % "slf4j-nop" % "1.6.4",
        "com.h2database" % "h2" % "1.3.170"
      ),
      // register manual sbt command
      slick <<= slickCodeGenTask,
      // register automatic code generation on every compile, remove for only manual use
      sourceGenerators in Compile <+= slickCodeGenTask
    )
  )

  // Slick's code generation task
  lazy val slick = TaskKey[Seq[File]]("gen-tables")

  lazy val slickCodeGenTask = (sourceManaged, dependencyClasspath in Compile, runner in Compile, streams) map { (dir, cp, r, s) =>
    // place generated files in sbt's managed sources folder
    val outputDir = (dir / "slick").getPath
    // connection info for a pre-populated throw-away, in-memory db for this demo, which is freshly initialized on every run
    val url = "jdbc:h2:mem:test;INIT=runscript from 'conf/sql/create.sql'"
    val jdbcDriver = "org.h2.Driver"
    val slickDriver = "scala.slick.driver.H2Driver"
    val pkg = "demo"
    toError(r.run("scala.slick.model.codegen.SourceCodeGenerator", cp.files, Array(slickDriver, jdbcDriver, url, outputDir, pkg), s.log))
    val fname = outputDir + "/demo/Tables.scala"
    Seq(file(fname))
  }
}

当我尝试使用sbt run运行我的应用程序时,我收到以下错误:

java.lang.RuntimeException: Overlapping output directories:/home/myuser/computer-database/target:
    ProjectRef(file:/home/myuser/computer-database/,main)
    ProjectRef(file:/home/myuser/computer-database/,root)
    at scala.sys.package$.error(package.scala:27)
    at scala.Predef$.error(Predef.scala:142)
    at sbt.Load$$anonfun$apply$8.apply(Load.scala:140)
    at sbt.Load$$anonfun$apply$8.apply(Load.scala:140)
    at scala.Option.foreach(Option.scala:236)
    at sbt.Load$.apply(Load.scala:140)
    at sbt.Load$.defaultLoad(Load.scala:37)
    at sbt.BuiltinCommands$.doLoadProject(Main.scala:473)
    at sbt.BuiltinCommands$$anonfun$loadProjectImpl$2.apply(Main.scala:467)
    at sbt.BuiltinCommands$$anonfun$loadProjectImpl$2.apply(Main.scala:467)
    at sbt.Command$$anonfun$applyEffect$1$$anonfun$apply$2.apply(Command.scala:60)
    at sbt.Command$$anonfun$applyEffect$1$$anonfun$apply$2.apply(Command.scala:60)
    at sbt.Command$$anonfun$applyEffect$2$$anonfun$apply$3.apply(Command.scala:62)
    at sbt.Command$$anonfun$applyEffect$2$$anonfun$apply$3.apply(Command.scala:62)
    at sbt.Command$.process(Command.scala:95)
    at sbt.MainLoop$$anonfun$1$$anonfun$apply$1.apply(MainLoop.scala:100)
    at sbt.MainLoop$$anonfun$1$$anonfun$apply$1.apply(MainLoop.scala:100)
    at sbt.State$$anon$1.process(State.scala:179)
    at sbt.MainLoop$$anonfun$1.apply(MainLoop.scala:100)
    at sbt.MainLoop$$anonfun$1.apply(MainLoop.scala:100)
    at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:18)
    at sbt.MainLoop$.next(MainLoop.scala:100)
    at sbt.MainLoop$.run(MainLoop.scala:93)
    at sbt.MainLoop$$anonfun$runWithNewLog$1.apply(MainLoop.scala:71)
    at sbt.MainLoop$$anonfun$runWithNewLog$1.apply(MainLoop.scala:66)
    at sbt.Using.apply(Using.scala:25)
    at sbt.MainLoop$.runWithNewLog(MainLoop.scala:66)
    at sbt.MainLoop$.runAndClearLast(MainLoop.scala:49)
    at sbt.MainLoop$.runLoggedLoop(MainLoop.scala:33)
    at sbt.MainLoop$.runLogged(MainLoop.scala:25)
    at sbt.StandardMain$.runManaged(Main.scala:57)
    at sbt.xMain.run(Main.scala:29)
    at xsbt.boot.Launch$$anonfun$run$1.apply(Launch.scala:109)
    at xsbt.boot.Launch$.withContextLoader(Launch.scala:129)
    at xsbt.boot.Launch$.run(Launch.scala:109)
    at xsbt.boot.Launch$$anonfun$apply$1.apply(Launch.scala:36)
    at xsbt.boot.Launch$.launch(Launch.scala:117)
    at xsbt.boot.Launch$.apply(Launch.scala:19)
    at xsbt.boot.Boot$.runImpl(Boot.scala:44)
    at xsbt.boot.Boot$.main(Boot.scala:20)
    at xsbt.boot.Boot.main(Boot.scala)
[error] Overlapping output directories:/home/myuser/computer-database/target:
[error]     ProjectRef(file:/home/myuser/computer-database/,main)
[error]     ProjectRef(file:/home/myuser/computer-database/,root)
[error] Use 'last' for the full log.

如果我将id = "main"更改为id = "root",则不再触发上一个错误,而是触发新错误:

java.lang.RuntimeException: No main class detected.
    at scala.sys.package$.error(package.scala:27)
[trace] Stack trace suppressed: run last compile:run for the full output.
[error] (compile:run) No main class detected.
[error] Total time: 1 s, completed 08-Jun-2014 20:22:41

项目ID似乎存在问题(无论是什么)。我在这里缺少什么?

3 个答案:

答案 0 :(得分:5)

解决方案是从root移除build.sbt声明并在PlayScala中启用Build.scala插件。

build.sbt

name := "computer-database"

version := "1.0"

libraryDependencies ++= Seq(
    jdbc,
    anorm,
    "com.typesafe.slick" %% "slick" % "2.0.2",
    "com.typesafe.play" %% "play-slick" % "0.7.0-M1"
)

scalaVersion := Option(System.getProperty("scala.version")).getOrElse("2.10.4")

project/Build.scala

import play.PlayScala
import sbt._
import Keys._


object myBuild extends Build {

    lazy val mainProject = Project(
        id = "main",
        base = file("."),
        settings = Defaults.coreDefaultSettings ++ Seq(
            scalaVersion := "2.10.4",
            libraryDependencies ++= List(
                "com.typesafe.slick" %% "slick" % "2.0.2",
                "org.slf4j" % "slf4j-nop" % "1.6.4",
                "com.h2database" % "h2" % "1.3.170"
            ),
            slick <<= slickCodeGenTask, // register manual sbt command
            sourceGenerators in Compile <+= slickCodeGenTask // register automatic code generation on every compile, remove for only manual use
        )
    ).enablePlugins(PlayScala)

    // code generation task
    lazy val slick = TaskKey[Seq[File]]("gen-tables")

    lazy val slickCodeGenTask = (sourceManaged, dependencyClasspath in Compile, runner in Compile, streams) map { (dir, cp, r, s) =>
        val outputDir = (dir / "slick").getPath // place generated files in sbt's managed sources folder
        val url = "jdbc:h2:mem:test;INIT=runscript from 'conf/sql/create.sql'" // connection info for a pre-populated throw-away, in-memory db for this demo, which is freshly initialized on every run
        val jdbcDriver = "org.h2.Driver"
        val slickDriver = "scala.slick.driver.H2Driver"
        val pkg = "demo"
        toError(r.run("scala.slick.model.codegen.SourceCodeGenerator", cp.files, Array(slickDriver, jdbcDriver, url, outputDir, pkg), s.log))
        val fname = outputDir + "/demo/Tables.scala"
        Seq(file(fname))
    }

}

答案 1 :(得分:3)

您是否在根目录中有build.sbt文件?比如这里https://github.com/playframework/playframework/blob/2.3.x/samples/scala/computer-database/build.sbt。这将解释重叠的输出目录错误。删除build.sbt中定义的项目根目录,因此使用Build.scala中的项目。

接下来,我猜在第二部分中将id从“main”更改为“root”会产生新的错误,因为你有一个play项目,但Build.scala中定义的“mainProject”没有Play插件所以{ {1}}表现不同。

答案 2 :(得分:2)

最好从config加载这些设置:

应用程序/ db.conf

db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:mem:test;INIT=runscript from 'db.sql'"
db.default.user=sa
db.default.password=""
db.slick.driver = "scala.slick.driver.H2Driver"

# From root
db.model.package = "models"
db.model.outputDir = "app" # not include package
db.model.outputFile = "Tables.scala"

build.sbt

object myBuild extends Build {
  lazy val slick = TaskKey[Seq[File]]("gen-tables")

  lazy val config = ConfigFactory.parseFile(new File("./conf/db.conf"))

  lazy val slickCodeGenTask = (sourceManaged, dependencyClasspath in Compile, runner in Compile, streams) map { (dir, cp, r, s) =>

    val outputDir = config.getString("db.model.outputDir") // place generated files in sbt's managed sources folder
    val url = config.getString("db.default.url")
    val jdbcDriver = config.getString("db.default.driver")
    val slickDriver = config.getString("db.slick.driver")
    val pkg = config.getString("db.model.package")
    toError(r.run("scala.slick.codegen.SourceCodeGenerator", cp.files, Array(slickDriver, jdbcDriver, url, outputDir, pkg), s.log))
    val fname = outputDir + config.getString("db.model.outputFile")
    Seq(file(fname))
  }

  lazy val mainProject = Project(
    id="main",
    base=file("."),
    settings = Defaults.coreDefaultSettings ++ Seq(
      slick <<= slickCodeGenTask
      // sourceGenerators in Compile <+= slickCodeGenTask
    )).enablePlugins(PlayScala)
}