Add support for lists on the command line.

svn: r17691
This commit is contained in:
Brian Matherly 2011-06-06 02:06:18 +00:00
parent 9d7e8e017c
commit bb17fd2af0
2 changed files with 157 additions and 6 deletions

View File

@ -52,6 +52,89 @@ from gen.plug import BasePluginManager
from gen.plug.report import CATEGORY_BOOK, CATEGORY_CODE
from cli.plug import cl_report
#-------------------------------------------------------------------------
#
# private functions
#
#-------------------------------------------------------------------------
def _split_options(options_str):
"""
Split the options for the action.
Rules:
* Entries in the list of options are separated by commas without spaces
between entries
* List values must be inclosed in brackets ("[" and "]")
* Entries within a list value are separated by commas
* Text values (as a value or as entries in a list) do not have to be
enclosed in quotes unless they include commas or quotation marks.
* Text containing double quotes must be contained in single quotes
* Text containing single quotes must be contained in double quotes
* Text cannot include both single and double quotes
Examples:
* Multiple options specified:
report -p 'name=ancestor_chart,father_disp=["$n born $b"]'
* Using text with commas and quotes:
title="This is some text with ,s and 's"
title='This is some text with ,s and "s'
* Using a list of text
textlist=[row1,row2,"row3 with ' and ,"]
"""
name = ""
value = ""
parsing_value = False
in_quotes = False
in_list = False
quote_type = ""
options_str_dict = {}
for char in options_str:
if not parsing_value:
# Parsing the name of the option
if char == "=":
#print char, "This value ends the name"
parsing_value = True
else:
#print char, "This value is part of the name"
name += char
else:
# Parsing the value of the option
if value == "" and char == '[':
#print char, "This character begins a list"
in_list = True
value += char
elif in_list == True and char == ']':
#print char, "This character ends the list"
in_list = False
value += char
elif not in_quotes and ( char == '"' or char == "'"):
#print char, "This character starts a quoted string"
in_quotes = True
quote_type = char
value += char
elif in_quotes and char == quote_type:
#print char, "This character ends a quoted string"
in_quotes = False
value += char
elif not in_quotes and not in_list and char == ",":
#print char, "This character ends the value of the option"
options_str_dict[name] = value
name = ""
value = ""
parsing_value = False
in_quotes = False
in_list = False
else:
#print char, "This character is part of the value"
value += char
if parsing_value and not in_quotes and not in_list:
# Add the last option
options_str_dict[name] = value
return options_str_dict
#-------------------------------------------------------------------------
# ArgHandler
#-------------------------------------------------------------------------
@ -465,8 +548,7 @@ class ArgHandler(object):
pmgr = BasePluginManager.get_instance()
if action == "report":
try:
options_str_dict = dict( [ tuple(chunk.split('='))
for chunk in options_str.split(',') ] )
options_str_dict = _split_options(options_str)
except:
options_str_dict = {}
print >> sys.stderr, "Ignoring invalid options string."

View File

@ -67,6 +67,71 @@ from cli.grampscli import CLIManager
# Private Functions
#
#------------------------------------------------------------------------
def _convert_str_to_match_type(str_val, type_val):
"""
Returns a value representing str_val that is the same type as type_val.
"""
str_val = str_val.strip()
ret_type = type(type_val)
if ret_type in (str, unicode):
if ( str_val.startswith("'") and str_val.endswith("'") ) or \
( str_val.startswith('"') and str_val.endswith('"') ):
# Remove enclosing quotes
return unicode(str_val[1:-1])
else:
return unicode(str_val)
elif ret_type == int:
if str_val.isdigit():
return int(str_val)
else:
print "%s is not an integer number" % str_val
return 0
elif ret_type == float:
if str_val.isdecimal():
return float(ret_type)
else:
print "%s is not a decimal number" % str_val
return 0.0
elif ret_type == bool:
if str_val == str(True):
return True
return False
elif ret_type == list:
ret_val = []
if not ( str_val.startswith("[") and str_val.endswith("]") ):
print "%s is not a list" % str_val
return ret_val
entry = ""
quote_type = None
# Search through characters between the brackets
for char in str_val[1:-1]:
if (char == "'" or char == '"') and quote_type == None:
# This character starts a string
quote_type = char
elif char == quote_type:
# This character ends a string
quote_type = None
elif quote_type == None and char == ",":
# This character ends an entry
ret_val.append(entry.strip())
entry = ""
quote_type = None
else:
entry += char
if entry != "":
# Add the last entry
ret_val.append(entry.strip())
return ret_val
def _validate_options(options, dbase):
"""
Validate all options by making sure that their values are consistent with
@ -291,13 +356,15 @@ class CommandLineReport(object):
elif isinstance(option, NumberOption):
self.options_help[name].append("A number")
elif isinstance(option, BooleanOption):
self.options_help[name].append(["False\tno", "True\tyes"])
self.options_help[name].append(["False", "True"])
elif isinstance(option, DestinationOption):
self.options_help[name].append("A file system path")
elif isinstance(option, StringOption):
self.options_help[name].append("Any text")
elif isinstance(option, TextOption):
self.options_help[name].append("Any text")
self.options_help[name].append(
"A list of text values. Each entry in the list "
"represents one line of text." )
elif isinstance(option, EnumeratedListOption):
ilist = []
for (value, description) in option.get_items():
@ -320,8 +387,10 @@ class CommandLineReport(object):
menu_opt_names = menu.get_all_option_names()
for opt in self.options_str_dict:
if opt in self.options_dict:
converter = Utils.get_type_converter(self.options_dict[opt])
self.options_dict[opt] = converter(self.options_str_dict[opt])
self.options_dict[opt] = \
_convert_str_to_match_type(self.options_str_dict[opt],
self.options_dict[opt])
self.option_class.handler.options_dict[opt] = \
self.options_dict[opt]