From: Michael Tremer Date: Thu, 18 Mar 2010 22:06:14 +0000 (+0100) Subject: naoki: Refactoring of command line parsing. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0ec7d269b764d2935aec4a3f62600392f760718f;p=ipfire-3.x.git naoki: Refactoring of command line parsing. --- diff --git a/naoki/terminal.py b/naoki/terminal.py index 49a598592..b28292ea9 100644 --- a/naoki/terminal.py +++ b/naoki/terminal.py @@ -3,8 +3,249 @@ import fcntl import os import struct +import sys import termios +from constants import * + +class ParsingError(Exception): + pass + + +class Parser(object): + def __init__(self, name, arguments=[], parsers=[]): + self.name = name + self.arguments = arguments + self.parsers = parsers + + self.subparser = None + + def __repr__(self): + return "" % self.name + + def check(self, args): + if not args: + return False + + return self.name == args[0] + + def parse(self, args): + if args and self.name == args[0]: + args = args[1:] + + for argument in self.arguments: + args = argument.parse(args) + + if args and self.parsers: + for parser in self.parsers: + if not parser.check(args): + continue + + self.subparser = parser + break + + if self.subparser: + args = self.subparser.parse(args) + + return args + + @property + def values(self): + ret = { + "name" : self.name + } + if self.subparser: + ret["subaction"] = self.subparser.values + + for argument in self.arguments: + ret[argument.name] = argument.value() + + return ret + + +class _Argument(object): + DEFAULT_HELP = "No help available" + + def __init__(self, name, args, **kwargs): + self.name = name + self.args = args + self.help = kwargs.get("help", self.DEFAULT_HELP) + + self._parsed = False + self._parsed_args = [] + + def parse(self, args): + raise NotImplementedError + + def value(self): + raise NotImplementedError + + +class Option(_Argument): + def parse(self, args): + self._parsed = True + + new_args = [] + for arg in args: + if arg in self.args: + self._parsed_args.append(arg) + else: + new_args.append(arg) + + return new_args + + def value(self): + for arg in self._parsed_args: + if arg in self.args: + return True + + return False + + +class Choice(_Argument): + def __init__(self, *args, **kwargs): + _Argument.__init__(self, *args, **kwargs) + + self.choices = kwargs.get("choices", []) + + def parse(self, args): + self._parsed = True + + new_args = [] + next_arg = False + for arg in args: + if next_arg: + if self.choices and not arg in self.choices: + raise ParsingError, "'%s' is not an allowed choice" % arg + + self._parsed_args.append(arg) + next_arg = False + continue + + if arg in self.args: + self._parsed_args.append(arg) + next_arg = True + else: + new_args.append(arg) + + return new_args + + def value(self): + if self._parsed_args: + return self._parsed_args[-1] + + return None + + +class List(_Argument): + def __init__(self, name, **kwargs): + _Argument.__init__(self, name, [], **kwargs) + + def parse(self, args): + self._parsed = True + self._parsed_args = args + + return [] + + def value(self): + return self._parsed_args + + +class Commandline(object): + def __init__(self, naoki): + self.naoki = naoki + + # Parse the stuff + args = self.__parse() + + # ... afterwards, process global directives + self.__process_global(args) + + def __process_global(self, args): + # Set quiet mode + self.naoki.logging.quiet(args.quiet) + + # XXX Set architecture + + def __parse(self): + parser = Parser("root", + arguments=[ + Option("help", ["-h", "--help"], help="Show help text"), + Option("quiet", ["-q", "--quiet"], help="Set quiet mode"), + Option("debug", ["-d", "--debug"], help="Set debugging mode"), + Choice("arch", ["-a", "--arch"], help="Set architecture", + choices=[arch for arch in arches.all]), + ], + parsers=[ + # Build + Parser("build", + arguments=[ + List("packages"), + ]), + + # Toolchain + Parser("toolchain", + parsers=[ + Parser("download"), + Parser("build"), + ]), + + # Package + Parser("package", + parsers=[ + Parser("info", + arguments=[ + Option("long", ["-l", "--long"]), + Option("machine", ["--machine"]), + Option("wiki", ["--wiki"]), + List("packages"), + ]), + Parser("tree"), + Parser("list", + arguments=[ + Option("long", ["-l", "--long"]), + ]), + Parser("groups", + arguments=[ + Option("wiki", ["--wiki"]), + ]), + ]), + + # Source + Parser("source", + parsers=[ + Parser("download", + arguments=[ + List("packages"), + ]), + Parser("upload", + arguments=[ + List("packages"), + ]), + Parser("clean"), + ]), + + # Check + Parser("check", + parsers=[ + Parser("host"), + ]), + + # Batch + Parser("batch", + parsers=[ + Parser("cron"), + ]), + ]) + + args = parser.parse(sys.argv[1:]) + + if args: + raise ParsingError, "Unknown argument(s) passed: %s" % args + + return parser.values + + DEFAULT_COLUMNS = 80 DEFAULT_LINES = 25 @@ -44,3 +285,7 @@ def get_lines(): def get_columns(): return get_size()[1] + + +if __name__ == "__main__": + cl = Commandline(naoki=None)