J'ai une tâche de râteau qui doit insérer une valeur dans plusieurs bases de données.
Je voudrais passer cette valeur dans la tâche de râteau à partir de la ligne de commande ou d' une autre tâche de râteau.
Comment puis-je faire ceci?
J'ai une tâche de râteau qui doit insérer une valeur dans plusieurs bases de données.
Je voudrais passer cette valeur dans la tâche de râteau à partir de la ligne de commande ou d' une autre tâche de râteau.
Comment puis-je faire ceci?
Réponses:
les options et les dépendances doivent être à l'intérieur des tableaux:
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
alors
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"}
REMARQUE: la variable
task
est l'objet de tâche, pas très utile à moins que vous ne connaissiez / vous souciez des internes de Rake.
NOTE SUR LES RAILS:
Si vous exécutez la tâche à partir de rails, il est préférable de précharger l'environnement en ajoutant
=> [:environment]
un moyen de configurer les tâches dépendantes .
task :work, [:option, :foo, :bar] => [:environment] do |task, args|
puts "work", args
end
rake thing:work[1, 2, 3]
car cela ne fonctionnera pas et vous obtiendrez une erreurDon't know how to build task
rake thing:work'[1,2,3]'
rake thing:work\[1,2,3\]
rake 'thing:work[1,2,3]'
:environment
symbole de votre tâche. les applications de rails ont une tâche d'environnement ...
t
signifie task
, pourquoi ne pas simplement utiliser task
comme nom de paramètre?
Vous pouvez spécifier des arguments formels dans rake en ajoutant des arguments de symbole à l'appel de tâche. Par exemple:
require 'rake'
task :my_task, [:arg1, :arg2] do |t, args|
puts "Args were: #{args} of class #{args.class}"
puts "arg1 was: '#{args[:arg1]}' of class #{args[:arg1].class}"
puts "arg2 was: '#{args[:arg2]}' of class #{args[:arg2].class}"
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
Ensuite, à partir de la ligne de commande:
> ratisser ma_tâche [1, faux] Les arguments étaient: {: arg1 => "1",: arg2 => "false"} de la classe Rake :: TaskArguments arg1 était: '1' de la classe String arg2 était: 'faux' de la classe String > ratisser "ma_tâche [1, 2]" Les arguments étaient: {: arg1 => "1",: arg2 => "2"} > râteau invoke_my_task Les arguments étaient: {: arg1 => "1",: arg2 => "2"} > râteau invoke_my_task_2 Les arguments étaient: {: arg1 => 3,: arg2 => 4} > ratisser avec_préalable [5,6] Les arguments étaient: {: arg1 => "5",: arg2 => "6"} > ratisser with_defaults Les arguments avec des valeurs par défaut étaient: {: arg1 =>: default_1,: arg2 =>: default_2} > ratisser avec_defaults ['x', 'y'] Les arguments avec des valeurs par défaut étaient: {: arg1 => "x",: arg2 => "y"}
Comme illustré dans le deuxième exemple, si vous souhaitez utiliser des espaces, les guillemets autour du nom cible sont nécessaires pour empêcher le shell de fractionner les arguments dans l'espace.
En regardant le code dans rake.rb , il semble que rake n'analyse pas les chaînes de tâches pour extraire les arguments des conditions préalables, vous ne pouvez donc pas le faire task :t1 => "dep[1,2]"
. La seule façon de spécifier différents arguments pour une condition préalable serait de l'invoquer explicitement dans l'action de tâche dépendante, comme dans :invoke_my_task
et :invoke_my_task_2
.
Notez que certains shells (comme zsh) nécessitent que vous échappiez aux crochets: rake my_task\['arg1'\]
WARNING: 'task :t, arg, :needs => [deps]' is deprecated. Please use 'task :t, [args] => [deps]' instead.
zsh: no matches found: ...
), de sorte que vous devez échapper aux crochets: rake my_task\['arg1'\]
. De robots.thoughtbot.com/post/18129303042/…
En plus de répondre par kch (je n'ai pas trouvé comment laisser un commentaire à ça, désolé):
Vous n'avez pas besoin de spécifier des variables en tant que ENV
variables avant la rake
commande. Vous pouvez simplement les définir comme des paramètres de ligne de commande habituels comme ça:
rake mytask var=foo
et accédez à celles de votre fichier rake en tant que variables ENV comme celles-ci:
p ENV['var'] # => "foo"
p
signifie exactement ?
Si vous voulez passer des arguments nommés (par exemple avec standard OptionParser
), vous pouvez utiliser quelque chose comme ceci:
$ rake user:create -- --user test@example.com --pass 123
notez le --
, qui est nécessaire pour contourner les arguments Rake standard. Devrait fonctionner avec Rake 0.9.x , <= 10.3.x .
Newer Rake a changé son analyse de --
, et maintenant vous devez vous assurer qu'il n'est pas passé à la OptionParser#parse
méthode, par exemple avecparser.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
à la fin s'assurera que les arguments supplémentaires ne seront pas interprétés comme une tâche Rake.
Le raccourci pour les arguments devrait également fonctionner:
rake user:create -- -u test@example.com -p 123
Lorsque les scripts de rake ressemblent à ceci, il est peut-être temps de chercher un autre outil qui permettrait cela tout de suite.
--option-names
. Ma seule suggestion serait d'utiliser exit
plutôt que abort
de abort
vous laisser avec un code retour de 1 au shell. Si la tâche de râteau fait partie d'un script de niveau supérieur, il est plus courant de supposer qu'une sortie non nulle est un type d'erreur.
--
? Comme passer des rake
arguments à la tâche réelle ou quelque chose? Comme task :my_task, :*args do |t, args|
ou quelque chose?
{username}
ça sert. Où est-il utilisé? Pourquoi n'est-il pas là -u {username}
? Santé
10.4.1
et rétablie 10.4.2
. github.com/ruby/rake/commit/…
J'ai trouvé la réponse sur ces deux sites: Net Maniac et Aimred .
Vous devez avoir la version> 0.8 de rake pour utiliser cette technique
La description de la tâche de râteau normale est la suivante:
desc 'Task Description'
task :task_name => [:depends_on_taskA, :depends_on_taskB] do
#interesting things
end
Pour passer des arguments, faites trois choses:
Pour accéder aux arguments du script, utilisez 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
Pour appeler cette tâche à partir de la ligne de commande, passez-lui les arguments dans [] s
rake task_name['Hello',4]
affichera
Hello
Hello
Hello
Hello
et si vous voulez appeler cette tâche à partir d'une autre tâche et lui passer des arguments, utilisez invoke
task :caller do
puts 'In Caller'
Rake::Task[:task_name].invoke('hi',2)
end
puis la commande
rake caller
affichera
In Caller
hi
hi
Je n'ai pas trouvé de moyen de passer des arguments dans le cadre d'une dépendance, car le code suivant se casse:
task :caller => :task_name['hi',2]' do
puts 'In Caller'
end
'task :t, arg, :needs => [deps]' is deprecated. Please use 'task :t, [args] => [deps]' instead.
Une autre option couramment utilisée consiste à transmettre des variables d'environnement. Dans votre code, vous les lisez via ENV['VAR']
et pouvez les transmettre juste avant la rake
commande, comme
$ VAR=foo rake mytask
rake blah -- --these --go --to --a-program
(notez le --
pour indiquer à rake que ses commutateurs sont terminés), voir stackoverflow.com/questions/5086224/…
Je ne pouvais pas comprendre comment passer les arguments et aussi l'environnement: jusqu'à ce que je résolve ceci:
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
Et puis j'appelle comme ça:
rake db:export['foo, /tmp/']
desc 'an updated version'
task :task_name, [:arg1, :arg2] => [:dependency1, :dependency2] do |t, args|
puts args[:arg1]
end
rake task_name[hello, world]
Je voulais juste pouvoir courir:
$ rake some:task arg1 arg2
C'est simple, non? (Nan!)
Rake interprète arg1
et en arg2
tant que tâches et essaie de les exécuter. Nous avortons donc juste avant.
namespace :some do
task task: :environment do
arg1, arg2 = ARGV
# your task...
exit
end
end
Prenez ça, crochets!
Avertissement : je voulais pouvoir le faire dans un joli petit projet pour animaux de compagnie. Non destiné à un usage «réel» car vous perdez la capacité de chaîner des tâches de râteau (c. rake task1 task2 task3
-à-d.). L'OMI n'en vaut pas la peine. Utilisez simplement le laid rake task[arg1,arg2]
.
_, arg1, arg2 = ARGV
car le premier argument était considéré comme le nom de la tâche de râteau. Mais c'est exit
une astuce intéressante.
rake task[arg1,arg2] && rake task2 && rake task3
Je ne sais pas si c'est moins moche que rake task[arg1,arg2] task2 task3
. Probablement moins efficace cependant.
_, *args = ARGV
est parfait pour capturer tous les arguments suivants! Merci des tas!
J'utilise un argument ruby régulier dans le fichier rake:
DB = ARGV[1]
puis je stub sur les tâches de râteau au bas du fichier (puisque râteau cherchera une tâche basée sur ce nom d'argument).
task :database_name1
task :database_name2
ligne de commande:
rake mytask db_name
cela me semble plus propre que le var = foo ENV var et la tâche args [blah, blah2] solutions.
le talon est un peu jenky, mais pas trop mal si vous n'avez que quelques environnements qui sont une configuration unique
dup
à la fin: db = ARGV [1] .dup
db = ARGV[1].dup unless ARGV[1].nil?
pour éviter l'exception de duper un néant.
Les façons de passer l'argument sont correctes dans la réponse ci-dessus. Cependant, pour exécuter la tâche de râteau avec des arguments, une petite technicité est impliquée dans la nouvelle version des rails
Cela fonctionnera avec le rake "namespace: taskname ['argument1']"
Notez les guillemets inversés lors de l'exécution de la tâche à partir de la ligne de commande.
Pour passer des arguments à la tâche par défaut, vous pouvez faire quelque chose comme ça. Par exemple, dites "version" est votre argument:
task :default, [:version] => [:build]
task :build, :version do |t,args|
version = args[:version]
puts version ? "version is #{version}" : "no version passed"
end
Ensuite, vous pouvez l'appeler ainsi:
$ 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
Cependant, je n'ai pas trouvé de moyen d'éviter de spécifier le nom de la tâche (par défaut ou build) en passant des arguments. J'adorerais entendre si quelqu'un connaît un moyen.
J'aime la syntaxe "querystring" pour le passage d'arguments, surtout quand il y a beaucoup d'arguments à passer.
Exemple:
rake "mytask[width=10&height=20]"
La "chaîne de requête" étant:
width=10&height=20
Attention: notez que la syntaxe est rake "mytask[foo=bar]"
et NON rake mytask["foo=bar"]
Une fois analysé à l'intérieur de la tâche de râteau en utilisant Rack::Utils.parse_nested_query
, nous obtenons Hash
:
=> {"width"=>"10", "height"=>"20"}
(Ce qui est cool, c'est que vous pouvez passer des hachages et des tableaux, plus ci-dessous)
Voici comment y parvenir:
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
Voici un exemple plus étendu que j'utilise avec Rails dans ma gemme delay_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]"
Analysé de la même manière que ci-dessus, avec une dépendance à l'environnement (pour charger l'environnement 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
Donne ce qui suit dans options
=> {"ebooks"=>{"workers_number"=>"16", "worker_timeout"=>"60"}, "albums"=>{"workers_number"=>"32", "worker_timeout"=>"120"}}
Si vous ne pouvez pas vous soucier de savoir quelle position d'argument est pour quoi et que vous voulez faire quelque chose comme un hachage d'argument rubis. Vous pouvez utiliser un argument pour passer une chaîne, puis regex cette chaîne dans un hachage d'options.
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
Et sur la ligne de commande, vous obtenez.
$ 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
La plupart des méthodes décrites ci-dessus ne fonctionnaient pas pour moi, peut-être qu'elles sont obsolètes dans les versions plus récentes. Le guide à jour peut être trouvé ici: http://guides.rubyonrails.org/command_line.html#custom-rake-tasks
un copier-coller ans du guide est ici:
task :task_name, [:arg_1] => [:pre_1, :pre_2] do |t, args|
# You can use args from here
end
Invoquez-le comme ça
bin/rake "task_name[value 1]" # entire argument string should be quoted
Pour exécuter des tâches de râteau avec un style d'arguments traditionnel:
rake task arg1 arg2
Et puis utilisez:
task :task do |_, args|
puts "This is argument 1: #{args.first}"
end
Ajoutez le patch suivant de 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
En passant des paramètres, il est préférable que l'option soit un fichier d'entrée, peut-il être un excel un json ou tout ce dont vous avez besoin et à partir de là, lisez la structure de données et les variables dont vous avez besoin, y compris le nom de la variable selon les besoins. Pour lire un fichier peut avoir la structure suivante.
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
{
"name_task": "I'm a task",
"user_id": 389,
"users_assigned": [389,672,524],
"task_id": 3
}
rake :name_task