首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >SBT sourceGenerators任务-只有当文件更改时才执行

SBT sourceGenerators任务-只有当文件更改时才执行
EN

Stack Overflow用户
提问于 2015-11-24 15:41:41
回答 1查看 1.8K关注 0票数 14

在我的SBT项目中,我有一个输入文件src/main/greeting/Greeting.txt,其内容如下:

代码语言:javascript
复制
Hello, world!

这是我的build.sbt,它从Greeting.txt文件生成Scala源:

代码语言:javascript
复制
sourceGenerators in Compile += Def.task{
  println("GENERATING FILES")
  val inputFile = file("src/main/greeting/Greeting.txt")
  val generatedFile =
    (sourceManaged in Compile).value / "scala" / "Main.scala"
  val greeting = IO.read(inputFile).trim
  IO.write(
    generatedFile,
    s"""object Main extends App { println("${greeting}") }"""
  )
  Seq(generatedFile)
}.taskValue

这个build.sbt运行良好,只不过每次编译/运行项目时,它都运行我的任务来生成Scala源代码。我希望它只在Greeting.txt-file更改后才运行这些任务。我怎样才能做到这一点?

MCVE

生成项目的Bash脚本:

代码语言:javascript
复制
#!/bin/bash
mkdir sourceGeneratorsExample
cd sourceGeneratorsExample
mkdir -p src/main/scala
mkdir -p src/main/greeting
echo "Hello, world!" >> src/main/greeting/Greeting.txt
cat <<HEREDOC > build.sbt
sourceGenerators in Compile += Def.task{
  println("GENERATING FILES")
  val inputFile = file("src/main/greeting/Greeting.txt")
  val generatedFile =
    (sourceManaged in Compile).value / "scala" / "Main.scala"
  val greeting = IO.read(inputFile).trim
  IO.write(
    generatedFile,
    "object Main extends App { println(\"" + greeting + "\") }"
  )
  Seq(generatedFile)
}.taskValue
HEREDOC

重复/文件

  • 是2012年的一个答案,自那以后发生了很大的变化。
  • 现行参考手册建议使用"__sbt.Tracked.{ inputChanged, outputChanged }等“,但没有对此进行扩展,手册中也没有提到Tracked对象。
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-02-23 06:24:53

您可以使用FileFunction.cached,它是:

通用更改检测助手,用于帮助构建/工件生成/等等步骤,检测它们是否需要运行。

它使用缓存文件夹,其中SBT自动保存文件更改的记录。使用FileFunction.cached,您的build.sbt可能如下所示:

代码语言:javascript
复制
sourceGenerators in Compile += Def.task{

  // * Create a cached function which generates the output files
  //   only if the input files have changed.
  // * The first parameter is a file instance of the path to
  //   the cache folder
  // * The second parameter is the function to process the input 
  //   files and return the output files
  val cachedFun = FileFunction.cached(
    streams.value.cacheDirectory / "greeting"
  ) { (in: Set[File]) =>

    println("GENERATING FILES")

    val generatedFile =
      (sourceManaged in Compile).value / "scala" / "Main.scala"
    val greeting = IO.read(in.head).trim
    IO.write(
      generatedFile,
      "object Main extends App { println(\"" + greeting + "\") }"
    )
    Set(generatedFile)
  }

  // get the input file
  val inputFile = file("src/main/greeting/Greeting.txt")

  // put the input file into a `Set` (as required by `cachedFun`),
  // pass it to the `cachedFun`,
  // convert the result to `Seq` (as required by `Def.task`)
  cachedFun(Set(inputFile)).toSeq

}.taskValue

FileFunction.cached的第一个参数是一个目录,用于存储缓存信息(例如,输入文件的散列)。在这里,我们传递了streams.value.cacheDirectory / "greeting",它将在target-directory的某个地方创建一个缓存子目录。其优点是在任务clean运行时将自动清除他的目录。

cached方法的第一个参数列表采用两个可选的inStyleoutStyle参数,它们决定如何检测更改(例如,通过修改日期或比较散列)。注意,在较早版本的SBT中,这两个参数是强制性的,因此您的cachedFun看起来有点像这样:

代码语言:javascript
复制
val cachedFun = FileFunction.cached(
  cacheBaseDirectory = streams.value.cacheDirectory / "greeting",
  inStyle = FilesInfo.lastModified,
  outStyle = FilesInfo.exists
)(cachedFunBodyImpl)

FileFunction.cached-method的第二个参数列表接受一个函数,该函数将输入文件的Set映射到输出文件的Set。只有在输入文件发生更改时才会调用它。

您可以找到关于较早版本的SBT 这里 (SBT0.13.5)的更多信息,该版本扩展了cached和文件跟踪样式。引用:

第一个参数列表有两个额外的参数,允许显式指定文件跟踪样式。默认情况下,根据文件上一次修改的时间,输入跟踪样式为FilesInfo.lastModified,输出跟踪样式为FilesInfo.exists,这仅取决于文件是否存在。另一种可用的样式是FilesInfo.hash,它根据其内容的散列来跟踪文件。

第一个代码段已经使用SBT1.2.8进行了测试。第二个代码片段也应该适用于早期的0.13.x版本。

票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33897874

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档