This blog has been moved to http://info.timkellogg.me/blog/

Wednesday, April 20, 2011

Scripting with rake

Rake is a great twist on traditional make (honestly, I never really liked Ant or NAnt). On the surface it looks more like make than Ant or Nant, but you can leverage the full syntax and standard library of Ruby (and there's no weird rules about tabs). As a .NET developer, albacore augments rake nicely with tasks for MSBuild (building Visual Studio projects and solutions), NUnit, ASP.NET precompiler, modifying your AssemblyInfo.cs (like for bumping the version number), and many more.

Since rake is just ruby code, you can do just about anything, but most file manipulation routines are even easier to write in rake, because most everything is already imported and ready to use. Unlike make, Ant, and Nant, you don't have to start a separate project just to develop tools to use in a rakefile, just write a ruby function!

Building dependencies first
A lot of people who aren't already familiar with build languages make some common mistakes. Among them, not using dependencies correctly. For instance, given a website solution that references framework

msbuild :framework do |msb|
  msb.solution = 'framework/src/framework.sln'
end

msbuild :website do |msb|
  msb.solution = 'src/website.sln'
end

task :default => [:framework, :website]

The default task is the task that's executed when you just type rake at the CLI. The reason this is terrible is that it's procedural and inflexible. Now, if I do rake website the build fails because framework hasn't been built yet. Instead, each task should specify what other tasks it directly relies on. This script should change to:

msbuild :framework do |msb|
  msb.solution = 'framework/src/framework.sln'
end

msbuild :website => :framework do |msb|
  msb.solution = 'src/website.sln'
end

task :default => :website

This way both rake and rake website work the same. This leverages rakes dependency framework that is at the core of all build languages.

Using file tasks
The other point that people often forget is that build languages are oriented around files. Make tasks were oriented around questions like "does this file need to be created?". This is where rakes file task comes in very handy. For instance, the above tasks can become

$framework_dll = 'framework/src/framework/bin/Debug/framework.dll'

file $framework_dll => :framework

$website_dll = 'website/bin/Debug/website.dll'

file $website_dll => :website

msbuild :framework do |msb|
  msb.solution = 'framework/src/framework.sln'
end

msbuild :website => $framework_dll do |msb|
  msb.solution = 'src/website.sln'
end

task :default => $website_dll

This makes it so that framework and website are only built if they aren't built already and won't be attempted unless they're missing.

Arbitrary scripting
Rake is a great platform for hosting arbitrary scripts that you might write to automate your development process. I have scripts to bump the assembly version and subsequently commit to git, deploy to our test server, and I plan to make tasks to interact with redmine via it's REST API (something certainly not possible in NAnt). Basically, any little task that I might write a script for (which is quite a bit) can be imported into the rakefile and mounted as a task (yes, ruby is very modular).

No comments:

Post a Comment