ruby command-line rake command-line-arguments

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:

  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 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