【问题标题】:Rake task with multiple prerequisites generating multiple outputs具有多个先决条件的 Rake 任务生成多个输出
【发布时间】:2017-05-26 21:33:33
【问题描述】:

我有一个方法,它依赖于两个文件作为输入,并产生两个或更多文件作为输出。每个输入文件和每个输出文件之间没有一对一的映射 - 该方法执行组合输入数据以生成各种输出文件的操作。

这是一个(有点做作的)示例:

class Util
  def self.perform
    `cat source1.txt source2.txt > target1.txt`
    `cat source2.txt source1.txt > target2.txt`
  end
end

编辑:在我的例子中,实际代码比这复杂得多,将生成每个目标文件的工作分成不同的部分是不可行的。因此,在我的情况下,为每个目标文件设置一个 文件任务 并不是一个真正的选择。

如何设置一个 rake 任务,以便在需要时才运行此方法一次,即。如果缺少一个或多个目标文件,或者任何源文件比任何目标文件新?

我目前的解决方案是这样的:

task :my_task => ['source1.txt', 'source2.txt'] do |t|
  targets = ['target1.txt', 'target2.txt']
  if targets.all? { |f| File.exist? f }
    mtime_newest_source = t.prerequisites.map {|f| File.mtime(f) }.max
    mtime_oldest_target = targets.map {|f| File.mtime(f) }.min
    # Stop task early if all targets are up to date
    next if mtime_newest_source < mtime_oldest_target
  end
  # Code that actually produces target files goes here
end

我正在寻找的是一种定义任务的方法,以便没有任何代码 除非需要重建目标文件,否则将在其块内运行。

【问题讨论】:

  • 你所说的 rake 功能是什么意思,你的意思是它应该在 rake 的帮助下每当文件更改时自动生成文件?还请包括当前的解决方案。
  • 我当前的解决方案是一个普通的task :my_task =&gt; ['source1.txt', 'source2.txt'],它在开头包含代码,明确检查所有目标文件是否存在并且 mtime 是否大于所有先决条件,然后跳过执行任何实际工作,如果这是案子。我想知道是否有任何方法可以定义一个 Rake 任务,以便其块中的任何代码都不会运行,除非在它生成的任何目标文件之后更改了任何先决条件。
  • 我用当前解决方案的示例更新了问题。
  • 我仍在寻找类似的解决方案。太糟糕了,耙子让这变得如此困难。用于窗口平台的 MSBuild 让它变得如此简单,而且速度也非常快。

标签: ruby rake rake-task


【解决方案1】:

FileTasks 正是为此而设计的。这是good old long explanation,下面是一个简单的示例:

file 'target1.txt' => ['source1.txt', 'source2.txt'] do
  # do something to generate target1.txt
  `cat source1.txt source2.txt > target1.txt`
end

file 'target2.txt' => ['source1.txt', 'source2.txt'] do
  # again, generate the file
  `cat source2.txt source1.txt > target2.txt`
end

文件任务可以依赖于磁盘上的其他 rake 任务或文件。如果您的任务依赖于一个文件,rake 将比较时间戳,并且仅在依赖文件较新时才运行您的任务。

更新

这是一个从两个任务生成所有目标的工作示例。 Rake 足够聪明,可以在第一个任务创建两个文件时跳过第二个任务。

def make_the_targets
  `cat source1.txt source2.txt > target1.txt`
  `cat source2.txt source1.txt > target2.txt`
end

file 'target1.txt' => ['source1.txt', 'source2.txt'] do
  puts "making target1.txt"
  make_the_targets
end

file 'target2.txt' => ['source1.txt', 'source2.txt'] do
  puts "making target2.txt"
  make_the_targets
end

task :make_targets => ['target1.txt', 'target2.txt']

【讨论】:

  • 此解决方案仅在生成不同目标文件的工作可以拆分为完全独立的部分时才有效。在我的情况下,情况并非如此。我将更新我的问题以使这一点更清楚。
  • 也许两个文件任务都调用一个共享函数来创建所有目标文件?您需要对其进行测试,以确保 rake 在运行第二个任务之前注意到新文件。我不确定 rake 是预先确定依赖关系还是在执行期间确定依赖关系。
  • 更新:等等,什么——就这么简单?呸!谢谢!我什至可以通过 ['target1.txt', 'target2.txt'].each { |target| file target =&gt; ['source1.txt', 'source2.txt'] { do_stuff_here } } 避免重复和方法提取
【解决方案2】:

我不相信上述答案是正确的。 拉斯的评论

['target1.txt', 'target2.txt'].each { |target| file target => ['source1.txt', 'source2.txt'] { do_stuff_here } }

如果调用 rake 'target1.txt', 'target2.txt',将运行两次 { do stuff here }。

我相信正确解决依赖关系是通过

file 'target1.txt' => ['source1.txt', 'source2.txt'] { do_stuff_here } file 'target2.txt' => 'target1.txt'

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-25
    • 1970-01-01
    • 2020-09-28
    • 1970-01-01
    • 2022-10-21
    • 2011-04-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多