degal/command.py
author Tero Marttila <terom@fixme.fi>
Wed, 01 Jul 2009 20:40:00 +0300
changeset 141 9387da0dc183
parent 120 55cb7fc9c8fb
child 144 97505a789003
permissions -rw-r--r--
move .config from filesystem to gallery/folder/image, rename degal_dir to app_dir
"""
    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))