lib/sprinkle/installers/installer.rb in sprinkle-0.7.4 vs lib/sprinkle/installers/installer.rb in sprinkle-0.7.5

- old
+ new

@@ -1,30 +1,30 @@ module Sprinkle # Installers are where the bulk of the work in Sprinkle happens. Installers are # the building blocks of packages. Typically each unique type of install # command has it's own installer class. - # + # module Installers # The base class which all installers must subclass, this class makes # sure all installers share some general features, which are outlined - # below. + # below. # # = Pre/Post Installation Hooks - # + # # With all installation methods you have the ability to specify multiple # pre/post installation hooks. This gives you the ability to specify - # commands to run before and after an installation takes place. + # commands to run before and after an installation takes place. # There are three ways to specify a pre/post hook. - + # Note about sudo: # When using the Capistrano actor all commands by default are run using - # sudo (unless your Capfile includes "set :use_sudo, false"). If you wish - # to use sudo periodically with "set :user_sudo, false" or with an actor - # other than Capistrano then you can just append it to your command. Some - # installers (transfer) also support a :sudo option, so check each + # sudo (unless your Capfile includes "set :use_sudo, false"). If you wish + # to use sudo periodically with "set :user_sudo, false" or with an actor + # other than Capistrano then you can just append it to your command. Some + # installers (transfer) also support a :sudo option, so check each # installer for details. - # + # # First, a single command: # # pre :install, 'echo "Hello, World!"' # post :install, 'rm -rf /' # @@ -47,84 +47,91 @@ # = Other Pre/Post Hooks # # Some installation methods actually grant you more fine grained # control of when commands are run rather than a blanket pre :install # or post :install. If this is the case, it will be documented on - # the installation method's corresponding documentation page. + # the installation method's corresponding documentation page. class Installer include Sprinkle::Attributes include Sprinkle::Sudo - + delegate :version, :to => :package - + attr_accessor :delivery, :package, :options, :pre, :post #:nodoc: def initialize(package, options = {}, &block) #:nodoc: @package = package @options = options || {} @pre = {}; @post = {} + @delivery = nil self.instance_eval(&block) if block end - + attributes :prefix, :archives, :builds - + class << self def subclasses @subclasses ||= [] end - + def api(&block) - Sprinkle::Package::Package.add_api &block + Sprinkle::Package::Package.add_api(&block) end - + def verify_api(&block) - Sprinkle::Verify.class_eval &block + Sprinkle::Verify.class_eval(&block) end def inherited(base) subclasses << base end end - + def escape_shell_arg(str) str.gsub("'", "'\\\\''").gsub("\n", '\n') end def pre(stage, *commands, &block) @pre[stage] ||= [] @pre[stage] += commands - @pre[stage] += commands_from_block(block) + @pre[stage] << defer(block) if block_given? + @pre[stage] end def post(stage, *commands, &block) @post[stage] ||= [] @post[stage] += commands - @post[stage] += commands_from_block(block) + @post[stage] << defer(block) if block_given? + @post[stage] end - + + # defer execution of command block until the package is being + # processed + def defer(block) + p = Proc.new { self.commands_from_block(block) } + end + def commands_from_block(block) return [] unless block out = nil - diff = @package.with_private_install_queue do - out = block.call - end + diff = @package.with_private_install_queue { out = block.call } + diff.each {|x| x.delivery = self.delivery } diff.empty? ? out : diff.map {|x| x.install_sequence } end - + def method_missing(method, *args, &block) if package.class.installer_methods.include?(method) @package.send(method, *args, &block) else super(method, *args, &block) end end - + def per_host? return false - @per_host end - + # Called right before an installer is exected, can be used for logging # and announcing what is about to happen def announce; end def process(roles) #:nodoc: @@ -142,21 +149,25 @@ # More complicated installers that have different stages, and require pre/post commands # within stages can override install_sequence and take complete control of the install # command sequence construction (eg. source based installer). def install_sequence commands = pre_commands(:install) + [ install_commands ] + post_commands(:install) - commands.flatten + flatten commands end - + protected - - def log(t, level=:info) + + def log(t, level=:info) #:nodoc: logger.send(level, t) end + def flatten(commands) #:nodoc: + commands.flatten.map {|c| c.is_a?(Proc) ? c.call : c }.flatten + end + # A concrete installer (subclass of this virtual class) must override this method - # and return the commands it needs to run as either a string or an array. + # and return the commands it needs to run as either a string or an array. # # <b>Overriding this method is required.</b> def install_commands raise 'Concrete installers implement this to specify commands to run to install their respective packages' end @@ -169,12 +180,12 @@ dress @post[stage] || [], :post end # Concrete installers (subclasses of this virtual class) can override this method to # specify stage-specific (pre-installation, post-installation, etc.) modifications - # of commands. + # of commands. # - # An example usage of overriding this would be to prefix all commands for a + # An example usage of overriding this would be to prefix all commands for a # certain stage to change to a certain directory. An example is given below: # # def dress(commands, stage) # commands.collect { |x| "cd #{magic_beans_path} && #{x}" } # end