Class: RSence::PluginManager

Inherits:
Object
  • Object
show all
Defined in:
lib/rsence/pluginmanager.rb

Overview

PluginManager is the service that loads and provides method delegation amongst its plugin bundles.

Usage

plugin_paths = [ 'plugins', '/home/me/rsence/plugins' ]
myPluginManager = RSence::PluginManager.new( plugin_paths )

Constant Summary collapse

@@incr =
0
@@prev_errors =

Prettier error handling.

[]
@@pluginmanager_id =
0

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ PluginManager

Initialize with a list of directories as plugin_paths. It’s an array containing all plugin directories to scan.



655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
# File 'lib/rsence/pluginmanager.rb', line 655

def initialize( options )
  
  options = {
    :plugin_paths => nil,
    :transporter => nil,
    :autoreload => false,
    :name_prefix => false,
    :resolved_deps => [],
    :resolved_categories => {},
    :parent_manager => nil
  }.merge( options )
  
  @pluginmanager_id = @@pluginmanager_id
  @@pluginmanager_id += 1
  
  @closed = false
  @plugin_paths = options[:plugin_paths]
  
  if options[:transporter]
    @transporter = options[:transporter]
    #@sessions    = options[:transporter].sessions
  end
  
  @autoreload = options[:autoreload]
  @name_prefix = options[:name_prefix]
  @parent_manager = options[:parent_manager]
  
  if @parent_manager == nil
    RSence.plugin_manager = self
  end
  
  @deps = Dependencies.new( options[:resolved_deps], options[:resolved_categories] )
  
  puts "Loading #{@name_prefix.to_s+' ' if @name_prefix}plugins..." if RSence.args[:verbose]
  init_bundles!
  puts %{Plugins #{"of #{@name_prefix} " if @name_prefix}loaded.} if RSence.args[:verbose]
  if @autoreload
    @thr = Thread.new do
      Thread.pass
      until @closed
        begin
          update_bundles!
        rescue => e
          plugin_error( e, "PluginManager#update_bundles!", "An error occurred while reloading bundles" )
        end
        sleep 3
      end
      puts "No longer reloading plugins of #{@name_prefix}." if RSence.args[:verbose]
    end
  end
  
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(sym, *args, &block) ⇒ Object

By default, calling a method not defined calls a plugin of that name



40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/rsence/pluginmanager.rb', line 40

def method_missing( sym, *args, &block )
  if @registry.has_key?(sym)
    if args == [] and block == nil
      return @registry[sym]
    elsif block == nil
      call( sym, *args )
    end
  elsif @parent_manager
    return @parent_manager.method_missing( sym, *args, &block )
  end
  warn "method or plugin #{sym.inspect} not found!"
  nil
end

Instance Attribute Details

#autoreloadObject (readonly)

Returns the value of attribute autoreload.



639
640
641
# File 'lib/rsence/pluginmanager.rb', line 639

def autoreload
  @autoreload
end

#name_prefixObject (readonly)

Returns the value of attribute name_prefix.



640
641
642
# File 'lib/rsence/pluginmanager.rb', line 640

def name_prefix
  @name_prefix
end

#parent_managerObject (readonly)

Returns the value of attribute parent_manager.



642
643
644
# File 'lib/rsence/pluginmanager.rb', line 642

def parent_manager
  @parent_manager
end

#plugin_pathsObject (readonly)

Returns the value of attribute plugin_paths.



641
642
643
# File 'lib/rsence/pluginmanager.rb', line 641

def plugin_paths
  @plugin_paths
end

#sessionsObject

Returns the value of attribute sessions.



16
17
18
# File 'lib/rsence/pluginmanager.rb', line 16

def sessions
  @sessions
end

#transporterObject (readonly)

Returns the value of attribute transporter.



16
17
18
# File 'lib/rsence/pluginmanager.rb', line 16

def transporter
  @transporter
end

Instance Method Details

#add_servlet(bundle_name) ⇒ Object



82
83
84
85
86
87
88
# File 'lib/rsence/pluginmanager.rb', line 82

def add_servlet( bundle_name )
  if @parent_manager
    sub_name = "#{@name_prefix.to_s}:#{bundle_name.to_s}"
    @parent_manager.add_servlet( sub_name )
  end
  @servlets.push( bundle_name )
end

#bundle_found(bundle_path, bundle_name, src_file) ⇒ Object

If a bundle is found, set its dependencies etc



433
434
435
# File 'lib/rsence/pluginmanager.rb', line 433

def bundle_found( bundle_path, bundle_name, src_file )
  @info[ bundle_name ] = bundle_info( bundle_path, bundle_name, src_file )
end

#bundle_info(bundle_path, bundle_name, src_file) ⇒ Object

Gets plugin information



284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
# File 'lib/rsence/pluginmanager.rb', line 284

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 => '>= 2.2.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,
    
    # Name of plugin manager, so the bundle internals know what its path is.
    :manager        => @name_prefix
    
  }
  
  # 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
  elsif RSence.args[:debug]
    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 override-able 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

#call(plugin_name, method_name, *args) ⇒ Object Also known as: run_plugin

Calls the method method_name with args args of the plugin plugin_name. Returns false, if no such plugin or method exists.



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/rsence/pluginmanager.rb', line 108

def call( plugin_name, method_name, *args )
  puts "#{plugin_name}.#{method_name}" if RSence.args[:trace_delegate]
  plugin_name_s = plugin_name.to_s
  if plugin_name_s.include?(':')
    colon_index = plugin_name_s.index(':')
    sub_manager_name = plugin_name_s[0..(colon_index-1)].to_sym
    plugin_name = plugin_name_s[(colon_index+1)..-1].to_sym
    if @registry.has_key?( sub_manager_name )
      sub_manager = @registry[sub_manager_name]
      if sub_manager.respond_to?( :plugin_plugins )
        return sub_manager.plugin_plugins.call( plugin_name, method_name, *args )
      end
    end
    return false
  end
  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 (#{@pluginmanager_id})! No such plugin: #{plugin_name.inspect} (tried to call #{method_name.inspect[0..100]} using args: #{args.inspect[0..100]}"
  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

#callable?(plugin_name, method_name) ⇒ Boolean

Returns:

  • (Boolean)


98
99
100
101
102
103
104
# File 'lib/rsence/pluginmanager.rb', line 98

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

#changed?(plugin_name) ⇒ Boolean

Returns true, if a plugin bundle has changed. Only compares timestamp, not checksum.

Returns:

  • (Boolean)


518
519
520
521
522
523
# File 'lib/rsence/pluginmanager.rb', line 518

def 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

#del_servlet(bundle_name) ⇒ Object



90
91
92
93
94
95
96
# File 'lib/rsence/pluginmanager.rb', line 90

def del_servlet( bundle_name )
  if @parent_manager
    sub_name = "#{@name_prefix.to_s}:#{bundle_name.to_s}"
    @parent_manager.del_servlet( sub_name )
  end
  @servlets.delete( bundle_name )
end

#delegate(method_name, *args) ⇒ Object

Delegates method_name with args to any loaded plugin that responds to the method.



233
234
235
236
237
# File 'lib/rsence/pluginmanager.rb', line 233

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

#delegate_reverse(method_name, *args) ⇒ Object

Reverse delegate method_name with args to any loaded plugin that responds to the method.



241
242
243
244
245
# File 'lib/rsence/pluginmanager.rb', line 241

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

#disabled?(bundle_path) ⇒ Boolean

Returns true, if the bundle is disabled

Returns:

  • (Boolean)


454
455
456
# File 'lib/rsence/pluginmanager.rb', line 454

def disabled?( bundle_path )
  File.exists?( File.join( bundle_path, 'disabled' ) )
end

#find_bundles(path) ⇒ Object

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'


469
470
471
472
473
474
475
476
477
478
479
480
481
482
# File 'lib/rsence/pluginmanager.rb', line 469

def find_bundles( 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
      unless disabled?( bundle_path )
        # bundle_name = "#{@name_prefix.to_s}.#{bundle_name}" if @name_prefix
        bundles_found.push( [bundle_path, bundle_name.to_sym, src_file] )
      end
    end
  end
  return bundles_found
end

#incrObject



19
20
21
# File 'lib/rsence/pluginmanager.rb', line 19

def incr
  return @@incr
end

#incr!Object



22
23
24
# File 'lib/rsence/pluginmanager.rb', line 22

def incr!
  @@incr += 1
end

#init_bundles!Object

Top-level method for scanning all plugin directories. Clears previously loaded plugins.



630
631
632
633
634
635
636
# File 'lib/rsence/pluginmanager.rb', line 630

def init_bundles!
  @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
  update_bundles!
end

#load_bundle(name) ⇒ Object

Loads a plugin bundle.



378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
# File 'lib/rsence/pluginmanager.rb', line 378

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} in bundle path: #{path.inspect}"
    end
  end
end

#load_bundlesObject

loads all bundles found in order of dependency



426
427
428
429
430
# File 'lib/rsence/pluginmanager.rb', line 426

def load_bundles
  @deps.list.each do |name|
    load_bundle( name ) if @deps.loadable?( name )
  end
end

#loaded?(bundle_name) ⇒ Boolean

Returns true, if the bundle is loaded.

Returns:

  • (Boolean)


459
460
461
# File 'lib/rsence/pluginmanager.rb', line 459

def loaded?( bundle_name )
  @registry.has_key?( bundle_name )
end

#match_servlet(req_type, req, resp, session) ⇒ Object

Calls the servlet that matches the req_type and req.fullpath with the highest score.



210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/rsence/pluginmanager.rb', line 210

def match_servlet( req_type, req, resp, session )
  req_uri = req.fullpath
  matches_order = match_servlet_uri( req_uri, req_type )
  return false unless matches_order
  matches_order.each do |servlet_name|
    begin
      call( servlet_name, req_type, req, resp, session )
      return true
    rescue => e
      plugin_error(
        e,
        "RSence::PluginManager.match_servlet",
        "servlet_name: #{servlet_name.inspect}, req_type: #{req_type.inspect}",
        servlet_name
      )
      next
    end
  end
  return false
end

#match_servlet_uri(uri, req_type = :get) ⇒ Object

Search servlets that match the uri and req_type



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/rsence/pluginmanager.rb', line 178

def match_servlet_uri( uri, req_type=:get )
  match_score = {}
  @servlets.each do | servlet_name |
    if call( servlet_name, :match, uri, req_type )
      score = call( servlet_name, :score )
      match_score[ score ] = [] unless match_score.has_key? score
      match_score[ score ].push( servlet_name )
    end
  end
  match_scores = match_score.keys.sort
  if match_scores.empty?
    return false
  else
    matches_order = []
    matches_best  = match_score[ match_scores[0] ]
    if matches_best.size > 1
      matches_best = matches_best[ rand( matches_best.size ) ]
    else
      matches_best = matches_best.first
    end
    matches_order.push( matches_best )
    match_score.keys.sort.each do |match_n|
      match_score[ match_n ].each do | match_name |
        matches_order.push( match_name ) unless matches_order.include? match_name
      end
    end
    return matches_order
  end
end

#most_recent(bundle_path, newest_date = 0) ⇒ Object

Finds the most recent file in the path



261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/rsence/pluginmanager.rb', line 261

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 == '.' # skip hidden, '.' and '..' 
      full_path = File.join( bundle_path, entry_name )
      if File.directory?( full_path )
        next if entry_name == 'plugins' # skip sub-plugins
      else
        next unless entry_name.include?('.')
        next unless ['yaml','rb'].include?( entry_name.split('.')[-1] )
      end
      newest_date = most_recent( full_path, newest_date )
    end
  end
  return newest_date
end

#plugin_error(e, err_location, err_location_descr, eval_repl = false) ⇒ Object



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/rsence/pluginmanager.rb', line 148

def plugin_error( e, err_location, err_location_descr, eval_repl=false )
  err_msg = [
    "*"*40,
    err_location,
    err_location_descr,
    "#{e.class.to_s}, #{e.message}",
    "Backtrace:",
    "\t"+e.backtrace.join("\n\t"),
    "*"*40
  ].join("\n")+"\n"
  error_say = "Error! #{err_location_descr.capitalize}. #{e.class.to_s}, #{e.message}?"
  unless @@prev_errors.include?( error_say )
    @@prev_errors.push( error_say )
    say error_say
  end
  @@prev_errors.shift if @@prev_errors.length > 10
  if eval_repl
    puts
    puts "plugin: #{eval_repl}"
    puts
    begin
      err_msg = err_msg.gsub(/^\t\(eval\)\:/s,"\t#{eval_repl}:")
    rescue Encoding::CompatibilityError => e
      $stderr.write( "Encoding::CompatibilityError in plugin error eval!" )
    end
  end
  $stderr.write( err_msg )
end

#register_alias(bundle_name, alias_name) ⇒ Object

Registers alias name for a plugin bundle.



55
56
57
58
59
60
61
# File 'lib/rsence/pluginmanager.rb', line 55

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

#register_bundle(inst, bundle_name) ⇒ Object

Registers plugin class inst into the registry using bundle_name



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/rsence/pluginmanager.rb', line 64

def register_bundle( inst, bundle_name )
  bundle_name = bundle_name.to_sym
  if @registry.has_key?( bundle_name )
    if registry[ bundle_name ] != inst
      warn "Tried to register a conflicting bundle name: #{bundle_name.inspect}; ignoring"
    else
      warn "Use @plugins.register_alias to register more than one name per plugin."
      register_alias( inst.name.to_sym, bundle_name )
    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 ) )
      add_servlet( bundle_name )
    end
  end
end

#registry(plugin_name = false) ⇒ Object Also known as: []

Returns the registry data for plugin bundle plugin_name



27
28
29
30
31
32
33
34
35
36
# File 'lib/rsence/pluginmanager.rb', line 27

def registry( plugin_name=false )
  return @registry unless plugin_name
  if @registry.has_key?( plugin_name )
    return @registry[ plugin_name ]
  elsif @parent_manager
    return @parent_manager.registry( plugin_name )
  else
    throw "Plugin not in registry: #{plugin_name.inspect}"
  end
end

#say(message) ⇒ Object

Logs and speaks the message, if the speech synthesis command “say” exists.



526
527
528
529
530
531
532
533
534
# File 'lib/rsence/pluginmanager.rb', line 526

def say( message )
  puts message
  if RSence.args[:say]
    Thread.new do
      Thread.pass
      system(%{say "#{message.gsub('"',"'").gsub('`',"'")}"})
    end
  end
end

#shutdownObject

Delegates the flush and close methods to any loaded plugins, in that order.



249
250
251
252
253
254
255
256
257
258
# File 'lib/rsence/pluginmanager.rb', line 249

def shutdown
  if @parent_manager
    @closed = true
  else
    @transporter.online = false
  end
  @deps.list.reverse.each do |bundle_name|
    unload_bundle( bundle_name )
  end
end

#unload_bundle(bundle_name) ⇒ Object

Unloads the plugin bundle named bundle_name



485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
# File 'lib/rsence/pluginmanager.rb', line 485

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 )
    if @transporter
      online_status = @transporter.online?
      @transporter.online = false
    end
    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 )
      del_servlet( bundle_name )
    end
    if @info.include?( bundle_name )
      @info.delete( bundle_name )
    end
    @transporter.online = online_status if @transporter
    return unload_order
  end
end

#update_bundles!Object

Checks for changed plugin bundles and unloads/loads/reloads them accordingly.



537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
# File 'lib/rsence/pluginmanager.rb', line 537

def update_bundles!
  (are_found, to_load, to_unload, to_reload) = [[],[],[],[]]
  found_map = {}
  @plugin_paths.each do |path|
    are_found += find_bundles( path )
  end
  are_found.each do |item|
    (path, name, src_file) = item
    found_map[name] = item
    is_loaded = loaded?( name )
    if is_loaded and changed?( name )
      to_reload.push( name )
    elsif not is_loaded
      to_load.push( name )
    end
  end
  @registry.keys.each do |name|
    to_unload.push( name ) if not found_map.has_key?( name )
  end
  to_unload.each do |name|
    next if @deps.category?( name )
    if RSence.args[:verbose]
      print "Unloading #{name.inspect}..."; STDOUT.flush
    end
    unload_bundle( name )
    puts "done!" if RSence.args[:verbose]
  end
  to_reload.each do |name|
    next if @deps.category?( name )
    if RSence.args[:verbose]
      print "Unloading #{name.inspect}..."; STDOUT.flush
    end
    unload_order = unload_bundle( name )
    to_load += unload_order
    puts "done!" if RSence.args[:verbose]
  end
  info_map = {}
  to_load.each do |name|
    next unless found_map.has_key? name
    info_map[name] = bundle_info( *found_map[name] )
  end
  no_deps = {}
  to_load.dup.each do |name|
    if @deps.unresolved?( name )
      no_deps[ name ] = @deps.deps_on( name )
      @deps.del_item( name )
      to_load.delete( name )
    end
  end
  to_open = []
  @deps.list.each do |name|
    next if @deps.category?( name )
    next unless to_load.include?( name )
    info = info_map[name]
    if RSence.args[:verbose]
      if to_reload.include?( name )
        print "Reloading #{name.inspect}..."
      else
        print "Loading #{name.inspect}..."
      end
      STDOUT.flush
    end
    @info[name] = info
    load_bundle( name )
    to_open.push( name )
    puts "done!" if RSence.args[:verbose]
  end
  unless no_deps.empty?
    warn "Warning! Unable to load the following bundles; missing dependencies:"
    no_deps.each do |name,deps|
      warn "  #{name} depends on: #{deps.join(', ')}"
    end
  end
  to_open.each do |name|
    if RSence.args[:verbose]
      print "Opening #{name.inspect}..."; STDOUT.flush
    end
    call( name, :open )
    puts "done!" if RSence.args[:verbose]
  end
  if not (to_load.empty? and to_unload.empty? and to_reload.empty?)
    incr!
    puts "@@incr: #{@@incr}" if RSence.args[:debug]
    puts "Plugin bundles:"
    puts "  loaded: #{to_load.join(', ')}" unless to_load.empty?
    puts "  unloaded: #{to_unload.join(', ')}" unless to_unload.empty?
    puts "  reloaded: #{to_reload.join(', ')}" unless to_reload.empty?
    puts "  opened: #{to_open.join(', ')}" unless to_open.empty?
  end
end

#valid_plugindir?(path, bundle_name) ⇒ Boolean

Returns false, if the plugin directory isn’t valid. Returns [bundle_path, src_file] otherwise.

Returns:

  • (Boolean)


439
440
441
442
443
444
445
446
447
448
449
450
451
# File 'lib/rsence/pluginmanager.rb', line 439

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