class Nucleon::Manager

Attributes

logger[R]

Public Class Methods

connection(name = :core) click to toggle source
# File lib/core/manager.rb, line 14
def self.connection(name = :core)
  Nucleon.manager(@@supervisors, name, self)
end
new() click to toggle source
# File lib/core/manager.rb, line 20
def initialize
  @logger = Nucleon.logger
  
  @namespaces = {}
  @types      = {}
  @load_info  = {}    
  @plugins    = {}
end

Public Instance Methods

autoload() click to toggle source
# File lib/core/manager.rb, line 252
def autoload
  logger.info("Autoloading registered plugins at #{Time.now}")
  
  @load_info.keys.each do |type|
    logger.debug("Autoloading type: #{type}")
    
    @load_info[type].each do |provider, plugin|
      logger.debug("Autoloading provider #{provider} at #{plugin[:directory]}")
      
      nucleon_require(plugin[:directory], provider)
      
      @load_info[type][provider][:class] = provider_class(plugin[:namespace], type, provider)
      logger.debug("Updated #{type} #{provider} load info: #{@load_info[type][provider].inspect}")
      
      # Make sure extensions are listening from the time they are loaded
      load(:extension, provider, { :name => provider }) if type == :extension # Create a persistent instance
    end
  end
end
check(method, options = {}) click to toggle source
# File lib/core/manager.rb, line 475
def check(method, options = {})
  config = Config.ensure(options)
  
  logger.debug("Checking extension #{method} given: #{config.export.inspect}")
  
  success = exec(method, config.import({ :extension_type => :check })) do |op, data|
    if op == :reduce
      ! data.values.include?(false)
    else
      data ? true : false
    end
  end
  
  success = success.nil? || success ? true : false
  
  logger.debug("Extension #{method} check result: #{success.inspect}")      
  success
end
class_const(name, separator = '::') click to toggle source
# File lib/core/manager.rb, line 577
def class_const(name, separator = '::')
  components = class_name(name, separator, TRUE)
  constant   = Object
  
  components.each do |component|
    constant = constant.const_defined?(component) ? 
                constant.const_get(component) : 
                constant.const_missing(component)
  end
  constant
end
class_name(name, separator = '::', want_array = FALSE) click to toggle source
# File lib/core/manager.rb, line 553
def class_name(name, separator = '::', want_array = FALSE)
  components = []
  
  case name
  when String, Symbol
    components = name.to_s.split(separator)
  when Array
    components = name 
  end
  
  components.collect! do |value|
    value    = value.to_s.strip      
    value[0] = value.capitalize[0] if value =~ /^[a-z]/ 
    value
  end
  
  if want_array
    return components
  end    
  components.join(separator)
end
collect(method, options = {}) click to toggle source
# File lib/core/manager.rb, line 513
def collect(method, options = {})
  config = Config.ensure(options)
  values = []
  
  logger.debug("Collecting extension #{method} values")
  
  exec(method, config.import({ :extension_type => :collect })) do |op, data|
    if op == :process
      values << data unless data.nil?  
    end
  end
  values = values.flatten
  
  logger.debug("Extension #{method} collected values: #{values.inspect}")  
  values
end
config(type, options = {}) click to toggle source
# File lib/core/manager.rb, line 452
def config(type, options = {})
  config = Config.ensure(options)
  
  logger.debug("Generating #{type} extended configuration from: #{config.export.inspect}")
    
  exec("#{type}_config", Config.new(config.export)) do |op, data|
    if op == :reduce
      data.each do |provider, result|
        config.import(result)
      end
      nil
    else
      data
    end
  end    
  config.delete(:extension_type)
   
  logger.debug("Final extended configuration: #{config.export.inspect}")
  config 
end
create(type, provider, options = {}) click to toggle source
# File lib/core/manager.rb, line 339
def create(type, provider, options = {})
  type     = type.to_sym
  provider = provider.to_sym
     
  unless @types.has_key?(type)
    logger.warn("Plugin type #{type} creation requested but it has not been registered yet")
    return nil
  end
  
  info = @load_info[type][provider] if Util::Data.exists?(@load_info, [ type, provider ])
      
  if info
    logger.debug("Plugin information for #{provider} #{type} found.")
    
    instance_name = "#{provider}_" + Nucleon.sha1(options)
    options       = translate(info[:namespace], type, provider, options)      
            
    @plugins[type] = {} unless @plugins.has_key?(type)
    
    unless instance_name && @plugins[type].has_key?(instance_name)
      info[:instance_name] = instance_name
      options[:meta]       = Config.new(info).import(Util::Data.hash(options[:meta]))
      
      logger.info("Creating new plugin #{provider} #{type}")
     
      plugin = info[:class].new(type, provider, options)
      
      @plugins[type][instance_name] = plugin 
    end
    return @plugins[type][instance_name]
  end
  
  logger.warn("Plugin information cannot be found for plugin #{type} #{provider}")      
  nil  
end
define_namespace(*names) click to toggle source
# File lib/core/manager.rb, line 46
def define_namespace(*names)
  names.each do |namespace|
    @namespaces[namespace.to_sym] = true
  end  
end
define_type(type_info) click to toggle source
# File lib/core/manager.rb, line 140
def define_type(type_info)
  if type_info.is_a?(Hash)
    logger.info("Defining plugin types at #{Time.now}")
    
    type_info.each do |type, default_provider|
      logger.debug("Mapping plugin type #{type} to default provider #{default_provider}")
      @types[type.to_sym] = default_provider
    end
  else
    logger.warn("Defined types must be specified as a hash to be registered properly")      
  end
end
exec(method, options = {}) { |:process, result| ... } click to toggle source
# File lib/core/manager.rb, line 408
def exec(method, options = {})
  results = nil
  
  if Nucleon.log_level == :hook # To save processing on rendering
    logger.hook("Executing extension hook #{Nucleon.blue(method)} at #{Nucleon.green(Time.now.to_s)}")
  end
  
  extensions = plugins(:extension)
  
  extensions.each do |name, plugin|
    provider = plugin.plugin_provider
    result   = nil      
    
    logger.debug("Checking extension #{provider}")
    
    if plugin.respond_to?(method)
      results = {} if results.nil?       
      
      result = plugin.send(method, options)
      logger.info("Completed hook #{method} at #{Time.now} with: #{result.inspect}")
                  
      if block_given?
        results[provider] = yield(:process, result)
        logger.debug("Processed extension result into: #{results[provider].inspect}")  
      end
      
      if results[provider].nil?
        logger.debug("Setting extension result to: #{result.inspect}") 
        results[provider] = result
      end
    end
  end
  
  if ! results.nil? && block_given? 
    results = yield(:reduce, results)
    logger.debug("Reducing extension results to: #{results.inspect}")
  else
    logger.debug("Final extension results: #{results.inspect}")     
  end        
  results    
end
get(type, name) click to toggle source
# File lib/core/manager.rb, line 377
def get(type, name)
  logger.info("Fetching plugin #{type} #{name}")
  
  if @plugins.has_key?(type)
    @plugins[type].each do |instance_name, plugin|
      if plugin.plugin_name.to_s == name.to_s
        logger.debug("Plugin #{type} #{name} found")
        return plugin
      end
    end
  end
  logger.debug("Plugin #{type} #{name} not found")
  nil  
end
load(type, provider = nil, options = {}) click to toggle source
# File lib/core/manager.rb, line 304
def load(type, provider = nil, options = {})
  default_provider = type_default(type)
  
  # Allow options to override provider
  config   = Config.ensure(options)
  provider = config.delete(:provider, provider)
  provider = default_provider unless provider
  
  load_base(type, provider, config)
end
load_base(type, provider, options = {}) click to toggle source
# File lib/core/manager.rb, line 274
def load_base(type, provider, options = {})
  logger.info("Fetching plugin #{type} provider #{provider} at #{Time.now}")
  
  options    = translate_type(type, options)    
  config     = Config.ensure(options)
  name       = config.get(:name, nil)
  ensure_new = config.delete(:new, false)
  
  if name
    logger.debug("Looking up existing instance of #{name}")
    
    if existing_instance = get(type, name)
      unless ensure_new
        config.export.each do |property_name, value|
          unless [ :name, :meta ].include?(property_name)
            existing_instance[property_name] = value  
          end
        end
        existing_instance.normalize(true)
    
        logger.debug("Using existing instance of #{type}, #{name}")
        return existing_instance
      end
    end
  end
  create(type, provider, options)   
end
load_multiple(type, data, build_hash = false, keep_array = false) click to toggle source
# File lib/core/manager.rb, line 317
def load_multiple(type, data, build_hash = false, keep_array = false)
  logger.info("Fetching multiple plugins of #{type} at #{Time.now}")
  
  group = ( build_hash ? {} : [] )
  klass = plugin_class(type)   
  data  = klass.build_info(type, data) if klass.respond_to?(:build_info)
  
  data.each do |options|
    if plugin = load(type, options[:provider], options)
      if build_hash
        group[plugin.plugin_name] = plugin
      else
        group << plugin
      end
    end
  end
  return group.shift if ! build_hash && group.length == 1 && ! keep_array
  group  
end
loaded_plugins(type = nil, provider = nil) click to toggle source
# File lib/core/manager.rb, line 66
def loaded_plugins(type = nil, provider = nil)
  results  = {}
  type     = type.to_sym if type
  provider = provider.to_sym if provider
  
  if type && @load_info.has_key?(type)
    if provider && @load_info.has_key?(provider)
      results = @load_info[type][provider]  
    else
      results = @load_info[type]
    end
  elsif ! type
    results = @load_info      
  end
  results
end
myself() click to toggle source
# File lib/core/manager.rb, line 36
def myself
  Nucleon.handle(self)
end
namespaces() click to toggle source
# File lib/core/manager.rb, line 42
def namespaces
  @namespaces.keys
end
plugin_class(type) click to toggle source
# File lib/core/manager.rb, line 591
def plugin_class(type)
  class_const([ :nucleon, :plugin, type ]) 
end
plugins(type = nil, provider = nil) click to toggle source
# File lib/core/manager.rb, line 85
def plugins(type = nil, provider = nil)
  results  = {}
  type     = type.to_sym if type
  provider = provider.to_sym if provider
  
  if type && @plugins.has_key?(type)
    if provider && ! @plugins[type].keys.empty?
      @plugins[type].each do |instance_name, plugin|
        plugin                 = @plugins[type][instance_name]
        results[instance_name] = plugin if plugin.plugin_provider == provider
      end
    else
      results = @plugins[type]
    end
  elsif ! type
    results = @plugins
  end    
  results
end
provider_class(namespace, type, provider) click to toggle source
# File lib/core/manager.rb, line 597
def provider_class(namespace, type, provider)
  class_const([ namespace, type, provider ])  
end
register(base_path, &code) click to toggle source
# File lib/core/manager.rb, line 178
def register(base_path, &code)
  namespaces.each do |namespace|
    namespace_path = File.join(base_path, namespace.to_s)
    register_namespace(namespace, namespace_path, &code)
  end
end
reload(core = false, &code) click to toggle source
# File lib/core/manager.rb, line 114
def reload(core = false, &code)
  logger.info("Loading Nucleon plugins at #{Time.now}")
  
  if core
    Celluloid.logger = logger if Nucleon.parallel?   
  
    define_namespace :nucleon
  
    define_type :extension     => nil,     # Core
                :action        => :update, # Core
                :project       => :git,    # Core
                :command       => :bash,   # Core
                :event         => :regex,  # Utility
                :template      => :json,   # Utility
                :translator    => :json    # Utility
  end
  
  # Allow block level namespace and type registration
  code.call(:define, myself) if code
                            
  load_plugins(core, &code)                                  
  logger.info("Finished loading Nucleon plugins at #{Time.now}")    
end
remove(plugin) click to toggle source
# File lib/core/manager.rb, line 394
def remove(plugin)
  if plugin && plugin.respond_to?(:plugin_type) && @plugins.has_key?(plugin.plugin_type)
    logger.debug("Removing #{plugin.plugin_type} #{plugin.plugin_name}")
    @plugins[plugin.plugin_type].delete(plugin.plugin_instance_name)
    plugin.remove_plugin
    plugin.terminate if plugin.respond_to?(:terminate) # For Celluloid plugins
  else
    logger.warn("Cannot remove plugin: #{plugin.inspect}")    
  end
end
test_connection() click to toggle source
# File lib/core/manager.rb, line 108
def test_connection
  true
end
translate(namespace, type, provider, options) click to toggle source
# File lib/core/manager.rb, line 543
def translate(namespace, type, provider, options)
  klass = provider_class(namespace, type, provider)
  logger.debug("Executing option translation for: #{klass.inspect}")
            
  options = klass.send(:translate, options) if klass.respond_to?(:translate)
  options
end
translate_type(type, options) click to toggle source
# File lib/core/manager.rb, line 533
def translate_type(type, options)
  klass = plugin_class(type)
  logger.debug("Executing option translation for: #{klass.inspect}")          
  
  options = klass.send(:translate, options) if klass.respond_to?(:translate)
  options
end
type_default(type) click to toggle source
# File lib/core/manager.rb, line 60
def type_default(type)
  @types[type.to_sym]
end
types() click to toggle source
# File lib/core/manager.rb, line 54
def types
  @types.keys
end
value(method, value, options = {}) click to toggle source
# File lib/core/manager.rb, line 496
def value(method, value, options = {})
  config = Config.ensure(options)
  
  logger.debug("Setting extension #{method} value given: #{value.inspect}")
  
  exec(method, config.import({ :value => value, :extension_type => :value })) do |op, data|
    if op == :process
      value = data unless data.nil?  
    end
  end
  
  logger.debug("Extension #{method} retrieved value: #{value.inspect}")
  value
end

Protected Instance Methods

add_build_info(namespace, type, file, &code) click to toggle source
# File lib/core/manager.rb, line 223
def add_build_info(namespace, type, file, &code)
  type = type.to_sym
  
  @load_info[type] = {} unless @load_info.has_key?(type)
  
  components = file.split(File::SEPARATOR)
  provider   = components.pop.sub(/\.rb/, '').to_sym
  directory  = components.join(File::SEPARATOR) 
  
  logger.info("Loading nucleon #{type} plugin #{provider} at #{Time.now}")
      
  unless @load_info[type].has_key?(provider)
    data = {
      :namespace => namespace,
      :type      => type,
      :provider  => provider,        
      :directory => directory,
      :file      => file
    }
    code.call(data) if code
    
    logger.debug("Plugin #{type} loaded: #{data.inspect}")
    @load_info[type][provider] = data
  end
end
load_plugins(core = false, &code) click to toggle source
# File lib/core/manager.rb, line 155
def load_plugins(core = false, &code)
  if core    
    # Register core plugins
    logger.info("Initializing core plugins at #{Time.now}")
    register(File.join(File.dirname(__FILE__), '..'))
  end
  
  # Register external Gem defined plugins
  Gems.register(true)
  
  # Register any other extension plugins
  exec(:register_plugins)
  
  # Catch any block level requests before autoloading
  code.call(:load, myself) if code
      
  # Autoload all registered plugins
  autoload
end
register_namespace(namespace, base_path, &code) click to toggle source
# File lib/core/manager.rb, line 187
def register_namespace(namespace, base_path, &code)
  if File.directory?(base_path)
    logger.info("Loading files from #{base_path} at #{Time.now}")
    
    Dir.glob(File.join(base_path, '*.rb')).each do |file|
      logger.debug("Loading file: #{file}")
      require file
    end
    
    logger.info("Loading directories from #{base_path} at #{Time.now}")
    Dir.entries(base_path).each do |path|
      unless path.match(/^\.\.?$/)
        register_type(namespace, base_path, path, &code) if types.include?(path.to_sym)      
      end
    end
  end  
end
register_type(namespace, base_path, plugin_type, &code) click to toggle source
# File lib/core/manager.rb, line 208
def register_type(namespace, base_path, plugin_type, &code)
  base_directory = File.join(base_path, plugin_type.to_s)
  
  if File.directory?(base_directory)
    logger.info("Registering #{base_directory} at #{Time.now}")
    
    Dir.glob(File.join(base_directory, '*.rb')).each do |file|
      add_build_info(namespace, plugin_type, file, &code)
    end
  end
end