lib/sprinkle/installers/transfer.rb in sprinkle-0.7.5 vs lib/sprinkle/installers/transfer.rb in sprinkle-0.7.6
- old
+ new
@@ -1,5 +1,7 @@
+require 'tempfile'
+
module Sprinkle
module Installers
# = File transfer installer
#
# This installer copies files from the local disk to remote servers using SCP.
@@ -23,112 +25,173 @@
#
# By default, transfers are recursive and you can move whole directories
# 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.
#
+ # As an alternative to :recursive, you can use the :tarball option. When this is
+ # supplied, the source file(s) are first packed in a tar.gz archive, then
+ # transferred to a temp dir and finally unpacked at the destination. This is usually
+ # much faster when transferring many small files (Such as a typical rails application)
+ # You can optionally supply :exclude, which is an array of glob-patterns to not
+ # include in the tarball
+ #
+ # package :webapp do
+ # transfer 'app/', '/var/www/' do
+ # tarball :exclude => %w(.git log/*)
+ # end
+ # end
+ #
# 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.
- #
+ #
# == Rendering templates
#
# Rendering templates with transfer has been depreciated. Please see the file
# installer if you want to use templates.
class Transfer < Installer
attr_accessor :source, :destination, :sourcepath #:nodoc:
-
+
+ # Include deprecated code
+ # Mainly, this makes it easier to see where to cut, when next major version comes along
+ DEPRECATED = true #:nodoc:
+
api do
def transfer(source, destination, options = {}, &block)
options.reverse_merge!(:binding => binding())
install Transfer.new(self, source, destination, options, &block)
end
end
- def initialize(parent, source, destination, options={}, &block) #:nodoc:
- @source = source
- @destination = destination
- @orig_destination = destination
- super parent, options, &block
- @binding = options[:binding]
- if sudo? # perform the transfer in two steps if we're using sudo
- final = @destination
- @destination = "/tmp/sprinkle_#{File.basename(@destination)}"
- # make sure we push the move ahead of any other post install tasks
- # a user may have requested
- post(:install).unshift ["#{sudo_cmd}mv #{@destination} #{final}"]
- end
+ def initialize(parent, source, destination, options = {}, &block) #:nodoc:
+ options.reverse_merge! :recursive => true
+
+ @source = source # Original source
+ @sourcepath = source # What the actor will transfer (may be the same as @source)
+ @final_destination = destination # Final destination
+ @destination = destination # Where the actor will place the file (May be same as @final_destination)
+
owner(options[:owner]) if options[:owner]
mode(options[:mode]) if options[:mode]
+ tarball(options[:tarball]) if options[:tarball]
+
+ super parent, options, &block
+
+ if DEPRECATED
+ @binding = options[:binding]
+ options[:render] = true if source_is_template?
+ options[:recursive] = false if options[:render]
+ setup_rendering if options[:render]
+ end
+ setup_tarball if tarball?
+ setup_sudo if sudo?
+ end
- options[:render]=true if source_is_template?
- options[:recursive]=false if options[:render]
+ def tarball(options = {})
+ @tarball = true
+ @exclude = options===true ? [] : options[:exclude]
end
-
+
def owner(owner)
@owner = owner
- post :install, "#{sudo_cmd}chown #{owner} #{@orig_destination}"
+ post(:install, "#{sudo_cmd}chown -R #{@owner} #{@final_destination}")
end
-
+
def mode(mode)
@mode = mode
- post :install, "#{sudo_cmd}chmod #{mode} #{@orig_destination}"
+ post(:install, "#{sudo_cmd}chmod -R #{@mode} #{@final_destination}")
end
- def install_commands
- :TRANSFER
+ def tarball?
+ @tarball
end
- def render_template(template, context, prefix)
- require 'tempfile'
-
- output = @package.template(template, context)
-
- final_tempfile = Tempfile.new(prefix.to_s)
- final_tempfile.print(output)
- final_tempfile.close
- final_tempfile
+ def install_commands
+ Commands::Transfer.new(sourcepath, destination,
+ :recursive => options[:recursive])
end
- def render_template_file(path, context, prefix)
- template = source_is_template? ? path : File.read(path)
- tempfile = render_template(template, context, @package.name)
- tempfile
- end
-
- def source_is_template?
- @source.split("\n").size>1
- end
+ if DEPRECATED
+ def render_template(template, context, prefix)
+ output = @package.template(template, context)
+ final_tempfile = Tempfile.new(prefix.to_s)
+ final_tempfile.print(output)
+ final_tempfile.close
+ final_tempfile
+ end
- def process(roles) #:nodoc:
- logger.debug "transfer: #{@source} -> #{@destination} for roles: #{roles}\n"
+ def render_template_file(path, context, prefix)
+ template = source_is_template? ? path : File.read(path)
+ tempfile = render_template(template, context, @package.name)
+ tempfile
+ end
- return if Sprinkle::OPTIONS[:testing]
-
- if options[:render]
+ def source_is_template?
+ @source.split("\n").size > 1
+ end
+
+ def setup_rendering
ActiveSupport::Deprecation.warn("transfer :render is depreciated, please use the `file` installer now.")
ActiveSupport::Deprecation.warn("transfer :render will be removed from Sprinkle v0.8")
- if options[:locals]
- context = {}
- options[:locals].each_pair do |k,v|
- if v.respond_to?(:call)
- context[k] = v.call
- else
- context[k] = v
+ if @options[:render]
+ raise "Incompatible combination of options :render and :tarball" if tarball?
+ if @options[:locals]
+ context = {}
+ @options[:locals].each_pair do |k,v|
+ if v.respond_to?(:call)
+ context[k] = v.call
+ else
+ context[k] = v
+ end
end
+ else
+ context = @binding
end
- else
- context = @binding
+
+ @tempfile = render_template_file(@source, context, @package.name).path
+ @sourcepath = @tempfile
+ @options[:recursive] = false
end
+ end
+ end
+
+ def setup_tarball
+ # tar files locally and scp to a temp location
+ # then untar after transfer
+ tar_options = @exclude.map {|glob| "--exclude \"#{glob}\" " }.join('')
+ @tempfile = make_tmpname
+ local_command = "cd '#{@source}' ; #{local_tar_bin} -zcf '#{@tempfile}' #{tar_options}."
+ logger.debug " --> Compressing #{@source} locally"
+ raise "Unable to tar #{@source}" unless system(local_command)
+ @sourcepath = @tempfile
+ @destination = "/tmp/#{File.basename(@tempfile)}"
+ post(:install).unshift [
+ "#{sudo_cmd}tar -zxf '#{@destination}' -C '#{@final_destination}'",
+ "#{sudo_cmd}rm '#{@destination}'"
+ ]
+ end
+
+ def setup_sudo
+ @destination = "/tmp/sprinkle_#{File.basename(@destination)}"
+ # make sure we push the move ahead of any other post install tasks
+ # a user may have requested
+ post(:install).unshift "#{sudo_cmd}mv #{@destination} #{@final_destination}"
+ end
- tempfile = render_template_file(@source, context, @package.name)
- @sourcepath = tempfile.path
- @options[:recursive] = false
- else
- @sourcepath = @source
+ protected
+ def local_tar_bin
+ @local_tar_bin ||= (`uname` =~ /Darwin/ ? "COPYFILE_DISABLE=true /usr/bin/gnutar" : "tar")
end
- logger.debug " --> Transferring #{sourcepath} to #{@orig_destination} for roles: #{roles}"
- @delivery.install(self, roles, :recursive => @options[:recursive])
- end
+ def post_process
+ return unless @tempfile
+ logger.debug " --> Deleting local temp file"
+ File.delete @tempfile
+ end
+
+ def make_tmpname
+ Dir::Tmpname.make_tmpname(['/tmp/sprinkle-', '.tar.gz'], nil)
+ end
+
end
end
end