views:

5834

answers:

4

I've got a rake task that I am making that needs to insert a value into multiple databases.

I'd like to be able to pass this value into the rake task from the command line, or from another rake task, how can I do this?

+39  A: 

You can specify formal arguments in rake by adding symbol arguments to the task call. For example:

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, :needs => :my_task

# equivalently...
task :with_prerequisite_2, [:arg1, :arg2] => :my_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

Then, from the command line:

F:\test\rake>rake my_task[1,2]
(in F:/test/rake)
Args were: {:arg1=>"1", :arg2=>"2"}

F:\test\rake>rake "my_task[1, 2]"
(in F:/test/rake)
Args were: {:arg1=>"1", :arg2=>"2"}

F:\test\rake>rake invoke_my_task
(in F:/test/rake)
Args were: {:arg1=>"1", :arg2=>"2"}

F:\test\rake>rake invoke_my_task_2
(in F:/test/rake)
Args were: {:arg1=>3, :arg2=>4}

F:\test\rake>rake with_prerequisite[5,6]
(in F:/test/rake)
Args were: {:arg1=>"5", :arg2=>"6"}

F:\test\rake>rake with_prerequisite_2[7,8]
(in F:/test/rake)
Args were: {:arg1=>"7", :arg2=>"8"}

F:\test\rake>rake with_defaults
(in F:/test/rake)
Args with defaults were: {:arg1=>:default_1, :arg2=>:default_2}

F:\test\rake>rake with_defaults['x','y']
(in F:/test/rake)
Args with defaults were: {:arg1=>"x", :arg2=>"y"}

As demonstrated in the second example, if you want to use spaces, the quotes around the target name are necessary to keep the shell from splitting up the arguments at the space.

Looking at the code in rake.rb, it appears that rake does not parse task strings to extract arguments for prerequisites, so you can't do task :t1 => "dep[1,2]". The only way to specify different arguments for a prerequisite would be to invoke it explicitly within the dependent task action, as in :invoke_my_task and :invoke_my_task_2.

Nick Desjardins
This doesn't tell me how to run the rake task with arguments from another task. It covers only command line usage
Tilendor
You're right. I have edited the answer to provide more thorough examples.
Nick Desjardins
To invoke a task within a namespace simpy do: Rake::Task['namespace:task'].invoke
ba
Wow, Nick. I wish I could vote this up twice. Thanks!
Peeja
Actually amazed, I've looked for the answer to this so many times and it's always been rake task arg1=2 arg2=3. This is much simpler when the arguments are in series.
opsb
+4  A: 

I've found the answer from these two websites: Net Maniac and Aimred.

You need to have version > 0.8 of rake to use this technique

The normal rake task description is this:

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

To pass arguments, do three things:

  1. Add the argument names after the task name, separated by commas.
  2. Put the dependencies at the end using :needs => [...]
  3. Place |t, args| after the do. (t is the object for this task)

To access the arguments in the script, use 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

To call this task from the command line, pass it the arguments in []s

rake task_name['Hello',4]

will output

Hello
Hello
Hello
Hello

and if you want to call this task from another task, and pass it arguments, use invoke

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

then the command

rake caller

will output

In Caller
hi
hi

I haven't found a way to pass arguments as part of a dependency, as the following code breaks:

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

Another commonly used option is to pass environment variables. In your code you read them via ENV['VAR'], and can pass them right before the rake command, like

$ VAR=foo rake mytask
kch
Frankly I was hoping for rake task -- these --go --to -a program and my task could get them from ARGV. Unfortunately I'm not sure if that's possible however I am currently using your solution: rake var1=val1 var2=val2
jhs
A: 

I have a follow up question (for Nick Desjardins). I have copied your example here:

task :with_defaults, :arg1, :arg2 do |t, args|
  args.with_defaults(:arg1 => :default_1, :arg2 => :default_2)
  puts "Args with defaults were: #{args}"
end

and it works flawlessly but when I make the following change:

desc "Task with defaults"
task :my_task, :arg1, :arg2 do |t, args|
  args.my_task(:arg1 => :default_1, :arg2 => :default_2)
  puts "Args with defaults were: #{args}"
end

it falls flat on its face. Is there something I'm missing here?

Thanks in advance.

j1n3l0
-1 this should be asked as a separate question, not as an answer to my question. You are confusing the name of the task :with_defaults and the hash function .with_defaults. Nick named his task after the method, but there is no actual connection. Change args.my_task... back to args.with_defaults.. and you're good.
Tilendor
Thanks a lot, that worked.
j1n3l0