كيفية تمرير وسيطات سطر الأوامر إلى مهمة أشعل النار
-
05-07-2019 - |
سؤال
لدي مهمة أشعل النار التي تحتاج إلى إدراج قيمة في قواعد بيانات متعددة.
أرغب في تمرير هذه القيمة إلى مهمة أشعل النار من سطر الأوامر، أو من آخر مهمة أشعل النار.
كيف يمكنني أن أفعل هذا؟
المحلول
يجب أن تكون الخيارات والتبعيات داخل المصفوفات:
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
ثم
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"}
ملحوظة:عامل
task
هو كائن المهمة، وهو ليس مفيدًا جدًا إلا إذا كنت تعرف/تهتم بالعناصر الداخلية لـ Rake.
ملاحظة القضبان:
في حالة تشغيل المهمة من Rails، فمن الأفضل تحميل البيئة مسبقًا عن طريق إضافة
=> [:environment]
وهي طريقة الإعداد متكل مهام.
task :work, [:option, :foo, :bar] => [:environment] do |task, args|
puts "work", args
end
نصائح أخرى
ويمكنك تحديد الحجج الرسمية في أشعل النار عن طريق إضافة الحجج رمزا للدعوة المهمة. على سبيل المثال:
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
وبعد ذلك، من سطر الأوامر:
> 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"}
وكما هو موضح في المثال الثاني، إذا كنت ترغب في استخدام المساحات، علامات الاقتباس حول اسم الهدف ضرورية للحفاظ على قذيفة من تقسيم تصل الحجج في الفضاء.
وإذا نظرنا إلى التعليمات البرمجية في <قوية> rake.rb ، أو يبدو أن أشعل النار لا تحليل السلاسل المهمة لاستخراج حجج لمتطلبات، لذلك لا يمكنك أن تفعل task :t1 => "dep[1,2]"
. الطريقة الوحيدة لتحديد حجج مختلفة للشرط أساسي يتمثل في استدعاء صراحة ضمن إجراءات مهمة تعتمد، كما هو الحال في :invoke_my_task
و:invoke_my_task_2
.
لاحظ أن بعض القذائف (مثل zsh) تتطلب منك للهروب من الأقواس: rake my_task\['arg1'\]
وبالإضافة إلى الإجابة عن طريق KCH (لم أجد كيفية ترك تعليق على ذلك، آسف):
وليس لديك لتحديد المتغيرات كمتغيرات ENV
قبل الأمر rake
. يمكنك فقط مجموعة منهم كما معلمات سطر الأوامر المعتادة مثل ما يلي:
rake mytask var=foo
ووالوصول إلى تلك من ملف أشعل النار بك كمتغيرات ENV مثل هذه:
p ENV['var'] # => "foo"
إذا كنت تريد تمرير الوسائط المسماة (على سبيل المثال.مع المعيار OptionParser
) يمكنك استخدام شيء مثل هذا:
$ rake user:create -- --user test@example.com --pass 123
لاحظ ال --
, ، وهذا ضروري لتجاوز وسيطات Rake القياسية.يجب أن تعمل مع أشعل النار 0.9.x, <= 10.3.x.
لقد غيرت Newer Rake تحليلها لـ --
, ، والآن عليك التأكد من عدم تمريره إلى OptionParser#parse
الطريقة، على سبيل المثال مع 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
في النهاية سوف نتأكد من أن الوسائط الإضافية لن يتم تفسيرها على أنها مهمة Rake.
يجب أيضًا أن يعمل اختصار الوسائط:
rake user:create -- -u test@example.com -p 123
عندما تبدو نصوص Rake بهذا الشكل، ربما يكون الوقت قد حان للبحث عن أداة أخرى تسمح بذلك خارج الصندوق.
لقد وجدت الجواب من هذين الموقعين: صافي مهووس و ايمد.
يجب أن يكون لديك الإصدار> 0.8 من Rake لاستخدام هذه التقنية
الوصف الطبيعي لمهمة أشعل النار هو:
desc 'Task Description'
task :task_name => [:depends_on_taskA, :depends_on_taskB] do
#interesting things
end
لتمرير الحجج، قم بثلاثة أشياء:
- أضف أسماء الوسيطات بعد اسم المهمة، مفصولة بفواصل.
- ضع التبعيات في النهاية باستخدام :needs => [...]
- مكان | T ، args | بعد القيام به.(t هو الكائن لهذه المهمة)
للوصول إلى الوسائط الموجودة في البرنامج النصي، استخدم 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
لاستدعاء هذه المهمة من سطر الأوامر، قم بتمرير الوسيطات في []s
rake task_name['Hello',4]
سوف يخرج
Hello
Hello
Hello
Hello
وإذا كنت تريد استدعاء هذه المهمة من مهمة أخرى، وتمرير الوسائط لها، فاستخدم الاستدعاء
task :caller do
puts 'In Caller'
Rake::Task[:task_name].invoke('hi',2)
end
ثم الأمر
rake caller
سوف يخرج
In Caller
hi
hi
لم أجد طريقة لتمرير الوسائط كجزء من التبعية، حيث ينكسر الكود التالي:
task :caller => :task_name['hi',2]' do
puts 'In Caller'
end
وثمة خيار آخر شيوعا هو لتمرير متغيرات البيئة. في التعليمات البرمجية قراءتها عبر ENV['VAR']
، ويمكن أن تمر منها الحق قبل الأمر rake
، مثل
$ VAR=foo rake mytask
والواقع أجابNick ديجاردان الكمال. ولكن فقط للتعليم: يمكنك استخدام نهج القذرة: استخدام حجة ENV
task :my_task do
myvar = ENV['myvar']
puts "myvar: #{myvar}"
end
rake my_task myvar=10
#=> myvar: 10
وأنا لم أستطع معرفة كيفية تمرير وسائط وأيضا: البيئة حتى عملت هذا الخروج:
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
وبعد ذلك أدعو من هذا القبيل:
rake db:export['foo, /tmp/']
desc 'an updated version'
task :task_name, [:arg1, :arg2] => [:dependency1, :dependency2] do |t, args|
puts args[:arg1]
end
وأردت فقط أن تكون قادرة على تشغيل:
$ rake some:task arg1 arg2
وبسيط، أليس كذلك؟ (كلا!)
والخليع يفسر arg1
وarg2
والمهام، ويحاول تشغيلها. لذلك نحن إجهاض فقط قبل أن يفعل.
namespace :some do
task task: :environment do
arg1, arg2 = ARGV
# your task...
exit
end
end
وخذ هذا، بين قوسين!
<القوي> تنويه : لأنني أريد أن أكون قادرة على القيام بذلك في مشروع الحيوانات الأليفة الصغيرة جدا. غير مخصص للاستخدام "العالم الحقيقي" منذ تفقد القدرة على المهام أشعل النار سلسلة (أي rake task1 task2 task3
). IMO لا يستحق كل هذا العناء. مجرد استخدام rake task[arg1,arg2]
قبيحة.
وأنا استخدم حجة روبي العادية في ملف أشعل النار:
DB = ARGV[1]
وبعد ذلك كعب بالمهام أشعل النار في الجزء السفلي من ملف (منذ أشعل النار سوف تبحث عن مهمة على أساس أن اسم الحجة).
task :database_name1
task :database_name2
وسطر الأوامر:
rake mytask db_name
وهذا يشعر أنظف لي من فار = فو ENV فار وسائط مهمة [بلاه، blah2] حلول.
كعب هو قليلا jenky، ولكن لا بأس إذا لديك فقط عدد قليل من البيئات التي هي الإعداد لمرة واحدة
والطرق لتمرير حجة صحيحة في الجواب أعلاه. ومع ذلك لتشغيل مهمة أشعل النار مع الحجج، وهناك تفصيل ضئيل المشاركة في إصدار أحدث من القضبان
وانها ستعمل مع أشعل النار "مساحة الاسم: taskname [ 'argument1']"
وملاحظة علامات الاقتباس مقلوب في تشغيل المهمة من سطر الأوامر.
تعجبني صيغة "سلسلة الاستعلام" لتمرير الوسيطة، خاصة عندما يكون هناك الكثير من الوسيطات المطلوب تمريرها.
مثال:
rake "mytask[width=10&height=20]"
"سلسلة الاستعلام" هي:
width=10&height=20
تحذير: لاحظ أن بناء الجملة هو rake "mytask[foo=bar]"
و لا rake mytask["foo=bar"]
عند التحليل داخل مهمة أشعل النار باستخدام Rack::Utils.parse_nested_query
، نحصل على Hash
:
=> {"width"=>"10", "height"=>"20"}
(الشيء الرائع هو أنه يمكنك تمرير التجزئة والمصفوفات، المزيد أدناه)
هذه هي الطريقة لتحقيق ذلك:
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
فيما يلي مثال أكثر شمولاً أستخدمه مع Rails في ملفي late_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]"
تم التحليل بنفس الطريقة المذكورة أعلاه، مع تبعية البيئة (من أجل تحميل بيئة 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
يعطي ما يلي في options
=> {"ebooks"=>{"workers_number"=>"16", "worker_timeout"=>"60"}, "albums"=>{"workers_number"=>"32", "worker_timeout"=>"120"}}
لتمرير الوسائط لهذه المهمة افتراضي، يمكنك أن تفعل شيئا من هذا القبيل. على سبيل المثال، ويقول "نسخة" هو حجتك:
task :default, [:version] => [:build]
task :build, :version do |t,args|
version = args[:version]
puts version ? "version is #{version}" : "no version passed"
end
وبعد ذلك يمكنك أن نسميها مثل ذلك:
$ rake
no version passed
أو
$ rake default[3.2.1]
version is 3.2.1
أو
$ rake build[3.2.1]
version is 3.2.1
ولكن، لم أجد وسيلة لتجنب تحديد اسم المهمة (الافتراضي أو بناء) أثناء مروره في الحجج. أحب أن أسمع إذا كان أي شخص يعرف من وسيلة.
ولم معظم الطرق المذكورة أعلاه لا تعمل بالنسبة لي، ربما يتم إهمال أنهم في إصدارات أحدث. دليل ما يصل إلى تاريخ يمكن الاطلاع هنا: HTTP: //guides.rubyonrails كافيه / command_line.html # خصيصا أشعل النار-المهام
وعلى الجواب النسخ واللصق من دليل هنا هو:
task :task_name, [:arg_1] => [:pre_1, :pre_2] do |t, args|
# You can use args from here
end
واستدعاء مثل هذا
bin/rake "task_name[value 1]" # entire argument string should be quoted
إذا كنت لا يمكن ازعجت أن نتذكر ما هو الموقف الحجة هو ما وتريد أن تفعل شيئا مثل تجزئة حجة روبي. يمكنك استخدام وسيطة واحدة لتمرير في سلسلة ثم REGEX هذه السلسلة إلى تجزئة الخيارات.
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
وعلى سطر الأوامر التي تحصل عليها.
$ 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
لتشغيل المهام أشعل النار مع نمط الحجج التقليدية:
rake task arg1 arg2
وبعد ذلك استخدام:
task :task do |_, args|
puts "This is argument 1: #{args.first}"
end
واضافة التالية التصحيح من الأحجار الكريمة أشعل النار:
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
وبينما يمر المعلمات، فمن الخيار الأفضل هو ملف إدخال، وهذا يمكن أن يكون التفوق لسلمان أو كل ما تحتاجه وهناك من يقرأ بنية البيانات والمتغيرات التي تحتاجها من أن تضمين اسم المتغير كما هو الحاجة. لقراءة ملف يمكن أن يكون البنية التالية.
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