Browse files

Support for rendering files with ERB before transfer

  • Loading branch information...
1 parent 5c64609 commit cd6b392c0dc9b9a011b7cb58183f3a4b115359fd Jacob Harris committed Jun 19, 2009
Showing with 152 additions and 10 deletions.
  1. +92 −3 lib/sprinkle/installers/transfer.rb
  2. +8 −0 script/console
  3. +52 −7 spec/sprinkle/installers/transfer_spec.rb
View
95 lib/sprinkle/installers/transfer.rb
@@ -1,3 +1,48 @@
+# Blatantly stole this from Chef
+class TemplateError < RuntimeError
+ attr_reader :original_exception, :context
+ SOURCE_CONTEXT_WINDOW = 2 unless defined? SOURCE_CONTEXT_WINDOW
+
+ def initialize(original_exception, template, context)
+ @original_exception, @template, @context = original_exception, template, context
+ end
+
+ def message
+ @original_exception.message
+ end
+
+ def line_number
+ @line_number ||= $1.to_i if original_exception.backtrace.find {|line| line =~ /\(erubis\):(\d+)/ }
+ end
+
+ def source_location
+ "on line ##{line_number}"
+ end
+
+ def source_listing
+ return nil if line_number.nil?
+
+ @source_listing ||= begin
+ line_index = line_number - 1
+ beginning_line = line_index <= SOURCE_CONTEXT_WINDOW ? 0 : line_index - SOURCE_CONTEXT_WINDOW
+ source_size = SOURCE_CONTEXT_WINDOW * 2 + 1
+ lines = @template.split(/\n/)
+ contextual_lines = lines[beginning_line, source_size]
+ output = []
+ contextual_lines.each_with_index do |line, index|
+ line_number = (index+beginning_line+1).to_s.rjust(3)
+ output << "#{line_number}: #{line}"
+ end
+ output.join("\n")
+ end
+ end
+
+ def to_s
+ "\n\n#{self.class} (#{message}) #{source_location}:\n\n" +
+ "#{source_listing}\n\n #{original_exception.backtrace.join("\n ")}\n\n"
+ end
+end
+
module Sprinkle
module Installers
# Beware, strange "installer" coming your way.
@@ -25,6 +70,10 @@ module Installers
# via this method. If you wish to disable recursive transfers, you can pass
# recursive => false, although it will not be obeyed when using the Vlad actor.
#
+ # If you pass the option :render => true, this tells transfer that the source file
+ # is an ERB template to be rendered locally before being transferred (you can declare
+ # variables in the package scope). When render is true, recursive is turned off.
+ #
# Finally, should you need to run commands before or after the file transfer (making
# directories or changing permissions), you can use the pre/post :install directives
# and they will be run.
@@ -41,6 +90,35 @@ def install_commands
nil
end
+ def self.render_template(template, context, prefix)
+ require 'tempfile'
+ require 'erubis'
+
+ puts "Foo: #{eval('foo', context)}"
+
+ begin
+ eruby = Erubis::Eruby.new(template)
+ output = eruby.result(context)
+ rescue Object => e
+ raise TemplateError.new(e, template, context)
+ end
+
+ final_tempfile = Tempfile.new(prefix)
+ final_tempfile.print(output)
+ final_tempfile.close
+ final_tempfile
+ end
+
+ def render_template(template, context, prefix)
+ self.class.render_template(template, context, prefix)
+ end
+
+ def render_template_file(path, context, prefix)
+ template = File.read(path)
+ tempfile = render_template(template, binding(), @package.name)
+ tempfile
+ end
+
def process(roles) #:nodoc:
assert_delivery
@@ -56,9 +134,20 @@ def process(roles) #:nodoc:
@delivery.process @package.name, sequence, roles
end
- logger.info "--> Transferring #{@source} to #{@destination} for roles: #{roles}"
- @delivery.transfer(@package.name, @source, @destination, roles)
-
+ recursive = @options[:recursive]
+
+ if options[:render]
+ tempfile = render_template_file(@source, binding(), @package.name)
+ sourcepath = tempfile.path
+ logger.info "Rendering template #{@source} to temporary file #{sourcepath}"
+ recursive = false
+ else
+ sourcepath = @source
+ end
+
+ logger.info "--> Transferring #{sourcepath} to #{@destination} for roles: #{roles}"
+ @delivery.transfer(@package.name, sourcepath, @destination, roles, recursive)
+
post = post_commands(:install)
unless post.empty?
sequence = post; sequence = sequence.join('; ') if sequence.is_a? Array
View
8 script/console
@@ -0,0 +1,8 @@
+#!/usr/bin/env ruby
+# File: script/console
+irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
+
+libs = " -r irb/completion"
+libs << " -r #{File.dirname(__FILE__) + '/../lib/sprinkle.rb'}"
+puts "Loading sprinkle gem"
+exec "#{irb} #{libs} --simple-prompt"
View
59 spec/sprinkle/installers/transfer_spec.rb
@@ -1,4 +1,5 @@
require File.dirname(__FILE__) + '/../../spec_helper'
+require 'tempfile'
describe Sprinkle::Installers::Transfer do
include Sprinkle::Deployment
@@ -24,7 +25,7 @@ def create_transfer(source, dest, options={}, &block)
end
describe 'when created' do
- it 'should accept a single package to install' do
+ it 'should accept a source and destination to install' do
@installer.source.should == @source
@installer.destination.should == @destination
end
@@ -36,18 +37,62 @@ def create_transfer(source, dest, options={}, &block)
pre :install, 'op1'
post :install, 'op2'
end
+
+ @delivery = @installer.delivery
end
it "should call the pre and post install commands around the file transfer" do
- delivery = @installer.delivery
-
- delivery.should_receive(:process).with(@package.name, 'op1', @roles).once.ordered.and_return
- delivery.should_receive(:transfer).with(@package.name, @source, @destination, @roles).ordered.and_return
- delivery.should_receive(:process).with(@package.name, 'op2', @roles).once.ordered.and_return
- end
+ @delivery.should_receive(:process).with(@package.name, 'op1', @roles).once.ordered.and_return
+ @delivery.should_receive(:transfer).ordered.and_return
+ @delivery.should_receive(:process).with(@package.name, 'op2', @roles).once.ordered.and_return
+ end
+
+ it "should call transfer with recursive defaulted to nil" do
+ @delivery.should_receive(:process).and_return
+ @delivery.should_receive(:transfer).with(@package.name, @source, @destination, @roles, nil)
+ end
after do
@installer.process @roles
end
end
+
+ describe "if the :render flag is true" do
+ before do
+ @installer = create_transfer @source, @destination, :render => true
+ @delivery = @installer.delivery
+ @delivery.stub!(:render_template_file)
+ end
+
+ it "should render the source file as a template to a tempfile" do
+ @tempfile = Tempfile.new("foo")
+ @installer.should_receive(:render_template_file).with(@source, anything, @package.name).and_return(@tempfile)
+ @delivery.stub!(:transfer)
+ end
+
+ it "should call transfer with recursive set to false" do
+ @tempfile = Tempfile.new("foo")
+ @installer.should_receive(:render_template_file).with(@source, anything, @package.name).and_return(@tempfile)
+ @delivery.should_receive(:transfer).with(@package.name, @tempfile.path, @destination, @roles, false).ordered.and_return
+ end
+
+ after do
+ @installer.process @roles
+ end
+ end
+
+ describe "if the :recursive flag is explicitly set to false" do
+ before do
+ @installer = create_transfer @source, @destination, :recursive => false
+ end
+
+ it "should call transfer with recursive set to false" do
+ delivery = @installer.delivery
+ delivery.should_receive(:transfer).with(@package.name, @source, @destination, @roles, false).ordered.and_return
+ end
+
+ after do
+ @installer.process @roles
+ end
+ end
end

0 comments on commit cd6b392

Please sign in to comment.