require 'tempfile' module Sprinkle module Installers # = File installer # # This installer creates a file on the remote server. # # == Example Usage # # Installing a nginx.conf onto remote servers # # package :nginx_conf do # file '/etc/nginx.conf', :content => File.read('files/nginx.conf'), # :sudo => true # end # # Sudo is only necessary when the user your sprinkle is running as does # not have necessarily permissions to create the file on its own. # Such as when the file is in /etc. # # 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. # # == Rendering templates # # Use the template render helper to render an ERB template to a remote file (you # can use variables in your templates by setting them as instance variables inside # your package. Templates have access to package methods such as opts, args, etc. # # package :nginx_conf do # @nginx_port = 8080 # file '/etc/nginx.conf', # :contents => render("nginx.conf") # # where [cwd] is the current working dir you're running sprinkle from # # [cwd]/templates/nginx.conf.erb or # # [cwd]/templates/nginx.conf should contain the erb template # end # # You can also tell the package where to look for templates, so that if you have # a complex package hierarchy such as: # # .../packages/p/postfix.rb # .../packages/p/postfix/templates/main.cf.erb # # package :postfix do # template_search_path File.dirname(__FILE__) # file '/etc/postfix/main.cf', :contents => render("main.cf") # # searches for: # # ../packages/p/main.cf[.erb] # # ../packages/p/templates/main.cf[.erb] # end class FileInstaller < Installer attr_reader :sourcepath, :destination, :contents #:nodoc: api do def file(destination, options = {}, &block) #:nodoc: # options.merge!(:binding => binding()) install FileInstaller.new(self, destination, options, &block) end end def initialize(parent, destination, options={}, &block) #:nodoc: @destination = destination @contents = options[:content] || options[:contents] raise "need :contents key for file" unless @contents super parent, options, &block # setup file attributes owner options[:owner] if options[:owner] mode options[:mode] if options[:mode] post_move_if_sudo setup_source end def install_commands #:nodoc: Commands::Transfer.new(sourcepath, destination) end # calls chown own to set the file ownership def owner(owner) @owner = owner post :install, "#{sudo_cmd}chown #{owner} #{@destination}" end # calls chmod to set the files permissions def mode(mode) @mode = mode post :install, "#{sudo_cmd}chmod #{mode} #{@destination}" end private def post_move_if_sudo return unless sudo? # perform the file copy 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 setup_source @file = Tempfile.new(@package.name.to_s) @file.print @contents @file.close @sourcepath = @file.path end def post_process @file.unlink end end end end