SBT sourceGenerators 任务 - 仅在文件更改时执行 [英] SBT sourceGenerators task - execute only if a file changes

查看:39
本文介绍了SBT sourceGenerators 任务 - 仅在文件更改时执行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In my SBT project, I have an input file src/main/greeting/Greeting.txt with the following content:

Hello, world!

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

This is my build.sbt that generates Scala source from the Greeting.txt file:

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 文件已更改时运行这些任务.我怎样才能做到这一点?

This build.sbt works fine, except that it runs my tasks to generate the Scala sources every time I compile/run my project. I would like it to only run these tasks when the Greeting.txt-file has changed. How can I achieve this?

生成项目的 Bash 脚本:

Bash-script that generates the project:

#!/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 对象在手册中的其他任何地方都没有提及.

  • Duplicates / Documentation

    • This is an answer from 2012, a lot has changed since then.
    • The current reference manual advises to use "sbt.Tracked.{ inputChanged, outputChanged } etc", but does not expand on that, and the Tracked object is not mentioned anywhere else in the manual.
    • 推荐答案

      您可以使用 FileFunction.cached,这是一个:

      You can use FileFunction.cached, which is a:

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

      Generic change-detection helper used to help build / artifact generation / etc. steps detect whether or not they need to run.

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

      It uses a cache folder, where SBT automatically keeps a record of the file changes. With FileFunction.cached, your build.sbt might look like this:

      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 目录内的某处创建一个缓存子目录.好处是他的目录会在任务clean运行时自动清理.

      The first parameter for FileFunction.cached is a directory that will be used to store cache information (e.g. hashes of the input files). Here, we passed streams.value.cacheDirectory / "greeting", which will create a cache subdirectory somewhere inside of the target-directory. The advantage is that his directory will be automatically cleaned when the task clean is run.

      cached 方法的第一个参数列表采用两个额外的可选 inStyleoutStyle 参数,它们决定了如何检测更改(例如通过修改日期,或通过比较哈希值).请注意,在旧版本的 SBT 中,这两个参数是必需的,因此您的 cachedFun 看起来有点像这样:

      The first argument list of the cached method takes two additional optional inStyle and outStyle arguments, which determine how changes are detected (e.g. by modification date, or by comparing hashes). Note that in older versions of SBT, these two arguments are mandatory, so that your cachedFun would look somewhat like this:

      val cachedFun = FileFunction.cached(
        cacheBaseDirectory = streams.value.cacheDirectory / "greeting",
        inStyle = FilesInfo.lastModified,
        outStyle = FilesInfo.exists
      )(cachedFunBodyImpl)
      

      FileFunction.cached 方法的第二个参数列表采用将输入文件的 Set 映射到输出的 Set 的函数文件.仅当输入文件发生更改时才会调用它.

      The second argument list of the FileFunction.cached-method takes a function that maps a Set of input files to the Set of output files. It is invoked only if the input files have changed.

      您可以找到有关旧版 SBT 的更多信息 here (SBT 0.13.5),它扩展了 cached 和文件跟踪样式.引用:

      You can find more info for an older version of SBT here (SBT 0.13.5), which expands on cached and file tracking styles. Quoting:

      第一个参数列表有两个额外的参数,允许明确指定文件跟踪样式.默认情况下,输入跟踪样式为 FilesInfo.lastModified,基于文件的最后修改时间,输出跟踪样式为 FilesInfo.exists,仅基于文件是否存在.另一种可用的样式是 FilesInfo.hash,它根据文件内容的哈希值跟踪文件.

      There are two additional arguments for the first parameter list that allow the file tracking style to be explicitly specified. By default, the input tracking style is FilesInfo.lastModified, based on a file's last modified time, and the output tracking style is FilesInfo.exists, based only on whether the file exists. The other available style is FilesInfo.hash, which tracks a file based on a hash of its contents.

      <小时>

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


      The first code snippet has been tested using SBT 1.2.8. The second code snippet should also work with earlier 0.13.x versions.

      这篇关于SBT sourceGenerators 任务 - 仅在文件更改时执行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆