【问题标题】:How do I make a Rake Task run after all other tasks? (i.e. a Rake AfterBuild task)如何让 Rake 任务在所有其他任务之后运行? (即 Rake AfterBuild 任务)
【发布时间】:2009-11-06 18:43:46
【问题描述】:

我是 Rake 新手,并使用它来构建 .net 项目。我感兴趣的是有一个总结任务,它打印出已经完成的总结。无论使用什么任务调用 rake,我都希望始终调用此任务。

有没有简单的方法可以做到这一点?

谢谢


更新问题,回复Patrick's answer 我想要的是在所有其他任务之后运行一次之后的任务,所以我想要的输出是:

task :test1 do 
  puts 'test1'
end

task :test2 do 
  puts 'test2'
end

Rake::Task.tasks.each do |t|
    <Insert rake magic here>
#  t.enhance do 
#    puts 'after'
#  end
end

$ rake test1
test1
after

$rake test2
test2
after

$rake test1 test2  
test1
test2
after

如果

task :test3 =>[:test1, :test2]
   puts 'test3'
end

    $rake test3
test1
test2
test3
after

即使赏金已经消失,任何进一步的帮助都非常感谢。 (遗憾的是,我不认为我可以提供另一个赏金。)

【问题讨论】:

    标签: ruby rake


    【解决方案1】:

    您应该可以使用“增强”来做到这一点:

    Rake::Task["my_task"].enhance do
      Rake::Task["my_after_task"].invoke
    end
    

    这将导致在“my_task”之后调用“my_after_task”。

    如果您想将此应用于所有任务,只需遍历所有任务并为每个任务调用增强:

    Rake::Task.tasks.each do |t| 
      t.enhance do 
        Rake::Task["my_after_task"].invoke
      end
    end
    

    完整的测试文件:

    task :test1 do 
      puts 'test1'
    end
    
    task :test2 do 
      puts 'test2'
    end
    
    Rake::Task.tasks.each do |t|
      t.enhance do 
        puts 'after'
      end
    end
    

    还有输出:

    $ rake test1
    test1
    after
    
    $ rake test2
    test2
    after
    

    【讨论】:

    • 谢谢。恐怕我没有清楚地说明我的问题。我希望 after 任务在其他任务完成后运行一次。所以: $ rake test1 test2 会在 $rake test1 test1 after $rake test2 test2 after 之后输出 test1 test2 知道如何实现吗?
    • 嗯,好的,为您找到了解决方案。不太优雅,但它的工作原理。如果你有兴趣,我可以详细解释我正在做些什么来让它工作......
    【解决方案2】:

    找到了这个简单优雅的答案here,它使用了Ruby方法at_exit

    值得注意的是,at_exit 之后定义的方法将在每次调用 rake 脚本时运行,无论任务运行如何,或者是否运行任何任务。这包括运行rake -T(列出可用任务)时。确保 at_exit 仅在前一个任务要求它这样做时才执行任何操作。

    rakefile.rb

    desc "Lovely task a"
    task :a do
      puts "a"
    end
    
    desc "Lovely task b"
    task :b do
      puts "b"
    end
    
    task :cleanup do
      puts "cleanup"
    end
    
    at_exit { Rake::Task[:cleanup].invoke if $!.nil? }
    

    外壳

    $ rake a b
    a
    b
    cleanup
    $ rake -T
    rake a # Lovely task a
    rake b # Lovely task b
    cleanup
    

    如果你不想让它运行任务,你也不需要。

    at_exit do
      puts "cleanup"
    end
    

    或者让它运行一个方法

    def on_exit_do_cleanup
      puts "cleanup"
    end
    
    at_exit { on_exit_do_cleanup }
    

    您可能希望确保仅在任务实际运行时才进行清理,这样rake -T 就不会也进行清理。

    rakefile.rb

    do_cleanup = false
    
    desc "Lovely task a"
    task :a do
      puts "a"
      do_cleanup = true
    end
    
    desc "Lovely task b"
    task :b do
      puts "b"
      do_cleanup = true
    end
    
    task :cleanup do
      return unless $!.nil? # No cleanup on error
      return unless do_cleanup # No cleanup if flag is false
      puts "cleanup"
    end
    
    at_exit { Rake::Task[:cleanup].invoke }
    

    【讨论】:

    • 什么是 $!.nil?表示..?
    • $! 包含最后引发的错误,如果 xnilx.nil? 返回 true,因此,... if $!.nil? 确保清理任务仅在没有错误的情况下运行这个脚本的运行。 (为澄清而编辑的答案)
    【解决方案3】:

    将此作为新答案发布,以保持另一个可用。这不太优雅,因为我必须深入了解 Rake 并手动更新任务列表,但它确实有效。

    task :test1 do
      puts 'test1'
    end
    
    task :test2 do 
      puts 'test2'
    end
    
    task :after do
      puts 'after'
    end
    
    # top_level_tasks is't writable so we need to do this ugly
    # instance_variable_set hack...
    current_tasks =  Rake.application.top_level_tasks
    current_tasks << :after
    Rake.application.instance_variable_set(:@top_level_tasks, current_tasks)
    

    输出:

    $ rake test1
    test1
    after
    
    $ rake test1 test2
    test1
    test2
    after
    

    【讨论】:

    • 太棒了!这正是我想要的。我很想知道这里发生了什么魔法。你能给我更多关于发生了什么的解释吗?同时,我会看看我能在 google 上找到什么。
    • 当然。顺便说一句,我在一次会议上找到了 Jim Weirich(rake 的作者),看看这是否是解决问题的最佳方法。他的回答是 Rake 没有内置的方法来做到这一点,但如果有人能想出一个通用的方法来做这件事,他愿意接受补丁。所以代码: Rake 应用程序有一个读取器来跟踪要运行的任务,称为“top_level_tasks”。因为它是只读的,所以我们需要将其读出、更新,然后使用 instance_variable_set 将更改推送回应用程序。如果是读写,我们可以在一行中全部完成。
    • 感谢@PatrickRitchie,太好了!顺便说一句,它将在一行上运行,如下所示:Rake.application.instance_variable_set(:@top_level_tasks, Rake.application.top_level_tasks + [:'printbot:status']).
    • 你根本不需要使用 instance_variable_set — Rake.application.top_level_tasks &lt;&lt; :after 就可以了。
    【解决方案4】:

    除了丑陋的Rake.application.instance_variable_set,你可以像这样增强命令行上的最后一个任务:

      last_task = Rake.application.top_level_tasks.last
      Rake::Task[last_task].enhance do
        puts 'after'
      end
    

    这应该正是你需要做的!

    【讨论】:

    • 你最后有一个 end 我猜不应该在那里。
    • 有趣。下面接受的解决方案是有效的,而且我已经很久没有修改脚本了,但是下次我会考虑使用这种方法。它肯定更优雅。
    【解决方案5】:

    您可以使用 Kernel.trap 调用并附加到“退出”信号。正常退出和异常退出都会触发。

    把它放在你的 rakefile 的早期:

    Kernel.trap("EXIT") do
      Rake::Task[:final].invoke
    end
    

    现在,每当您执行“最终”任务时,它都会在程序的最后执行。无论如何。

    task :final do
      puts "Hit return to continue..."
      STDIN.getc
    end
    

    【讨论】:

    • 酷。谢谢。下次需要的时候我会试试的。
    【解决方案6】:

    我不知道这是否是最好的方法,但它更简单:

    将你所有的“公共任务”摘要称为真正的任务。

    task :compile => :realcompile do
       summary stuff
    end
    

    【讨论】:

      【解决方案7】:

      如果有人来这里寻找如何在所有其他任务之前运行任务,您仍然可以使用相同的增强方法,除了第一个参数:

      task :environment do
        env = (ENV['RACK_ENV'] || 'production').downcase
        # do things before other tasks
      end
      
      # run environment task before all tasks for setup
      Rake::Task.tasks.each do |t|
        next if t.name == 'environment'
        t.enhance [:environment]
      end
      

      【讨论】:

        猜你喜欢
        • 2010-10-09
        • 1970-01-01
        • 2013-09-06
        • 2016-02-22
        • 2012-05-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-15
        相关资源
        最近更新 更多