Wie führe ich Rake-Aufgaben aus Rake-Aufgaben heraus aus?


410

Ich habe ein Rakefile, das das Projekt auf zwei Arten kompiliert, entsprechend der globalen Variablen $build_type, die :debugoder sein kann :release(die Ergebnisse werden in separaten Verzeichnissen gespeichert ):

task :build => [:some_other_tasks] do
end

Ich möchte eine Aufgabe erstellen, die das Projekt mit beiden Konfigurationen nacheinander kompiliert.

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

Gibt es eine Möglichkeit, eine Aufgabe so aufzurufen, als wäre es eine Methode? Oder wie kann ich etwas Ähnliches erreichen?


7
Welches ist die Antwort?
Nurettin

Ich würde mit der Community-Abstimmung gehen und die Antwort 221 Mal (zum Zeitpunkt des Schreibens) positiv auswählen. Das Originalplakat hat SO
MPritchard am


Zu Ihrer Information, die Verwendung von so etwas Rake::Task["build"].invokekann viel leistungsfähiger sein als die Verwendung, system rake buildda kein neuer Thread erstellt und die Rails-Umgebung geladen werden muss, was system rake buildzu tun ist.
Joshua Pinter

Antworten:


639

Wenn Sie die Aufgabe als Methode benötigen, wie wäre es dann mit einer tatsächlichen Methode?

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

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

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

Wenn Sie sich lieber an rakedie Redewendungen halten möchten, finden Sie hier Ihre Möglichkeiten, die aus früheren Antworten zusammengestellt wurden:

  • Dadurch wird die Aufgabe immer ausgeführt, ihre Abhängigkeiten werden jedoch nicht ausgeführt:

    Rake::Task["build"].execute
  • Dieser führt die Abhängigkeiten aus, führt die Aufgabe jedoch nur aus, wenn sie noch nicht aufgerufen wurde:

    Rake::Task["build"].invoke
  • Dadurch wird zuerst der bereits aufgerufene Status der Aufgabe zurückgesetzt, sodass die Aufgabe erneut ausgeführt werden kann, Abhängigkeiten und alles:

    Rake::Task["build"].reenable
    Rake::Task["build"].invoke

    (Beachten Sie, dass bereits aufgerufene Abhängigkeiten nicht erneut ausgeführt werden.)


96
Beachten Sie, dass Sie den Namespace beim Aufrufen der Aufgabe angeben müssen, wenn sich Ihre Aufgaben in Namespaces befinden. Z.B. Rake::Task['db:reset'].invoke
David Tuite

126
Wenn die Aufgabe in Fragen Argumente akzeptiert, können Sie diese als Argumente an #invoke übergeben. Z.B. Rake::Task['with:args'].invoke("pizza")
Traber

26
Wenn Sie eine Umgebungsvariable festlegen müssen, tun Sie dies, bevor Sie invoke aufrufen. Zum Beispiel: ENV['VERSION'] = '20110408170816'; Rake::Task['db:migrate'].invokeSiehe hier für weitere Erklärung.
Michael Stalker

12
Ich habe kürzlich festgestellt, #reenable()dass Pre-Reqs nicht wieder aktiviert werden und benötigt werden. Diese Hinzufügung zu Rake (> = 10.3.2) #all_prerequisite_tasks()iteriert alle Aufgaben, einschließlich der Voranforderungen der Voranforderungen . Also,Rake::Task[task].all_prerequisite_tasks.each &:reenable
Richard Michael

4
@kch, können Sie diese aneinander reihen (wie rake db:reset db:migratezum Beispiel in der Kommandozeile ). Können Sie etwas tun wie: Rake::Task["db:reset", "db:migrate"].invoke
Jeff

125

zum Beispiel:

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

6
Dies ruft die Aufgabe nur auf, wenn sie nicht bereits aufgerufen wurde. Aber ich muss die Aufgaben mit allen anderen Aufgaben aufrufen, von denen es zweimal abhängt.

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

Das sollte dich klären, brauchte nur das Gleiche.


Dies ist funktional, aber viel zu ausführlich. Sicher gibt es nichts besseres?
kch

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

Einer der Gründe, warum ich eine solche Lösung brauchte, ist, dass das Laden von Rake-Aufgaben viel Zeit in Anspruch nimmt. Sparen Sie durch die Implementierung einer Lösung wie oben Ladezeit?
Dipan Mehta

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

Es funktioniert nicht, weil es nur den Hauptteil der: build-Aufgabe ausführt und die davon abhängigen Aufgaben nicht aufruft.

4

Wenn Sie möchten, dass jede Aufgabe unabhängig von Fehlern ausgeführt wird, können Sie Folgendes tun:

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

Ich würde vorschlagen, keine allgemeinen Debug- und Release-Aufgaben zu erstellen, wenn das Projekt wirklich kompiliert wird und so zu Dateien führt. Sie sollten mit Datei-Tasks arbeiten, was in Ihrem Beispiel durchaus machbar ist, da Sie angeben, dass Ihre Ausgabe in verschiedene Verzeichnisse geht. Angenommen, Ihr Projekt kompiliert nur eine test.c-Datei nach out / debug / test.out und out / release / test.out mit gcc. Sie können Ihr Projekt folgendermaßen einrichten:

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]

Dieses Setup kann wie folgt verwendet werden:

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

Dies macht ein wenig mehr als gewünscht, zeigt aber meine Punkte:

  1. Ausgabeverzeichnisse werden nach Bedarf erstellt.
  2. Die Dateien werden nur bei Bedarf neu kompiliert (dieses Beispiel gilt nur für die einfachste test.c-Datei).
  3. Sie haben alle Aufgaben zur Hand, wenn Sie den Release-Build oder den Debug-Build auslösen möchten.
  4. Dieses Beispiel enthält eine Möglichkeit, auch kleine Unterschiede zwischen Debug- und Release-Builds zu definieren.
  5. Es ist nicht erforderlich, eine Build-Aufgabe erneut zu aktivieren, die mit einer globalen Variablen parametrisiert ist, da die verschiedenen Builds jetzt unterschiedliche Aufgaben haben. Die Codereuse der Build-Task erfolgt durch Wiederverwendung des Codes zur Definition der Build-Tasks. Sehen Sie, wie die Schleife nicht zweimal dieselbe Aufgabe ausführt, sondern stattdessen erstellte Aufgaben erstellt, die später ausgelöst werden können (entweder von der All-Task oder indem Sie eine davon in der Rake-Befehlszeile auswählen).
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.