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

Tengo una tarea de rake que necesita insertar un valor en múltiples bases de datos.

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

¿Cómo puedo hacer esto?

las opciones y las dependencias deben estar dentro de las matrices:

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 task variable es el objeto de la tarea, no es muy útil a menos que sepa o se preocupe por el funcionamiento interno del rastrillo.

NOTA DE LOS RIELES:

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

  task :work, [:option, :foo, :bar] => [:environment] do |task, args| puts "work", args end 

Puede especificar argumentos formales en rake agregando argumentos de símbolos 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 comando:

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

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

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

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

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

 > rake with_defaults
 Args con los valores predeterminados eran: {: arg1 =>: default_1,: arg2 =>: default_2}

 > rake with_defaults ['x', 'y']
 Args con los valores predeterminados eran: {: arg1 => "x",: arg2 => "y"}

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

Al observar el código en rake.rb , parece que el rake no analiza las cadenas de tareas para extraer argumentos para los requisitos previos, por lo que no puede hacer la task :t1 => "dep[1,2]" . La única forma de especificar diferentes argumentos para un requisito previo sería invocarlo explícitamente dentro de la acción dependiente de la tarea, como en :invoke_my_task y :invoke_my_task_2 .

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

Además de responder por kch (no encontré cómo dejar un comentario sobre eso, lo siento):

No tiene que especificar variables como variables ENV antes del comando de rake . Puedes simplemente configurarlos como parámetros de línea de comando habituales como ese:

 rake mytask var=foo 

y acceda a los de su archivo rake como variables ENV como las siguientes:

 p ENV['var'] # => "foo" 

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

 $ rake user:create -- --user test@example.com --pass 123 

observe el -- , eso es necesario para pasar por alto los argumentos de Rake estándar. Debería funcionar con Rake 0.9.x , <= 10.3.x.

Newer Rake ha cambiado su análisis de -- , y ahora debe asegurarse de que no se pase al método OptionParser#parse parser.parse!(ARGV[2..-1]) , 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 se interpretarán como tarea de Rake.

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

  rake user:create -- -u test@example.com -p 123 

Cuando las secuencias de comandos de rake se ven así, tal vez es hora de buscar otra herramienta que permita esto recién salido de la caja.

Encontré la respuesta de estos dos sitios web: Net Maniac y Aimred .

Necesitas tener una versión> 0.8 de rastrillo para usar esta técnica

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

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

Para pasar argumentos, haz tres cosas:

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

Para acceder a los argumentos en el script, use 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 comando, pásale los argumentos en [] s

 rake task_name['Hello',4] 

saldrá

 Hello Hello Hello Hello 

y si desea llamar a esta tarea desde otra tarea y pasar sus argumentos, use invoke

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

entonces el comando

 rake caller 

saldrá

 In Caller hi hi 

No he encontrado una forma de pasar argumentos como parte de una dependencia, ya que el siguiente código se rompe:

 task :caller => :task_name['hi',2]' do puts 'In Caller' end 

Otra opción comúnmente utilizada es pasar variables de entorno. En su código, los lee mediante ENV['VAR'] , y puede pasarlos justo antes del comando de rake , como

 $ VAR=foo rake mytask 

De hecho, @Nick Desjardins respondió perfecto. Pero solo por educación: puede usar un enfoque sucio: usando el argumento ENV

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

No pude resolver 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/'] 
 desc 'an updated version' task :task_name, [:arg1, :arg2] => [:dependency1, :dependency2] do |t, args| puts args[:arg1] end 

Uso un argumento de ruby ​​regular en el archivo de rake:

 DB = ARGV[1] 

luego resuelvo 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 comando:

 rake mytask db_name 

esto me parece más limpio que var = foo ENV var y la tarea args [blah, blah2] soluciones.
el talón es un poco jenky, pero no está mal si solo tienes algunos entornos que son una configuración única

Solo quería poder ejecutar:

 $ rake some:task arg1 arg2 

Simple, ¿verdad? (¡No!)

Rake interpreta arg1 y arg2 como tareas, e intenta ejecutarlas. Entonces abortamos antes de que ocurra.

 namespace :some do task task: :environment do arg1, arg2 = ARGV # your task... exit end end 

Toma eso, corchetes!

Descargo de responsabilidad : quería poder hacer esto en un proyecto de mascota bastante pequeño. No está diseñado para el uso del “mundo real” ya que se pierde la capacidad de encadenar tareas de rake (es decir, rake task1 task2 task3 ). IMO no vale la pena. Solo usa la fea rake task[arg1,arg2] .

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

Funcionará con raske “namespace: taskname [‘argument1’]”

Tenga en cuenta las comillas invertidas al ejecutar la tarea desde la línea de comandos.

Me gusta la syntax de “querystring” para la aprobación de argumentos, especialmente cuando hay muchos argumentos para aprobar.

Ejemplo:

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

La “querystring” es:

 width=10&height=20 

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

Cuando se analiza dentro de la tarea de 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)

Esta es la forma de 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 extenso que estoy usando con Rails en mi gem retrayed_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 arriba, con una dependencia del 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"}} 

Para pasar argumentos a la tarea predeterminada, puede hacer algo como esto. Por ejemplo, di “versión” es tu 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 comstackción) al pasar los argumentos. Me encantaría saber si alguien sabe de alguna manera.

La mayoría de los métodos descritos anteriormente no me funcionaron, tal vez están en desuso 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 pegar 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 

Invocarlo así

 bin/rake "task_name[value 1]" # entire argument string should be quoted 

Si no puede molestarse en recordar qué posición de argumento es para qué y desea hacer algo como un hash de argumento de ruby. Puede usar un argumento para pasar una cadena y luego convertir 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 comando obtienes.

 $ 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 

Mientras pasa los parámetros, es mejor que la opción sea un archivo de entrada, puede ser una herramienta excelente o lo que sea que necesite y desde allí lea la estructura de datos y las variables que necesita, incluido el nombre de la variable, según sea 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