Làm cách nào để chạy các tác vụ Rake từ bên trong các tác vụ Rake?


411

Tôi có một Rakefile biên dịch dự án theo hai cách, theo biến toàn cục $build_type, có thể :debughoặc :release(kết quả đi trong các thư mục riêng biệt):

task :build => [:some_other_tasks] do
end

Tôi muốn tạo một tác vụ biên dịch dự án với cả hai cấu hình lần lượt, đại loại như thế này:

task :build_all do
  [ :debug, :release ].each do |t|
    $build_type = t
    # call task :build with all the tasks it depends on (?)
  end
end

Có cách nào để gọi một tác vụ như thể nó là một phương thức không? Hoặc làm thế nào tôi có thể đạt được bất cứ điều gì tương tự?


7
câu trả lời nào
Nurettin

Tôi sẽ đi với phiếu bầu của cộng đồng và chọn câu trả lời được nâng cấp lên tới 221 lần (tại thời điểm viết bài). Các poster ban đầu đã rời SO
MPritchard


FYI, sử dụng một cái gì đó giống như Rake::Task["build"].invokecó thể hiệu quả hơn nhiều so với sử dụng system rake buildbởi vì nó không phải tạo ra một luồng mới và tải lên môi trường Rails, điều system rake buildcần phải làm.
Joshua Pinter

Câu trả lời:


639

Nếu bạn cần tác vụ để hành xử như một phương thức, làm thế nào về việc sử dụng một phương thức thực tế?

task :build => [:some_other_tasks] do
  build
end

task :build_all do
  [:debug, :release].each { |t| build t }
end

def build(type = :debug)
  # ...
end

Nếu bạn thích rakesử dụng các thành ngữ, đây là khả năng của bạn, được tổng hợp từ các câu trả lời trước đây:

  • Điều này luôn luôn thực thi nhiệm vụ, nhưng nó không thực hiện các phụ thuộc của nó:

    Rake::Task["build"].execute
  • Cái này thực thi các phụ thuộc, nhưng nó chỉ thực thi tác vụ nếu nó chưa được gọi:

    Rake::Task["build"].invoke
  • Điều này trước tiên đặt lại trạng thái đã sẵn sàng của tác vụ, cho phép tác vụ được thực hiện lại, phụ thuộc và tất cả:

    Rake::Task["build"].reenable
    Rake::Task["build"].invoke
  • Lưu ý rằng các phụ thuộc đã được gọi không được tự động thực hiện lại trừ khi chúng được kích hoạt lại. Trong Rake> = 10.3.2, bạn cũng có thể sử dụng cách sau để bật lại những thứ đó:

    Rake::Task["build"].all_prerequisite_tasks.each(&:reenable)

96
Lưu ý rằng nếu các tác vụ của bạn nằm trong không gian tên, bạn phải bao gồm không gian tên khi bạn gọi tác vụ. Ví dụ. Rake::Task['db:reset'].invoke
David Tuite

126
Nếu tác vụ trong câu hỏi có đối số, bạn có thể chuyển chúng dưới dạng đối số cho #invoke. Ví dụ. Rake::Task['with:args'].invoke("pizza")
Trotter

26
Nếu bạn cần đặt một biến môi trường, hãy làm điều đó trước khi gọi invoke. Ví dụ: ENV['VERSION'] = '20110408170816'; Rake::Task['db:migrate'].invokeXem ở đây để giải thích thêm.
Michael Stalker

13
Gần đây tôi phát hiện ra #reenable()không kích hoạt lại preq req và cần nó. Ngoài Rake (> = 10.3.2), #all_prerequisite_tasks()sẽ lặp lại tất cả các tác vụ, bao gồm cả các yêu cầu trước của req. Vì vậy,Rake::Task[task].all_prerequisite_tasks.each &:reenable
Richard Michael

4
@kch, bạn có thể xâu chuỗi chúng lại với nhau không ( rake db:reset db:migrateví dụ như trên dòng lệnh ). Bạn có thể làm một cái gì đó như: Rake::Task["db:reset", "db:migrate"].invoke
Jeff

125

ví dụ:

Rake::Task["db:migrate"].invoke

6
Điều này chỉ gọi nhiệm vụ nếu nó chưa được gọi. Nhưng tôi cần phải gọi các nhiệm vụ với tất cả các nhiệm vụ khác, nó phụ thuộc vào hai lần.

58
task :build_all do
  [ :debug, :release ].each do |t|
    $build_type = t
    Rake::Task["build"].reenable
    Rake::Task["build"].invoke
  end
end

Điều đó sẽ loại bạn ra, chỉ cần điều tương tự bản thân mình.


Đây là chức năng, nhưng cách quá dài dòng. Chắc chắn không có gì tốt hơn?
kch

13
task :invoke_another_task do
  # some code
  Rake::Task["another:task"].invoke
end

Một trong những lý do tại sao tôi cần một giải pháp như thế này, là vì tải tác vụ cào mất rất nhiều thời gian. Bằng cách thực hiện một giải pháp như trên, nó sẽ tiết kiệm thời gian tải?
Dipan Mehta

11
task :build_all do
  [ :debug, :release ].each do |t|
    $build_type = t
    Rake::Task["build"].execute
  end
end

Nó không hoạt động, bởi vì nó chỉ thực thi phần thân của: xây dựng nhiệm vụ và không gọi các nhiệm vụ phụ thuộc vào nó.

4

Nếu bạn muốn mỗi tác vụ chạy bất kể thất bại, bạn có thể làm một cái gì đó như:

task :build_all do
  [:debug, :release].each do |t| 
    ts = 0
    begin  
      Rake::Task["build"].invoke(t)
    rescue
      ts = 1
      next
    ensure
      Rake::Task["build"].reenable # If you need to reenable
    end
    return ts # Return exit code 1 if any failed, 0 if all success
  end
end

-1

Tôi sẽ đề nghị không tạo các tác vụ gỡ lỗi và phát hành chung nếu dự án thực sự là thứ được biên dịch và do đó dẫn đến các tệp. Bạn nên đi với các tác vụ tệp hoàn toàn có thể thực hiện được trong ví dụ của bạn, như bạn nêu, rằng đầu ra của bạn đi vào các thư mục khác nhau. Giả sử dự án của bạn chỉ biên dịch tệp test.c thành out / debug / test.out và out / release / test.out với gcc bạn có thể thiết lập dự án của mình như thế này:

WAYS = ['debug', 'release']
FLAGS = {}
FLAGS['debug'] = '-g'
FLAGS['release'] = '-O'
def out_dir(way)
  File.join('out', way)
end
def out_file(way)
  File.join(out_dir(way), 'test.out')
end
WAYS.each do |way|
  desc "create output directory for #{way}"
  directory out_dir(way)

  desc "build in the #{way}-way"
  file out_file(way) => [out_dir(way), 'test.c'] do |t|
    sh "gcc #{FLAGS[way]} -c test.c -o #{t.name}"
  end
end
desc 'build all ways'
task :all => WAYS.map{|way|out_file(way)}

task :default => [:all]

Thiết lập này có thể được sử dụng như:

rake all # (builds debug and release)
rake debug # (builds only debug)
rake release # (builds only release)

Điều này làm nhiều hơn một chút khi được yêu cầu, nhưng cho thấy quan điểm của tôi:

  1. thư mục đầu ra được tạo ra, khi cần thiết.
  2. các tệp chỉ được biên dịch lại nếu cần (ví dụ này chỉ đúng với các tệp test.c đơn giản nhất).
  3. bạn có sẵn tất cả các nhiệm vụ nếu muốn kích hoạt bản dựng phát hành hoặc bản dựng gỡ lỗi.
  4. ví dụ này bao gồm một cách để xác định những khác biệt nhỏ giữa gỡ lỗi và phát hành bản dựng.
  5. không cần phải thực hiện một nhiệm vụ xây dựng được tham số hóa với một biến toàn cục, bởi vì bây giờ các bản dựng khác nhau có các nhiệm vụ khác nhau. mã hóa của tác vụ xây dựng được thực hiện bằng cách sử dụng lại mã để xác định các tác vụ xây dựng. xem cách vòng lặp không thực hiện cùng một tác vụ hai lần, nhưng thay vào đó, các tác vụ được tạo, sau đó có thể được kích hoạt (bằng toàn bộ tác vụ hoặc chọn một trong số chúng trên dòng lệnh cào).
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.