I have a rake task that needs to insert a value into multiple databases.
I'd like to pass this value into the rake task from the command line, or from another rake task.
How can I do this?
I have a rake task that needs to insert a value into multiple databases.
I'd like to pass this value into the rake task from the command line, or from another rake task.
How can I do this?
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} 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
Then, from the command line:
> 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"}
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.
Note that some shells (like zsh) require you to escape the brackets: rake my_task\['arg1'\]
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:
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
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
namespace :namespace1 do
task :task1, [:arg1, :arg2, :arg3] => :environment do |_t, args|
p args[:arg1]
end
end
calling
rake namespace1:task1["1","2","3"]
No need to provide environment while calling
in zsh need to enclose calling in quotes
rake 'namespace1:task1["1","2","3"]'
To run rake tasks with traditional arguments style:
rake task arg1 arg2
And then use:
task :task do |_, args|
puts "This is argument 1: #{args.first}"
end
Add following patch of rake gem:
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
One thing I don't see here is how to handle arbitrary arguments. If you pass arguments that are not listed in the task definition, they are still accessible under args.extras:
task :thing, [:foo] do |task, args|
puts args[:foo] # named argument
puts args.extras # any additional arguments that were passed
end