lib/sprinkle/installers/installer.rb in sprinkle-0.1.5 vs lib/sprinkle/installers/installer.rb in sprinkle-0.1.6

- old
+ new

@@ -1,36 +1,72 @@ module Sprinkle module Installers + # The base class which all installers must subclass, this class makes + # sure all installers share some general features, which are outlined + # below. + # + # = Pre/Post Installation Hooks + # + # With all intallation 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. All + # commands by default are sudo'd so there is no need to include "sudo" + # in the command itself. There are three ways to specify a pre/post hook. + # + # First, a single command: + # + # pre :install, 'echo "Hello, World!"' + # post :install, 'rm -rf /' + # + # Second, an array of commands: + # + # commands = ['echo "First"', 'echo "Then Another"'] + # pre :install, commands + # post :install, commands + # + # Third, a block which returns either a single or multiple commands: + # + # pre :install do + # amount = 7 * 3 + # "echo 'Before we install, lets plant #{amount} magic beans...'" + # end + # post :install do + # ['echo "Now... let's hope they sprout!", 'echo "Indeed they have!"'] + # end + # + # = 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. class Installer - attr_accessor :delivery, :package, :options, :pre, :post + include Sprinkle::Configurable + attr_accessor :delivery, :package, :options, :pre, :post #:nodoc: - def initialize(package, options = {}, &block) + def initialize(package, options = {}, &block) #:nodoc: @package = package @options = options @pre = {}; @post = {} self.instance_eval(&block) if block end def pre(stage, *commands) @pre[stage] ||= [] @pre[stage] += commands + @pre[stage] += [yield] if block_given? end def post(stage, *commands) @post[stage] ||= [] @post[stage] += commands + @post[stage] += [yield] if block_given? end - def defaults(deployment) - defaults = deployment.defaults[self.class.name.split(/::/).last.downcase.to_sym] - self.instance_eval(&defaults) if defaults - @delivery = deployment.style - end + def process(roles) #:nodoc: + assert_delivery - def process(roles) - raise 'Unknown command delivery target' unless @delivery - if logger.debug? sequence = install_sequence; sequence = sequence.join('; ') if sequence.is_a? Array logger.debug "#{@package.name} install sequence: #{sequence} for roles: #{roles}\n" end @@ -38,47 +74,46 @@ logger.info "--> Installing #{package.name} for roles: #{roles}" @delivery.process(@package.name, install_sequence, roles) end end - def method_missing(sym, *args, &block) - unless args.empty? # mutate if not set - @options[sym] = *args unless @options[sym] - end - - @options[sym] || @package.send(sym, *args, &block) # try the parents options if unknown - end - protected - - # Installation is separated into two styles that concrete derivative installer classes - # can implement. - # - # Simple installers that issue a single or set of commands can overwride - # install_commands (eg. apt, gem, rpm). Pre/post install commands are included in this - # style for free. - # # 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 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. + # + # <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 - def pre_commands(stage) + def pre_commands(stage) #:nodoc: dress @pre[stage] || [], :pre end - def post_commands(stage) + def post_commands(stage) #:nodoc: 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. + # + # 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 + # + # By default, no modifications are made to the commands. def dress(commands, stage); commands; end end end end