#这一部分用来加载Module下各模块 module Aio::Module require "find" require "pathname" class Loader Reg_klass_filter = /class (.*) < Aio::Module::Cmd/ Reg_ruby_file = /.rb$/ attr_accessor :module_manager def initialize(module_manager) @module_manager = module_manager end # 分析各个文件夹目录 # 目录格式 ~/aio/lib/modules/cisco/show_version.rb def each_module_reference_name(path, opts={}) ::Dir.foreach(path) do |entry| if entry.downcase == "." or entry.downcase == ".." next end full_entry_path = ::File.join(path, entry) device_type = entry unless ::File.directory?(full_entry_path) and module_manager.device_type_enable?(device_type) next end # device_type = "cisco" # full_entry_path = "~/aio/lib/modules/cisco" full_entry_pathname = Pathname.new(full_entry_path) Find.find(full_entry_path) do |entry_descendant_path| if File.directory?(entry_descendant_path) next end # 判断是不是.rb 结尾,而不是 .rb.swp 结尾 unless vaild_ruby_file?(entry_descendant_path) next end # entry_descendant_path 为ruby文件的完整绝对路径 entry_descendant_pathname = Pathname.new(entry_descendant_path) # 查询是否有效并且取得模块的类名 module_klass_name = get_module_klass_name(entry_descendant_pathname) if module_klass_name.empty? next end relative_entry_descendant_pathname = entry_descendant_pathname.relative_path_from(full_entry_pathname) relative_entry_descendant_path = relative_entry_descendant_pathname.to_s module_reference_name = module_reference_name_from_path(relative_entry_descendant_path) yield entry_descendant_path, device_type, module_reference_name, module_klass_name end end end # 取模块的类名,以便以后调用 def get_module_klass_name(full_path) fo = File.open(full_path) fo.each_line do |l| l = safe_string(l) klass_name = Reg_klass_filter.match(l) if klass_name == nil next end klass_name = klass_name[1].strip return klass_name end return "" end def module_reference_name_from_path(path) path.gsub(Reg_ruby_file, '') end def vaild_ruby_file?(path) if Reg_ruby_file.match(path) return true end return false end # 遇到了 invalid byte sequence in UTF-8 (ArgumentError) 问题 # 解决办法参考 https://stackoverflow.com/questions/29877310/invalid-byte-sequence-in-utf-8-argumenterror def safe_string(str) if ! str.valid_encoding? str = str.encode("UTF-16be", :invalid=>:replace, :replace=>"?").encode('UTF-8') end return str end # 全局加载模块 def load_modules(path, opts={}) count_by_device_type = {} each_module_reference_name(path, opts={}) do |full_module_path, device_type, module_reference_name, module_klass_name| load_module(full_module_path, device_type, module_reference_name, module_klass_name, { # :recalcuate_by_device_type => recalculate_by_device_type, :count_by_device_type => count_by_device_type, } ) end module_manager.notify({ :count_by_device_type => count_by_device_type, }) end # 真正加载处 # 并将模块全部实例化 def load_module(full_module_path, device_type, module_reference_name, module_klass_name, opts={}) require "#{full_module_path}" begin module_klass = Object::const_get(module_klass_name).new rescue Exception puts "[-] Can not load module: #{full_module_path}" puts caller return end @module_manager.add_module(full_module_path, device_type, module_reference_name, module_klass) # 计数 count_by_device_type = opts[:count_by_device_type] if count_by_device_type count_by_device_type[device_type] ||= 0 count_by_device_type[device_type] += 1 end end end #class end #module