【问题标题】:sbt plugin dynamically load user defined code?sbt 插件动态加载用户定义的代码?
【发布时间】:2015-01-17 10:46:11
【问题描述】:

我是working on a sbt plugin,它使用Slick code generator在给定数据库的情况下生成 Scala 模型

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

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

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

这里是关于这个的完整讨论:https://github.com/papauschek/play-slick-evolutions-plugin/issues/1

【问题讨论】:

  • 由于类加载器分离,我认为您不能在插件中使用项目中的依赖项。但我认为我对this question 的回答与您想要实现的目标有些相似。
  • 只是一个提示:不要进行代码生成。考虑使用小的“可堆叠”宏,每个宏都有一个非常特殊的用途。很难在生成的代码中找到错误并处理生成代码中的语法错误。使用宏可以直接操作 AST,因此搞砸的机会更少。
  • @stefan.schwetschke:你能解释一下你的意思吗?需要说明的是,我自己并没有编写代码生成器——只是使用了 slick 的。我正在做的就是编写一个 sbt 插件来在编译时自动调用它...

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


【解决方案1】:

最终,您需要运行一些代码来生成 Scala 源文件。

生成文件

如你所知,sbt 有一个名为sourceGenerators 的用于生成源文件的钩子,它在Generating files 中有记录。 作为插件作者,您应该提供一个任务,使用 Slick 代码生成器作为默认实现在 (sourceManaged in Compile).value / "garfield" 下生成 Seq[File]。我们称之为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 会根据它们之间的依赖关系自动排序任务并并行运行多个任务,动态执行代码充满了意想不到的危险。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-12-05
    • 1970-01-01
    • 2017-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-17
    相关资源
    最近更新 更多