8

正在开发一个 sbt 插件,它使用Slick 代码生成器在给定数据库的情况下生成 Scala 模型

我当然希望用户覆盖代码生成器,所以我的插件需要支持这一点:

  • 无论如何,我可以在 build.sbt 插件键中动态加载给定路径的 Scala 类?例如,在用户的父 build.sbt 中,她会提供类似这样codegen.override=com.company.project.CustomCodegenerator的内容

  • 与上述有关;自定义代码生成器可能会使用其他一些库,因此简单的动态类加载可能不够。无论如何,一个 sbt 插件可以使用该插件继承项目的依赖项吗?

以下是关于此的完整讨论:https ://github.com/papauschek/play-slick-evolutions-plugin/issues/1

4

1 回答 1

3

归根结底,您需要运行一些代码来生成 Scala 源文件。

生成文件

如您所知,sbt 有一个用于生成源文件的钩子,称为sourceGenerators,它记录在生成文件中。作为插件作者,您应该提供一个使用 Slick 代码生成器作为默认实现生成Seq[File]的任务。(sourceManaged in Compile).value / "garfield"让我们称之为generateModel. 您的插件可能具有以下设置:

sourceGenerators in Compile += generateModel.taskValue,
generateModel := defaultGenerateModel.value,
defaultGenerateModel := { ... }

如果您的构建用户想要重新布线generateModel,他或她可以这样做:

generateModel := {
  val file = (sourceManaged in Compile).value / "garfield" / "Foo.scala"
  IO.write(file, """case class Foo() {}""")
  Seq(file)
}

如果代码生成包含在 sbt 插件中,就像上面一样,你不需要做任何动态的事情。由于play-slick-evolutions-codegen-plugin依赖于 slick-codegen,这应该不是问题。

动态加载用户代码

由于问题直接在于动态加载用户的代码,因此我也提出了一些指示。

  • 一种方法是使用现有配置中的sbt.RunAPI 。这相当于run使用一些自定义参数调用任务。如果您正在为Compile配置生成代码,那么将运行器用于任何依赖于它的配置都不是一个好主意。
  • 另一种类似的方法是使用sbt.ForkAPI。分叉允许您在插件之外运行代码。

鉴于 sbt 会根据它们之间的依赖关系自动排序任务并并行运行多个任务,动态执行的代码充满了意想不到的危险。

于 2015-01-09T07:44:37.113 回答