具有多个先决条件的Rake任务生成多个输出

时间:2014-06-03 22:34:15

标签: ruby rake rake-task

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

这是一个(有点人为的)例子:

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

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

2 个答案:

答案 0 :(得分:4)

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']

答案 1 :(得分:0)

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

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

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

我相信

可以正确解决依赖关系问题

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