Як запускати завдання Rake із завдань Rake?


411

У мене є Rakefile, який компілює проект двома способами, відповідно до глобальної змінної $build_type, яка може бути :debugабо :release(результати йдуть в окремих каталогах):

task :build => [:some_other_tasks] do
end

Я хочу створити завдання, яке компілює проект з обома конфігураціями по черзі, приблизно так:

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

Чи є спосіб викликати завдання так, ніби це метод? Або як я можу досягти чогось подібного?


7
на яку відповідь?
Нуреттін

Я хотів би взяти участь у голосуванні громади та обрати відповідь, яку було оскаржено 221 раз (під час написання). Оригінальний плакат покинув SO
MPritchard

правильна відповідь - stackoverflow.com/a/1290119/1536309
Блер Андерсон

FYI, використовуючи щось на зразок, Rake::Task["build"].invokeможе бути набагато ефективнішим, ніж використання, system rake buildоскільки не потрібно створювати нову нитку та завантажувати середовище Rails, що system rake buildмає робити.
Джошуа Пінтер

Відповіді:


639

Якщо вам потрібне завдання вести себе як метод, як щодо використання фактичного методу?

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

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

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

Якщо ви бажаєте дотримуватися rakeідіоми, ось ваші можливості, складені з попередніх відповідей:

  • Це завжди виконує завдання, але не виконує його залежності:

    Rake::Task["build"].execute
  • Цей виконує залежності, але він виконує завдання лише в тому випадку, коли його вже не викликали:

    Rake::Task["build"].invoke
  • Це спочатку скидає стан вже виклику завдання, що дозволяє виконувати завдання знову, залежно від усіх:

    Rake::Task["build"].reenable
    Rake::Task["build"].invoke
  • Зауважте, що вже викликані залежності не виконуються автоматично, якщо їх не ввімкнути повторно. У Rake> = 10.3.2 ви також можете скористатись такими, щоб знову ввімкнути такі:

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

96
Зауважте, що якщо ваші завдання знаходяться в просторах імен, ви повинні включати простір імен, коли ви викликаєте завдання. Напр. Rake::Task['db:reset'].invoke
Девід Туйте

126
Якщо завдання у запитаннях містить аргументи, ви можете передати їх як аргументи #invoke. Напр. Rake::Task['with:args'].invoke("pizza")
Trotter

26
Якщо вам потрібно встановити змінну середовища, зробіть це перед тим, як викликати виклик. Наприклад: ENV['VERSION'] = '20110408170816'; Rake::Task['db:migrate'].invokeДивіться тут для отримання додаткових пояснень.
Майкл Сталкер

13
Нещодавно я виявив, #reenable()що не вмикає перереквізити і потрібен. Це доповнення до Rake (> = 10.3.2) #all_prerequisite_tasks()дозволить повторити всі завдання, включаючи попередні реквізити попередніх запитів. Отже,Rake::Task[task].all_prerequisite_tasks.each &:reenable
Річард Майкл

4
@kch, чи можете ви з'єднати їх між собою (як, наприклад, у командному рядку rake db:reset db:migrate). Ви можете зробити щось на кшталт: Rake::Task["db:reset", "db:migrate"].invoke
Jeff

125

наприклад:

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

6
Це викликає завдання лише в тому випадку, якщо воно вже не викликалося. Але мені потрібно викликати завдання з усіма іншими завданнями, від яких залежить двічі.

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

Це повинно розібратися з вами, саме мені потрібно було те саме.


Це функціонально, але занадто багатослівно. Впевнені, що немає нічого кращого?
кч

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

Однією з причин, чому мені було потрібно таке рішення, є те, що завантаження граблів займає багато часу. Реалізуючи подібне рішення, це заощадить на завантаженні часу?
Діпан Мехта

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

Це не працює, оскільки він просто виконує тіло завдання: build і не викликає залежних від нього завдань.

4

Якщо ви хочете, щоб кожне завдання виконувалося незалежно від будь-яких збоїв, ви можете зробити щось на кшталт:

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

Я б запропонував не створювати загальних завдань налагодження та випуску, якщо проект дійсно щось компілюється і таким чином призводить до файлів. Вам слід виконати файлові завдання, що цілком можливо у вашому прикладі, як ви заявляєте, що ваш результат надходить у різні каталоги. Скажіть, що ваш проект просто компілює файл test.c для виходу / налагодження / test.out та out / release / test.out за допомогою gcc, ви можете налаштувати свій проект так:

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]

Цю установку можна використовувати так:

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

Це робить трохи більше, як просили, але показує мої моменти:

  1. Вихідні каталоги створюються за потребою.
  2. файли рекомпілюються лише за потреби (цей приклад правильний лише для найпростіших файлів test.c).
  3. у вас є всі завдання під рукою, якщо ви хочете запустити збірку випуску або збірку налагодження.
  4. цей приклад включає спосіб також визначити невеликі відмінності між налагодженнями та версіями версій.
  5. немає необхідності повторно використовувати завдання збирання, параметризовані глобальною змінною, тому що зараз у різних збірок є різні завдання. повторне використання коду завдання збірки здійснюється шляхом повторного використання коду для визначення завдань збирання. подивіться, як цикл не виконує одне і те ж завдання двічі, а натомість створив завдання, які згодом можуть бути запущені (або всезадачею, або вибираючи одну з них у командному рядку рейка).
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.