1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-22 18:50:08 +03:00

feature #1427: Improve command_parser

* Add support for commands without actions (create..): main
	* Add exit_code method
    * Add option method instead of set :option (deprecated)
	* Add format method instead of set :format (deprecated)
	* Improve option :proc handling(cherry picked from commit 8572f13fe8cac6583d3bff250fa9e7953272d4f4)
This commit is contained in:
Daniel Molina 2012-08-23 14:22:11 +02:00
parent 98048f42f7
commit c71ba4a27e
4 changed files with 203 additions and 189 deletions

View File

@ -54,25 +54,18 @@ module CommandParser
attr_reader :options, :args
def initialize(args=[], &block)
@opts = Array.new
@available_options = Array.new
@commands = Hash.new
@formats = Hash.new
@script = nil
@main = nil
@exit_code = nil
@args = args
@options = Hash.new
set :format, :file, "Path to a file" do |arg|
format_file(arg)
end
set :format, :range, "List of id's in the form 1,8..15" do |arg|
format_range(arg)
end
set :format, :text, "String" do |arg|
format_text(arg)
end
define_default_formats
instance_eval(&block)
@ -80,11 +73,7 @@ module CommandParser
end
def usage(str)
@usage=<<EOT
## SYNOPSIS
#{str}
EOT
@usage=str
end
def version(str)
@ -95,15 +84,27 @@ EOT
@description = str
end
def set(e, *args, &block)
case e
when :option
add_option(args[0])
when :format
add_format(args[0], args[1], block)
def format(format, description, &block)
@formats[format] = {
:desc => description,
:proc => block
}
end
def option(options)
if options.instance_of?(Array)
options.each { |o| @available_options << o }
elsif options.instance_of?(Hash)
@available_options << options
end
end
# Define the exit code to be returned by the command
# @param [Integer] code
def exit_code(code)
@exit_code = code
end
def exit_with_code(code, output=nil)
puts output if output
exit code
@ -130,28 +131,40 @@ EOT
@commands[name.to_sym] = cmd
end
def script(*args_format, &block)
@script=Hash.new
@script[:args_format] = Array.new
def main(*args_format, &block)
@main=Hash.new
@main[:arity] = 0
@main[:args_format] = Array.new
args_format.collect {|args|
if args.instance_of?(Array)
@script[:arity]+=1 unless args.include?(nil)
@script[:args_format] << args
@main[:arity]+=1 unless args.include?(nil)
@main[:args_format] << args
elsif args.instance_of?(Hash) && args[:options]
@opts << args[:options]
@available_options << args[:options]
else
@script[:arity]+=1
@script[:args_format] << [args]
@main[:arity]+=1
@main[:args_format] << [args]
end
}
@script[:proc] = block
@main[:proc] = block
end
# DEPRECATED, use format and options instead
def set(e, *args, &block)
case e
when :option
option(args[0])
when :format
format(args[0], args[1], &block)
end
end
def run
comm_name=""
if @script
comm=@script
if @main
comm=@main
elsif
if @args[0] && !@args[0].match(/^-/)
comm_name=@args.shift.to_sym
@ -160,7 +173,7 @@ EOT
end
if comm.nil?
help
print_help
exit -1
end
@ -175,133 +188,17 @@ EOT
puts rc[1]
exit rc.first
else
exit rc
exit(@exit_code || rc)
end
end
end
def help
puts @usage if @usage
puts
puts @description if @description
puts
print_options
puts
print_commands
puts
print_formatters
puts
if @version
puts "## LICENSE"
puts @version
end
end
private
def print_options
puts "## OPTIONS"
shown_opts = Array.new
opt_format = "#{' '*5}%-25s %s"
@commands.each{ |key,value|
value[:options].flatten.each { |o|
if shown_opts.include?(o[:name])
next
else
shown_opts << o[:name]
str = ""
str << o[:short].split(' ').first << ', ' if o[:short]
str << o[:large]
printf opt_format, str, o[:description]
puts
end
}
}
@opts.each{ |o|
str = ""
str << o[:short].split(' ').first << ', ' if o[:short]
str << o[:large]
printf opt_format, str, o[:description]
puts
}
end
def print_commands
puts "## COMMANDS"
cmd_format5 = "#{' '*3}%s"
cmd_format10 = "#{' '*8}%s"
@commands.each{ |key,value|
printf cmd_format5, "* #{key} "
args_str=value[:args_format].collect{ |a|
if a.include?(nil)
"[<#{a.compact.join("|")}>]"
else
"<#{a.join("|")}>"
end
}.join(' ')
printf "#{args_str}"
puts
value[:desc].split("\n").each { |l|
printf cmd_format10, l
puts
}
unless value[:options].empty?
opts_str=value[:options].flatten.collect{|o|
o[:name]
}.join(', ')
printf cmd_format10, "valid options: #{opts_str}"
puts
end
puts
}
end
def print_formatters
puts "## ARGUMENT FORMATS"
cmd_format5 = "#{' '*3}%s"
cmd_format10 = "#{' '*8}%s"
@formats.each{ |key,value|
printf cmd_format5, "* #{key}"
puts
value[:desc].split("\n").each { |l|
printf cmd_format10, l
puts
}
puts
}
end
def add_option(option)
if option.instance_of?(Array)
option.each { |o| @opts << o }
elsif option.instance_of?(Hash)
@opts << option
end
end
def add_format(format, description, block)
@formats[format] = {
:desc => description,
:proc => block
}
end
def parse(extra_options)
@cmdparse=OptionParser.new do |opts|
merge = @opts
merge = @opts + extra_options if extra_options
merge = @available_options
merge = @available_options + extra_options if extra_options
merge.flatten.each do |e|
args = []
args << e[:short] if e[:short]
@ -311,9 +208,16 @@ EOT
opts.on(*args) do |o|
if e[:proc]
e[:proc].call(o, @options)
rc = e[:proc].call(o, @options)
if rc.instance_of?(Array) && rc[0] == 0
options[e[:name].to_sym] = rc[1]
else
puts rc[1]
puts "option #{e[:name]}: Parsing error"
exit -1
end
elsif e[:name]=="help"
help
print_help
exit
elsif e[:name]=="version"
puts @version
@ -399,7 +303,126 @@ EOT
end
########################################################################
# Formatters for arguments
# Printers
########################################################################
def print_help
if @usage
puts "## SYNOPSIS"
puts
puts @usage
puts
end
puts @description if @description
puts
print_options
puts
print_commands
puts
print_formatters
puts
if @version
puts "## LICENSE"
puts @version
end
end
def print_options
puts "## OPTIONS"
shown_opts = Array.new
opt_format = "#{' '*5}%-25s %s"
@commands.each{ |key,value|
value[:options].flatten.each { |o|
if shown_opts.include?(o[:name])
next
else
shown_opts << o[:name]
str = ""
str << o[:short].split(' ').first << ', ' if o[:short]
str << o[:large]
printf opt_format, str, o[:description]
puts
end
}
}
@available_options.each{ |o|
str = ""
str << o[:short].split(' ').first << ', ' if o[:short]
str << o[:large]
printf opt_format, str, o[:description]
puts
}
end
def print_commands
cmd_format5 = "#{' '*3}%s"
cmd_format10 = "#{' '*8}%s"
if @main
print_command(@main)
else
puts "## COMMANDS"
@commands.each{ |key,value|
printf cmd_format5, "* #{key} "
print_command(value)
}
end
end
def print_command(command)
args_str=command[:args_format].collect{ |a|
if a.include?(nil)
"[<#{a.compact.join("|")}>]"
else
"<#{a.join("|")}>"
end
}.join(' ')
printf "#{args_str}"
puts
command[:desc].split("\n").each { |l|
printf cmd_format10, l
puts
}
unless command[:options].empty?
opts_str=command[:options].flatten.collect{|o|
o[:name]
}.join(', ')
printf cmd_format10, "valid options: #{opts_str}"
puts
end
puts
end
def print_formatters
puts "## ARGUMENT FORMATS"
cmd_format5 = "#{' '*3}%s"
cmd_format10 = "#{' '*8}%s"
@formats.each{ |key,value|
printf cmd_format5, "* #{key}"
puts
value[:desc].split("\n").each { |l|
printf cmd_format10, l
puts
}
puts
}
end
########################################################################
# Default Formatters for arguments
########################################################################
def format_text(arg)
arg.instance_of?(String) ? [0,arg] : [-1]
@ -432,6 +455,20 @@ EOT
return 0,ids.uniq
end
def define_default_formats
format :file, "Path to a file" do |arg|
format_file(arg)
end
format :range, "List of id's in the form 1,8..15" do |arg|
format_range(arg)
end
format :text, "String" do |arg|
format_text(arg)
end
end
end
end

View File

@ -25,18 +25,10 @@ class OneClusterHelper < OpenNebulaHelper::OneHelper
:description => "Selects the cluster",
:format => String,
:proc => lambda { |o, options|
ch = OneClusterHelper.new
rc, cid = ch.to_id(o)
if rc == 0
options[:cluster] = cid
else
puts cid
puts "option cluster: Parsing error"
exit -1
end
OpenNebulaHelper.rname_to_id(o, "CLUSTER")
}
}
def self.rname
"CLUSTER"
end

View File

@ -24,15 +24,7 @@ class OneDatastoreHelper < OpenNebulaHelper::OneHelper
:description => "Selects the datastore",
:format => String,
:proc => lambda { |o, options|
ch = OneDatastoreHelper.new
rc, dsid = ch.to_id(o)
if rc == 0
options[:datastore] = dsid
else
puts dsid
puts "option datastore: Parsing error"
exit -1
end
OpenNebulaHelper.rname_to_id(o, "DATASTORE")
}
}

View File

@ -32,14 +32,7 @@ class OneVMHelper < OpenNebulaHelper::OneHelper
:description => "Selects the image",
:format => String,
:proc => lambda { |o, options|
rc, imid = OpenNebulaHelper.rname_to_id(o, "IMAGE")
if rc == 0
options[:image] = imid
else
puts imid
puts "option image: Parsing error"
exit -1
end
OpenNebulaHelper.rname_to_id(o, "IMAGE")
}
}
@ -188,13 +181,13 @@ class OneVMHelper < OpenNebulaHelper::OneHelper
"USED CPU" => "CPU",
"NET_TX" => "NET_TX",
"NET_RX" => "NET_RX"
}
}
poll_attrs.each { |k,v|
poll_attrs.each { |k,v|
if k == "USED CPU"
puts str % [k,vm[v]]
puts str % [k,vm[v]]
elsif k == "USED MEMORY"
puts str % [k, OpenNebulaHelper.unit_to_str(vm[v].to_i, {})]
puts str % [k, OpenNebulaHelper.unit_to_str(vm[v].to_i, {})]
else
puts str % [k, OpenNebulaHelper.unit_to_str(vm[v].to_i/1024, {})]
end