degal/command.py
author Tero Marttila <terom@fixme.fi>
Wed, 01 Jul 2009 20:15:08 +0300
changeset 139 d3167c40e7b9
parent 120 55cb7fc9c8fb
child 144 97505a789003
permissions -rw-r--r--
remove old scripts/cgi-bin stuff. They wouldn't work as such with the new version, and replacements can be written while referring to the history
"""
    Command implementations
"""

import inspect, logging, traceback, concurrent

class CommandList (object) :
    """
        A list of available Commands

        XXX: not yet used
    """

    def __init__ (self, commands) :
        """
            Store with given initial commands
        """

        self.list = commands
        self.dict = dict((cmd.name, cmd) for cmd in commands)

    def lookup (self, name) :
        """
            Lookup a command by name
        """

        return self.dict[name]

class Command (object) :
    """
        A Command is simply a function that can be executed from the command line with some options/arguments
    """

    def __init__ (self, name, func, doc=None) :
        """
            Create a new Command

             name       - the name of the command
             func       - the callable python function
             doc        - descriptive help text
        """

        self.name = name
        self.func = func
        self.doc = doc

    def setup (self, config, gallery) :
        """
            Run the command with the given context
        """
        
        return CommandContext(self, config, gallery)

class CommandContext (object) :
    """
        A CommandContext is the context that a Command executes in

        It is bound to a Configuration and a Gallery.
    """

    def __init__ (self, command, config, gallery) :
        """
            Create the execution environment
        """

        self.command = command
        self.config = config
        self.gallery = gallery

        # conccurency
        self.concurrent = concurrent.Manager(thread_count=config.thread_count)

    def execute (self, *args, **kwargs) :
        """
            Run the command in this context
        """

        return self.command.func(self, *args, **kwargs)
    
    def run (self, *args, **kwargs) :
        """
            Run the command with error handling
        """

        try :
            # run it
            return self.execute(*args, **kwargs)
        
        except KeyboardInterrupt :
            self.log_error("Interrupted")

        except :
            # dump traceback
            # XXX: skip all crap up to the actual function
            self.handle_error()

    def log_msg (self, level, msg, *args, **kwargs) :
        """
            Output a log message with the given level

            XXX: unicode
        """
        
        # control level of output
        if level < self.config.log_level :
            return
        
        # format?
        if args or kwargs :
            if args and not kwargs :
                msg = msg % args

            elif kwargs and not args :
                msg = msg % kwargs

            else :
                raise Exception("log_msg called with both args and kwargs")
        
        # output
        # XXX: stdout/err?
        print msg

    def log_debug (self, msg, *args, **kwargs) :
        self.log_msg(logging.DEBUG, msg, *args, **kwargs)

    def log_info (self, msg, *args, **kwargs) :
        self.log_msg(logging.INFO, msg, *args, **kwargs)
    
    def log_warning (self, msg, *args, **kwargs) :
        self.log_msg(logging.WARNING, msg, *args, **kwargs)

    def log_error (self, msg, *args, **kwargs) :
        self.log_msg(logging.ERROR, msg, *args, **kwargs)
    
    def handle_error (self, exc_info=None) :
        """
            Do something to handle an error that occured
        """
        
        if exc_info :
            traceback.print_execption(*exc_info)

        else :
            traceback.print_exc()

def command (func) :
    """
        A function decorator used to define Commands automatically
    """

    return Command(func.__name__, func, inspect.getdoc(func))