Komut satırı bağımsız değişkenlerini bir komisyon görevine geçirme


1096

Birden çok veritabanına bir değer eklemek için bir komisyon görevi var.

Bu değeri komut satırından veya başka bir komisyon görevinden komisyon görevine geçirmek istiyorum .

Bunu nasıl yapabilirim?



3
Dokümanlar SeattleRb tarafından yansıtıldı.
Jonathan Allard

1
Kabul edilen cevabı şimdi çok eski olduğu için lütfen kabul edilen cevabı @BlairAnderson'dan değiştirebilir misiniz? Bu soru bu konuda Google'da yüksek görünüyor!
rmcsharry

Yanıtlar:


377

seçenekler ve bağımlılıklar dizilerin içinde olmalıdır:

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

Sonra

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

NOT: Değişken taskgörev nesnesidir, Rake içlerini bilmiyorsanız / önemsemediğiniz sürece çok yararlı değildir.

RAYLAR NOT:

Görevi raylardan çalıştırıyorsanız, bağımlı görevleri => [:environment]kurmanın bir yolunu ekleyerek ortamı önceden yüklemek en iyisidir .

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

28
Ayrıca, bağımsız değişkenler arasında boşluk kullanmadığınızdan emin olun. Örneğin, bunu yapma: rake thing:work[1, 2, 3]işe yaramaz ve bir hata alırsınızDon't know how to build task
rpbaltazar

9
Ayrıca, argümanı dizeye eklediğinizden emin olun. Örneğin komut satırınızdan komisyon görevini şu şekilde çalıştırın rake thing:work'[1,2,3]'
theterminalguy

36
Ne yazık ki, zsh çağrıyı doğru ayrıştıramıyor, zsh üzerine şu komutu yazmanız gerekiyor: rake thing:work\[1,2,3\]veya burake 'thing:work[1,2,3]'
hutusi

1
@sakurashinken :environmentsembolü görevinizden çıkarabilirsiniz . raylar uygulamaları bir: çevre görevi var ...
Blair Anderson

3
Bunun yerine açıklamak için bir not sahip taraçlar task, neden sadece kullanmayın taskparam adı olarak?
Joshua Pinter

1132

Görev çağrısına sembol bağımsız değişkenleri ekleyerek komisyonda resmi bağımsız değişkenler belirleyebilirsiniz. Örneğin:

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

Ardından, komut satırından:

> komisyon my_task [1, false]
Bağımsız değişkenler: Rake :: TaskArguments sınıfının {: arg1 => "1",: arg2 => "false"}
arg1 oldu: '1' sınıf String
arg2: Sınıf String'in 'false' değeri

> komisyon "my_task [1, 2]"
Bağımsız değişkenler: {: arg1 => "1",: arg2 => "2"}

> rake Instagram Hesabındaki Resim ve Videoları invoke_my_task
Bağımsız değişkenler: {: arg1 => "1",: arg2 => "2"}

> komisyon invoke_my_task_2
Bağımsız değişkenler: {: arg1 => 3,: arg2 => 4}

> ön koşullu komisyon [5,6]
Bağımsız değişkenler: {: arg1 => "5",: arg2 => "6"}

> de_defaults ile komisyon
Varsayılanları olan bağımsız değişkenler şunlardı: {: arg1 =>: varsayılan_1,: arg2 =>: varsayılan_2}

> ifla_defaults ['x', 'y']
Varsayılanları olan bağımsız değişkenler şunlardı: {: arg1 => "x",: arg2 => "y"}

İkinci örnekte gösterildiği gibi, boşluk kullanmak istiyorsanız, kabuğun boşluktaki bağımsız değişkenleri ayırmasını önlemek için hedef adının etrafındaki tırnak işaretleri gereklidir.

Rake.rb dosyasındaki koda bakıldığında , komisyonun önkoşullar için bağımsız değişkenler ayıklamak üzere görev dizelerini ayrıştırmadığı anlaşılamaz task :t1 => "dep[1,2]". Bir ön koşul olduğu gibi, bağımlı görev eylem içinde açıkça çağırmak olacaktır tek yolu farklı argüman belirtmek :invoke_my_taskve :invoke_my_task_2.

Bazı mermilerin (zsh gibi) parantezlerden kaçmanızı gerektirdiğini unutmayın: rake my_task\['arg1'\]


5
Bir ad alanı simpy içindeki bir görevi çağırmak için şunu yapın: Rake :: Task ['namespace: task'].
İnvoke

1
Bu ayrı bir soru, Igoru, ancak çağırma çağrınızın sadece bir kez çalıştırılmasının nedeni, komisyonun bağımlılık odaklı olmasıdır, bu yüzden sadece gerektiğinde bir görevi yürütür. Genel görevler için bu, daha önce çalışmadıysa anlamına gelir. Bir görevi bağımlılıklarından bağımsız olarak veya gerekiyorsa açıkça yürütmek için, invoke yerine execute komutunu çağırın.
Nick Desjardins

10
Not: Komisyona göre, görevlerdeki değişkenleri kabul etmek için bu sözdizimi kullanımdan kaldırılmıştır:WARNING: 'task :t, arg, :needs => [deps]' is deprecated. Please use 'task :t, [args] => [deps]' instead.
Ajedi32

57
Zsh doğru (komut satırı argümanları ayrıştırmak için başarısız olduğunu Not zsh: no matches found: ...parantez kaçmak gerekir, böylece): rake my_task\['arg1'\]. Gönderen robots.thoughtbot.com/post/18129303042/...
Seth Bro

2
@SethBro EVET. Sadece yorumunuz "Diğer yorumları gör" bağlantısının arkasına gizlenmemiş olsaydı, 10 dakika bu işi yapamazdım boşa gitmezdim.
GMA

342

Kch tarafından cevap vermenin yanı sıra (buna nasıl bir yorum bırakacağım, üzgünüm):

ENVKomuttan önce değişkenleri değişken olarak belirtmeniz gerekmez rake. Bunları normal komut satırı parametreleri olarak şu şekilde ayarlayabilirsiniz:

rake mytask var=foo

ve komisyon dosyanızdaki gibi ENV değişkenleri olarak bunlara erişin:

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

2
Bu en iyi cevap IMO. Hemen çalıştı. Tam olarak ne pdemek?
stevec

1
@ user5783745 Koyar ama value.to_s dosyasını standart çıktıya kaydetmek yerine Obj.inspect'i çağırır ve bunu standart çıktıya kaydeder. ruby-doc.org/core-2.0.0/Kernel.html#method-ip
kqcef

Ortam değişkenlerini geçersiz kılsın mı? Fantastik!
Damien Roche

Tırmık tamamen aşırı derecede dağınıktır ve işe yarayan tek yol budur. Ve bu sadece ben değil, bu cevap "doğru" cevapla aynı oy sayısına sahip.
lzap

108

Adlandırılmış bağımsız değişkenleri (örneğin standart ile OptionParser) iletmek isterseniz, bunun gibi bir şey kullanabilirsiniz:

$ rake user:create -- --user test@example.com --pass 123

--bunun standart Rake argümanlarını atlamak için gerekli olduğunu unutmayın . Komisyon 0.9.x , <= 10.3.x ile çalışmalıdır .

Yeni Komisyon ayrıştırmasını değiştirdi --ve şimdi bunun OptionParser#parseyönteme geçmediğinden emin olmalısınız , örneğinparser.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 sonunda ekstra argümanların Komisyon görevi olarak yorumlanmamasını sağlayacaktır.

Ayrıca argüman kısayolu da çalışmalıdır:

 rake user:create -- -u test@example.com -p 123

Komisyon senaryoları bu şekilde göründüğünde, belki de bunun kutudan çıkmasına izin verecek başka bir araç aramanın zamanı gelmiştir.


13
Benim açımdan bu gerçekten en iyi cevap. Ortam değişkeni kludgeslerini atla, görev argümanlarıyla garip sözdizimi, standart için ek fayda --option-names. Tek önerim kullanmak olacaktır exitziyade abortolarak abortkabuğun 1 ila dönüş kodunu size bırakacaktır. Komisyon görevi daha üst düzey bir komut dosyasının parçasıysa, sıfır dışında bir çıkışın bir tür hata olduğunu varsaymak daha yaygındır.
Joe

1
Joe'ya katılıyorum, bu en iyi cevap. Doğal olan, bir betiğe seçenekleri iletirken yaptığınız gibi, rake seçenekleri aktarmak için aynı arabirimi kullanmaktır.
Rik Smith-Unna

1
Bunun en iyi cevap olduğuna katılıyorum. Çirkinliği atlamanın bir yolu yok --mu? rakeAsıl göreve veya başka bir şeye argüman iletmek gibi mi? Beğendim task :my_task, :*args do |t, args|falan?
Augustin Riedinger

1
Üstelik {username}burada ne için olduğunu anlamıyorum . Nerede kullanılır? Neden orada değil -u {username}? Şerefe
Augustin Riedinger

2
Rake'in ARGV'yi ayrıştırma şekli değiştirildi 10.4.1ve geri alındı 10.4.2. github.com/ruby/rake/commit/…
Tombart

58

Bu iki web sitesinden cevap buldum: Net Maniac ve Aimred .

Bu tekniği kullanmak için> 0.8 tırmık sürüme sahip olmanız gerekir

Normal komisyon görevi açıklaması şudur:

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

Argümanları iletmek için üç şey yapın:

  1. Bağımsız değişken adlarını virgülle ayırarak görev adından sonra ekleyin.
  2. Bağımlılıkları kullanarak sonuna ekleyin: needs => [...]
  3. Yer | t, args | sonra. (t bu görevin nesnesidir)

Koddaki bağımsız değişkenlere erişmek için args.arg_name komutunu kullanın

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

Bu görevi komut satırından çağırmak için [] s

rake task_name['Hello',4]

çıktı olacak

Hello
Hello
Hello
Hello

ve bu görevi başka bir görevden çağırıp bağımsız değişkenlerini iletmek istiyorsanız, invoke komutunu kullanın

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

sonra komut

rake caller

çıktı olacak

In Caller
hi
hi

Aşağıdaki kod kırıldığı gibi, bağımlılık bir parçası olarak bağımsız değişkenler geçmek için bir yol bulamadık:

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

15
Bu işlevin biçimi şu uyarıda belirtildiği gibi değişti: 'task :t, arg, :needs => [deps]' is deprecated. Please use 'task :t, [args] => [deps]' instead.
madh

29

Yaygın olarak kullanılan bir başka seçenek de ortam değişkenlerini geçirmektir. Kodunuzda bunları okursunuz ENV['VAR']ve rakekomuttan hemen önce geçirebilirsiniz , örneğin

$ VAR=foo rake mytask

Açıkçası tırmık görevi umuyordum - bu --go - to - bir program ve görevim onları ARGV'den alabilirdi. Ne yazık ki bunun mümkün olup olmadığından emin değilim ancak şu anda çözümünüzü kullanıyorum: rake var1 = val1 var2 = val2
JasonSmith

3
@jhs: rake blah -- --these --go --to --a-program( --tırmığın anahtarlarının bittiğini söylemek için not edin ), bkz. stackoverflow.com/questions/5086224/…
mu çok kısa

28

Aslında @Nick Desjardins mükemmel cevap verdi. Ancak sadece eğitim için: kirli yaklaşımı kullanabilirsiniz: ENVargüman kullanma

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

rake my_task myvar=10
#=> myvar: 10

27

Ben bunu çözene kadar nasıl args ve ayrıca: çevre geçmek anlayamadık:

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

Sonra şöyle diyorum:

rake db:export['foo, /tmp/']

23
desc 'an updated version'
task :task_name, [:arg1, :arg2] => [:dependency1, :dependency2] do |t, args|
    puts args[:arg1]
end

Bunu aramak için:rake task_name[hello, world]
Dex

2
dan rake.rubyforge.org/files/doc/rakefile_rdoc.html dikkatli Sadece birkaç kelime". tırmık görev adı ve argümanları tırmık tek komut satırı argümanı olması gerekir. Bu genellikle boşluk anlamına gelmektedir. boşluklar gerekiyorsa , daha sonra tüm tırmık + argüman dizisi alıntı edilmelidir şey bu: tırmık "adını [billy smith bob]" ".
Gayle

19

Sadece koşmak istedim:

$ rake some:task arg1 arg2

Basit, değil mi? (Hayır!)

Komisyon, yorum olarak arg1ve arg2görevler olarak çalışır ve bunları çalıştırmaya çalışır. Bu yüzden sadece iptal etmeden önce iptal ediyoruz.

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

    # your task...

    exit
  end
end

Al şunu, parantez!

Feragatname : Bunu oldukça küçük bir evcil hayvan projesinde yapmak istedim. Tırmık görevlerini zincirleme yeteneğinizi (yani rake task1 task2 task3) kaybettiğiniz için "gerçek dünya" kullanımı için tasarlanmamıştır . IMO buna değmez. Sadece çirkin kullanın rake task[arg1,arg2].


3
Bunu _, arg1, arg2 = ARGVilk argüman olarak yapmak gerekiyordu, komisyon görevinin adı olarak görülüyordu. Ama bu exittemiz bir numara.
Yağlı

rake task[arg1,arg2] && rake task2 && rake task3Bundan daha çirkin olup olmadığından emin değilim rake task[arg1,arg2] task2 task3. Muhtemelen daha az verimli.
Nuclearman

_, *args = ARGVsonraki tüm argümanları yakalamak için mükemmel! Teşekkürler yığınları!
XtraSimplicity

12

Komisyon dosyasında düzenli bir yakut argümanı kullanıyorum:

DB = ARGV[1]

daha sonra dosyanın altındaki komisyon görevlerini sapladım (çünkü komisyon bu argüman adına dayalı bir görev arayacaktır).

task :database_name1
task :database_name2

Komut satırı:

rake mytask db_name

bu bana var = foo ENV var ve görev argümanlarından [blah, blah2] daha temiz geliyor.
saplama biraz cenky, ama sadece bir kerelik kurulum olan birkaç ortamınız varsa çok kötü değil


2
Donmuş dizeleri önlemek dupiçin, sonunda kullanın : db = ARGV [1] .dup
Juanda

db = ARGV[1].dup unless ARGV[1].nil?Bir nil çoğaltma istisna önlemek için daha iyi olay .
Andre Figueiredo

5

Tartışmayı iletmenin yolları yukarıdaki cevapta doğrudur. Bununla birlikte, komisyon görevini argümanlarla çalıştırmak için, rayların daha yeni versiyonunda küçük bir teknik vardır

Komisyon "namespace: taskname ['argument1']" ile çalışır

Görevi komut satırından çalıştırırken Ters tırnaklara dikkat edin.


3

Varsayılan göreve argüman iletmek için böyle bir şey yapabilirsiniz. Örneğin, argümanınız "sürüm" deyin:

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

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

Sonra şöyle diyebilirsiniz:

$ rake
no version passed

veya

$ rake default[3.2.1]
version is 3.2.1

veya

$ rake build[3.2.1]
version is 3.2.1

Ancak, argümanlar iletirken görev adını (varsayılan veya derleme) belirtmekten kaçınmanın bir yolunu bulamadım. Herkes bir yol biliyorsa duymak isterim.


3

Özellikle geçirilecek argümanlar çok olduğunda, argüman geçen "querystring" sözdizimi gibi.

Misal:

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

"Querystring" varlık:

width=10&height=20

Uyarı: sözdiziminin rake "mytask[foo=bar]"ve NOT rake mytask["foo=bar"]

Kullanarak tırmıklama görevinin içinde ayrıştırıldığında Rack::Utils.parse_nested_queryşunları elde ederiz Hash:

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

(Harika olan şey, daha fazla karma ve dizileri geçebilmenizdir)

Bunu başarmak için:

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

İşte benim delayed_job_active_record_threaded gem Rails ile kullandığım daha genişletilmiş bir örnek :

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

Ortam bağımlılığına sahip olarak yukarıdakiyle aynı şekilde ayrıştırılır (Rails ortamını yüklemek için)

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

Aşağıdakileri verir: options

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

3

Eğer ne için argüman pozisyonunun ne olduğunu hatırlamaktan rahatsız olamazsanız ve yakut argüman karması gibi bir şey yapmak istersiniz. Bir dizeyi iletmek için bir argüman kullanabilir ve ardından bu dizeyi bir seçenekler karmasına yeniden düzenleyebilirsiniz.

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

Ve komut satırında olsun.

$ 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

1
Kodunuzun birkaç iyi yerleştirilmiş boş satıra ihtiyacı var. O metin duvarını nasıl okuduğunu bilmiyorum.
Joshua Pinter

2

Yukarıda açıklanan yöntemlerin çoğu benim için işe yaramadı, belki de yeni sürümlerde kullanımdan kaldırıldı. Güncel kılavuzu şu adreste bulabilirsiniz: http://guides.rubyonrails.org/command_line.html#custom-rake-tasks

rehberden bir kopyala ve yapıştır ans burada:

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

Bu şekilde çağır

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

1

Komisyon görevlerini geleneksel argümanlar stiliyle çalıştırmak için:

rake task arg1 arg2

Ve sonra kullanın:

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

Komisyon geminin aşağıdaki yamasını ekleyin:

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

-5

Parametreleri iletirken, daha iyi bir seçenek bir giriş dosyasıdır, bu bir excel olabilir veya ihtiyacınız olan her şey olabilir ve oradan ihtiyaç duyduğunuz değişken adını da içeren veri yapısını ve değişkenleri okuyabilirsiniz. Bir dosyayı okumak için aşağıdaki yapıya sahip olabilir.

  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

Örnek json

{
  "name_task": "I'm a task",
  "user_id": 389,
  "users_assigned": [389,672,524],
  "task_id": 3
}

infaz

rake :name_task 

4
Komisyon göreviniz için bir JSON talimatları dosyasına ihtiyacınız varsa, Komisyon görevinizde muhtemelen çok fazla şey yapıyorsunuzdur.
ZiggyTheHamster

Bu yolu inanılmaz basit bir şeyi aşırı karmaşık hale getirdi.
jeffdill2
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.