Depending on transient values in Rake
gga
#2013-03-03
Calatrava has a reasonably complex build system to enforce its
opinions. One of these opinions is that the environment you’re
building for should be configurable. You set the environment by
setting the CALATRAVA_ENV
environment variable. But what if you
change it between runs? Some things should be re-built, but what?
And what if you didn’t change it between runs? How do you make part of
your build depend on the transient value of an environment variable?
What about file sets? Calatrava includes lists of JavaScript files to load for different platforms. It’s easy enough to make sure new files are added to these lists (modification times will usually make a rebuild happen — but not always.) But how do you remove a deleted file?
One solution is a to always perform a clean re-build. This works, but is slow and in-elegant. Inspired by the custom build system at a previous job, I’ve added a transient task feature to Rake as used by Calatrava.
require 'digest/sha1'
module Rake
module DSL
def transient(name, value)
transients = File.join('.rake', 'transients')
FileUtils.mkdir_p transients
value_file = File.join(transients, name.to_s)
value_hash = Digest::SHA1.hexdigest(value.to_s)
if File.exists? value_file
previous_hash = IO.read(value_file)
FileUtils.rm value_file if previous_hash != value_hash
end
file value_file do
File.open(value_file, "w+") { |f| f.print value_hash }
end
task name => value_file
end
end
end
You create a transient task with the transient
method, and then use
that as you would any other dependency.
transient :calatrava_env, ENV['CALATRAVA_ENV']
task :build => :calatrava_env
This works by tracking a hash of the value in a file under a .rake
directory at the same level as your Rakefile
. If the value changes,
then the file is deleted. A file
task will re-create the file by
writing the new hash. A regular task depends on the existence of the
file. To cause anything to run when your transient value changes, just
depend on that intermediate task.
I’d like to look into getting this added to Rake directly at some point, but in the meantime feel free to use it in your projects.