Blame lib/dbtexmf/dblatex/grubber/plugins.py

Packit 0f19cf
# This file is part of Rubber and thus covered by the GPL
Packit 0f19cf
# (c) Emmanuel Beffara, 2002--2006
Packit 0f19cf
"""
Packit 0f19cf
Mechanisms to dynamically load extra modules to help the LaTeX compilation.
Packit 0f19cf
All the modules must be derived from the TexModule class.
Packit 0f19cf
"""
Packit 0f19cf
import imp
Packit 0f19cf
Packit 0f19cf
from os.path import *
Packit 5164a5
from dbtexmf.dblatex.grubber.msg import _, msg
Packit 0f19cf
Packit 0f19cf
import sys
Packit 0f19cf
Packit 0f19cf
class TexModule (object):
Packit 0f19cf
    """
Packit 0f19cf
    This is the base class for modules. Each module should define a class
Packit 0f19cf
    named 'Module' that derives from this one. The default implementation
Packit 0f19cf
    provides all required methods with no effects.
Packit 0f19cf
    """
Packit 0f19cf
    def __init__ (self, env, dict):
Packit 0f19cf
        """
Packit 0f19cf
        The constructor receives two arguments: 'env' is the compiling
Packit 0f19cf
        environment, 'dict' is a dictionary that describes the command that
Packit 0f19cf
        caused the module to load.
Packit 0f19cf
        """
Packit 0f19cf
Packit 0f19cf
    def pre_compile (self):
Packit 0f19cf
        """
Packit 0f19cf
        This method is called before the first LaTeX compilation. It is
Packit 0f19cf
        supposed to build any file that LaTeX would require to compile the
Packit 0f19cf
        document correctly. The method must return true on failure.
Packit 0f19cf
        """
Packit 0f19cf
        return 0
Packit 0f19cf
Packit 0f19cf
    def post_compile (self):
Packit 0f19cf
        """
Packit 0f19cf
        This method is called after each LaTeX compilation. It is supposed to
Packit 0f19cf
        process the compilation results and possibly request a new
Packit 0f19cf
        compilation. The method must return true on failure.
Packit 0f19cf
        """
Packit 0f19cf
        return 0
Packit 0f19cf
Packit 0f19cf
    def last_compile (self):
Packit 0f19cf
        """
Packit 0f19cf
        This method is called after the last LaTeX compilation.
Packit 0f19cf
        It is supposed to terminate the compilation for its specific needs.
Packit 0f19cf
        The method must return true on failure.
Packit 0f19cf
        """
Packit 0f19cf
        return 0
Packit 0f19cf
Packit 0f19cf
    def clean (self):
Packit 0f19cf
        """
Packit 0f19cf
        This method is called when cleaning the compiled files. It is supposed
Packit 0f19cf
        to remove all the files that this modules generates.
Packit 0f19cf
        """
Packit 0f19cf
Packit 0f19cf
    def command (self, cmd, args):
Packit 0f19cf
        """
Packit 0f19cf
        This is called when a directive for the module is found in the source.
Packit 0f19cf
        The method can raise 'AttributeError' when the directive does not
Packit 0f19cf
        exist and 'TypeError' if the syntax is wrong. By default, when called
Packit 0f19cf
        with argument "foo" it calls the method "do_foo" if it exists, and
Packit 0f19cf
        fails otherwise.
Packit 0f19cf
        """
Packit 0f19cf
        getattr(self, "do_" + cmd)(*args)
Packit 0f19cf
Packit 0f19cf
    def get_errors (self):
Packit 0f19cf
        """
Packit 0f19cf
        This is called if something has failed during an operation performed
Packit 0f19cf
        by this module. The method returns a generator with items of the same
Packit 0f19cf
        form as in LaTeXDep.get_errors.
Packit 0f19cf
        """
Packit 0f19cf
        if None:
Packit 0f19cf
            yield None
Packit 0f19cf
Packit 0f19cf
Packit 0f19cf
class Plugins (object):
Packit 0f19cf
    """
Packit 0f19cf
    This class gathers operations related to the management of external Python
Packit 0f19cf
    modules. Modules are requested through the `register' method, and
Packit 0f19cf
    they are searched for first in the current directory, then in the
Packit 0f19cf
    (possibly) specified Python package (using Python's path).
Packit 0f19cf
    """
Packit 0f19cf
    def __init__ (self, path=None):
Packit 0f19cf
        """
Packit 0f19cf
        Initialize the module set, possibly setting a path name in which
Packit 0f19cf
        modules will be searched for.
Packit 0f19cf
        """
Packit 0f19cf
        self.modules = {}
Packit 0f19cf
        if not path:
Packit 0f19cf
            self.path = [dirname(__file__)]
Packit 0f19cf
            sys.path.append(self.path[0])
Packit 0f19cf
        else:
Packit 0f19cf
            self.path = path
Packit 0f19cf
Packit 0f19cf
    def __getitem__ (self, name):
Packit 0f19cf
        """
Packit 0f19cf
        Return the module object of the given name.
Packit 0f19cf
        """
Packit 0f19cf
        return self.modules[name]
Packit 0f19cf
Packit 0f19cf
    def register (self, name):
Packit 0f19cf
        """
Packit 0f19cf
        Attempt to register a module with the specified name. If an
Packit 0f19cf
        appropriate module is found, load it and store it in the object's
Packit 0f19cf
        dictionary. Return 0 if no module was found, 1 if a module was found
Packit 0f19cf
        and loaded, and 2 if the module was found but already loaded.
Packit 0f19cf
        """
Packit 5164a5
        if name in self.modules:
Packit 0f19cf
            return 2
Packit 0f19cf
        try:
Packit 0f19cf
            file, path, descr = imp.find_module(name, [""])
Packit 0f19cf
        except ImportError:
Packit 0f19cf
            if not self.path:
Packit 0f19cf
                return 0
Packit 0f19cf
            try:
Packit 0f19cf
                file, path, descr = imp.find_module(name, self.path)
Packit 0f19cf
            except ImportError:
Packit 0f19cf
                return 0
Packit 0f19cf
        module = imp.load_module(name, file, path, descr)
Packit 0f19cf
        file.close()
Packit 0f19cf
        self.modules[name] = module
Packit 0f19cf
        return 1
Packit 0f19cf
Packit 0f19cf
    def clear(self):
Packit 0f19cf
        """
Packit 0f19cf
        Empty the module table, unregistering every module registered. No
Packit 0f19cf
        modules are unloaded, however, but this has no other effect than
Packit 0f19cf
        speeding the registration if the modules are loaded again.
Packit 0f19cf
        """
Packit 0f19cf
        self.modules.clear()
Packit 0f19cf
Packit 0f19cf
Packit 0f19cf
class Modules (Plugins):
Packit 0f19cf
    """
Packit 0f19cf
    This class gathers all operations related to the management of modules.
Packit 0f19cf
    The modules are    searched for first in the current directory, then as
Packit 0f19cf
    scripts in the 'modules' directory in the program's data directort, then
Packit 0f19cf
    as a Python module in the package `rubber.latex'.
Packit 0f19cf
    """
Packit 0f19cf
    def __init__ (self, env):
Packit 0f19cf
        #Plugins.__init__(self, rubber.rules.latex.__path__)
Packit 0f19cf
        Plugins.__init__(self)
Packit 0f19cf
        self.env = env
Packit 0f19cf
        self.objects = {}
Packit 0f19cf
        self.commands = {}
Packit 0f19cf
Packit 0f19cf
    def __getitem__ (self, name):
Packit 0f19cf
        """
Packit 0f19cf
        Return the module object of the given name.
Packit 0f19cf
        """
Packit 0f19cf
        return self.objects[name]
Packit 0f19cf
Packit 5164a5
    def __contains__ (self, name):
Packit 0f19cf
        """
Packit 0f19cf
        Check if a given module is loaded.
Packit 0f19cf
        """
Packit 5164a5
        return name in self.objects
Packit 0f19cf
Packit 0f19cf
    def register (self, name, dict={}):
Packit 0f19cf
        """
Packit 0f19cf
        Attempt to register a package with the specified name. If a module is
Packit 0f19cf
        found, create an object from the module's class called `Module',
Packit 0f19cf
        passing it the environment and `dict' as arguments, and execute all
Packit 0f19cf
        delayed commands for this module. The dictionary describes the
Packit 0f19cf
        command that caused the registration.
Packit 0f19cf
        """
Packit 5164a5
        if name in self:
Packit 0f19cf
            msg.debug(_("module %s already registered") % name)
Packit 0f19cf
            return 2
Packit 0f19cf
Packit 0f19cf
        # First look for a script
Packit 0f19cf
Packit 0f19cf
        moddir = ""
Packit 0f19cf
        mod = None
Packit 0f19cf
        for path in "", join(moddir, "modules"):
Packit 0f19cf
            file = join(path, name + ".rub")
Packit 0f19cf
            if exists(file):
Packit 0f19cf
                mod = ScriptModule(self.env, file)
Packit 0f19cf
                msg.log(_("script module %s registered") % name)
Packit 0f19cf
                break
Packit 0f19cf
Packit 0f19cf
        # Then look for a Python module
Packit 0f19cf
Packit 0f19cf
        if not mod:
Packit 0f19cf
            if Plugins.register(self, name) == 0:
Packit 0f19cf
                msg.debug(_("no support found for %s") % name)
Packit 0f19cf
                return 0
Packit 0f19cf
            mod = self.modules[name].Module(self.env, dict)
Packit 0f19cf
            msg.log(_("built-in module %s registered") % name)
Packit 0f19cf
Packit 0f19cf
        # Run any delayed commands.
Packit 0f19cf
Packit 5164a5
        if name in self.commands:
Packit 0f19cf
            for (cmd, args, vars) in self.commands[name]:
Packit 0f19cf
                msg.push_pos(vars)
Packit 0f19cf
                try:
Packit 0f19cf
                    mod.command(cmd, args)
Packit 0f19cf
                except AttributeError:
Packit 0f19cf
                    msg.warn(_("unknown directive '%s.%s'") % (name, cmd))
Packit 0f19cf
                except TypeError:
Packit 0f19cf
                    msg.warn(_("wrong syntax for '%s.%s'") % (name, cmd))
Packit 0f19cf
                msg.pop_pos()
Packit 0f19cf
            del self.commands[name]
Packit 0f19cf
Packit 0f19cf
        self.objects[name] = mod
Packit 0f19cf
        return 1
Packit 0f19cf
Packit 0f19cf
    def clear (self):
Packit 0f19cf
        """
Packit 0f19cf
        Unregister all modules.
Packit 0f19cf
        """
Packit 0f19cf
        Plugins.clear(self)
Packit 0f19cf
        self.objects = {}
Packit 0f19cf
        self.commands = {}
Packit 0f19cf
Packit 0f19cf
    def command (self, mod, cmd, args):
Packit 0f19cf
        """
Packit 0f19cf
        Send a command to a particular module. If this module is not loaded,
Packit 0f19cf
        store the command so that it will be sent when the module is register.
Packit 0f19cf
        """
Packit 5164a5
        if mod in self.objects:
Packit 0f19cf
            self.objects[mod].command(cmd, args)
Packit 0f19cf
        else:
Packit 5164a5
            if mod not in self.commands:
Packit 0f19cf
                self.commands[mod] = []
Packit 0f19cf
            self.commands[mod].append((cmd, args, self.env.vars.copy()))
Packit 0f19cf