как передать аргументы командной строки в задачу rake

<p>у меня есть грабли задача, которая должна вставить значение в несколько баз данных. </p><p>я хотел бы передать это значение в задачу rake из командной строки или из<em> другой </em>rake задачи.</p><p>как я могу это сделать?</p>

<p>параметры и зависимости должны быть внутри массивов:</p><pre><code>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 </code></pre><p>затем</p><pre><code>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"} </code></pre><blockquote> <p>примечание: переменная <code>task</code> является объектом задачи, она не очень полезна, если вы не знаете/не заботитесь о внутренностях rake. </p> </blockquote><p><strong> рельсы примечание: </strong></p><blockquote> <p>если вы запускаете задачу из rails, лучше всего предварительно загрузить среду, добавив <code>=> [:environment]</code>, который является способом настройки <em>зависимых</em> задач. </p> </blockquote><pre><code> task :work, [:option, :foo, :bar] => [:environment] do |task, args| puts "work", args end </code></pre>

<p>вы можете указать формальные аргументы в rake, добавив символьные аргументы к вызову задачи. например:</p><pre><code>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 </code></pre><p>затем из командной строки:</p><pre> > rake my\_task [1,2] аргументы были: {: arg1 => "1",: arg2 => "2"} > rake "my\_task [1, 2]" аргументы были: {: arg1 => "1",: arg2 => "2"} > rake invoke\_my\_task аргументы были: {: arg1 => "1",: arg2 = > "2"} > rake invoke\_my\_task\_2 аргументы были: {: arg1 => 3,: arg2 => 4} > rake with\_prerequisite [5,6] аргументы были: {: arg1 => "5",: arg2 => "6"} > rake with\_defaults аргументы со значениями по умолчанию были: {: arg1 =>: default\_1,: arg2 =>: default\_2} > rake with\_defaults ['x', 'y'] аргументы со значениями по умолчанию: {: arg1 => "x",: arg2 => "y"} </pre><p>как показано во втором примере, если вы хотите использовать пробелы, кавычки вокруг целевого имени необходимы, чтобы не допустить разбиения командной оболочки аргументов в пробеле.</p><p>глядя на код в<strong> rake.rb </strong>, выясняется, что rake не анализирует строки задач для извлечения аргументов для предварительных условий, поэтому вы не можете выполнить <code>task :t1 => "dep[1,2]"</code>. единственный способ указать различные аргументы для предварительного условия - это явно вызвать его в зависимом действии задачи, как в <code>:invoke\_my\_task</code> и <code>:invoke\_my\_task\_2</code>.</p><p>обратите внимание, что некоторые оболочки (например, zsh) требуют, чтобы вы выходили за скобки: <code>rake my\_task\['arg1'\]</code></p>

<p>в дополнение к ответу по kch (я не нашел, как оставить комментарий к этому, извините):</p><p>вам не нужно указывать переменные как переменные <code>env</code> перед командой <code>rake</code>. вы можете просто установить их как обычные параметры командной строки:</p><pre><code>rake mytask var=foo </code></pre><p>и получить доступ к ним из вашего файла rake как переменные env, например:</p><pre><code>p env['var'] # => "foo" </code></pre>

<p>если вы хотите передать именованные аргументы (например, с помощью стандартной <code>optionparser</code>), вы можете использовать что-то вроде этого:</p><pre><code>$ rake user:create -- --user test@example.com --pass 123 обратите внимание на --, который необходим для обхода стандартных аргументов rake. должен работать с rake<strong> 0.9.x </strong>,<strong> <= 10.3.x </strong>.более новые 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-скрипты выглядят так, возможно, пришло время искать другой инструмент, который позволил бы это просто из коробки.

я нашел ответ на этих двух веб-сайтах: <a href="http://nhw.pl/wp/2008/10/11/rake-and-arguments-for-tasks">net maniac и <a href="http://www.aimred.com/news/developers/2008/10/16/arguments-for-rake/">aimred .вы должны иметь версию> 0.8 рейка, чтобы использовать эту техникуобычное описание граблей:desc 'task description' task :task_name => [:depends_on_taska, :depends_on_taskb] do #interesting things end чтобы передать аргументы, сделайте три вещи: добавьте имена аргументов после имени задачи, разделяя их запятыми. поместите зависимости в конце, используя: needs => [...] place | t, args | после того как (т является объектом для этой задачи) чтобы получить доступ к аргументам в сценарии, используйте args.arg_namedesc '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 чтобы вызвать эту задачу из командной строки, передайте ей аргументы в [] srake task_name['hello',4] будет выводитьhello hello hello hello и если вы хотите вызвать эту задачу из другой задачи и передать ей аргументы, используйте invoketask :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 </code></pre>

<p>на самом деле @nick desjardins ответил идеально. но только для образования: вы можете использовать грязный подход: используя аргумент <code>env</code></p><pre><code>task :my\_task do myvar = env['myvar'] puts "myvar: #{myvar}" end rake my\_task myvar=10 #=> myvar: 10 </code></pre>

<p>я не мог понять, как передавать аргументы, а также окружение, пока не решил это:</p><pre><code>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 </code></pre><p>и тогда я звоню так:</p><pre><code>rake db:export['foo, /tmp/'] </code></pre>

<pre><code>desc 'an updated version' task :task\_name, [:arg1, :arg2] => [:dependency1, :dependency2] do |t, args| puts args[:arg1] end </code></pre>

<p>я просто хотел иметь возможность бежать:</p><pre><code>$ rake some:task arg1 arg2 просто, правда? (нету!)rake интерпретирует arg1 и arg2 как задачи и пытается их запустить. таким образом, мы просто прерываем, прежде чем это произойдет.namespace :some do task task: :environment do arg1, arg2 = argv # your task... exit end end возьми это, скобки!<strong> отказ от ответственности </strong>: я хотел быть в состоянии сделать это в довольно маленьком домашнем проекте. не предназначен для использования в "реальном мире", так как вы теряете возможность связывать рейк-задачи (т.е. rake task1 task2 task3). имо не стоит. просто используйте уродливый rake task[arg1,arg2].

я использую обычный аргумент ruby в файле rake:db = argv[1] затем я заглушаю задачи rake внизу файла (поскольку rake будет искать задачу по имени этого аргумента).task :database_name1 task :database_name2 командная строка:rake mytask db_name это кажется мне чище, чем var = foo env var и args [blah, blah2]. заглушка немного дрянная, но не слишком плохая, если у вас есть несколько сред, которые являются одноразовыми

способы передачи аргумента верны в ответе выше. однако, чтобы запустить грабли с аргументами, есть небольшая техническая часть, связанная с более новой версией railsон будет работать с граблями "namespace: taskname ['arguments1']"обратите внимание на перевернутые кавычки при запуске задачи из командной строки. 

мне нравится синтаксис querystring для передачи аргументов, особенно когда нужно передать много аргументов. пример:rake "mytask[width=10&height=20]" «строка запроса»:width=10&height=20 <strong>предупреждение:</strong> обратите внимание, что синтаксис rake "mytask[foo=bar]" и <strong>не</strong> 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 в моем <a href="https://github.com/zxiest/delayed_job_active_record_threaded">delayed_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]" анализируется так же, как и выше, с зависимостью от среды (для загрузки среды 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"}} 

чтобы передать аргументы задаче по умолчанию, вы можете сделать что-то вроде этого. например, скажите "version" - ваш аргумент: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 </code></pre><p>или же </p><pre><code>$ rake default[3.2.1] version is 3.2.1 или же$ rake build[3.2.1] version is 3.2.1 </code></pre><p>однако я не нашел способа избежать указания имени задачи (по умолчанию или сборка) при передаче аргументов. хотелось бы услышать, если кто-нибудь знает способ.</p>

<p>большинство методов, описанных выше, у меня не сработали, может быть, они устарели в более новых версиях .... современное руководство можно найти здесь: <a href="http://guides.rubyonrails.org/command\_line.html#custom-rake-tasks">http://guides.rubyonrails.org/command\_line. html # custom-rake-tasks</a> </p><p>копирование и вставка из руководства здесь:</p><pre><code>task :task\_name, [:arg\_1] => [:pre\_1, :pre\_2] do |t, args| # you can use args from here end </code></pre><p>вызвать это так</p><pre><code>bin/rake "task\_name[value 1]" # entire argument string should be quoted </code></pre>

<p>если вы не можете вспомнить, какая позиция аргумента для чего, и вы хотите сделать что-то вроде хэша аргумента ruby. вы можете использовать один аргумент, чтобы передать строку, а затем пересмотреть эту строку в хэш опций. </p><pre><code>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 </code></pre><p>и в командной строке вы получите.</p><pre><code>$ 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 </code></pre>

<p>для запуска граблей с традиционным стилем аргументов:</p><pre><code>rake task arg1 arg2 </code></pre><p>а затем используйте:</p><pre><code>task :task do |\_, args| puts "this is argument 1: #{args.first}" end </code></pre><p>добавьте следующий патч rake gem:</p><pre><code>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 </code></pre>