terom@65: """ terom@65: Command implementations terom@65: """ terom@65: terom@117: import inspect, logging, traceback, concurrent terom@65: terom@65: class CommandList (object) : terom@65: """ terom@65: A list of available Commands terom@65: terom@65: XXX: not yet used terom@65: """ terom@65: terom@65: def __init__ (self, commands) : terom@65: """ terom@65: Store with given initial commands terom@65: """ terom@65: terom@65: self.list = commands terom@65: self.dict = dict((cmd.name, cmd) for cmd in commands) terom@65: terom@65: def lookup (self, name) : terom@65: """ terom@65: Lookup a command by name terom@65: """ terom@65: terom@65: return self.dict[name] terom@65: terom@65: class Command (object) : terom@65: """ terom@65: A Command is simply a function that can be executed from the command line with some options/arguments terom@65: """ terom@65: terom@65: def __init__ (self, name, func, doc=None) : terom@65: """ terom@65: Create a new Command terom@65: terom@65: name - the name of the command terom@65: func - the callable python function terom@65: doc - descriptive help text terom@65: """ terom@65: terom@65: self.name = name terom@65: self.func = func terom@65: self.doc = doc terom@65: terom@76: def setup (self, config, gallery) : terom@65: """ terom@65: Run the command with the given context terom@65: """ terom@65: terom@76: return CommandContext(self, config, gallery) terom@65: terom@65: class CommandContext (object) : terom@65: """ terom@65: A CommandContext is the context that a Command executes in terom@65: terom@65: It is bound to a Configuration and a Gallery. terom@65: """ terom@65: terom@65: def __init__ (self, command, config, gallery) : terom@65: """ terom@65: Create the execution environment terom@65: """ terom@65: terom@65: self.command = command terom@65: self.config = config terom@65: self.gallery = gallery terom@65: terom@117: # conccurency terom@117: self.concurrent = concurrent.Manager(thread_count=config.thread_count) terom@117: terom@92: def execute (self, *args, **kwargs) : terom@65: """ terom@65: Run the command in this context terom@65: """ terom@65: terom@65: return self.command.func(self, *args, **kwargs) terom@92: terom@92: def run (self, *args, **kwargs) : terom@92: """ terom@92: Run the command with error handling terom@92: """ terom@92: terom@92: try : terom@92: # run it terom@92: return self.execute(*args, **kwargs) terom@92: terom@92: except KeyboardInterrupt : terom@92: self.log_error("Interrupted") terom@92: terom@92: except : terom@114: # dump traceback terom@120: # XXX: skip all crap up to the actual function terom@114: self.handle_error() terom@65: terom@65: def log_msg (self, level, msg, *args, **kwargs) : terom@65: """ terom@65: Output a log message with the given level terom@65: terom@65: XXX: unicode terom@65: """ terom@65: terom@65: # control level of output terom@65: if level < self.config.log_level : terom@65: return terom@65: terom@65: # format? terom@65: if args or kwargs : terom@65: if args and not kwargs : terom@65: msg = msg % args terom@65: terom@65: elif kwargs and not args : terom@65: msg = msg % kwargs terom@65: terom@65: else : terom@65: raise Exception("log_msg called with both args and kwargs") terom@65: terom@65: # output terom@65: # XXX: stdout/err? terom@65: print msg terom@65: terom@65: def log_debug (self, msg, *args, **kwargs) : terom@76: self.log_msg(logging.DEBUG, msg, *args, **kwargs) terom@65: terom@65: def log_info (self, msg, *args, **kwargs) : terom@76: self.log_msg(logging.INFO, msg, *args, **kwargs) terom@65: terom@65: def log_warning (self, msg, *args, **kwargs) : terom@76: self.log_msg(logging.WARNING, msg, *args, **kwargs) terom@65: terom@65: def log_error (self, msg, *args, **kwargs) : terom@76: self.log_msg(logging.ERROR, msg, *args, **kwargs) terom@76: terom@76: def handle_error (self, exc_info=None) : terom@76: """ terom@76: Do something to handle an error that occured terom@76: """ terom@76: terom@76: if exc_info : terom@76: traceback.print_execption(*exc_info) terom@76: terom@76: else : terom@76: traceback.print_exc() terom@65: terom@65: def command (func) : terom@65: """ terom@65: A function decorator used to define Commands automatically terom@65: """ terom@65: terom@65: return Command(func.__name__, func, inspect.getdoc(func)) terom@65: