Come passare gli argomenti della riga di comando a un'attività rake
-
05-07-2019 - |
Domanda
Ho un'attività rake che deve inserire un valore in più database.
Mi piacerebbe passare questo valore all'attività rake dalla riga di comando o da un altro compito di rastrello.
Come posso fare questo?
Soluzione
opzioni e dipendenze devono essere all'interno di array:
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
Poi
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 variabile
task
è l'oggetto dell'attività, non molto utile a meno che tu non sappia / ti interessi degli interni di Rake.
NOTA BINARIO:
Se si esegue l'attività dai binari, è meglio precaricare l'ambiente aggiungendo
=> [:environment]
che è un modo per impostare le attività dipendenti .
task :work, [:option, :foo, :bar] => [:environment] do |task, args|
puts "work", args
end
Altri suggerimenti
È possibile specificare argomenti formali nel rake aggiungendo argomenti simbolo alla chiamata attività. Ad esempio:
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
Quindi, dalla riga di 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"}
Come dimostrato nel secondo esempio, se si desidera utilizzare gli spazi, le virgolette attorno al nome di destinazione sono necessarie per impedire alla shell di dividere gli argomenti nello spazio.
Guardando il codice in rake.rb , sembra che rake non analizzi le stringhe di attività per estrarre argomenti per i prerequisiti, quindi non puoi fare task :t1 => "dep[1,2]"
. L'unico modo per specificare argomenti diversi per un prerequisito sarebbe invocarlo esplicitamente nell'azione dell'attività dipendente, come in :invoke_my_task
e :invoke_my_task_2
.
Nota che alcune shell (come zsh) richiedono di sfuggire alle parentesi: rake my_task\['arg1'\]
Oltre a rispondere di kch (non ho trovato il modo di lasciare un commento, scusa):
Non è necessario specificare le variabili come ENV
variabili prima del comando rake
. Puoi semplicemente impostarli come al solito parametri della riga di comando come questo:
rake mytask var=foo
e accedi a quelli dal tuo file rake come variabili ENV come queste:
p ENV['var'] # => "foo"
Se vuoi passare argomenti con nome (ad es. con standard OptionParser
) puoi usare qualcosa del genere:
$ rake user:create -- --user test@example.com --pass 123
osserva --
, che è necessario per bypassare gli argomenti standard di Rake. Dovrebbe funzionare con Rake 0.9.x , & Lt; = 10.3.x .
Il rake più recente ha modificato l'analisi di OptionParser#parse
e ora è necessario assicurarsi che non sia passato al metodo parser.parse!(ARGV[2..-1])
, ad esempio 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
<=> alla fine farà in modo che gli argomenti extra non vengano interpretati come attività Rake.
Anche il collegamento per gli argomenti dovrebbe funzionare:
rake user:create -- -u test@example.com -p 123
Quando gli script di rake sembrano così, forse è il momento di cercare un altro strumento che consenta questo appena pronto.
Ho trovato la risposta da questi due siti Web: Net Maniac e Aimred .
Devi avere la versione > 0,8 di rake per usare questa tecnica
La normale descrizione dell'attività del rake è questa:
desc 'Task Description'
task :task_name => [:depends_on_taskA, :depends_on_taskB] do
#interesting things
end
Per passare argomenti, fai tre cose:
- Aggiungi i nomi degli argomenti dopo il nome dell'attività, separati da virgole.
- Metti le dipendenze alla fine usando: needs = > [...]
- Posiziona | t, args | dopo il do. (t è l'oggetto per questa attività)
Per accedere agli argomenti nello script, utilizzare 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
Per chiamare questa attività dalla riga di comando, passagli gli argomenti in [] s
rake task_name['Hello',4]
verrà emesso
Hello
Hello
Hello
Hello
e se si desidera chiamare questa attività da un'altra attività e passare argomenti, utilizzare invoke
task :caller do
puts 'In Caller'
Rake::Task[:task_name].invoke('hi',2)
end
quindi il comando
rake caller
verrà emesso
In Caller
hi
hi
Non ho trovato il modo di passare argomenti come parte di una dipendenza, poiché il seguente codice si rompe:
task :caller => :task_name['hi',2]' do
puts 'In Caller'
end
Un'altra opzione comunemente usata è passare variabili d'ambiente. Nel tuo codice li leggi tramite ENV['VAR']
e puoi passarli subito prima del comando rake
, come
$ VAR=foo rake mytask
In realtà @Nick Desjardins ha risposto perfettamente. Ma solo per l'istruzione: puoi usare un approccio sporco: usando ENV
argomento
task :my_task do
myvar = ENV['myvar']
puts "myvar: #{myvar}"
end
rake my_task myvar=10
#=> myvar: 10
Non sono riuscito a capire come superare args e anche l'ambiente: fino a quando non ho capito:
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
E poi chiamo così:
rake db:export['foo, /tmp/']
desc 'an updated version'
task :task_name, [:arg1, :arg2] => [:dependency1, :dependency2] do |t, args|
puts args[:arg1]
end
Volevo solo essere in grado di eseguire:
$ rake some:task arg1 arg2
Semplice, vero? (No!)
Rake interpreta arg1
e arg2
come attività e tenta di eseguirle. Quindi interrompiamo prima di farlo.
namespace :some do
task task: :environment do
arg1, arg2 = ARGV
# your task...
exit
end
end
Prendi questo, parentesi!
Disclaimer : volevo essere in grado di farlo in un progetto piuttosto piccolo per animali domestici. Non inteso per & Quot; mondo reale & Quot; utilizzo poiché perdi la possibilità di concatenare attività di rastrellamento (ad es. rake task1 task2 task3
). IMO non ne vale la pena. Usa il brutto rake task[arg1,arg2]
.
Utilizzo un normale argomento ruby nel file rake:
DB = ARGV[1]
quindi elimino le attività rake nella parte inferiore del file (poiché rake cercherà un'attività in base a quel nome di argomento).
task :database_name1
task :database_name2
riga di comando:
rake mytask db_name
questo mi sembra più pulito delle soluzioni var=foo ENV var e task args[blah, blah2].
lo stub è un po' traballante, ma non troppo male se hai solo alcuni ambienti che sono una configurazione una tantum
I modi per passare l'argomento sono corretti nella risposta sopra. Tuttavia, per eseguire attività rake con argomenti, c'è un piccolo tecnicismo coinvolto nella versione più recente delle rotaie
Funzionerà con rake " namespace: taskname ['argomento1'] "
Nota le virgolette invertite nell'esecuzione dell'attività dalla riga di comando.
Mi piace il " querystring " sintassi per il passaggio degli argomenti, soprattutto quando ci sono molti argomenti da passare.
Esempio:
rake "mytask[width=10&height=20]"
Il " querystring " essere:
width=10&height=20
Avviso: nota che la sintassi è rake "mytask[foo=bar]"
e NON rake mytask["foo=bar"]
Quando analizzato all'interno dell'attività di rake usando Rack::Utils.parse_nested_query
, otteniamo un Hash
:
=> {"width"=>"10", "height"=>"20"}
(Il bello è che puoi passare hash e array, più sotto)
Ecco come raggiungere questo obiettivo:
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
Ecco un esempio più esteso che sto usando con Rails nella mia delayed_job_active_record_threaded gem:
bundle exec rake "dj:start[ebooks[workers_number]=16&ebooks[worker_timeout]=60&albums[workers_number]=32&albums[worker_timeout]=120]"
Analizzato come sopra, con una dipendenza dall'ambiente (per caricare l'ambiente 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
Fornisce quanto segue in options
=> {"ebooks"=>{"workers_number"=>"16", "worker_timeout"=>"60"}, "albums"=>{"workers_number"=>"32", "worker_timeout"=>"120"}}
Per passare argomenti all'attività predefinita, puoi fare qualcosa del genere. Ad esempio, diciamo & Quot; & Versione quot; è il tuo argomento:
task :default, [:version] => [:build]
task :build, :version do |t,args|
version = args[:version]
puts version ? "version is #{version}" : "no version passed"
end
Quindi puoi chiamarlo così:
$ 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
Tuttavia, non ho trovato un modo per evitare di specificare il nome dell'attività (impostazione predefinita o build) durante il passaggio degli argomenti. Mi piacerebbe sapere se qualcuno conosce un modo.
La maggior parte dei metodi sopra descritti non ha funzionato per me, forse sono deprecati nelle versioni più recenti. La guida aggiornata è disponibile qui: http: //guides.rubyonrails .org / command_line.html # custom-rake-task
un copia-e-incolla ans dalla guida è qui:
task :task_name, [:arg_1] => [:pre_1, :pre_2] do |t, args|
# You can use args from here
end
Invocalo in questo modo
bin/rake "task_name[value 1]" # entire argument string should be quoted
Se non puoi essere disturbato a ricordare quale posizione dell'argomento è per cosa e vuoi fare qualcosa come un hash dell'argomento ruby. È possibile utilizzare un argomento per passare una stringa e quindi regexare quella stringa in un hash di opzioni.
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
E dalla riga di comando si ottiene.
$ 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
Per eseguire attività rake con lo stile degli argomenti tradizionali:
rake task arg1 arg2
E poi usa:
task :task do |_, args|
puts "This is argument 1: #{args.first}"
end
Aggiungi la seguente patch di rake gem:
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
Mentre si passano i parametri, è meglio l'opzione è un file di input, può essere un eccellente json o qualunque cosa tu abbia bisogno e da lì leggere la struttura dei dati e le variabili di cui hai bisogno tra cui il nome della variabile come è necessario. Per leggere un file può avere la seguente struttura.
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
Esempio json
{
"name_task": "I'm a task",
"user_id": 389,
"users_assigned": [389,672,524],
"task_id": 3
}
Esecuzione
rake :name_task