class MCollective::Applications
Public Class Methods
# File lib/mcollective/applications.rb 3 def self.[](appname) 4 load_application(appname) 5 PluginManager["#{appname}_application"] 6 end
Filters a string of opts out using Shellwords keeping only things related to –config and -c
# File lib/mcollective/applications.rb 49 def self.filter_extra_options(opts) 50 res = "" 51 words = Shellwords.shellwords(opts) 52 words.each_with_index do |word,idx| 53 if word == "-c" 54 return "--config=#{words[idx + 1]}" 55 elsif word == "--config" 56 return "--config=#{words[idx + 1]}" 57 elsif word =~ /\-c=/ 58 return word 59 elsif word =~ /\-\-config=/ 60 return word 61 end 62 end 63 64 return "" 65 end
Returns an array of applications found in the lib dirs
# File lib/mcollective/applications.rb 36 def self.list 37 load_config 38 39 PluginManager.find("application") 40 rescue SystemExit 41 exit 1 42 rescue Exception => e 43 STDERR.puts "Failed to generate application list: #{e.class}: #{e}" 44 exit 1 45 end
# File lib/mcollective/applications.rb 26 def self.load_application(appname) 27 return if PluginManager.include?("#{appname}_application") 28 29 load_config 30 31 PluginManager.loadclass "MCollective::Application::#{appname.capitalize}" 32 PluginManager << {:type => "#{appname}_application", :class => "MCollective::Application::#{appname.capitalize}"} 33 end
We need to know the config file in order to know the libdir so that we can find applications.
The problem is the CLI might be stuffed with options only the app in the libdir might understand so we have a chicken and egg situation.
We're parsing and filtering MCOLLECTIVE_EXTRA_OPTS removing all but config related options and parsing the options looking just for the config file.
We're handling failures gracefully and finally restoring the ARG and MCOLLECTIVE_EXTRA_OPTS to the state they were before we started parsing.
This is mostly a hack, when we're redoing how config works this stuff should be made less sucky
# File lib/mcollective/applications.rb 84 def self.load_config 85 return if Config.instance.configured 86 87 original_argv = ARGV.clone 88 original_extra_opts = ENV["MCOLLECTIVE_EXTRA_OPTS"].clone rescue nil 89 configfile = nil 90 91 parser = OptionParser.new 92 parser.on("--config CONFIG", "-c", "Config file") do |f| 93 configfile = f 94 end 95 96 parser.program_name = $0 97 98 parser.on("--help") 99 100 # avoid option parsers own internal version handling that sux 101 parser.on("-v", "--verbose") 102 103 if original_extra_opts 104 begin 105 # optparse will parse the whole ENV in one go and refuse 106 # to play along with the retry trick I do below so in 107 # order to handle unknown options properly I parse out 108 # only -c and --config deleting everything else and 109 # then restore the environment variable later when I 110 # am done with it 111 ENV["MCOLLECTIVE_EXTRA_OPTS"] = filter_extra_options(ENV["MCOLLECTIVE_EXTRA_OPTS"].clone) 112 parser.environment("MCOLLECTIVE_EXTRA_OPTS") 113 rescue Exception => e 114 Log.error("Failed to parse MCOLLECTIVE_EXTRA_OPTS: #{e}") 115 end 116 117 ENV["MCOLLECTIVE_EXTRA_OPTS"] = original_extra_opts.clone 118 end 119 120 begin 121 parser.parse! 122 rescue OptionParser::InvalidOption => e 123 retry 124 end 125 126 ARGV.clear 127 original_argv.each {|a| ARGV << a} 128 129 configfile = Util.config_file_for_user unless configfile 130 131 Config.instance.loadconfig(configfile) 132 end
# File lib/mcollective/applications.rb 8 def self.run(appname) 9 load_config 10 11 begin 12 load_application(appname) 13 rescue Exception => e 14 e.backtrace.first << Util.colorize(:red, " <----") 15 STDERR.puts "Application '#{appname}' failed to load:" 16 STDERR.puts 17 STDERR.puts Util.colorize(:red, " #{e} (#{e.class})") 18 STDERR.puts 19 STDERR.puts " %s" % [e.backtrace.join("\n ")] 20 exit 1 21 end 22 23 PluginManager["#{appname}_application"].run 24 end