Are task dependencies always run in a specific order with rake? - ruby

I have the following example which is based on the structure i want my rakefile to use:
task :default do
puts 'Tasks you can run: dev, stage, prod'
end
task :dev => [:init,:devrun,:clean]
task :devrun do
puts 'Dev stuff'
end
task :stage => [:init,:stagerun,:clean]
task :stagerun do
puts 'Staging stuff'
end
task :prod => [:init,:prodrun,:clean]
task :prodrun do
puts 'Production stuff'
end
task :init do
puts 'Init...'
end
task :clean do
puts 'Cleanup'
end
Will the tasks always be run in the same order? I read somewhere that they wouldn't, and somewhere else that they would, so i'm not sure.
Or if you can suggest a better way to do what i'm trying to achieve (eg have a common init and cleanup step surrounding a depending-upon-environment step), that'd also be good.
Thanks

From the Rake source code:
# Invoke all the prerequisites of a task.
def invoke_prerequisites(task_args, invocation_chain) # :nodoc:
#prerequisites.each { |n|
prereq = application[n, #scope]
prereq_args = task_args.new_scope(prereq.arg_names)
prereq.invoke_with_call_chain(prereq_args, invocation_chain)
}
end
So it appears that the code normally just iterates the array and runs the prerequisite tasks sequentially.
However:
# Declare a task that performs its prerequisites in parallel. Multitasks does
# *not* guarantee that its prerequisites will execute in any given order
# (which is obvious when you think about it)
#
# Example:
# multitask :deploy => [:deploy_gem, :deploy_rdoc]
#
def multitask(args, &block)
Rake::MultiTask.define_task(args, &block)
end
So you are right, both can be true, but order can only be off if you prefix your task with multitask It looks like regular tasks are run in order.

Related

Run all rake tasks?

How can I run all rake tasks?
task :a do
# stuff
end
task :b do
# stuff
end
task :c do
# stuff
end
task :all do
# Run all other tasks?
end
I know I can just do
task :all => [:a, :b, :c] do
end
but if I add new task, I also need to add it to :all dependencies. I would
like to avoid the need to do it manually since it seems like easy thing to forget.
Here's one way:
namespace :hot_tasks do |hot_tasks_namespace|
task :task1 do
puts 1
end
task :task2 do
puts 2
end
task :all do
hot_tasks_namespace.tasks.each do |task|
Rake::Task[task].invoke
end
end
end
running it:
# bundle exec rake hot_tasks:all
1
2
More (not necessarily better) ideas at this question, especially if you're in a rails app.

Rake before task hook

Is there a straight forward way to modify a Rake task to run some bit of code before running the existing task? I'm looking for something equivalent to enhance, that runs at the beginning rather than the end of the task.
Rake::Task['lame'].enhance(['i_run_afterwards_ha_ha'])
You can use the dependency of Rake task to do that, and the fact that Rake allows you to redefine existing task.
Rakefile
task :your_task do
puts 'your_task'
end
task :before do
puts "before"
end
task :your_task => :before
As result
$ rake your_task
before
your_task
Or you could use the rake-hooks gem to do before and after hooks:
https://github.com/guillermo/rake-hooks
namespace :greetings do
task :hola do puts "Hola!" end ;
task :bonjour do puts "Bonjour!" end ;
task :gday do puts "G'day!" end ;
end
before "greetings:hola", "greetings:bonjour", "greetings:gday" do
puts "Hello!"
end
rake greetings:hola # => "Hello! Hola!"

Alias of task name in Rake

When I need to alias some task's name, how should I do it?
For example, how do I turn the task name:
rake db:table
rake db:create
rake db:schema
rake db:migration
to:
rake db:t
rake db:c
rake db:s
rake db:m
Editing after getting the answer:
def alias_task(tasks)
tasks.each do |new_name, old_name|
task new_name, [*Rake.application[old_name].arg_names] => [old_name]
end
end
alias_task [
[:ds, :db_schema],
[:dc, :db_create],
[:dr, :db_remove]
]
Why do you need an alias? You may introduce a new task without any code, but with a prerequisite to the original task.
namespace :db do
task :table do
puts "table"
end
#kind of alias
task :t => :table
end
This can be combined with parameters:
require 'rake'
desc 'My original task'
task :original_task, [:par1, :par2] do |t, args|
puts "#{t}: #{args.inspect}"
end
#Alias task.
#Parameters are send to prerequisites, if the keys are identic.
task :alias_task, [:par1, :par2] => :original_task
To avoid to search for the parameters names you may read the parameters with arg_names:
#You can get the parameters of the original
task :alias_task2, *Rake.application[:original_task].arg_names, :needs => :original_task
Combine it to a define_alias_task-method:
def define_alias_task(alias_task, original)
desc "Alias #{original}"
task alias_task, *Rake.application[original].arg_names, :needs => original
end
define_alias_task(:alias_task3, :original_task)
Tested with ruby 1.9.1 and rake-0.8.7.
Hmmm, well, I see that's more or less exactly the same solution RyanTM already posted some hours ago.
Here is some code someone wrote to do it: https://gist.github.com/232966
def alias_task(name, old_name)
t = Rake::Task[old_name]
desc t.full_comment if t.full_comment
task name, *t.arg_names do |_, args|
# values_at is broken on Rake::TaskArguments
args = t.arg_names.map { |a| args[a] }
t.invoke(args)
end
end

How do I know if a rake task has been invoked from another task or from the shell?

Let's say we have:
task :something => [:something_else] do
# some of stuff
end
task :something_else do
# some verbose stuff
# some quiet stuff
end
Now I want something_else to do the verbose stuff when called from the shell (rake something_else) and the silent ones when called as a dependency to rake something.
i think it might be a better idea to work with parameters or different tasks instead.
one thing that you could do is look for top-level task like that:
task :something_else do |t|
puts "some verbose stuff" if t.application.top_level_tasks.include? 'something_else'
puts "some quiet stuff"
end
You could look what was passed to ARGV. For example:
task :something_else do
if ARGV[0] == 'something_else'
puts "Verbose Stuff!"
end
end

Avoiding duplication in setting properties on the task in Rake tasks

I have a bunch of rake building tasks.
They each have unique input / output properties, but the majority of the properties I set on the tasks are the same each time. Currently I'm doing that via simple repetition like this:
task :buildThisModule => "bin/modules/thisModule.swf"
mxmlc "bin/modules/thisModule.swf" do |t|
t.input = "src/project/modules/ThisModule.as"
t.prop1 = value1
t.prop2 = value2 ... (And many more property=value sets that are the same in each task)
end
task :buildThatModule => "bin/modules/thatModule.swf"
mxmlc "bin/modules/thatModule.swf" do |t|
t.input = "src/project/modules/ThatModule.as"
t.prop1 = value1
t.prop2 = value2 ... (And many more property=value sets that are the same in each task)
end
In my usual programming headspace I'd expect to be able to break out the population of the recurring task properties to a re-usable function.
Is there a rake analogy for this? Some way I can have a single function where the shared properties are set on any task? Something equivalent to:
task :buildThisModule => "bin/modules/thisModule.swf"
mxmlc "bin/modules/thisModule.swf" do |t|
addCommonTaskParameters(t)
t.input = "src/project/modules/ThisModule.as"
end
task :buildThatModule => "bin/modules/thatModule.swf"
mxmlc "bin/modules/thatModule.swf" do |t|
addCommonTaskParameters(t)
t.input = "src/project/modules/ThatModule.as"
end
Thanks.
======
In reply to SR:
Thanks Stephen,
I'm obviously missing something - I've got:
desc 'Compile run the test harness'
unit :test do |t|
populate_test_task(t)
end
def populate_test_task(t)
t.source_path << "support"
t.prepended_args = '+configname=air -define+=CONFIG::LocalDebug,true'
end
I've tried defining the function immediately after the task (there's no namespace: in this file) and right at the end of the file after the last task, and I'm getting "undefined method `populate_test_task' for main:Object" - which seems to me like it's not finding the function.
What am I missing?
You can call regular methods defined lower down the rake file, e.g.
namespace :build do
desc 'builds ABC module'
task :abc do
build_mod('abc')
end
desc 'builds DEF module'
taks :def do
build_mod('def')
end
end
def build_mod(module_name)
# stuff to build the module
end
then call it with rake build:abc and rake build:def
sr
Sorry about the confusion here....
This problem is a side effect of how Project Sprouts creates Rake tasks. Because some parameters in the block need to modify the prerequisites of the task, some of our tasks evaluate their associated block as they are defined.
It's for this reason that your configure function has to be defined before the tasks that use it.
Awesome team work!
Thanks to both, answer was to break out the population of the task properties to a function, but to define that function above the block using it (for project sprouts reasons).
Like this:
def populate_test_task(t)
t.source_path << "support"
t.prepended_args = '+configname=air -define+=CONFIG::LocalDebug,true'
end
desc 'Compile run the test harness'
unit :test do |t|
populate_test_task(t)
end

Resources