I have a Rakefile that compiles the project in two ways, according to the global variable $build_type
, which can be :debug
or :release
(the results go in separate directories):
task :build => [:some_other_tasks] do
end
I wish to create a task that compiles the project with both configurations in turn, something like this:
task :build_all do
[ :debug, :release ].each do |t|
$build_type = t
# call task :build with all the tasks it depends on (?)
end
end
Is there a way to call a task as if it were a method? Or how can I achieve anything similar?
Rake::Task["build"].invoke
can be much more performant than using system rake build
because it doesn't have to create a new thread and load up the Rails environment, which system rake build
does have to do.
If you need the task to behave as a method, how about using an actual method?
task :build => [:some_other_tasks] do
build
end
task :build_all do
[:debug, :release].each { |t| build t }
end
def build(type = :debug)
# ...
end
If you'd rather stick to rake's idioms, here are your possibilities, compiled from past answers:
This always executes the task, but it doesn't execute its dependencies: Rake::Task["build"].execute
This one executes the dependencies, but it only executes the task if it has not already been invoked: Rake::Task["build"].invoke
This first resets the task's already_invoked state, allowing the task to then be executed again, dependencies and all: Rake::Task["build"].reenable Rake::Task["build"].invoke
Note that dependencies already invoked are not automatically re-executed unless they are re-enabled. In Rake >= 10.3.2, you can use the following to re-enable those as well: Rake::Task["build"].all_prerequisite_tasks.each(&:reenable)
for example:
Rake::Task["db:migrate"].invoke
task :build_all do
[ :debug, :release ].each do |t|
$build_type = t
Rake::Task["build"].reenable
Rake::Task["build"].invoke
end
end
That should sort you out, just needed the same thing myself.
task :invoke_another_task do
# some code
Rake::Task["another:task"].invoke
end
task :build_all do
[ :debug, :release ].each do |t|
$build_type = t
Rake::Task["build"].execute
end
end
If you want each task to run regardless of any failures, you can do something like:
task :build_all do
[:debug, :release].each do |t|
ts = 0
begin
Rake::Task["build"].invoke(t)
rescue
ts = 1
next
ensure
Rake::Task["build"].reenable # If you need to reenable
end
return ts # Return exit code 1 if any failed, 0 if all success
end
end
I would suggest not to create general debug and release tasks if the project is really something that gets compiled and so results in files. You should go with file-tasks which is quite doable in your example, as you state, that your output goes into different directories. Say your project just compiles a test.c file to out/debug/test.out and out/release/test.out with gcc you could setup your project like this:
WAYS = ['debug', 'release']
FLAGS = {}
FLAGS['debug'] = '-g'
FLAGS['release'] = '-O'
def out_dir(way)
File.join('out', way)
end
def out_file(way)
File.join(out_dir(way), 'test.out')
end
WAYS.each do |way|
desc "create output directory for #{way}"
directory out_dir(way)
desc "build in the #{way}-way"
file out_file(way) => [out_dir(way), 'test.c'] do |t|
sh "gcc #{FLAGS[way]} -c test.c -o #{t.name}"
end
end
desc 'build all ways'
task :all => WAYS.map{|way|out_file(way)}
task :default => [:all]
This setup can be used like:
rake all # (builds debug and release)
rake debug # (builds only debug)
rake release # (builds only release)
This does a little more as asked for, but shows my points:
output directories are created, as necessary. the files are only recompiled if needed (this example is only correct for the simplest of test.c files). you have all tasks readily at hand if you want to trigger the release build or the debug build. this example includes a way to also define small differences between debug and release-builds. no need to reenable a build-task that is parametrized with a global variable, because now the different builds have different tasks. the codereuse of the build-task is done by reusing the code to define the build-tasks. see how the loop does not execute the same task twice, but instead created tasks, that can later be triggered (either by the all-task or be choosing one of them on the rake commandline).
Success story sharing
Rake::Task['db:reset'].invoke
Rake::Task['with:args'].invoke("pizza")
ENV['VERSION'] = '20110408170816'; Rake::Task['db:migrate'].invoke
See here for more explanation.#reenable()
doesn't re-enable pre-req's, and needed it. This addition to Rake (>= 10.3.2),#all_prerequisite_tasks()
will iterate all tasks, including pre-req's of pre-req's. So,Rake::Task[task].all_prerequisite_tasks.each &:reenable
rake db:reset db:migrate
for example). Can you do something like:Rake::Task["db:reset", "db:migrate"].invoke