Como passar argumentos de linha de comando para uma tarefa rake
-
05-07-2019 - |
Pergunta
Eu tenho uma tarefa rake que precisa inserir um valor em vários bancos de dados.
Eu gostaria de passar esse valor na tarefa rake a partir da linha de comando, ou a partir de outro tarefa rake.
Como posso fazer isso?
Solução
opções e dependências preciso estar dentro de matrizes:
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
Em seguida
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: variable
task
é o objeto tarefa, não muito útil se você não sabe / cuidado sobre o funcionamento interno do ancinho.
TRILHOS NOTA:
Se você estiver executando a tarefa de trilhos, o seu melhor para pré-carregar o ambiente, adicionando
=> [:environment]
que é uma maneira de configurar dependentes tarefas.
task :work, [:option, :foo, :bar] => [:environment] do |task, args|
puts "work", args
end
Outras dicas
Você pode especificar argumentos formais em rake, acrescentando argumentos símbolo para a chamada de tarefa. Por exemplo:
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
Em seguida, a partir da linha 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 demonstrado no segundo exemplo, se você quiser utilizar espaços, as aspas em torno do nome de destino são necessárias para manter a casca de dividir os argumentos no espaço.
Olhando para o código em rake.rb , parece que ancinho não analisa seqüências de tarefas para argumentos Extrato de pré-requisitos, então você não pode fazer task :t1 => "dep[1,2]"
. A única maneira de especificar diferentes argumentos para um pré-requisito seria para invocá-lo explicitamente no âmbito da acção tarefa dependente, como em :invoke_my_task
e :invoke_my_task_2
.
Note que algumas conchas (como zsh) exigem que você escapar do parêntesis: rake my_task\['arg1'\]
Além de resposta por kch (eu não veja como deixe um comentário para que, sorry):
Você não tem que especificar variáveis ??como variáveis ??ENV
antes do comando rake
. Você pode apenas configurá-los como parâmetros habituais de linha de comando como o seguinte:
rake mytask var=foo
e acesso aqueles de seu arquivo ancinho como variáveis ??ENV como tal:
p ENV['var'] # => "foo"
Se você quer passar argumentos nomeados (por exemplo, com OptionParser
padrão), você pode usar algo como isto:
$ rake user:create -- --user test@example.com --pass 123
observe o --
, o que é necessário para contornar argumentos Rake padrão. Deve trabalhar com Rake 0.9.x , <= 10.3.x .
recente Rake mudou sua análise de --
, e agora você tem que ter certeza que não é passado para o método OptionParser#parse
, por exemplo, com 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
no final irá certificar-se que os argumentos extras não será interpretado como tarefa Rake.
Além disso, o atalho para argumentos deve funcionar:
rake user:create -- -u test@example.com -p 123
Quando os scripts de rake parecido com este, talvez seja hora de olhar para outra ferramenta que permitiria que este apenas fora da caixa.
Eu encontrei a resposta destes dois sites: Maniac Net e Aimred .
Você precisa ter versão> 0.8 de rake para usar esta técnica
A descrição normal de tarefa rake é o seguinte:
desc 'Task Description'
task :task_name => [:depends_on_taskA, :depends_on_taskB] do
#interesting things
end
Para passar argumentos, fazer três coisas:
- Adicione os nomes de argumentos depois do nome da tarefa, separados por vírgulas.
- Coloque as dependências no final usando: necessidades => [...]
- Coloque | t, args | após o tumulto. (T é o objeto para esta tarefa)
Para acessar os argumentos no script, o uso 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 chamar esta tarefa a partir da linha de comando, passe-os argumentos em [] s
rake task_name['Hello',4]
saída vontade
Hello
Hello
Hello
Hello
e se você quiser chamar esta tarefa a partir de uma outra tarefa, e passá-lo argumentos, o uso de invocação
task :caller do
puts 'In Caller'
Rake::Task[:task_name].invoke('hi',2)
end
então o comando
rake caller
saída vontade
In Caller
hi
hi
Eu não encontrei uma maneira de passar argumentos como parte de uma dependência, como as quebras de código a seguir:
task :caller => :task_name['hi',2]' do
puts 'In Caller'
end
Outra opção é comumente usado para passar variáveis ??de ambiente. Em seu código você lê-los via ENV['VAR']
, e pode passá-los para a direita antes do comando rake
, como
$ VAR=foo rake mytask
Na verdade @ Nick Desjardins respondeu perfeito. Mas só para a educação: você pode usar abordagem suja: usando argumento ENV
task :my_task do
myvar = ENV['myvar']
puts "myvar: #{myvar}"
end
rake my_task myvar=10
#=> myvar: 10
Eu não conseguia descobrir como passar args e também a: ambiente até que eu trabalhei isso:
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 então eu chamo assim:
rake db:export['foo, /tmp/']
desc 'an updated version'
task :task_name, [:arg1, :arg2] => [:dependency1, :dependency2] do |t, args|
puts args[:arg1]
end
Eu só queria ser capaz de executar:
$ rake some:task arg1 arg2
Simples, certo? (Não!)
interpreta Rake arg1
e arg2
como tarefas, e tenta executá-los. Então, nós apenas abortar antes que ele faz.
namespace :some do
task task: :environment do
arg1, arg2 = ARGV
# your task...
exit
end
end
Tome isso, suportes!
Aviso : eu queria ser capaz de fazer isso em um muito pequeno projeto de estimação. Não se destina para uso "mundo real", uma vez que você perde a capacidade de tarefas rake cadeia (ou seja rake task1 task2 task3
). IMO não vale a pena. Basta usar o rake task[arg1,arg2]
feio.
Eu uso um argumento regulares ruby ??no arquivo ancinho:
DB = ARGV[1]
então eu stub as tarefas rake na parte inferior do arquivo (desde ancinho vai olhar para uma tarefa com base nesse nome do argumento).
task :database_name1
task :database_name2
linha de comando:
rake mytask db_name
este se sente mais limpo para mim do que a var = var foo ENV e os argumentos de tarefas [blah, blah2] soluções.
o stub é um pouco Jenky, mas não muito ruim se você só tem alguns ambientes que são uma configuração única
As formas de passar argumento está correto em resposta acima. No entanto, para executar tarefa rake com argumentos, há um pequeno detalhe técnico envolvido na versão mais recente do rails
Ele vai trabalhar com o ancinho "namespace: taskname [ 'argument1']"
Observe as aspas invertidas em executar a tarefa a partir da linha de comando.
Eu gosto da sintaxe "querystring" para a passagem argumento, especialmente quando há um monte de argumentos a serem passados.
Exemplo:
rake "mytask[width=10&height=20]"
O "querystring" ser:
width=10&height=20
Aviso: Note que a sintaxe é rake "mytask[foo=bar]"
e não rake mytask["foo=bar"]
Quando analisado dentro da tarefa rake usando Rack::Utils.parse_nested_query
, temos um Hash
:
=> {"width"=>"10", "height"=>"20"}
(O legal é que você pode passar hashes e arrays, mais abaixo)
Este é como conseguir isso:
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
Aqui está um exemplo mais prolongado que eu estou usando com Rails na minha 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]"
Parsed da mesma maneira como acima, com uma dependência ambiente (na ordem de carga do ambiente trilhos)
namespace :dj do
task :start, [ :args_expr ] => :environment do |t, args|
# defaults here...
options = Rack::Utils.parse_nested_query(args[:args_expr])
end
end
profere o presente em options
=> {"ebooks"=>{"workers_number"=>"16", "worker_timeout"=>"60"}, "albums"=>{"workers_number"=>"32", "worker_timeout"=>"120"}}
Para passar argumentos para a tarefa padrão, você pode fazer algo como isto. Por exemplo, digamos "Versão" é o seu argumento:
task :default, [:version] => [:build]
task :build, :version do |t,args|
version = args[:version]
puts version ? "version is #{version}" : "no version passed"
end
Em seguida, você pode chamá-lo assim:
$ rake
no version passed
ou
$ rake default[3.2.1]
version is 3.2.1
ou
$ rake build[3.2.1]
version is 3.2.1
No entanto, eu não encontrei uma maneira de evitar especificando o nome da tarefa (padrão ou de construção), enquanto passando em argumentos. Gostaria de saber se alguém sabe de uma maneira.
A maioria dos métodos descritos acima não funcionou para mim, talvez eles são preteridos nas versões mais recentes. O guia de up-to-date pode ser encontrada aqui: http: //guides.rubyonrails .org / command_line.html # costume-ancinho-tarefas
a copiar-e-colar ans do guia está aqui:
task :task_name, [:arg_1] => [:pre_1, :pre_2] do |t, args|
# You can use args from here
end
invocá-lo como este
bin/rake "task_name[value 1]" # entire argument string should be quoted
Se você não pode ser incomodado para lembrar que posição argumento é para o que e você quer fazer algo como um hash argumento rubi. Você pode usar um argumento para passar uma cadeia e, em seguida, regex que string em um hash de opções.
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 na linha de comando que você começa.
$ 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 executar tarefas rake com estilo argumentos tradicionais:
rake task arg1 arg2
E, em seguida, use:
task :task do |_, args|
puts "This is argument 1: #{args.first}"
end
Adicionar seguinte patch de gem ancinho:
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
Ao passar parâmetros, é melhor opção é um arquivo de entrada, isso pode ser um excel um JSON ou o que você precisa e de lá ler a estrutura de dados e variáveis ??que você precisa de que a inclusão do nome da variável como é a necessidade. Para ler um arquivo pode ter a seguinte estrutura.
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
Exemplo json
{
"name_task": "I'm a task",
"user_id": 389,
"users_assigned": [389,672,524],
"task_id": 3
}
Execução
rake :name_task