I got asked about a rake script I use to manage my vendor/rails directory in the various apps I’m working on. The script is in the extended part of this article below and the explanation is here.
The basic idea is not to have to use svn:externals for vendor/rails. I use darcs when I can which rules this out. Plus it’s a good idea to have easy control over which revision of the Rails trunk you’re running on incase it goes through a period of unstability.
This was inspired by this Rails Weenie tip, though there are slight differences in how I lay ouy my local copies of revisions. I have a ~/dev directory which has a Rakefile containing the task below and a rails_revisions directory. This makes it (slightly) easier to get which revision an app is currently running on just by looking at the symlink.
To use this do something like:
rake link_apps_to_edge APPS=foo,bar REVISION=3800
One nice thing about the tip linked above is the switchtower capistrano task which links the app on the server to the revision specified in deploy.rb. I’m going to extend my setup in the future to use something similar, but rather than specify which revision explicitly it will pick it up by looking at the symlink. This would mean you don’t have to muck with deploy.rb, just link to a revision you like, make sure your tests pass and deploy.
Let me know if you find this useful.
desc "Get a revision of rails to ~/dev/rails_revisions defaults to head, use REVISION=x to get a specific revision"
task :get_edge do
get_edge(ENV['REVISION'])
end
desc "Link sites in dev to a specific revision from ~/dev/revisions, use APPS=a,b,c REVISION=x Does nothing if any of the apps given do not exist. Defaults to HEAD if REVISION not used. Will get the revision if it doesn't exist locally"
task :link_apps_to_edge do
if ENV['APPS'].nil?
puts 'Must specify some apps with APPS=a,b,c'
exit
end
apps = ENV['APPS'].split(',')
exit unless apps_exist?(apps)
edge_path = get_edge(ENV['REVISION'])
apps.each do |app_path|
Dir.glob("#{app_path}/**/vendor").each do |vendor_path|
next if vendor_path.include?("_darcs")
rails_path = File.join(vendor_path, 'rails')
if File.symlink? rails_path
FileUtils.rm rails_path
end
if File.exists? rails_path
puts "A non-linked version of rails exists in app #{app_path}, dir #{rails_path}. Not doing anything"
else
FileUtils.ln_s File.expand_path(edge_path), rails_path
puts "linked #{edge_path} to #{rails_path}"
end
end
end
end
def get_edge(revision)
revision ||= `svn info http://dev.rubyonrails.org/svn/rails/trunk`.match(/Revision: (\d+)/).captures[0]
export_path = "rails_revisions/#{revision}"
if File.exists? export_path
puts "Revision #{revision} already exists, doing nothing"
else
puts "About to export #{revision} to #{export_path}"
puts `svn export -r #{revision} http://dev.rubyonrails.org/svn/rails/trunk #{export_path}`
end
export_path
end
def apps_exist?(apps)
non_existant_paths = apps.collect { |app_path| app_path unless File.exists? app_path }.compact
if non_existant_paths.empty?
true
else
non_existant_paths.each { |path| puts "#{path} does not exist" }
puts "Nothing done"
false
end
end