lib/plugins/pluginmanager.rb in rsence-2.0.0.8.pre vs lib/plugins/pluginmanager.rb in rsence-2.0.0.9.pre
- old
+ new
@@ -4,10 +4,11 @@
#
# You should have received a copy of the GNU General Public License along
# with this software package. If not, contact licensing@riassence.com
##
require 'plugins/plugins'
+require 'plugins/dependencies'
module RSence
## = Abstract
## PluginManager is the service that loads and provides method delegation
@@ -19,36 +20,15 @@
##
class PluginManager
attr_reader :transporter, :sessions
- # Initialize with a list of directories as plugin_paths.
- # It's an array containing all plugin directories to scan.
- def initialize( plugin_paths, transporter=nil, autoreload=false, name_prefix=false )
- if transporter
- @transporter = transporter
- @sessions = transporter.sessions
- end
- @name_prefix = name_prefix
- @plugin_paths = plugin_paths
- puts "Loading #{name_prefix+' ' if name_prefix}plugins..." if RSence.args[:verbose]
- scan_plugins
- puts "Plugins #{name_prefix+' ' if name_prefix}loaded." if RSence.args[:verbose]
- if autoreload
- @thr = Thread.new do
- Thread.pass
- while true
- begin
- changed_plugins!
- rescue => e
- warn e.inspect
- end
- sleep 3
- end
- end
- end
+ # Returns the registry data for plugin bundle +plugin_name+
+ def registry( plugin_name )
+ return @registry[ plugin_name ]
end
+ alias [] registry
# By default, calling a method not defined calls a plugin of that name
def method_missing( sym, *args, &block )
if @registry.has_key?(sym)
if args == [] and block == nil
@@ -57,252 +37,19 @@
call( sym, *args )
end
end
end
- # Checks for changed plugin bundles and unloads/loads/reloads them accordingly.
- def changed_plugins!
- @plugin_paths.each do |path|
- next unless File.directory? path
- Dir.entries(path).each do |bundle_name|
- next if bundle_name =~ /&\./
- bundle_path = File.expand_path( File.join( path, bundle_name ) )
- next unless File.directory?( bundle_path )
- bundle_file = bundle_name+'.rb'
- next unless File.exists?( File.join( bundle_path, bundle_file ) )
- if File.exists?( File.join( bundle_path, 'disabled' ) )
- if @registry.has_key?( bundle_name.to_sym )
- puts "Disabling bundle #{bundle_name}..."
- online_status = @transporter.online?
- @transporter.online = false
- unload_bundle( bundle_name.to_sym )
- @transporter.online = online_status
- if RSence.args[:say]
- Thread.new do
- Thread.pass
- system(%{say "Unloaded #{bundle_name.to_s}."})
- end
- end
- end
- else
- if not @registry.has_key?( bundle_name.to_sym )
- puts "Loading bundle #{bundle_name}..."
- online_status = @transporter.online?
- @transporter.online = false
- load_bundle( bundle_path, bundle_name.to_sym, bundle_name+'.rb' )
- call( bundle_name.to_sym, :open )
- @transporter.online = online_status
- if RSence.args[:say]
- Thread.new do
- Thread.pass
- system(%{say "Loaded #{bundle_name.to_s}."})
- end
- end
- else
- # puts "Checking if bundle #{bundle_name} is changed..."
- info = @info[bundle_name.to_sym]
- if info[:reloadable] and plugin_changed?( bundle_name.to_sym )
- puts "Bundle #{bundle_name} has changed, reloading..."
- online_status = @transporter.online?
- @transporter.online = false
- unload_bundle( bundle_name.to_sym )
- load_bundle( bundle_path, bundle_name.to_sym, bundle_name+'.rb' )
- call( bundle_name.to_sym, :open )
- @transporter.online = online_status
- if RSence.args[:say]
- Thread.new do
- Thread.pass
- system(%{say "Reloaded #{bundle_name.to_s}."})
- end
- end
- end
- end
- end
- end
+ # Registers alias name for a plugin bundle.
+ def register_alias( bundle_name, alias_name )
+ if @aliases.has_key?( alias_name.to_sym )
+ warn "Alias already taken: #{alias_name.inspect}"
+ else
+ @aliases[ alias_name ] = bundle_name.to_sym
end
end
- # Unloads the plugin bundle named +bundle_name+
- def unload_bundle( bundle_name )
- puts "unloading bundle: #{bundle_name.inspect}" if RSence.args[:debug]
- if @registry.has_key?( bundle_name )
- call( bundle_name, :flush )
- call( bundle_name, :close )
- @registry.delete( bundle_name )
- @aliases.each do |a_name,b_name|
- if b_name == bundle_name
- @aliases.delete( a_name )
- end
- end
- if @servlets.include?( bundle_name )
- @servlets.delete( bundle_name )
- end
- if @info.include?( bundle_name )
- @info.delete( bundle_name )
- end
- end
- end
-
- # Returns true, if a plugin bundle has changed.
- # Only compares timestamp, not checksum.
- def plugin_changed?( plugin_name )
- info = @info[plugin_name]
- last_changed = info[:last_changed]
- newest_change = most_recent( info[:path], last_changed )
- return last_changed < newest_change
- end
-
- # Top-level method for scanning all plugin directories.
- # Clears previously loaded plugins.
- def scan_plugins
- @registry = {}
- @info = {}
- @aliases = {}
- @servlets = []
- @plugin_paths.each do |path|
- next unless File.directory? path
- scan_plugindir( path )
- end
- delegate( :open )
- end
-
- # Returns the registry data for plugin bundle +plugin_name+
- def registry( plugin_name )
- return @registry[ plugin_name ]
- end
- alias [] registry
-
- # Scans a directory of plugins, calls +load_plugin+ for bundles that match
- # the definition of a plugin bundle.
- # - Skips bundles starting with a dot
- # - Skips bundles without a ruby source file with the same
- # name as the directory (plus '.rb').
- # - Skips bundles containing a file or directory named 'disabled'
- def scan_plugindir( path )
- Dir.entries(path).each do |bundle_name|
- next if bundle_name[0].chr == '.'
- bundle_path = File.expand_path( File.join( path, bundle_name ) )
- next unless File.directory?( bundle_path )
- bundle_file = bundle_name+'.rb'
- if not File.exists?( File.join( bundle_path, bundle_file ) )
- bundle_file = 'main.rb'
- next unless File.exists?( File.join( bundle_path, bundle_file ) )
- end
- next if File.exists?( File.join( bundle_path, 'disabled' ) )
-
- load_bundle( bundle_path, bundle_name.to_sym, bundle_file )
- end
- end
-
- # Finds the most recent file in the path
- def most_recent( bundle_path, newest_date=0 )
- path_date = File.stat( bundle_path ).mtime.to_i
- is_dir = File.directory?( bundle_path )
- if path_date > newest_date and not is_dir
- # puts "File is newer: #{bundle_path}"
- newest_date = path_date
- end
- if is_dir
- Dir.entries( bundle_path ).each do |entry_name|
- next if entry_name[0].chr == '.'
- full_path = File.join( bundle_path, entry_name )
- unless File.directory?( full_path )
- next unless entry_name.include?('.') and ['yaml','rb'].include?( entry_name.split('.')[-1] )
- end
- newest_date = most_recent( full_path, newest_date )
- end
- end
- return newest_date
- end
-
- # Gets plugin information
- def bundle_info( bundle_path )
-
- bundle_name = File.split( bundle_path )[1]
-
- # Default bundle information
- info = {
- # The human-readable product name of the package
- :title => bundle_name.capitalize,
-
- # The human-readable version of the package
- :version => '0.0.0',
-
- # A brief description of the package (rdoc formatting supported)
- :description => 'No Description',
-
- # A flag (when false) prevents the plugin from automatically reload when changed.
- :reloadable => true,
-
- # System version requirement.
- :sys_version => '>= 1.0.0',
-
- # Path to bundle
- :path => bundle_path,
-
- # Name of bundle
- :name => bundle_name.to_sym,
-
- # Last change
- :last_changed => most_recent( bundle_path )
-
- }
-
- info_path = File.join( bundle_path, 'info.yaml' )
- if File.exists?( info_path )
- info_yaml = YAML.load( File.read( info_path ) )
- info_yaml.each do |info_key,info_value|
- info[ info_key.to_sym ] = info_value
- end
- end
- return info
-
- end
-
- # Loads a plugin bundle.
- def load_bundle( bundle_path, bundle_name, bundle_file )
- puts "loading bundle: #{bundle_name.inspect}" if RSence.args[:debug]
- if @registry.has_key?( bundle_name.to_sym )
- warn "Warning: Bundle #{bundle_name} already loaded."
- return
- end
-
- bundle_file_path = File.join( bundle_path, bundle_file )
-
- bundle_info = bundle_info( bundle_path )
-
- @info[bundle_name.to_sym] = bundle_info
-
- bundle_src = File.read( bundle_file_path )
-
- module_ns = Plugins.bundle_loader( {
- :bundle_path => bundle_path,
- :bundle_name => bundle_name,
- :bundle_info => bundle_info,
- :plugin_manager => self,
- :src_path => bundle_file_path,
- :src => bundle_src
- } )
-
- module_ns.constants.each do |module_const_name|
- module_const = module_ns.const_get( module_const_name )
- if module_const.class == Class
- bundle_type = module_const.bundle_type
- if [:Servlet, :Plugin, :GUIPlugin].include? bundle_type
- bundle_inst = module_const.new( bundle_name, bundle_info, bundle_path, self )
- bundle_inst.register( bundle_name ) if [ :Plugin, :GUIPlugin ].include?( bundle_type )
- break
- else
- warn "Can't init class: #{module_const.to_s}"
- break
- end
- else
- warn "Invalid module_const.class: #{module_const.class.inspect}"
- end
- end
- end
-
# Registers plugin class +inst+ into the registry using +bundle_name+
def register_bundle( inst, bundle_name )
bundle_name = bundle_name.to_sym
if @registry.has_key?( bundle_name )
if registry[ bundle_name ] != inst
@@ -313,24 +60,48 @@
end
else
inst.init if inst.respond_to? :init and not inst.inited
@registry[ bundle_name ] = inst
if inst.respond_to?( :match ) and ( inst.respond_to?( :get ) or inst.respond_to?( :post ) )
- puts " --- servlet: #{bundle_name.inspect}, #{inst.respond_to?(:match)}, #{inst.post}" if bundle_name == :welcome
@servlets.push( bundle_name )
end
end
end
- # Registers alias name for a plugin bundle.
- def register_alias( bundle_name, alias_name )
- if @aliases.has_key?( alias_name.to_sym )
- warn "Alias already taken: #{alias_name.inspect}"
- else
- @aliases[ alias_name ] = bundle_name.to_sym
+ def callable?( plugin_name, method_name )
+ return false if @deps.category?( plugin_name )
+ return false unless @registry.has_key?( plugin_name )
+ plugin = @registry[plugin_name]
+ return false unless plugin.respond_to?( method_name )
+ return true
+ end
+
+ # Calls the method +method_name+ with args +args+ of the plugin +plugin_name+.
+ # Returns false, if no such plugin or method exists.
+ def call( plugin_name, method_name, *args )
+ plugin_name = plugin_name.to_sym
+ if callable?( plugin_name, method_name )
+ begin
+ return @registry[ plugin_name ].send( method_name, *args )
+ rescue => e
+ plugin_error(
+ e,
+ "RSence::PluginManager.call error",
+ "plugin_name: #{plugin_name.inspect}, method_name: #{method_name.inspect}",
+ plugin_name
+ )
+ end
+ elsif @deps.category?( plugin_name )
+ warn "Warning! Tried to call category: #{plugin_name.inpsect}"
+ elsif not @registry.has_key?( plugin_name )
+ warn "Warning! No such plugin: #{plugin_name.inspect}"
+ elsif not @registry[ plugin_name ].respond_to?( method_name )
+ warn "Warning! Plugin: #{plugin_name.inspect} does not respond to #{method_name.inspect}"
end
+ return false
end
+ alias run_plugin call
# Prettier error handling.
def plugin_error( e, err_location, err_location_descr, eval_repl=false )
err_msg = [
"*"*40,
@@ -390,54 +161,10 @@
end
return matches_order
end
end
- # Delegates +method_name+ with +args+ to any loaded
- # plugin that responds to the method.
- def delegate( method_name, *args )
- @registry.each do | plugin_name, plugin |
- if plugin.respond_to?( method_name )
- begin
- plugin.send( method_name, *args )
- rescue => e
- plugin_error(
- e,
- "RSence::PluginManager.delegate error",
- "plugin_name: #{plugin_name.inspect}, method_name: #{method_name.inspect}",
- plugin_name
- )
- end
- end
- end
- end
-
- # Delegates the +flush+ and +close+ methods to any
- # loaded plugins, in that order.
- def shutdown
- delegate( :flush )
- delegate( :close )
- end
-
- # Calls the method +method_name+ with args +args+ of the plugin +plugin_name+.
- # Returns false, if no such plugin or method exists.
- def call( plugin_name, method_name, *args )
- plugin_name = plugin_name.to_sym
- if @registry.has_key?( plugin_name )
- if @registry[ plugin_name ].respond_to?( method_name )
- return @registry[ plugin_name ].send( method_name, *args )
- else
- puts "No method #{method_name.inspect} for plugin #{plugin_name.inspect}"
- return false
- end
- else
- puts "No such plugin: #{plugin_name.inspect}"
- return false
- end
- end
- alias run_plugin call
-
# Calls the servlet that matches the +req_type+ and +req.fullpath+ with
# the highest score.
def match_servlet( req_type, req, resp, session )
req_uri = req.fullpath
matches_order = match_servlet_uri( req_uri, req_type )
@@ -456,7 +183,412 @@
next
end
end
return false
end
+
+ # Delegates +method_name+ with +args+ to any loaded
+ # plugin that responds to the method.
+ def delegate( method_name, *args )
+ @deps.list.each do |plugin_name|
+ call( plugin_name, method_name, *args ) if callable?( plugin_name, method_name )
+ end
+ end
+
+ # Reverse delegate +method_name+ with +args+ to any loaded
+ # plugin that responds to the method.
+ def delegate_reverse( method_name, *args )
+ @deps.list.reverse.each do |plugin_name|
+ call( plugin_name, method_name, *args ) if callable?( plugin_name, method_name )
+ end
+ end
+
+ # Delegates the +flush+ and +close+ methods to any
+ # loaded plugins, in that order.
+ def shutdown
+ @transporter.online = false
+ @deps.list.reverse.each do |bundle_name|
+ unload_bundle( bundle_name )
+ end
+ end
+
+ # Finds the most recent file in the path
+ def most_recent( bundle_path, newest_date=0 )
+ path_date = File.stat( bundle_path ).mtime.to_i
+ is_dir = File.directory?( bundle_path )
+ if path_date > newest_date and not is_dir
+ newest_date = path_date
+ end
+ if is_dir
+ Dir.entries( bundle_path ).each do |entry_name|
+ next if entry_name[0].chr == '.'
+ full_path = File.join( bundle_path, entry_name )
+ unless File.directory?( full_path )
+ has_dot = entry_name.include?('.')
+ next unless has_dot
+ is_src_file = ['yaml','rb'].include?( entry_name.split('.')[-1] )
+ next unless is_src_file
+ end
+ newest_date = most_recent( full_path, newest_date )
+ end
+ end
+ return newest_date
+ end
+
+ # Gets plugin information
+ def bundle_info( bundle_path, bundle_name, src_file )
+
+ # Default bundle information
+ info = {
+
+ # The human-readable product name of the package
+ :title => bundle_name.to_s.capitalize,
+
+ # The human-readable version of the package
+ :version => '0.0.0',
+
+ # A brief description of the package (rdoc formatting supported)
+ :description => 'No Description',
+
+ # A flag (when false) prevents the plugin from automatically reload when changed.
+ :reloadable => true,
+
+ # System version requirement.
+ # NOTE: Has no effect yet!
+ :sys_version => '>= 1.0.0',
+
+ # Dependency, by default the system category (built-in plugins).
+ # A nil ( "~" in yaml ) value means no dependencies.
+ :depends_on => :system,
+
+ # Optional, name of category. The built-in plugins are :system
+ :category => nil,
+
+ # Optional, name of plugin to replace
+ # NOTE: Has no effect yet!
+ :replaces => nil,
+
+ # Optional, reverse dependency. Loads before the prepended plugin(category).
+ # NOTE: Doesn't support packages yet!
+ :prepends => nil
+
+ }
+
+ # Merge info.yaml data into info
+ info_path = File.join( bundle_path, 'info.yaml' )
+ if File.exists?( info_path )
+ info_yaml = YAML.load( File.read( info_path ) )
+ info_yaml.each do |info_key,info_value|
+ info[ info_key.to_sym ] = info_value
+ end
+ else
+ warn "Expected info.yaml, using defaults:"
+ warn " #{info_path}"
+ end
+
+ @deps.set_deps( bundle_name, info[:depends_on] )
+ if info[:category]
+ if info[:category].class == Symbol
+ @deps.add_category( info[:category] ) unless @deps.category?( info[:category] )
+ @deps.set_deps( info[:category], bundle_name )
+ else
+ warn "Invalid category: #{info[:category].inspect}"
+ end
+ end
+ if info[:prepends]
+ if info[:prepends].class == Array
+ info[:prepends].each do |prep|
+ @deps.set_deps( prep, bundle_name )
+ end
+ else
+ @deps.set_deps( info[:prepends], bundle_name )
+ end
+ end
+
+ # Extra information, not overrideable in info.yaml
+
+ # Path of bundle
+ info[:path] = bundle_path
+
+ # Name of bundle
+ info[:name] = bundle_name
+
+ # Full path of source file
+ info[:src_file] = src_file
+
+ # Timestamp of last changed file
+ info[:last_changed] = most_recent( bundle_path )
+
+ # ..however, don't accept future timestamps:
+ time_now = Time.now.to_i
+ info[:last_changed] = time_now if info[:last_changed] > time_now
+
+ return info
+ end
+
+ # Loads a plugin bundle.
+ def load_bundle( name )
+
+ if @deps.unresolved?(name)
+ warn "Warning: Bundle #{name} has unmet dependencies."
+ return
+ end
+
+ if @registry.has_key?( name )
+ warn "Warning: Bundle #{name} already loaded."
+ return
+ end
+ puts "Loading bundle: #{name.inspect}" if RSence.args[:debug]
+
+ info = @info[ name ]
+
+ path = info[:path]
+ src_file = info[:src_file]
+
+ bundle_src = File.read( src_file )
+
+ module_ns = Plugins.bundle_loader( {
+ :bundle_path => path,
+ :bundle_name => name,
+ :bundle_info => info,
+ :plugin_manager => self,
+ :src_path => src_file,
+ :src => bundle_src
+ } )
+
+ module_ns.constants.each do |module_const_name|
+ module_const = module_ns.const_get( module_const_name )
+ if module_const.class == Class
+ type = module_const.bundle_type
+ if [:Servlet, :Plugin, :GUIPlugin].include? type
+ bundle_inst = module_const.new( name, info, path, self )
+ bundle_inst.register( name ) if [ :Plugin, :GUIPlugin ].include?( type )
+ break
+ else
+ warn "Can't init class: #{module_const.to_s}"
+ break
+ end
+ else
+ warn "Invalid module_const.class: #{module_const.class.inspect}"
+ end
+ end
+ end
+
+ # loads all bundles found in order of dependency
+ def load_bundles
+ @deps.list.each do |name|
+ load_bundle( name ) if @deps.loadable?( name )
+ end
+ end
+
+ # If a bundle is found, set its dependencies etc
+ def bundle_found( bundle_path, bundle_name, src_file )
+ @info[ bundle_name ] = bundle_info( bundle_path, bundle_name, src_file )
+ end
+
+ # Returns false, if the plugin directory isn't valid.
+ # Returns [bundle_path, src_file] otherwise.
+ def valid_plugindir?( path, bundle_name )
+ return false if bundle_name[0].chr == '.'
+ bundle_path = File.expand_path( File.join( path, bundle_name ) )
+ return false unless File.directory?( bundle_path )
+ bundle_file = bundle_name+'.rb'
+ src_file = File.join( bundle_path, bundle_file )
+ if not File.exists?( src_file )
+ bundle_file = 'main.rb'
+ src_file = File.join( bundle_path, bundle_file )
+ return false unless File.exists?( src_file )
+ end
+ return [ bundle_path, src_file ]
+ end
+
+ # Returns true, if the bundle is disabled
+ def is_disabled?( bundle_path )
+ File.exists?( File.join( bundle_path, 'disabled' ) )
+ end
+
+ # Returns true, if the bundle is loaded.
+ def is_loaded?( bundle_name )
+ @registry.has_key?( bundle_name )
+ end
+
+ # Scans a directory of plugins, calls +load_plugin+ for bundles that match
+ # the definition of a plugin bundle.
+ # - Skips bundles starting with a dot
+ # - Skips bundles without a ruby source file with the same
+ # name as the directory (plus '.rb').
+ # - Skips bundles containing a file or directory named 'disabled'
+ def scan_plugindir( path )
+ bundles_found = []
+ Dir.entries(path).each do |bundle_name|
+ bundle_status = valid_plugindir?( path, bundle_name )
+ if bundle_status
+ (bundle_path, src_file) = bundle_status
+ bundles_found.push( [bundle_path, bundle_name.to_sym, src_file] )
+ end
+ end
+ return bundles_found
+ end
+
+ # Top-level method for scanning all plugin directories.
+ # Clears previously loaded plugins.
+ def scan_plugins
+ @registry = {} # bundle_name => bundle_instance mapping
+ @info = {} # bundle_name => bundle_info mapping
+ @aliases = {} # bundle_alias => bundle_name mapping
+ @servlets = [] # bundle_name list of Servlet class instances
+ bundles_found = []
+ @plugin_paths.each do |path|
+ next unless File.directory? path
+ bundles_found += scan_plugindir( path )
+ end
+ bundles_found.each do |bundle_path, bundle_name, src_file|
+ unless is_disabled?( bundle_path )
+ bundle_found( bundle_path, bundle_name, src_file )
+ end
+ end
+ load_bundles
+ delegate( :open )
+ end
+
+ # Unloads the plugin bundle named +bundle_name+
+ def unload_bundle( bundle_name )
+ if @registry.has_key?( bundle_name )
+ unload_order = @deps.del_order( bundle_name )
+ unload_order.each do |unload_dep|
+ unload_bundle( unload_dep ) unless unload_dep == bundle_name
+ end
+ puts "Unloading bundle: #{bundle_name.inspect}" if RSence.args[:debug]
+ @deps.del_item( bundle_name )
+ online_status = @transporter.online?
+ @transporter.online = false
+ call( bundle_name, :flush )
+ call( bundle_name, :close )
+ @registry.delete( bundle_name )
+ @aliases.each do |a_name,b_name|
+ if b_name == bundle_name
+ @aliases.delete( a_name )
+ end
+ end
+ if @servlets.include?( bundle_name )
+ @servlets.delete( bundle_name )
+ end
+ if @info.include?( bundle_name )
+ @info.delete( bundle_name )
+ end
+ @transporter.online = online_status
+ end
+ end
+
+ # Returns true, if a plugin bundle has changed.
+ # Only compares timestamp, not checksum.
+ def plugin_changed?( plugin_name )
+ info = @info[plugin_name]
+ last_changed = info[:last_changed]
+ newest_change = most_recent( info[:path], last_changed )
+ return last_changed < newest_change
+ end
+
+ # Logs and speaks the message
+ def say( message )
+ puts message
+ if RSence.args[:say]
+ Thread.new do
+ Thread.pass
+ system(%{say "#{message.gsub('"','')}"})
+ end
+ end
+ end
+
+ # Checks for changed plugin bundles and unloads/loads/reloads them accordingly.
+ def changed_plugins!
+ bundles_found = []
+ @plugin_paths.each do |path|
+ bundles_found += scan_plugindir( path )
+ end
+ bundle_names_found = []
+ bundles_found.each do |bundle_path, bundle_name, src_file|
+ bundle_names_found.push( bundle_name )
+ is_loaded = is_loaded?( bundle_name )
+ if is_loaded and is_disabled?( bundle_path )
+ # bundle already loaded but disabled now, should be unloaded:
+ unload_bundle( bundle_name )
+ say( "Unloaded #{bundle_name}." )
+ elsif is_loaded and plugin_changed?( bundle_name )
+ # bundle changed, should be reloaded:
+ unload_bundle( bundle_name )
+ unless @info.has_key?( bundle_name ) and not plugin_changed?( bundle_name )
+ @info[bundle_name] = bundle_info( bundle_path, bundle_name, src_file )
+ end
+ if @deps.resolved?( bundle_name )
+ load_bundle( bundle_name )
+ say( "Reloaded #{bundle_name}." )
+ end
+ elsif not is_loaded
+ # bundle not loaded, should be loaded:
+ unless @info.has_key?( bundle_name ) and not plugin_changed?( bundle_name )
+ @info[bundle_name] = bundle_info( bundle_path, bundle_name, src_file )
+ end
+ if @deps.resolved?( bundle_name )
+ load_bundle( bundle_name )
+ say( "Loaded #{bundle_name}." )
+ end
+ end
+ end
+ bundles_missing = @info.keys - bundle_names_found
+ bundles_missing.each do |bundle_name|
+ say( "#{bundle_name} deleted, unloading.." )
+ unload_bundle( bundle_name )
+ end
+ end
+
+ # Initialize with a list of directories as plugin_paths.
+ # It's an array containing all plugin directories to scan.
+ def initialize( plugin_paths, transporter=nil,
+ autoreload=false, name_prefix=false,
+ resolved_deps=[], resolved_categories={} )
+ if transporter
+ @transporter = transporter
+ @sessions = transporter.sessions
+ end
+ @name_prefix = name_prefix
+ @plugin_paths = plugin_paths
+ @deps = Dependencies.new( resolved_deps, resolved_categories )
+ puts "Loading #{name_prefix+' ' if name_prefix}plugins..." if RSence.args[:verbose]
+ scan_plugins
+ puts %{Plugins #{"of #{name_prefix} " if name_prefix}loaded.} if RSence.args[:verbose]
+ if autoreload
+ @thr = Thread.new do
+ Thread.pass
+ while true
+ begin
+ changed_plugins!
+ rescue => e
+ warn e.inspect
+ end
+ sleep 3
+ end
+ end
+ end
+ end
end
end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+