У меня есть задача с граблями, которая должна вставить значение в несколько баз данных.
Я хотел бы передать это значение в задачу rake из командной строки или из другой задачи rake.
Как я могу это сделать?
У меня есть задача с граблями, которая должна вставить значение в несколько баз данных.
Я хотел бы передать это значение в задачу rake из командной строки или из другой задачи rake.
Как я могу это сделать?
Параметры и зависимости должны быть внутри массивов:
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
rake thing:work[1, 2, 3]
, так как это не сработает, и вы получите сообщение об ошибке Don't know how to build task
- person rpbaltazar; 29.09.2016
rake thing:work'[1,2,3]'
- person theterminalguy; 14.01.2017
rake thing:workd[true,false,cheese]
значения будут строками!
- person Blair Anderson; 11.02.2017
rake thing:work\[1,2,3\]
, или это rake 'thing:work[1,2,3]'
- person hutusi; 27.07.2017
Don't know how to build task 'environment' (see --tasks)
Ответ Ника Дежардена сработал отлично.
- person sakurashinken; 16.04.2018
:environment
из своей задачи. В приложениях rails есть задача: environment ...
- person Blair Anderson; 16.04.2018
t
означает task
, почему бы просто не использовать task
в качестве имени параметра?
- person Joshua Pinter; 05.05.2018
Вы можете указать формальные аргументы в rake, добавив аргументы символа к вызову задачи. Например:
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
Затем из командной строки:
> rake my_task[1,false] Args were: {:arg1=>"1", :arg2=>"false"} of class Rake::TaskArguments arg1 was: '1' of class String arg2 was: 'false' of class String > 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, кажется, что rake не анализирует строки задач для извлечения аргументов для предварительных условий, поэтому вы не можете сделать task :t1 => "dep[1,2]"
. Единственный способ указать разные аргументы для предварительного требования - это явно вызвать его внутри действия зависимой задачи, как в :invoke_my_task
и :invoke_my_task_2
.
Обратите внимание, что некоторые оболочки (например, zsh) требуют, чтобы вы избегали скобок: rake my_task\['arg1'\]
5.times { Rake::Task[:my_task].invoke }
, и это сработало только в первый раз.
- person igorsantos07; 18.08.2011
WARNING: 'task :t, arg, :needs => [deps]' is deprecated. Please use 'task :t, [args] => [deps]' instead.
- person Ajedi32; 16.08.2012
zsh: no matches found: ...
), поэтому вам нужно избегать скобок: rake my_task\['arg1'\]
. Из robots.oughttbot.com/post / 18129303042 /
- person Seth Bro; 17.07.2013
alias rake='noglob rake'
в свой .zshrc
и забудьте о скобках.
- person Roberto; 24.02.2016
task :task_name, [:var1, :var2] => :environment do |t, vars|
. Внутренние вары задач выглядят так: {:var1 => val, :var2 => val}
- person res; 07.09.2016
rake my_task[1,2]
вместо rake my_task[1, 2]
. В противном случае вы получите ужасную Don't know how to build task 'my_task[1,'
ошибку и будете чесать затылок дольше, чем хотели бы признать.
- person Joshua Pinter; 08.05.2018
with_defaults
или имя задачи и имя метода просто совпадают?
- person vlsd; 28.05.2021
x
и y
в rake with_defaults['x','y']
? В любом случае rake
получает with_defaults[x,y]
.
- person x-yuri; 05.07.2021
В дополнение к ответу kch (я не нашел, как оставить комментарий к этому, извините):
Вам не нужно указывать переменные как ENV
переменные перед командой rake
. Вы можете просто установить их как обычные параметры командной строки, например:
rake mytask var=foo
и получить доступ к ним из вашего rake-файла как переменные ENV, например:
p ENV['var'] # => "foo"
p
?
- person stevec; 02.06.2019
Если вы хотите передать именованные аргументы (например, со стандартным OptionParser
), вы можете использовать что-то вроде этого:
$ rake user:create -- --user [email protected] --pass 123
обратите внимание на --
, который необходим для обхода стандартных аргументов Rake. Должен работать с Rake 0.9.x, ‹= 10.3.x.
В новой версии 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 [email protected] -p 123
Когда скрипты rake выглядят так, возможно, пришло время поискать другой инструмент, который позволил бы это прямо из коробки.
--option-names
. Мое единственное предложение - использовать exit
, а не abort
, поскольку abort
оставит вам код возврата 1 для оболочки. Если задача rake является частью сценария более высокого уровня, чаще предполагается, что ненулевой выход - это какой-то тип ошибки.
- person Joe; 01.12.2013
--
? Например, передать rake
аргумента реальной задаче или что-то в этом роде? Типа task :my_task, :*args do |t, args|
или что-то в этом роде?
- person Augustin Riedinger; 02.04.2014
{username}
. Где это используется? Почему его нет в -u {username}
? Ваше здоровье
- person Augustin Riedinger; 03.04.2014
--
(просто не используя грабли). {username}
следует заменить на свое настоящее имя пользователя. Это просто обозначение переменной, оно не интерпретируется рубином.
- person Tombart; 03.04.2014
exit("account created.")
вызывает ошибку rake aborted!
не будет ли puts "account created"; exit(0)
лучший подход?
- person Justin Tanner; 20.11.2014
ARGV.shift
удалил create:user
и --
из ARGV
. Я уверен, что так не следует делать. Буду признателен, если кто-нибудь покажет, как это исправить.
- person pawel7318; 23.01.2015
10.4.0
- person Tombart; 25.01.2015
10.4.1
и возвращен в 10.4.2
. github.com/ruby/rake/commit/
- person Tombart; 25.01.2015
exit 0
является то, что эта задача выходит из Rake по завершении. Итак, если у вас есть задача, которая вызывает 2 задачи, и она сначала вызывает вышеуказанное, вторая задача не будет запущена.
- person karatedog; 23.07.2021
Я нашел ответ на этих двух веб-сайтах: Net Maniac и Нацеленный.
Для использования этой техники у вас должна быть версия rake> 0.8.
Обычное описание рейк-задачи таково:
desc 'Task Description'
task :task_name => [:depends_on_taskA, :depends_on_taskB] do
#interesting things
end
Чтобы передать аргументы, сделайте три вещи:
Чтобы получить доступ к аргументам в скрипте, используйте 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
и если вы хотите вызвать эту задачу из другой задачи и передать ей аргументы, используйте invoke
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
'task :t, arg, :needs => [deps]' is deprecated. Please use 'task :t, [args] => [deps]' instead.
- person madh; 15.01.2012
На самом деле @Nick Desjardins ответил идеально. Но только для образования: вы можете использовать грязный подход: использовать аргумент ENV
task :my_task do
myvar = ENV['myvar']
puts "myvar: #{myvar}"
end
rake my_task myvar=10
#=> myvar: 10
Другой часто используемый вариант - передать переменные среды. В вашем коде вы читаете их через ENV['VAR']
и можете передавать их прямо перед командой rake
, например
$ VAR=foo rake mytask
rake blah -- --these --go --to --a-program
(обратите внимание на --
, чтобы сообщить граблям, что его переключатели закончились), см. stackoverflow.com/questions/5086224/
- person mu is too short; 27.02.2011
exit
в конце задачи. Выйти проще, но это сломает любую сложную задачу, которая пытается запустить существующую задачу вместе с другими, поскольку exit
остановит выполнение задачи и выйдет из Rake.
- person karatedog; 22.07.2021
--switch1 value1 --switch2 value2
.
- person karatedog; 23.07.2021
Я не мог понять, как передавать аргументы, а также среду:, пока не разобрался с этим:
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/']
Я просто хотел уметь бегать:
$ rake some:task arg1 arg2
Все просто, правда? (Неа!)
Rake интерпретирует arg1
и arg2
как задачи и пытается их запустить. Поэтому мы просто прерываем работу до того, как это произойдет.
namespace :some do
task task: :environment do
arg1, arg2 = ARGV
# your task...
exit
end
end
Возьмите это, скобки!
Заявление об ограничении ответственности: я хотел иметь возможность сделать это в небольшом домашнем проекте. Не предназначен для использования в «реальном мире», так как вы теряете возможность связывать задачи с граблями (т.е. rake task1 task2 task3
). ИМО не стоит. Просто используйте уродливый rake task[arg1,arg2]
.
_, arg1, arg2 = ARGV
, поскольку первый аргумент был виден как имя задачи с граблями. Но это exit
- изящный трюк.
- person fatty; 13.09.2016
rake task[arg1,arg2] && rake task2 && rake task3
Не уверен, что это менее уродливо, чем rake task[arg1,arg2] task2 task3
. Хотя, вероятно, менее эффективен.
- person Nuclearman; 11.11.2016
_, *args = ARGV
идеально подходит для сбора всех последующих аргументов! Большое спасибо!
- person XtraSimplicity; 18.11.2018
Я использую обычный аргумент ruby в файле rake:
DB = ARGV[1]
затем я убираю задачи rake в нижней части файла (поскольку rake будет искать задачу на основе этого имени аргумента).
task :database_name1
task :database_name2
командная строка:
rake mytask db_name
мне это кажется чище, чем решения var = foo ENV var и task args [blah, blah2].
заглушка немного дурацкая, но не так уж плохо, если у вас есть несколько сред, которые являются одноразовыми настраивать
dup
в конце: db = ARGV [1] .dup
- person Juanda; 18.01.2013
db = ARGV[1].dup unless ARGV[1].nil?
, чтобы предотвратить исключение дублирования нуля.
- person Andre Figueiredo; 30.06.2016
Способы передачи аргумента верны в приведенном выше ответе. Однако для запуска задачи rake с аргументами есть небольшая техническая сторона, связанная с новой версией rails.
Он будет работать с граблями "namespace: taskname ['argument1']"
Обратите внимание на перевернутые кавычки при запуске задачи из командной строки.
Чтобы передать аргументы задаче по умолчанию, вы можете сделать что-то вроде этого. Например, ваш аргумент - это версия:
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
or
$ rake default[3.2.1]
version is 3.2.1
or
$ rake build[3.2.1]
version is 3.2.1
Однако я не нашел способа избежать указания имени задачи (по умолчанию или сборки) при передаче аргументов. Хотелось бы услышать, знает ли кто-нибудь способ.
Мне нравится синтаксис "querystring" для передачи аргументов, особенно когда нужно передать много аргументов.
Пример:
rake "mytask[width=10&height=20]"
«Строка запроса»:
width=10&height=20
Предупреждение: обратите внимание, что синтаксис - rake "mytask[foo=bar]"
, а НЕ rake mytask["foo=bar"]
.
При парсинге внутри задачи rake с использованием 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 в моем геме delayed_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"}}
Большинство описанных выше методов у меня не работали, возможно, они устарели в более новых версиях. Актуальное руководство можно найти здесь: http://guides.rubyonrails.org/command_line.html#custom-rake-tasks.
Здесь можно скопировать и вставить ответ из руководства:
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
Если вас не беспокоит запоминание позиции аргумента для чего, и вы хотите сделать что-то вроде хеша аргумента рубина. Вы можете использовать один аргумент для передачи строки, а затем регулярное выражение этой строки в хэш параметров.
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-задачи с традиционным стилем аргументов:
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
Я не вижу здесь как обрабатывать произвольные аргументы. Если вы передаете аргументы, которые не указаны в определении задачи, они по-прежнему доступны в args.extras
:
task :thing, [:foo] do |task, args|
puts args[:foo] # named argument
puts args.extras # any additional arguments that were passed
end
При передаче параметров лучшим вариантом является входной файл, может ли это быть excel json или что-то еще, что вам нужно, и оттуда прочитать структуру данных и переменные, которые вам нужны, включая имя переменной по мере необходимости. Для чтения файл может иметь следующую структуру.
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
rake task_name[hello, world]
- person Dex; 27.04.2014