[yum-cvs] yum/yum parser.py,NONE,1.1

Paul Nasrat pnasrat at login.linux.duke.edu
Tue Oct 11 15:35:05 UTC 2005


Update of /home/groups/yum/cvs/yum/yum
In directory login:/tmp/cvs-serv25370

Added Files:
	parser.py 
Log Message:
New configuration parser routines

--- NEW FILE parser.py ---
import re
import copy
import shlex
import string
import os.path
from ConfigParser import ConfigParser, NoSectionError, NoOptionError

#TODO: problem: interpolation tokens are lost when config files are rewritten
#       - workaround is to not set vars, not sure if this is ok
#       - maybe we should do interpolation at the Option level after all?
#TODO: include'ing of URLs (Yum currently supports this)
#TODO: separate $var interpolation into YumParser?

class IncludingConfigParser(ConfigParser):

    def __init__(self, vars=None, include="include"):
        """
        @param vars: A dictionary of subsitution variables.
        @param include: Name of option that lists files for inclusion
        """
        self.include = include

        # Dictionary of filenames -> included configparser objects
        self._fns = {}

        # Dictionary of sections -> filenames
        self._included = {}

        self.cwd = None
        ConfigParser.__init__(self, vars)

    def defaults(self):
        """Return a dictionary containing the instance-wide defaults."""
        return self.defaults

    def sections(self):
        """Return a list of the sections available in file and includes."""
        s = self.__sections()
        for included in self._included.keys():
            s.append(included)
        return s

    def has_section(self, section): 
        """Indicates whether the named section is present in 
        the configuration and includes."""
        if section in self.__sections() or section in self._included.keys():
            return True
        else:
            return False

    def has_option(self, section, option):
        if not self.has_section(section):
            raise NoSectionError(section)
        if section in self._included.keys():
            fn = self._included[section]
            return self._fns[fn].has_option(section, option)
        else:
            return ConfigParser.has_option(self,  section, option)
        
    def options(self, section):
        """Return a list of option names for the given section name"""
        if not self.has_section(section):
            raise NoSectionError(section)
        if section in self._included.keys():
            fn = self._included[section]
            return self._fns[fn].options(section)
        else:
            return ConfigParser.options(self,  section)

    def items(self, section):
        if not self.has_section(section):
            raise NoSectionError(section)
        if section in self._included.keys():
            fn = self._included[section]
            return self._fns[fn].items(section)
        else:
            return ConfigParser.items(self, section)

    def remove_section(self, section):
        if not self.has_section(section):
            raise NoSectionError(section)
        if section in self._included.keys():
            fn = self._included[section]
            return self._fns[fn].remove_section(section)
        else:
            return ConfigParser.remove_section(self, section)

    def add_include(self, section, fn):
        """Add a included file to config section"""
        if not self.has_section(section):
            raise NoSectionError(section)
        if not self.has_option(section, self.include):
            raise NoOptionError(self.include, section)
        inc = self.get(section, self.include)
        if fn in shlex.split(inc):
            return
        self._add_include(section, fn)

        
    def remove_include(self, section, fn):
        """Remove an included config parser"""
        if not self.has_section(section):
            raise NoSectionError(section)
        if not self.has_option(section, self.include):
            raise NoOptionError(self.include, section)
        #XXX: raise NoIncludeError???
        if not self._included.has_key(fn):
            return

        
    def __sections(self):
        return ConfigParser.sections(self) 

    def read(self, filenames):
        #XXX: support multiple filenames
        for filename in shlex.split(filenames):
            self.cwd = os.path.dirname(os.path.realpath(filename))
            ConfigParser.read(self,filename)
            self._readincludes()

    def _add_include(self, section, filename):
        c = IncludingConfigParser(self._defaults)
        if not filename.startswith(os.path.sep):
            filename = os.path.join(self.cwd, filename)
        c.read(filename)
        for includesection in c.sections():
            self._included[includesection] = filename
        self._fns[filename] = c

    def _remove_include(self, section, filename):
        inc = self.get(section, self.include)
        filenames = shlex.split(inc)
        if filename in filenames:
            filenames.remove(filename)
        self.set(section, self.include, string.join(filenames, ' ')
        self._included.pop(filename)

    def _readincludes(self):
        for section in ConfigParser.sections(self):
            if self.has_option(section, self.include):
                for filename in shlex.split(self.get(section, self.include)):
                    self._add_include(section, filename)
            
    def get(self, section, option, raw=False, vars=None):
        """Return section from file or included files"""
        if section in self._included:
            fn = self._included[section]
            return self._fns[fn].get(section, option, raw, vars)
        return ConfigParser.get(self, section, option, raw, vars)

    def set(self, section, option, value):
        if section in self._included:
            fn = self._included[section]
            return self._fns[fn].set(section, option, value)
        return ConfigParser.set(self, section, option, value)

    def write(self, fp):
        """Take a file object and write it"""

        # Don't call the parent write() method because it dumps out
        # self._defaults as its own section which isn't desirable here.

        # Write out the items for this file
        for section in self._sections:
            fp.write("[%s]\n" % section)
            for (key, value) in self._sections[section].items():
                if key == '__name__':
                    continue
                fp.write("%s = %s\n" % (key, str(value).replace('\n', '\n\t')))
            fp.write("\n")

        # Write out any included files
        for fn in self._fns.keys():
            inc = open(fn, 'w')
            self._fns[fn].write(inc)

    _KEYCRE = re.compile(r"\$(\w+)")

    def _interpolate(self, section, option, rawval, vars):
        '''Perform $var subsitution (this overides the default %(..)s subsitution)

        Only the rawval and vars arguments are used. The rest are present for
        compatibility with the parent class.
        '''
        done = []                           # Completed chunks to return

        while rawval:
            m = self._KEYCRE.search(rawval)
            if not m:
                done.append(rawval)
                break

            # Determine replacement value (if unknown variable then preserve original)
            varname = m.group(1).lower()
            replacement = vars.get(varname, m.group())

            start, end = m.span()
            done.append(rawval[:start])     # Keep stuff leading up to token
            done.append(replacement)        # Append replacement value
            rawval = rawval[end:]           # Continue with remainder of string

        return ''.join(done)


class IncludedDirConfigParser(IncludingConfigParser):
    """A conf.d recursive parser - supporting one level of included dirs"""

    def __init__(self, defaults = None, includedir=None, includeglob="*.conf", include="include"):
        self.includeglob = includeglob
        self.includedir = includedir
        IncludingConfigParser.__init__()

    def read(self, filenames):
        for filename in shlex.split(filenames):
            IncludingConfigParser.read(self,filename)
            self._includedir()

    def _includedir(self):
        for section in ConfigParser.sections(self):
            if self.has_option(section, self.includedir):
                dir = self.get(section, self.includedir)
                matches = glob.glob("%s/%s" % dir, includeglob) 
                # glob dir, open files, include
                for match in matches:
                    self._add_include(section, filename)





More information about the Yum-cvs-commits mailing list