Capistrano::Configuration.instance.load do # configurations root directory config_root = File.expand_path(fetch(:config_root, "config/deploy")) # list of configurations files config_files = Dir["#{config_root}/**/*.rb"] # remove configuration file if it's top-level file or part of another configuration config_files.reject! do |config_file| config_dir = config_file.gsub(/\.rb$/, '/') config_file.count('/') == (config_root.count('/') + 1) || config_files.any? { |file| file.start_with?(config_dir) } end # build configuration names list config_names = config_files.map do |config_file| config_file.sub("#{config_root}/", '').sub(/\.rb$/, '').gsub('/', ':') end # ensure that configuration segments don't override any method, task or namespace config_names.each do |config_name| config_name.split(':').each do |segment| if all_methods.any? { |m| m == segment } raise ArgumentError, "Config task #{config_name} name overrides #{segment.inspect} (method|task|namespace)" end end end # create configuration task for each configuration name config_names.each do |config_name| segments = config_name.split(':') namespace_names = segments[0, segments.size - 1] task_name = segments.last # create configuration task block. # NOTE: Capistrano 'namespace' DSL invokes instance_eval that # that pass evaluable object as argument to block. block = lambda do |parent| desc "Load #{config_name} configuration" task(task_name, :multiconfig => true) do # set configuration name as :config_name variable top.set(:config_name, config_name) # recursively load configurations segments.size.times do |i| path = ([config_root] + segments[0..i]).join('/') + '.rb' top.load(:file => path) if File.exists?(path) end top_stage_path = File.join(config_root, segments.last) + '.rb' top.load(:file => top_stage_path) if File.exists?(top_stage_path) end end # wrap task block into namespace blocks # # namespace_names = [nsN, ..., ns2, ns1] # # block = block0 = lambda do |parent| # desc "DESC" # task(:task_name) { TASK } # end # block = block1 = lambda { |parent| parent.namespace(:ns1, &block0) } # block = block2 = lambda { |parent| parent.namespace(:ns2, &block1) } # ... # block = blockN = lambda { |parent| parent.namespace(:nsN, &blockN-1) } # block = namespace_names.reverse.inject(block) do |child, name| lambda do |parent| parent.namespace(name, &child) end end # create namespaced configuration task # # block = lambda do # namespace :nsN do # ... # namespace :ns2 do # namespace :ns1 do # desc "DESC" # task(:task_name) { TASK } # end # end # ... # end # end block.call(top) end # set configuration names list set(:config_names, config_names) end