it-swarm.com.de

So übergeben Sie Befehlszeilenargumente an eine Rake-Task

Ich habe eine Rake-Aufgabe, die einen Wert in mehrere Datenbanken einfügen muss. 

Ich möchte diesen Wert in die Rake-Task von der Befehlszeile oder von einer anderen Rake-Task übergeben.

Wie kann ich das machen?

998
Tilendor

optionen und Abhängigkeiten müssen sich innerhalb von Arrays befinden:

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

Dann

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

HINWEIS: Die Variable task ist das Task-Objekt. Es ist nicht sehr hilfreich, wenn Sie sich nicht mit Rake-Internals auskennen. 

Schienen HINWEIS:

Wenn Sie die Task über Rails ausführen, laden Sie die Umgebung am besten vorab, indem Sie => [:environment] hinzufügen. Dies ist eine Möglichkeit, abhängige -Tasks einzurichten. 

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

Sie können formale Argumente in Rake angeben, indem Sie dem Task-Aufruf Symbolargumente hinzufügen. Zum Beispiel:

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

Dann von der Kommandozeile aus:

> rake my_task [1,2] 
 Args waren: {: arg1 => "1",: arg2 => "2"} 

> rake "my_task [1, 2]" 
 Args waren: {: arg1 => "1",: arg2 => "2"} 

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

> Rechen invoke_my_task_2 
 Args waren: {: arg1 => 3,: arg2 => 4} 

> Rechen mit Vorbedingung [5,6] 
 Args waren: {: arg1 => "5",: arg2 => "6"} 

> Rake with_defaults 
 Args mit Standardwerten waren: {: arg1 =>: default_1,: arg2 =>: default_2} 

> rake with_defaults ['x', 'y'] 
 Standardeinstellungen waren: {: arg1 => "x",: arg2 => "y"} 

Wie im zweiten Beispiel gezeigt, müssen Sie die Anführungszeichen um den Zielnamen verwenden, wenn Sie Leerzeichen verwenden möchten, damit die Shell die Argumente an der Leiste nicht aufteilt.

Wenn Sie sich den Code in rake.rb anschauen, sieht es so aus, als würde Rake Taskstrings nicht analysieren, um Argumente für Voraussetzungen zu extrahieren. Daher können Sie task :t1 => "dep[1,2]" nicht ausführen. Die einzige Möglichkeit, verschiedene Argumente für eine Voraussetzung anzugeben, besteht darin, sie explizit in der abhängigen Task-Aktion aufzurufen, wie in :invoke_my_task und :invoke_my_task_2.

Beachten Sie, dass bei einigen Shells (wie zsh) die Klammern nicht angezeigt werden müssen: rake my_task\['arg1'\]

1095
Nick Desjardins

Zusätzlich zur Antwort von kch (ich habe nicht gefunden, wie ich einen Kommentar dazu hinterlassen kann, sorry):

Sie müssen vor dem Befehl ENV keine Variablen als rake-Variablen angeben. Sie können sie einfach als gewöhnliche Befehlszeilenparameter wie folgt einstellen:

rake mytask var=foo

und greifen Sie als ENV-Variablen auf die Dateien aus Ihrer Rake-Datei zu:

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

Wenn Sie benannte Argumente übergeben möchten (z. B. mit dem Standard OptionParser), können Sie Folgendes verwenden:

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

beachten Sie den --, der für das Umgehen von Standard-Rake-Argumenten erforderlich ist. Sollte mit Rake 0.9.x , <= 10.3.x arbeiten.

Der neuere Rake hat seine Analyse von -- geändert, und Sie müssen jetzt sicherstellen, dass er nicht an die OptionParser#parse-Methode übergeben wird, beispielsweise mit 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 am Ende stellt sicher, dass die zusätzlichen Argumente nicht als Rake-Task interpretiert werden. 

Auch die Verknüpfung für Argumente sollte funktionieren:

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

Wenn Rake-Skripts so aussehen, ist es vielleicht an der Zeit, nach einem anderen Werkzeug zu suchen, mit dem dies einfach möglich ist.

102
Tombart

Ich habe die Antwort auf diesen beiden Websites gefunden: Net Maniac und Aimred .

Sie benötigen eine Version> 0.8 des Rechen, um diese Technik zu verwenden

Die normale Rake-Aufgabenbeschreibung lautet wie folgt:

desc 'Task Description'
task :task_name => [:depends_on_taskA, :depends_on_taskB] do
  #interesting things
end

Um Argumente zu übergeben, machen Sie drei Dinge:

  1. Fügen Sie die Argumentnamen nach dem Tasknamen hinzu, getrennt durch Kommas.
  2. Setze die Abhängigkeiten am Ende mit: needs => [...]
  3. Platzieren Sie | t, args | nach dem do. (t ist das Objekt für diese Aufgabe)

Verwenden Sie args.arg_name, um auf die Argumente im Skript zuzugreifen

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

Um diese Task von der Befehlszeile aus aufzurufen, übergeben Sie die Argumente in [] s

rake task_name['Hello',4]

wird ausgegeben

Hello
Hello
Hello
Hello

wenn Sie diese Task von einer anderen Task aus aufrufen und Argumente übergeben möchten, verwenden Sie invoke

task :caller do
  puts 'In Caller'
  Rake::Task[:task_name].invoke('hi',2)
end

dann der Befehl

rake caller

wird ausgegeben

In Caller
hi
hi

Ich habe keine Möglichkeit gefunden, Argumente als Teil einer Abhängigkeit zu übergeben, da der folgende Code bricht:

task :caller => :task_name['hi',2]' do
   puts 'In Caller'
end
57
Tilendor

Eine andere häufig verwendete Option ist das Übergeben von Umgebungsvariablen. In Ihrem Code lesen Sie sie über ENV['VAR'] und können sie direkt vor dem Befehl rake übergeben, z

$ VAR=foo rake mytask
29
kch

Eigentlich hat @Nick Desjardins perfekt geantwortet. Aber nur für die Bildung: Sie können den Dirty-Ansatz verwenden: ENV-Argument

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

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

Ich konnte nicht herausfinden, wie man Argumente und auch die: Umgebung weitergibt, bis ich das herausgefunden habe:

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

Und dann rufe ich so an:

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

Ich wollte nur laufen können:

$ rake some:task arg1 arg2

Einfach, richtig? (Nee!)

Rake interpretiert arg1 und arg2 als Aufgaben und versucht sie auszuführen. Also brechen wir einfach ab, bevor es funktioniert.

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

    # your task...

    exit
  end
end

Nimm das, Klammern!

Disclaimer : Ich wollte das in einem ziemlich kleinen Haustierprojekt machen. Nicht für die Verwendung in der "realen Welt" gedacht, da Sie die Möglichkeit verlieren, Rake-Aufgaben (d. H. rake task1 task2 task3) zu verketten. IMO lohnt sich nicht. Verwenden Sie einfach den hässlichen rake task[arg1,arg2].

16
jassa

Ich benutze ein reguläres Ruby-Argument in der Rake-Datei:

DB = ARGV[1]

dann stub ich die Rake-Tasks am Ende der Datei aus (da Rake nach einer Aufgabe sucht, die auf diesem Argumentnamen basiert).

task :database_name1
task :database_name2

befehlszeile:

rake mytask db_name

das fühlt sich für mich sauberer an als die var = foo ENV var und die aufgabe args [bla, blah2] lösungen.
der Stub ist ein wenig jenky, aber nicht schlecht, wenn Sie nur wenige Umgebungen haben, die einmalig sind

12
djburdick

Die Möglichkeiten, Argumente zu übergeben, sind in der obigen Antwort richtig. Um eine Rake-Task mit Argumenten auszuführen, ist in der neueren Version von Rails jedoch eine geringe technische Funktionalität erforderlich

Es wird mit Rake "Namespace: Taskname ['Argument1']" arbeiten.

Beachten Sie die umgekehrten Anführungszeichen, wenn Sie die Task von der Befehlszeile aus ausführen. 

5
Asim Mushtaq

Ich mag die "querystring" -Syntax für das Übergeben von Argumenten, insbesondere wenn viele Argumente übergeben werden müssen. 

Beispiel:

rake "mytask[width=10&height=20]"

Die "Querzeichenfolge" lautet:

width=10&height=20

Warnung: Beachten Sie, dass die Syntax rake "mytask[foo=bar]" ist und NICHTrake mytask["foo=bar"].

Wenn Sie die Rake-Task mit Rack::Utils.parse_nested_query analysieren, erhalten Sie eine Hash:

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

(Die coole Sache ist, dass Sie Hashes und Arrays passieren können, mehr unten)

So erreichen Sie das:

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

Hier ein ausführlicheres Beispiel, das ich mit Rails in meinem delayed_job_active_record_threaded gem verwende:

bundle exec rake "dj:start[ebooks[workers_number]=16&ebooks[worker_timeout]=60&albums[workers_number]=32&albums[worker_timeout]=120]"

Wird wie oben analysiert, mit einer Umgebungsabhängigkeit (um die Rails-Umgebung zu laden)

namespace :dj do
  task :start, [ :args_expr ] => :environment do |t, args|
    # defaults here...
    options = Rack::Utils.parse_nested_query(args[:args_expr])  
  end
end

Gibt Folgendes in options

=> {"ebooks"=>{"workers_number"=>"16", "worker_timeout"=>"60"}, "albums"=>{"workers_number"=>"32", "worker_timeout"=>"120"}}
4
Abdo

Um Argumente an die Standardaufgabe zu übergeben, können Sie Folgendes tun. Zum Beispiel sagen Sie "Version" ist Ihr Argument:

task :default, [:version] => [:build]

task :build, :version do |t,args|
  version = args[:version]
  puts version ? "version is #{version}" : "no version passed"
end

Dann kannst du es so nennen:

$ rake
no version passed

oder 

$ rake default[3.2.1]
version is 3.2.1

oder

$ rake build[3.2.1]
version is 3.2.1

Ich habe jedoch keine Möglichkeit gefunden, bei der Übergabe von Argumenten die Angabe des Aufgabennamens (Standard oder Build) zu vermeiden. Würde gerne hören, wenn jemand einen Weg kennt.

3
Gal

Die meisten der oben beschriebenen Methoden haben bei mir nicht funktioniert, vielleicht sind sie in den neueren Versionen nicht mehr empfohlen .. Die aktuelle Anleitung finden Sie hier: http://guides.rubyonrails.org/command_line html # custom-rake-task

ein copy-and-paste aus dem Guide ist hier:

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

Beschreibe es so

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

Wenn Sie sich nicht die Mühe machen müssen, sich daran zu erinnern, welche Argumentposition für was gilt, und Sie möchten etwas wie einen Ruby-Argumenthash tun. Sie können ein Argument verwenden, um einen String zu übergeben und diesen String dann in einen Optionshash auszudehnen. 

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

Und auf der Kommandozeile bekommst du.

$ 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

Rake-Tasks mit traditionellen Argumenten ausführen:

rake task arg1 arg2

Und dann verwenden Sie:

task :task do |_, args|
  puts "This is argument 1: #{args.first}"
end

Fügen Sie den folgenden Rake-Edelstein hinzu:

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