Rake before task hook - ruby

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!"

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.

How to know which task is being executed with rake

I'd like to know from within a rake ask what is the name of the task that is being executed? How to do this? For example, in the code bellow, when I run rake my_incredible_task, it should print "my_incredible_task":
task :boot do
task_name = <what comes here?>
puts task_name
end
task :my_incredible_task => [:boot] do
#do some stuff
end
I'm not sure there is a way out of the box, however you can do something like this:
require 'rake'
module Rake
class Application
attr_accessor :current_task_name
end
class Task
alias :old_execute :execute
def execute(args=nil)
Rake.application.current_task_name = #name
old_execute(args)
end
end
end
namespace :so do
task :my_task do
puts Rake.application.current_task_name
end
end
Not sure how this will work out with tasks that run in parallel...
You can use a parameter in the block :
task :my_incredible_task do |t|
puts t.name
end
EDIT
You could use methods instead :
task :boot do |t|
boot(t.name)
end
task :my_incredible_task do |t|
boot(t.name)
#do some stuff
end
def boot task_name
# do stuff
end

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

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

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.

Adding Growl notifications after Rake tasks are finished

Is there a way to add Growl notifications to the end of all Rake tasks?
I initially thought of creating a task that Growls, and adding it as a dependency to tasks I want alerts from, but realized the dependencies get run before the task begins. Is there a way to add tasks to be run after certain Rake tasks are finished?
It'd be really useful so I don't have to sit there waiting for long tasks.
** update 8/17/2010 **
Here is the solution for doing it with growlnotify...put this in your Rakefile:
def growl(message)
growlnotify = `which growlnotify`.chomp
system %(#{growlnotify} -sm #{message})
end
task_names = Rake.application.top_level_tasks
task_names.each do |name|
Rake.application[name].enhance { growl "'Task #{name} completed (#{Time.now})'" }
end
-- Credit to Alkaline - see his solution for using ruby-growl below --
Here's how you can implicitly invoke a growl action for the calling (top level) tasks
require 'rake'
require 'ruby-growl'
task :task1 do puts "Doing task 1"; sleep 1; end
task :task2 do puts "Doing task 2"; sleep 1; end
task :default => [:task1, :task2]
# Add a growl action to all top level tasks
task_names = Rake.application.top_level_tasks
task_names.each do |name|
Rake.application[name].enhance {growl(name)}
end
def growl(name)
g = Growl.new "localhost", "ruby-growl", ["ruby-growl Notification"]
g.notify "ruby-growl Notification", "My Project", "Task #{name} completed"
end
The gem rakegrowl does this very simply. All you have to do is install the rakegrowl gem and alias rake to rake -rubygems -r rakegrowl in your .bashrc.

Resources