¿Cómo ejecutar tareas de Rake desde las tareas de Rake?

411

Tengo un Rakefile que compila el proyecto de dos maneras, de acuerdo con la variable global $build_type, que puede ser :debugo :release(los resultados van en directorios separados):

task :build => [:some_other_tasks] do
end

Deseo crear una tarea que compile el proyecto con ambas configuraciones a su vez, algo como esto:

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

¿Hay alguna manera de llamar a una tarea como si fuera un método? ¿O cómo puedo lograr algo similar?

Andrew Marshall
fuente
77
cual es la respuesta
nurettin
Iría con el voto de la comunidad y elegiría la respuesta votada 221 veces (al momento de escribir esto). El póster original se fue SO
MPritchard
la respuesta correcta es stackoverflow.com/a/1290119/1536309
Blair Anderson el
Para su información, usar algo así Rake::Task["build"].invokepuede ser mucho más eficaz que usarlo system rake buildporque no tiene que crear un nuevo hilo y cargar el entorno Rails, lo que system rake buildsí tiene que hacer.
Joshua Pinter

Respuestas:

639

Si necesita que la tarea se comporte como un método, ¿qué tal usar un método real?

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

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

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

Si prefiere apegarse a rakelas expresiones idiomáticas, aquí están sus posibilidades, compiladas a partir de respuestas pasadas:

  • Esto siempre ejecuta la tarea, pero no ejecuta sus dependencias:

    Rake::Task["build"].execute
  • Éste ejecuta las dependencias, pero solo ejecuta la tarea si aún no se ha invocado:

    Rake::Task["build"].invoke
  • Esto restablece primero el estado ya invocado de la tarea, permitiendo que la tarea se ejecute nuevamente, dependencias y todo:

    Rake::Task["build"].reenable
    Rake::Task["build"].invoke
    
  • Tenga en cuenta que las dependencias ya invocadas no se vuelven a ejecutar automáticamente a menos que se vuelvan a habilitar. En Rake> = 10.3.2, puede usar lo siguiente para volver a habilitarlos también:

    Rake::Task["build"].all_prerequisite_tasks.each(&:reenable)
kch
fuente
96
Tenga en cuenta que si sus tareas están en espacios de nombres, debe incluir el espacio de nombres cuando invoque la tarea. P.ej. Rake::Task['db:reset'].invoke
David Tuite
126
Si la tarea en preguntas toma argumentos, puede pasarlos como argumentos para #invocar. P.ej. Rake::Task['with:args'].invoke("pizza")
Trotter
27
Si necesita establecer una variable de entorno, hágalo antes de llamar a invoke. Por ejemplo: ENV['VERSION'] = '20110408170816'; Rake::Task['db:migrate'].invokeVea aquí para más explicaciones.
Michael Stalker
13
Recientemente descubrí #reenable()que no vuelve a habilitar los requisitos previos, y lo necesitaba. Esta adición a Rake (> = 10.3.2) #all_prerequisite_tasks()iterará todas las tareas, incluidas las pre-req de pre-req. Entonces,Rake::Task[task].all_prerequisite_tasks.each &:reenable
Richard Michael
44
@kch, ¿puedes unirlos (por ejemplo, en la línea rake db:reset db:migratede comandos )? ¿Puedes hacer algo como: Rake::Task["db:reset", "db:migrate"].invoke
Jeff
125

por ejemplo:

Rake::Task["db:migrate"].invoke
Marcin Urbanski
fuente
66
Esto invoca la tarea solo si aún no se ha invocado. Pero necesito invocar las tareas con todas las demás tareas de las que depende dos veces.
58
task :build_all do
  [ :debug, :release ].each do |t|
    $build_type = t
    Rake::Task["build"].reenable
    Rake::Task["build"].invoke
  end
end

Eso debería resolverlo, solo necesitaba lo mismo para mí.

darkliquid
fuente
Esto es funcional, pero demasiado detallado. ¿Seguro que no hay nada mejor?
kch
13
task :invoke_another_task do
  # some code
  Rake::Task["another:task"].invoke
end
Neeraj Kumar
fuente
Una de las razones por las que necesitaba una solución como esta es porque la carga de tareas de rastrillo lleva mucho tiempo. Al implementar una solución como la anterior, ¿ahorrará tiempo de carga?
Dipan Mehta
11
task :build_all do
  [ :debug, :release ].each do |t|
    $build_type = t
    Rake::Task["build"].execute
  end
end
pjb3
fuente
No funciona, porque solo ejecuta el cuerpo de la tarea: build y no invoca las tareas que dependen de ella.
4

Si desea que cada tarea se ejecute independientemente de cualquier falla, puede hacer algo como:

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
bbbco
fuente
-1

Sugeriría no crear tareas generales de depuración y liberación si el proyecto es realmente algo que se compila y resulta en archivos. Debería ir con las tareas de archivo, que es bastante factible en su ejemplo, como usted dice, que su salida va a diferentes directorios. Digamos que su proyecto solo compila un archivo test.c a / debug / test.out y out / release / test.out con gcc, podría configurar su proyecto así:

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]

Esta configuración se puede usar como:

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

Esto hace un poco más de lo solicitado, pero muestra mis puntos:

  1. Se crean directorios de salida, según sea necesario.
  2. los archivos solo se vuelven a compilar si es necesario (este ejemplo solo es correcto para los archivos test.c más simples).
  3. tiene todas las tareas a mano si desea activar la versión de lanzamiento o la versión de depuración.
  4. Este ejemplo incluye una manera de definir también pequeñas diferencias entre depuración y versiones de lanzamiento.
  5. no es necesario volver a habilitar una tarea de compilación que se parametriza con una variable global, porque ahora las diferentes compilaciones tienen tareas diferentes. La reutilización del código de la tarea de compilación se realiza reutilizando el código para definir las tareas de compilación. vea cómo el bucle no ejecuta la misma tarea dos veces, sino que crea tareas, que luego pueden activarse (ya sea por todas las tareas o eligiendo una de ellas en la línea de comandos de rake).
Gizmomogwai
fuente