From 07369510fd2b15b75ae2970eadfc03fd9989b7a5 Mon Sep 17 00:00:00 2001 From: Matthew Vliet Date: Mon, 24 Jan 2011 19:55:12 -0800 Subject: [PATCH] Updated with functionality and bug fixes, etc. --- repoman-client/repoman_client/parsers.py | 206 +++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 repoman-client/repoman_client/parsers.py diff --git a/repoman-client/repoman_client/parsers.py b/repoman-client/repoman_client/parsers.py new file mode 100644 index 0000000..4d8d79a --- /dev/null +++ b/repoman-client/repoman_client/parsers.py @@ -0,0 +1,206 @@ +from repoman_client.config import config +import argparse +import sys +from pprint import pprint + +__all__ = ['RepomanCLI'] + +def generate_help(title, commands): + # Get the length of the longest command for formatting + max_len = max([len(c.command) for c in commands]) + help_lines = ["%s:\n"%title.upper()] + for c in commands: + if not c.hidden: + #left justify each command and print + help_lines.append(" %s%s\n" % (c.command.ljust(max_len+4), c.description)) + return "".join(help_lines) + + +def arg_value_pairs(args): + if len(args) % 2: + raise ArgumentFormatError('Unable to parse argument/value pairs due to uneven number of values.') + for x in range(0, len(args), 2): + yield args[x], args[x+1] + + +def parse_unknown_args(args): + """ + expect args to be a list in the form of: + ['--arg1', 'value1', '--arg2', 'value', ...] + therfor args must contain an even number of items. + """ + arg_pairs = {} + for arg, value in arg_value_pairs(args): + if not arg.startswith('--'): + raise ArgumentFormatError("Found a value first, check arg/value order.") + else: + if value in ['true', 'True', 'TRUE']: + value = True + elif value in ['false', 'False', 'FALSE']: + value = False + arg_pairs.update({arg.lstrip('--'):value}) + return arg_pairs + + +class ArgumentFormatError(Exception): + def __init__(self, message): + self.message = message + + def __repr__(self): + return self.message + + def __str__(self): + return self.__repr__ + + + +class CommandGroup(object): + def __init__(self, title): + self.title = title + self.commands = [] # An ordered list used to generate help + self.command_lookup = {} # A dictionart to do command-->function lookups + + def format_help(self): + return generate_help(self.title, self.commands) + + def add_command(self, command): + if command not in self.commands: + self.commands.append(command) + self.command_lookup.update({command.command:command}) + + def get_command(self, command): + return self.command_lookup.get(command) + + + +class RepomanCLI(object): + def __init__(self, version): + self.version = version + self.parser = self.get_parser() + self.commands = [] # list of commands with no group specified + self.command_lookup = {} # command string --> class lookup + self.groups = [] # list of groups in order of appearence + self.group_lookup = {} # group_name --> class lookup + + def __call__(self): + (args, extra) = self.parse_known_args() + if args.help_all: + self.print_help(long=True) + elif args.help: + self.print_help(long=False) + + if not args.subcommand: + self.parser.error('Specify a subcommand to run, or run --help') + + # Overwrite config values with command line options if available + if args.proxy: + config.user_proxy_cert = args.proxy + if args.host: + config.repository_host = args.host + if args.port: + config.repository_port = args.port + + self.dispatch(args.subcommand, extra) + + def get_parser(self): + p = argparse.ArgumentParser(add_help=False) + p.add_argument('subcommand', metavar='SUBCOMMAND', nargs='?') + p.add_argument('-h', '--help', action='store_true', default=False) + p.add_argument('--help-all', action='store_true', default=False) + p.add_argument('--version', action='version', version='%s' % self.version) + p.add_argument('-H', '--host', help='Override host setting') + p.add_argument('-P', '--port', type=int, help='Override port setting for host') + p.add_argument('--proxy', help='Override default proxy certificate') + return p + + def parse_known_args(self, args=None): + if args is None: + args = sys.argv[1:] + + # Bit of a hack to get the help for subcommands + # if '-h' or '--help' occur in the args in anyplace other args[0], + # it will be removed temporarily. The main parser will be called, + # then the help switch will be re-inserted into the args and passed to + # the subcommand parser. + if '-h' or '--help' in args: + help_index = None + try: + help_index = args.index('-h') + except ValueError: + pass + try: + new_index = args.index('--help') + if not help_index: + help_index = new_index + elif help_index and new_index < help_index: + help_index = new_index + except ValueError: + pass + + help_extracted = False + if help_index and help_index != 0: + help_extracted = True + [args.remove('--help') for i in range(args.count('--help'))] + [args.remove('-h') for i in range(args.count('-h'))] + + (main_args, sub_args) = self.parser.parse_known_args(args) + if help_extracted: + sub_args.append('--help') + + return main_args, sub_args + + def print_help(self, long=False, exit=0): + print self.parser.format_help() + print generate_help('subcommands', self.commands) + if long: + for g in self.groups: + print self.group_lookup[g].format_help() + sys.exit(exit) + + def _add_command_group(self, group_name): + if group_name not in self.groups: + self.groups.append(group_name) + group = CommandGroup(group_name) + self.group_lookup.update({group_name:group}) + return group + else: + return self.group_lookup.get(group_name) + + def add_command(self, command_class): + group = command_class.command_group or None + if not group and command_class not in self.commands: + self.commands.append(command_class) + self.command_lookup.update({command_class.command:command_class}) + elif group: + group = self._add_command_group(group) + group.add_command(command_class) + + def lookup_command(self, command): + cmd = self.command_lookup.get(command) + if not cmd: + for name, group in self.group_lookup.iteritems(): + cmd = group.get_command(command) + if cmd: + break + return cmd + + def dispatch(self, command, args): + cmd = self.lookup_command(command) + if cmd: + if cmd.validate_config: + config.validate() + cmd = cmd() + cmd_parser = cmd.get_parser() + cmd_parser.prog = command + if cmd.parse_known_args: + (args, extra) = cmd_parser.parse_known_args(args) + else: + args = cmd_parser.parse_args(args) + extra = None + cmd(args, extra) + sys.exit(0) + else: + print ("Invalid SubCommand. Please run program with the '--help' " + "flag for available subcommands") + sys.exit(1) +