Cómo pasar argumentos de línea de comandos para una tarea rake
-
05-07-2019 - |
Pregunta
Tengo una tarea de rake que necesita para insertar un valor en múltiples bases de datos.
Me gustaría pasar este valor en la tarea de rake desde la línea de comandos, o desde otro tarea de rake.
¿Cómo puedo hacer esto?
Solución
opciones y 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 variable
task
es el objeto de la tarea, no es muy útil a menos que conozca / se preocupe por las partes internas de Rake.
NOTA DE RAILS:
Si ejecuta la tarea desde rieles, es mejor 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
Otros consejos
Puede especificar argumentos formales en el rastrillo por la adición de símbolo argumentos a la tarea de llamar.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
Entonces, 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 muestra en el segundo ejemplo, si desea utilizar los espacios, las comillas alrededor del nombre de destino son necesarios para mantener la concha de la división de seguridad de los argumentos en el espacio.
Mirando el código en de rake.rb, parece que el rake no analiza tarea cadenas para extraer argumentos para requisitos previos, por lo que no puede hacer task :t1 => "dep[1,2]"
.La única manera de especificar diferentes argumentos para un requisito previo sería invoca explícitamente dentro de la dependiente de la acción de la tarea, como en :invoke_my_task
y :invoke_my_task_2
.
Tenga en cuenta que algunas de las conchas (como zsh) requieren que escapar de los corchetes: rake my_task\['arg1'\]
Además de responder por kch (no encontré cómo dejar un comentario a eso, lo siento):
No tiene que especificar variables como ENV
variables antes del comando rake
. Simplemente puede configurarlos como parámetros de línea de comandos habituales como ese:
rake mytask var=foo
y acceda a ellos desde su archivo rake como variables ENV como tales:
p ENV['var'] # => "foo"
Si desea pasar argumentos con nombre (por ejemplo, con el estándar OptionParser
) puede usar algo como esto:
$ rake user:create -- --user test@example.com --pass 123
tenga en cuenta --
, eso es necesario para omitir los argumentos estándar de Rake. Debería funcionar con Rake 0.9.x , & Lt; = 10.3.x .
Newer Rake ha cambiado su análisis de OptionParser#parse
, y ahora debe asegurarse de que no se pasa al método parser.parse!(ARGV[2..-1])
, por ejemplo con exit
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
<=> al final se asegurará de que los argumentos adicionales no se interpreten como tarea Rake.
También el atajo para argumentos debería funcionar:
rake user:create -- -u test@example.com -p 123
Cuando los scripts de rastrillo se ven así, tal vez sea hora de buscar otra herramienta que permita esto de forma inmediata.
He encontrado la respuesta de estos dos sitios web: Net Maniac y Aimred .
Necesita tener la versión > 0.8 de rastrillo para usar esta técnica
La descripción normal de la tarea de rastrillo es esta:
desc 'Task Description'
task :task_name => [:depends_on_taskA, :depends_on_taskB] do
#interesting things
end
Para pasar argumentos, haga 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 de 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]
generará
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
luego el comando
rake caller
generará
In Caller
hi
hi
No he encontrado una manera 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 de uso común es pasar variables de entorno. En su código, los lee a través de ENV['VAR']
, y puede pasarlos justo antes del comando rake
, como
$ VAR=foo rake mytask
En realidad, @Nick Desjardins respondió perfecto. Pero solo para la educación: puede usar un enfoque sucio: usar ENV
argumento
task :my_task do
myvar = ENV['myvar']
puts "myvar: #{myvar}"
end
rake my_task myvar=10
#=> myvar: 10
No pude entender 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
Yo sólo quería ser capaz de ejecutar:
$ rake some:task arg1 arg2
Sencillo, ¿verdad?(No!)
Rake interpreta arg1
y arg2
como tareas, y trata de ejecutar.Así que acaba de abortar antes de que suceda.
namespace :some do
task task: :environment do
arg1, arg2 = ARGV
# your task...
exit
end
end
Tomar que, entre paréntesis!
Descargo de responsabilidad:Yo quería ser capaz de hacer esto en una hermosa pequeña mascota del proyecto.No destinados al "mundo real" de uso ya que se pierde la capacidad de de la cadena de tareas rake (es decir, rake task1 task2 task3
).IMO no vale la pena.Sólo uso el feo rake task[arg1,arg2]
.
Yo uso regular de ruby argumento en el rastrillo de archivo:
DB = ARGV[1]
entonces yo punta de el rastrillo de tareas en la parte inferior del archivo (desde rake buscará una tarea basada en el argumento nombre).
task :database_name1
task :database_name2
línea de comandos:
rake mytask db_name
esto se siente más limpio para mí que el var=foo ENV var y la tarea args[bla, blah2] las soluciones.
la punta es un poco jenky, pero no demasiado malo si sólo tienes un par de ambientes que son de un solo tiempo de instalación
Las formas de pasar el argumento son correctas en la respuesta anterior. Sin embargo, para ejecutar la tarea de rastrillo con argumentos, hay un pequeño tecnicismo involucrado en la versión más nueva de los rieles
Funcionará con rake " namespace: taskname ['argumento1'] "
Tenga en cuenta las comillas invertidas al ejecutar la tarea desde la línea de comandos.
Me gusta la "cadena" de la sintaxis de un argumento que pasa, especialmente cuando hay una gran cantidad de argumentos que se pasan.
Ejemplo:
rake "mytask[width=10&height=20]"
La "cadena ser":
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 el uso de Rack::Utils.parse_nested_query
obtenemos una Hash
:
=> {"width"=>"10", "height"=>"20"}
(Lo bueno es que se puede pasar de hashes y matrices, más abajo)
Esta es la manera 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
He aquí una más extendida ejemplo que estoy usando con Rieles en mi delayed_job_active_record_threaded gema:
bundle exec rake "dj:start[ebooks[workers_number]=16&ebooks[worker_timeout]=60&albums[workers_number]=32&albums[worker_timeout]=120]"
Se analiza de la misma forma que anteriormente, con un ambiente de dependencia (en orden de cargar el entorno de 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 el 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 (predeterminado o compilación) al pasar argumentos. Me encantaría saber si alguien sabe de alguna manera.
La mayoría de los métodos descritos anteriormente no funcionaron para mí, 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-tareas
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
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 rubí. Puede usar un argumento para pasar una cadena y luego volver a expresar 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 que 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
Para ejecutar tareas de rastrillo con estilo de argumentos tradicionales:
rake task arg1 arg2
Y luego usa:
task :task do |_, args|
puts "This is argument 1: #{args.first}"
end
Agregue el siguiente parche de gema de rastrillo:
Rake::Application.class_eval do
alias origin_top_level top_level
def top_level
@top_level_tasks = [top_level_tasks.join(' ')]
origin_top_level
end
def parse_task_string(string) # :nodoc:
parts = string.split ' '
return parts.shift, parts
end
end
Rake::Task.class_eval do
def invoke(*args)
invoke_with_call_chain(args, Rake::InvocationChain::EMPTY)
end
end
Al pasar los parámetros, es mejor que la opción sea un archivo de entrada, puede ser un excel a json o lo que sea que necesite y, a partir de ahí, lea 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