sbt插件动态加载用户定义的代码?

时间:2014-11-19 19:06:49

标签: scala sbt slick slick-2.0 slick-codegen

working on a sbt plugin使用Slick code generator

为数据库生成Scala模型

我当然希望用户覆盖代码生成器,因此我的插件需要支持:

  • 无论如何,我可以动态加载一个Scala类,在build.sbt插件中给出一个路径吗?例如,在用户的父build.sbt中,她会提供类似codegen.override=com.company.project.CustomCodegenerator looks like this

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

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

1 个答案:

答案 0 :(得分:3)

在一天结束时,您需要运行一些代码来生成Scala源文件。

生成文件

如您所知,sbt有一个用于生成名为sourceGenerators的源文件的钩子,在Generating files中有记录。 作为插件作者,您应该使用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.Run API。这相当于使用一些自定义参数调用run任务。如果您正在为Compile配置生成代码,那么使用转轮进行任何依赖于它的配置都不是一个好主意。
  • 另一种类似的方法是使用sbt.Fork API。 Forking允许您在插件之外运行代码。

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