Cómo pasar argumentos de línea de comandos a una tarea de rake


Tengo una tarea de rake que necesita insertar un valor en varias bases de datos.

Me gustaría pasar este valor a la tarea rake desde la línea de comandos, o desde otra tarea rake.

¿Cómo puedo hacer esto?

Author: the Tin Man, 2009-05-05

17 answers

Las opciones y dependencias deben estar dentro de los arrays:

namespace :thing do
  desc "it does a thing"
  task :work, [:option, :foo, :bar] do |task, args|
    puts "work", args
  end

  task :another, [:option, :foo, :bar] do |task, args|
    puts "another #{args}"
    Rake::Task["thing:work"].invoke(args[:option], args[:foo], args[:bar])
    # or splat the args
    # Rake::Task["thing:work"].invoke(*args)
  end

end

Entonces

rake thing:work[1,2,3]
=> work: {:option=>"1", :foo=>"2", :bar=>"3"}

rake thing:another[1,2,3]
=> another {:option=>"1", :foo=>"2", :bar=>"3"}
=> work: {:option=>"1", :foo=>"2", :bar=>"3"}

NOTA: la variable task es el objeto task, no es muy útil a menos que sepa/se preocupe por los internos de Rake.

RAILS NOTA:

Si ejecuta la tarea desde rails, lo mejor es precargar el entorno agregando => [:environment] que es una forma de configurar tareas dependientes.

  task :work, [:option, :foo, :bar] => [:environment] do |task, args|
    puts "work", args
  end
 240
Author: Blair Anderson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-11 19:22:00

Puede especificar argumentos formales en rake añadiendo argumentos de símbolo a la llamada a la tarea. Por ejemplo:

require 'rake'

task :my_task, [:arg1, :arg2] do |t, args|
  puts "Args were: #{args}"
end

task :invoke_my_task do
  Rake.application.invoke_task("my_task[1, 2]")
end

# or if you prefer this syntax...
task :invoke_my_task_2 do
  Rake::Task[:my_task].invoke(3, 4)
end

# a task with prerequisites passes its 
# arguments to it prerequisites
task :with_prerequisite, [:arg1, :arg2] => :my_task #<- name of prerequisite task

# to specify default values, 
# we take advantage of args being a Rake::TaskArguments object
task :with_defaults, :arg1, :arg2 do |t, args|
  args.with_defaults(:arg1 => :default_1, :arg2 => :default_2)
  puts "Args with defaults were: #{args}"
end

Luego, desde la línea de comandos:

> rake my_task[1,2]
Args were: {:arg1=>"1", :arg2=>"2"}

> rake "my_task[1, 2]"
Args were: {:arg1=>"1", :arg2=>"2"}

> rake invoke_my_task
Args were: {:arg1=>"1", :arg2=>"2"}

> rake invoke_my_task_2
Args were: {:arg1=>3, :arg2=>4}

> rake with_prerequisite[5,6]
Args were: {:arg1=>"5", :arg2=>"6"}

> rake with_defaults
Args with defaults were: {:arg1=>:default_1, :arg2=>:default_2}

> rake with_defaults['x','y']
Args with defaults were: {:arg1=>"x", :arg2=>"y"}

Como se demostró en el segundo ejemplo, si desea usar espacios, las comillas alrededor del nombre de destino son necesarias para evitar que el shell divida los argumentos en el espacio.

Mirando el código en rake.rb , parece que rake no analiza cadenas de tareas para extraer argumentos para prerrequisitos, por lo que no puedes hacer task :t1 => "dep[1,2]". La única manera de especificar diferentes argumentos para un prerrequisito sería invocarlo explícitamente dentro de la acción de tarea dependiente, como en :invoke_my_task y :invoke_my_task_2.

Ten en cuenta que algunos shells (como zsh) requieren que escapes de los corchetes: rake my_task\['arg1'\]

 1084
Author: Nick Desjardins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-08 15:32:57

Además de la respuesta de kch (no encontré cómo dejar un comentario a eso, lo siento):

No es necesario especificar variables como ENV variables antes del comando rake. Simplemente puede configurarlos como parámetros de línea de comandos habituales así:

rake mytask var=foo

Y acceder a los de su archivo de rake como variables ENV como tales:

p ENV['var'] # => "foo"
 292
Author: timurb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-16 19:35:18

Si desea pasar argumentos con nombre (por ejemplo, con estándar OptionParser) podría usar algo como esto:

$ rake user:create -- --user [email protected] --pass 123

Tenga en cuenta el --, que es necesario para evitar los argumentos de Rake estándar. Debería funcionar con Rake 0.9.x, .

El Rake más nuevo ha cambiado su análisis de --, y ahora debe asegurarse de que no se pase al método OptionParser#parse, por ejemplo con parser.parse!(ARGV[2..-1])

require 'rake'
require 'optparse'
# Rake task for creating an account

namespace :user do |args|
  desc 'Creates user account with given credentials: rake user:create'
  # environment is required to have access to Rails models
  task :create do
    options = {}
    OptionParser.new(args) do |opts|
      opts.banner = "Usage: rake user:create [options]"
      opts.on("-u", "--user {username}","User's email address", String) do |user|
        options[:user] = user
      end
      opts.on("-p", "--pass {password}","User's password", String) do |pass|
        options[:pass] = pass
      end
    end.parse!

    puts "creating user account..."
    u = Hash.new
    u[:email] = options[:user]
    u[:password] = options[:pass]
    # with some DB layer like ActiveRecord:
    # user = User.new(u); user.save!
    puts "user: " + u.to_s
    puts "account created."
    exit 0
  end
end

exit al final se asegurará de que los argumentos adicionales no serán interpretado como tarea Rake.

También el atajo para los argumentos debería funcionar:

 rake user:create -- -u [email protected] -p 123

Cuando los scripts de rake se ven así, tal vez sea hora de buscar otra herramienta que permita esto solo fuera de la caja.

 97
Author: Tombart,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-11 10:49:28

He encontrado la respuesta en estos dos sitios web: Net Maniacy Aimred.

Necesita tener una versión > 0.8 de rake para usar esta técnica

La descripción normal de la tarea rake es esta:

desc 'Task Description'
task :task_name => [:depends_on_taskA, :depends_on_taskB] do
  #interesting things
end

Para pasar argumentos, haga tres cosas: {[13]]}

  1. Agregue los nombres de los argumentos después del nombre de la tarea, separados por comas.
  2. Ponga las dependencias al final usando: needs = > [...]
  3. Lugar |t, args| después del do. (t es el objeto de esta tarea)

Para acceder a los argumentos del script, utilice args.arg_name

desc 'Takes arguments task'
task :task_name, :display_value, :display_times, :needs => [:depends_on_taskA, :depends_on_taskB] do |t, args|
  args.display_times.to_i.times do
    puts args.display_value
  end
end

Para llamar a esta tarea desde la línea de comandos, pásele los argumentos en [] s

rake task_name['Hello',4]

Producirá

Hello
Hello
Hello
Hello

Y si desea llamar a esta tarea desde otra tarea, y pasarle argumentos, use invoke

task :caller do
  puts 'In Caller'
  Rake::Task[:task_name].invoke('hi',2)
end

Entonces el comando

rake caller

Producirá

In Caller
hi
hi

No he encontrado una manera de pasar argumentos como parte de una dependencia, ya que el siguiente código descansos:

task :caller => :task_name['hi',2]' do
   puts 'In Caller'
end
 56
Author: Tilendor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-05 16:51:45

Otra opción comúnmente utilizada es pasar variables de entorno. En tu código los lees a través de ENV['VAR'], y puedes pasarlos justo antes del comando rake, como

$ VAR=foo rake mytask
 30
Author: kch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-05 16:53:13

En realidad @Nick Desjardins respondió perfecto. Pero solo para la educación: puede usar el enfoque sucio: usando ENV argumento

task :my_task do
  myvar = ENV['myvar']
  puts "myvar: #{myvar}"
end 

rake my_task myvar=10
#=> myvar: 10
 30
Author: fl00r,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-28 20:06:33

No podía averiguar cómo pasar args y también el: entorno hasta que resolví esto:

namespace :db do
  desc 'Export product data'
  task :export, [:file_token, :file_path] => :environment do |t, args|
    args.with_defaults(:file_token => "products", :file_path => "./lib/data/")

       #do stuff [...]

  end
end

Y luego llamo así:

rake db:export['foo, /tmp/']
 24
Author: Nate Flink,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-29 19:38:18
desc 'an updated version'
task :task_name, [:arg1, :arg2] => [:dependency1, :dependency2] do |t, args|
    puts args[:arg1]
end
 23
Author: Feng,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-16 07:36:27

Uso un argumento ruby regular en el archivo rake:

DB = ARGV[1]

Entonces extraigo las tareas de rake en la parte inferior del archivo (ya que rake buscará una tarea basada en ese nombre de argumento).

task :database_name1
task :database_name2

Línea de comandos:

rake mytask db_name

Esto me parece más limpio que las soluciones var=foo ENV var y task args[blah, blah2].
el stub es un poco jenky, pero no está tan mal si solo tiene unos pocos entornos que son una configuración de una sola vez

 13
Author: djburdick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-29 02:48:52

Solo quería ser capaz de ejecutar:

$ rake some:task arg1 arg2

Simple, ¿verdad? (¡No!)

Rake interpreta arg1 y arg2 como tareas, e intenta ejecutarlas. Así que abortamos antes de que lo haga.

namespace :some do
  task task: :environment do
    arg1, arg2 = ARGV

    # your task...

    exit
  end
end

Toma eso, paréntesis!

Disclaimer: Quería ser capaz de hacer esto en un proyecto mascota bastante pequeño. No está pensado para el uso en el" mundo real", ya que pierde la capacidad de encadenar tareas de rake (es decir, rake task1 task2 task3). IMO no vale la pena. Solo usa el feo rake task[arg1,arg2].

 13
Author: jassa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-17 22:20:57

Las formas de pasar el argumento son correctas en la respuesta anterior. Sin embargo, para ejecutar la tarea rake con argumentos, hay un pequeño tecnicismo involucrado en la versión más reciente de rails

Funcionará con rake " namespace: taskname ['argument1']"

Observe las comillas invertidas al ejecutar la tarea desde la línea de comandos.

 5
Author: Asim Mushtaq,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-05 07:21:16

Me gusta la sintaxis "querystring" para pasar argumentos, especialmente cuando hay muchos argumentos a pasar.

Ejemplo:

rake "mytask[width=10&height=20]"

El" querystring " es:

width=10&height=20

Advertencia: tenga en cuenta que la sintaxis es rake "mytask[foo=bar]" y NO rake mytask["foo=bar"]

Cuando se analiza dentro de la tarea rake usando Rack::Utils.parse_nested_query, obtenemos un Hash:

=> {"width"=>"10", "height"=>"20"}

(Lo bueno es que puedes pasar hashes y matrices, más abajo)

Esto es cómo lograr esto:

require 'rack/utils'

task :mytask, :args_expr do |t,args|
  args.with_defaults(:args_expr => "width=10&height=10")
  options = Rack::Utils.parse_nested_query(args[:args_expr])
end

Aquí hay un ejemplo más extendido que estoy usando con Rails en mi gema delayed_job_active_record_threaded:

bundle exec rake "dj:start[ebooks[workers_number]=16&ebooks[worker_timeout]=60&albums[workers_number]=32&albums[worker_timeout]=120]"

Analizado de la misma manera que el anterior, con una dependencia de entorno (para cargar el entorno Rails)

namespace :dj do
  task :start, [ :args_expr ] => :environment do |t, args|
    # defaults here...
    options = Rack::Utils.parse_nested_query(args[:args_expr])  
  end
end

Da lo siguiente en options

=> {"ebooks"=>{"workers_number"=>"16", "worker_timeout"=>"60"}, "albums"=>{"workers_number"=>"32", "worker_timeout"=>"120"}}
 4
Author: Abdo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-16 22:05:07

Para pasar argumentos a la tarea predeterminada, puede hacer algo como esto. Por ejemplo, digamos "versión" es su argumento:

task :default, [:version] => [:build]

task :build, :version do |t,args|
  version = args[:version]
  puts version ? "version is #{version}" : "no version passed"
end

Entonces puedes llamarlo así:

$ rake
no version passed

O

$ rake default[3.2.1]
version is 3.2.1

O

$ rake build[3.2.1]
version is 3.2.1

Sin embargo, no he encontrado una manera de evitar especificar el nombre de la tarea (por defecto o compilación) al pasar argumentos. Me encantaría saber si alguien sabe de una manera.

 3
Author: Gal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-20 19:03:37

La mayoría de los métodos descritos anteriormente no funcionaron para mí, tal vez estén obsoletos en las versiones más recientes. La guía actualizada se puede encontrar aquí: http://guides.rubyonrails.org/command_line.html#custom-rake-tasks

Una copia y pega ans de la guía está aquí:

task :task_name, [:arg_1] => [:pre_1, :pre_2] do |t, args|
  # You can use args from here
end

Invócalo así

bin/rake "task_name[value 1]" # entire argument string should be quoted
 2
Author: hexinpeter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-03 01:15:17

Si no se molesta en recordar qué argumento es position para qué y desea hacer algo como un hash de argumento ruby. Puede usar un argumento para pasar una cadena y luego regex esa cadena en un hash de opciones.

namespace :dummy_data do
  desc "Tests options hash like arguments"
  task :test, [:options] => :environment do |t, args|
    arg_options = args[:options] || '' # nil catch incase no options are provided
    two_d_array = arg_options.scan(/\W*(\w*): (\w*)\W*/)
    puts two_d_array.to_s + ' # options are regexed into a 2d array'
    string_key_hash = two_d_array.to_h
    puts string_key_hash.to_s + ' # options are in a hash with keys as strings'
    options = two_d_array.map {|p| [p[0].to_sym, p[1]]}.to_h
    puts options.to_s + ' # options are in a hash with symbols'
    default_options = {users: '50', friends: '25', colour: 'red', name: 'tom'}
    options = default_options.merge(options)
    puts options.to_s + ' # default option values are merged into options'
  end
end

Y en la línea de comandos se obtiene.

$ rake dummy_data:test["users: 100 friends: 50 colour: red"]
[["users", "100"], ["friends", "50"], ["colour", "red"]] # options are regexed into a 2d array
{"users"=>"100", "friends"=>"50", "colour"=>"red"} # options are in a hash with keys as strings
{:users=>"100", :friends=>"50", :colour=>"red"} # options are in a hash with symbols
{:users=>"100", :friends=>"50", :colour=>"red", :name=>"tom"} # default option values are merged into options
 1
Author: xander-miller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-12 01:44:06

Al pasar parámetros, es mejor opción es un archivo de entrada, puede ser un excel, un json o lo que sea que necesite y desde allí leer la estructura de datos y las variables que necesita de eso incluyendo el nombre de la variable como es la necesidad. Para leer un archivo puede tener la siguiente estructura.

  namespace :name_sapace_task do
    desc "Description task...."
      task :name_task  => :environment do
        data =  ActiveSupport::JSON.decode(File.read(Rails.root+"public/file.json")) if defined?(data)
    # and work whit yoour data, example is data["user_id"]

    end
  end

Ejemplo json

{
  "name_task": "I'm a task",
  "user_id": 389,
  "users_assigned": [389,672,524],
  "task_id": 3
}

Ejecución

rake :name_task 
 -4
Author: tundervirld,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-11 23:43:07