web-dev-qa-db-fra.com

Comment passer des arguments de ligne de commande à une tâche rake

J'ai une tâche de rake qui doit insérer une valeur dans plusieurs bases de données. 

J'aimerais transmettre cette valeur à la tâche rake à partir de la ligne de commande ou de autre tâche rake.

Comment puis-je faire ceci?

998
Tilendor

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

Ensuite

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 la tâche, elle n’est pas très utile si vous ne connaissez pas les soins internes de Rake. 

Rails NOTE:

Si vous exécutez la tâche à partir de Rails, il est préférable de précharger l'environnement en ajoutant => [:environment], qui permet de configurer les tâches dependantes

  task :work, [:option, :foo, :bar] => [:environment] do |task, args|
    puts "work", args
  end
282
Blair Anderson

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}"
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:

> rake my_task [1,2] 
 Les args étaient: {: arg1 => "1",: arg2 => "2"} 

> rake "mon_task [1, 2]" 
 Args étaient: {: arg1 => "1",: arg2 => "2"} 

> Rake invoke_my_task 
 Args était: {: arg1 => "1",: arg2 = > "2"} 

> Rake invoke_my_task_2 
 Les args étaient: {: arg1 => 3,: arg2 => 4} 

> Rake avec_prerequisite [5,6] 
 Les args étaient: {: arg1 => "5",: arg2 => "6"} 

> Rake with_defaults 
 Les args avec des valeurs par défaut étaient: {: arg1 =>: default_1,: arg2 =>: default_2} 

> rake with_defaults ['x', 'y'] 
 Les arguments par défaut étaient les suivants: {: arg1 => "x",: arg2 => "y"} 

Comme illustré dans le deuxième exemple, si vous souhaitez utiliser des espaces, les guillemets autour du nom de la cible sont nécessaires pour empêcher le shell de fractionner les arguments au niveau de l'espace.

En regardant le code dans rake.rb , il apparaît que rake n'analyse pas les chaînes de tâches pour extraire les arguments des conditions préalables. Vous ne pouvez donc pas utiliser task :t1 => "dep[1,2]". La seule façon de spécifier différents arguments pour un prérequis 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) vous obligent à échapper aux crochets: rake my_task\['arg1'\]

1095
Nick Desjardins

En plus de répondre par kch (désolé, je n'ai pas trouvé comment commenter cela):

Il n'est pas nécessaire de spécifier des variables en tant que variables ENV avant la commande rake. Vous pouvez simplement les définir comme paramètres de ligne de commande habituels, comme ceci:

rake mytask var=foo

et accédez à ceux de votre fichier rake en tant que variables ENV telles que:

p ENV['var'] # => "foo"
307
timurb

Si vous voulez passer des arguments nommés (par exemple avec la variable standard OptionParser), vous pouvez utiliser quelque chose comme ceci:

$ rake user:create -- --user [email protected] --pass 123

notez le --, nécessaire pour ignorer les arguments standard de Rake. Devrait fonctionner avec Rake 0.9.x , <= 10.3.x .

Newer Rake a changé son analyse de --, et vous devez maintenant vous assurer que cela n'est pas passé à la méthode OptionParser#parse, par exemple avec 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 à la fin assurera que les arguments supplémentaires ne seront pas interprétés comme une tâche Rake. 

De plus, le raccourci pour les arguments devrait fonctionner:

 rake user:create -- -u [email protected] -p 123

Quand les scripts de rake ressemblent à ceci, il est peut-être temps de chercher un autre outil qui permettrait de sortir de la boîte.

102
Tombart

J'ai trouvé la réponse de ces deux sites: Net Maniac et Aimred .

Vous devez avoir la version> 0.8 de rake pour utiliser cette technique

La description normale de la tâche de rake 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:

  1. Ajoutez les noms des arguments après le nom de la tâche, séparés par des virgules.
  2. Mettez les dépendances à la fin en utilisant: needs => [...]
  3. Lieu | t, args | après le faire. (t est l'objet de cette tâche)

Pour accéder aux arguments dans le 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, transmettez-lui les arguments dans [] s

rake task_name['Hello',4]

va sortir

Hello
Hello
Hello
Hello

et si vous voulez appeler cette tâche depuis 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

alors la commande

rake caller

va sortir

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

Une autre option couramment utilisée consiste à transmettre des variables d’environnement. Dans votre code, vous les lisez via ENV['VAR'] et vous pouvez les transmettre juste avant la commande rake, comme

$ VAR=foo rake mytask
29
kch

En fait, @Nick Desjardins a répondu parfaitement. Mais juste pour l'éducation: vous pouvez utiliser une approche sale: en utilisant l'argument ENV

task :my_task do
  myvar = ENV['myvar']
  puts "myvar: #{myvar}"
end 

rake my_task myvar=10
#=> myvar: 10
29
fl00r

Je n'arrivais pas à comprendre comment passer des arguments et l'environnement:

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/']
25
Nate Flink
desc 'an updated version'
task :task_name, [:arg1, :arg2] => [:dependency1, :dependency2] do |t, args|
    puts args[:arg1]
end
22
Feng

Je voulais juste pouvoir courir:

$ rake some:task arg1 arg2

Simple, non? (Nan!)

Rake interprète arg1 et arg2 en tant que tâches et tente de les exécuter. Donc, nous avortons juste avant.

namespace :some do
  task task: :environment do
    arg1, arg2 = ARGV

    # your task...

    exit
  end
end

Prenez ça, entre parenthèses!

Disclaimer : Je voulais pouvoir faire cela dans un assez petit projet animalier. Non destiné à une utilisation "réelle" car vous perdez la possibilité de chaîner des tâches ratissées (c'est-à-dire rake task1 task2 task3) L'OMI n'en vaut pas la peine. Il suffit d'utiliser le rake task[arg1,arg2] laid.

16
jassa

J'utilise un argument Ruby régulier dans le fichier rake:

DB = ARGV[1]

ensuite, je décompose les tâches de rake au bas du fichier (car rake 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 var = foo ENV var et que la tâche propose des solutions [blah, blah2].
le stub est un peu jenky, mais pas trop mal si vous avez juste quelques environnements qui sont une configuration unique

12
djburdick

Les manières de passer l'argument sont correctes dans la réponse ci-dessus. Cependant, pour exécuter une tâche rake avec des arguments, la nouvelle version de Rails présente une petite technicité

Cela fonctionnera avec rake "namespace: taskname ['argument1']"

Notez les guillemets inversés dans l'exécution de la tâche à partir de la ligne de commande. 

5
Asim Mushtaq

J'aime la syntaxe "querystring" pour le passage d'arguments, en particulier lorsqu'il y a beaucoup d'arguments à transmettre. 

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 NOTrake mytask["foo=bar"]

Lorsque analysé dans la tâche de rake en utilisant Rack::Utils.parse_nested_query, nous obtenons une Hash:

=> {"width"=>"10", "height"=>"20"}

(La chose intéressante est que vous pouvez passer des hachages et des tableaux, plus bas)

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 mon delay_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]"

Analysé de la même manière que ci-dessus, avec une dépendance d'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"}}
4
Abdo

Pour passer des arguments à la tâche par défaut, vous pouvez faire quelque chose comme ceci. 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 comme suit:

$ 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é le moyen d'éviter de spécifier le nom de la tâche (par défaut ou build) lors de la transmission des arguments. J'aimerais entendre si quelqu'un connaît un moyen.

3
Gal

La plupart des méthodes décrites ci-dessus n'ont pas fonctionné pour moi, elles sont peut-être obsolètes dans les versions les plus récentes ..__ Le guide mis à jour est disponible à l'adresse suivante: http://guides.rubyonrails.org/command_line. html # custom-rake-tasks

un copier-coller du guide est ici:

task :task_name, [:arg_1] => [:pre_1, :pre_2] do |t, args|
  # You can use args from here
end

Invoquer comme ça

bin/rake "task_name[value 1]" # entire argument string should be quoted
2
hexinpeter

Si vous ne voulez pas vous soucier de savoir quelle est la position de l'argument et que vous voulez faire quelque chose comme un hachage d'argument Ruby Vous pouvez utiliser un seul argument pour passer une chaîne, puis regexer 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
2
xander-miller

Pour exécuter des tâches rake avec un style d'arguments traditionnel:

rake task arg1 arg2

Et ensuite utiliser:

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
0
Dan Key