ruby - Cómo pasar argumentos de línea de comando a una tarea de rake
command-line command-line-arguments (17)
Tengo una tarea de rake que necesita insertar un valor en varias bases de datos.
Me gustaría pasar este valor a la tarea de rake desde la línea de comandos o desde otra tarea de rake.
¿Cómo puedo hacer esto?
Además de responder por kch (no encontré cómo dejar un comentario para eso, lo siento):
No es necesario especificar variables como variables ENV
antes del comando de rake
. Puede simplemente configurarlos como parámetros de línea de comando habituales de esa manera:
rake mytask var=foo
y acceda a los de su archivo de rastrillo como variables ENV como:
p ENV[''var''] # => "foo"
En realidad @Nick Desjardins respondió perfecto. Pero solo para la educación: puedes usar un enfoque sucio: usar el argumento ENV
task :my_task do
myvar = ENV[''myvar'']
puts "myvar: #{myvar}"
end
rake my_task myvar=10
#=> myvar: 10
He encontrado la respuesta de estos dos sitios web: Net Maniac y Aimred .
Necesitas tener una versión> 0.8 de rake para usar esta técnica.
La descripción normal de la tarea de rake es esta:
desc ''Task Description''
task :task_name => [:depends_on_taskA, :depends_on_taskB] do
#interesting things
end
Para pasar argumentos, haz tres cosas:
- Agregue los nombres de los argumentos después del nombre de la tarea, separados por comas.
- Ponga las dependencias al final usando: needs => [...]
- Lugar | 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ásele los argumentos en [] s
rake task_name[''Hello'',4]
dará salida
Hello
Hello
Hello
Hello
y si desea llamar a esta tarea desde otra tarea y pasarle argumentos, use invocar
task :caller do
puts ''In Caller''
Rake::Task[:task_name].invoke(''hi'',2)
end
entonces el comando
rake caller
dará salida
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
La mayoría de los métodos descritos anteriormente no funcionaron para mí, tal vez están obsoletos en las versiones más nuevas. La guía actualizada se puede encontrar aquí: http://guides.rubyonrails.org/command_line.html#custom-rake-tasks
Un ans de copiar y pegar 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
Invocalo asi
bin/rake "task_name[value 1]" # entire argument string should be quoted
Las formas de pasar el argumento 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 rieles
Funcionará con rake "namespace: taskname [''argument1'']"
Tenga en cuenta las comillas invertidas en la ejecución de la tarea desde la línea de comandos.
Me gusta la sintaxis de "cadena de consulta" para el paso de argumentos, especialmente cuando hay muchos argumentos que deben pasarse.
Ejemplo:
rake "mytask[width=10&height=20]"
La "cadena de consulta" 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 de rake utilizando Rack::Utils.parse_nested_query
, obtenemos un Hash
:
=> {"width"=>"10", "height"=>"20"}
(Lo bueno es que puedes pasar hashes y matrices, más abajo)
Así es como 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]"
Se analizó de la misma manera que anteriormente, 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"}}
Mientras se pasan los parámetros, es mejor optar por un archivo de entrada, ¿puede ser esto un excel a json o lo que necesite y desde allí leer la estructura de datos y las variables que necesita, incluido el nombre de la variable, según sea necesario? 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
No pude 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/'']
Otra opción comúnmente utilizada es pasar las 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
Para pasar argumentos a la tarea predeterminada, puedes hacer algo como esto. Por ejemplo, decir "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 (predeterminado o compilación) al pasar los argumentos. Me encantaría escuchar si alguien sabe de alguna manera.
Puede especificar argumentos formales en rake agregando argumentos de símbolo a la llamada de 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 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 del objetivo son necesarias para evitar que el shell divida los argumentos en el espacio.
Al observar el código en rake.rb , parece que rake no analiza 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 de tarea dependiente, como en :invoke_my_task
y :invoke_my_task_2
.
Tenga en cuenta que algunos shells (como zsh) requieren que escape de los corchetes: rake my_task/[''arg1''/]
Si desea pasar argumentos con nombre (por ejemplo, con OptionParser
estándar) podría usar algo como esto:
$ rake user:create -- --user [email protected] --pass 123
tenga en cuenta que, eso es necesario para omitir los argumentos estándar de Rake. 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 haya pasado 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 se interpretarán como tareas de Rake.
También el atajo para argumentos debería funcionar:
rake user:create -- -u [email protected] -p 123
Cuando los scripts de rake se ven así, tal vez es hora de buscar otra herramienta que permita que esto salga de la caja.
Si no puedes molestarte en recordar cuál es la posición del argumento para qué y quieres hacer algo como un hash de argumento de rubí. Puede usar un argumento para pasar una cadena y luego regexar 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 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
Solo quería poder correr:
$ rake some:task arg1 arg2
Simple, ¿verdad? (¡No!)
Rake interpreta arg1
y arg2
como tareas e intenta ejecutarlas. Así que simplemente abortamos antes de que lo haga.
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 una mascota bastante pequeña. No está diseñado para uso en el "mundo real", ya que pierde la capacidad de encadenar tareas (es decir, rake task1 task2 task3
). OMI no vale la pena. Solo usa la rake task[arg1,arg2]
feo rake task[arg1,arg2]
.
Uso un argumento de ruby regular en el archivo de rastrillo:
DB = ARGV[1]
luego apago las tareas de rake en la parte inferior del archivo (ya que rake buscará una tarea basada en el nombre de ese argumento).
task :database_name1
task :database_name2
línea de comando:
rake mytask db_name
esto me parece más limpio que la var = foo ENV var y la tarea args [blah, blah2] solutions.
El código auxiliar es un poco jenky, pero no está tan mal si solo tiene algunos entornos que son una configuración de una sola vez
Las opciones y dependencias deben estar dentro de los arreglos:
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 / le interesen los internos de Rake.
NOTA DE RIELES:
Si ejecuta la tarea desde rieles, 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
desc ''an updated version''
task :task_name, [:arg1, :arg2] => [:dependency1, :dependency2] do |t, args|
puts args[:arg1]
end