Jak uruchamiać zadania prowizji z poziomu zadań prowizji?


411

Mam plik Rakefile, który kompiluje projekt na dwa sposoby, zgodnie ze zmienną globalną $build_type, którą może być :debuglub :release(wyniki znajdują się w osobnych katalogach):

task :build => [:some_other_tasks] do
end

Chcę utworzyć zadanie, które po kolei kompiluje projekt z obiema konfiguracjami, mniej więcej tak:

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

Czy istnieje sposób na wywołanie zadania tak, jakby to była metoda? Lub jak mogę osiągnąć coś podobnego?


7
który jest odpowiedzią?
nurettin

Poszedłem z głosowaniem społeczności i wybrałem odpowiedź głosowaną 221 razy (w momencie pisania). Oryginalny plakat opuścił SO
MPritchard


Do twojej wiadomości, użycie czegoś takiego Rake::Task["build"].invokemoże być o wiele bardziej wydajne niż używanie, system rake buildponieważ nie musi tworzyć nowego wątku i ładować środowiska Rails, co system rake buildtrzeba zrobić.
Joshua Pinter,

Odpowiedzi:


639

Jeśli potrzebujesz, aby zadanie zachowywało się jak metoda, co powiesz na użycie rzeczywistej metody?

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

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

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

Jeśli wolisz trzymać się rakeidiomów, oto twoje możliwości, zebrane na podstawie wcześniejszych odpowiedzi:

  • To zawsze wykonuje zadanie, ale nie wykonuje jego zależności:

    Rake::Task["build"].execute
  • Ten wykonuje zależności, ale wykonuje zadanie tylko wtedy, gdy nie zostało jeszcze wywołane:

    Rake::Task["build"].invoke
  • To najpierw resetuje stan już wywołanego zadania, umożliwiając jego ponowne wykonanie, zależności i wszystkie:

    Rake::Task["build"].reenable
    Rake::Task["build"].invoke
  • Należy zauważyć, że wywołane już zależności nie są automatycznie ponownie uruchamiane, chyba że zostaną ponownie włączone. W Rake> = 10.3.2 możesz również użyć tych opcji, aby je ponownie włączyć:

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

96
Pamiętaj, że jeśli twoje zadania znajdują się w przestrzeniach nazw, musisz uwzględnić przestrzeń nazw podczas wywoływania zadania. Na przykład. Rake::Task['db:reset'].invoke
David Tuite,

126
Jeśli zadanie w pytaniach przyjmuje argumenty, możesz przekazać je jako argumenty do #invoke. Na przykład. Rake::Task['with:args'].invoke("pizza")
Kłusak

26
Jeśli musisz ustawić zmienną środowiskową, zrób to przed wywołaniem invoke. Na przykład: ENV['VERSION'] = '20110408170816'; Rake::Task['db:migrate'].invokezobacz tutaj, aby uzyskać więcej wyjaśnień.
Michael Stalker,

13
Niedawno odkryłem, #reenable()że nie włącza ponownie wymagań wstępnych i potrzebowałem tego. Ten dodatek do Rake (> = 10.3.2) #all_prerequisite_tasks()spowoduje iterację wszystkich zadań, w tym wstępnych wymagań wstępnych. Tak więcRake::Task[task].all_prerequisite_tasks.each &:reenable
Richard Michael

4
@kch, czy możesz je połączyć razem (na rake db:reset db:migrateprzykład w wierszu poleceń ). Czy możesz zrobić coś takiego: Rake::Task["db:reset", "db:migrate"].invoke
Jeff

125

na przykład:

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

6
To wywołuje zadanie tylko wtedy, gdy nie zostało jeszcze wywołane. Ale muszę wywoływać zadania ze wszystkimi innymi zadaniami, od których zależy dwa razy.

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

To powinno cię załatwić, sam potrzebowałem tego samego.


Jest to funkcjonalne, ale zbyt szczegółowe. Pewnie, że nie ma nic lepszego?
kch

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

Jednym z powodów, dla których potrzebowałem takiego rozwiązania, jest to, że ładowanie zadań prowizji zajmuje dużo czasu. Czy dzięki wdrożeniu takiego rozwiązania jak wyżej zaoszczędzisz czas ładowania?
Dipan Mehta,

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

Nie działa, ponieważ po prostu wykonuje treść zadania: build i nie wywołuje zależnych od niego zadań.

4

Jeśli chcesz, aby każde zadanie działało bez względu na awarie, możesz zrobić coś takiego:

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

Sugerowałbym, aby nie tworzyć ogólnych zadań debugowania i zwalniania, jeśli projekt jest tak naprawdę kompilowany, co powoduje powstanie plików. Powinieneś przejść do zadań związanych z plikami, co jest całkiem wykonalne w twoim przykładzie, gdy stwierdzasz, że twoje wyjście trafia do różnych katalogów. Powiedz, że twój projekt po prostu kompiluje plik test.c do out / debug / test.out i out / release / test.out za pomocą gcc, możesz skonfigurować swój projekt w następujący sposób:

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]

Tej konfiguracji można użyć w następujący sposób:

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

Robi to nieco więcej, o co prosiłem, ale pokazuje moje punkty:

  1. w razie potrzeby tworzone są katalogi wyjściowe.
  2. pliki są rekompilowane tylko w razie potrzeby (ten przykład jest poprawny tylko dla najprostszych plików test.c).
  3. masz wszystkie zadania pod ręką, jeśli chcesz uruchomić kompilację wersji lub kompilację debugowania.
  4. ten przykład zawiera sposób na zdefiniowanie również niewielkich różnic między kompilacjami debugowania i wydań.
  5. nie ma potrzeby ponownego włączania zadania kompilacji sparametryzowanego zmienną globalną, ponieważ teraz różne kompilacje mają różne zadania. użycie kod-kompilacji zadania kompilacji odbywa się poprzez ponowne użycie kodu do zdefiniowania zadań kompilacji. zobacz, jak pętla nie wykonuje tego samego zadania dwa razy, ale zamiast tego utworzyła zadania, które później mogą zostać uruchomione (albo przez wszystkie zadania, albo wybierając jedno z nich w linii poleceń rake).
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.