[yum-cvs] yum/yum __init__.py, 1.257, 1.258 config.py, 1.103, 1.104 parser.py, 1.7, 1.8
Seth Vidal
skvidal at linux.duke.edu
Mon Oct 2 03:46:59 UTC 2006
Update of /home/groups/yum/cvs/yum/yum
In directory login1.linux.duke.edu:/tmp/cvs-serv11169/yum
Modified Files:
__init__.py config.py parser.py
Log Message:
make the include= and yum -c http://path/to/file behave like I thought they
should.
This, ultimately, removes the need for parser.IncludingConfigParser and
parser.IncludedConfigParser but I haven't removed them yet b/c I wanted to
verify that they are not used elsewhere, first.
Index: __init__.py
===================================================================
RCS file: /home/groups/yum/cvs/yum/yum/__init__.py,v
retrieving revision 1.257
retrieving revision 1.258
diff -u -r1.257 -r1.258
--- __init__.py 29 Sep 2006 14:45:21 -0000 1.257
+++ __init__.py 2 Oct 2006 03:46:57 -0000 1.258
@@ -26,7 +26,7 @@
import glob
import logging
import logging.config
-from ConfigParser import ParsingError
+from ConfigParser import ParsingError, ConfigParser
import Errors
import rpmsack
import rpmUtils.updates
@@ -36,6 +36,7 @@
import config
import repos
import misc
+from parser import ConfigPreProcessor
import transactioninfo
import urlgrabber
from urlgrabber.grabber import URLGrabError
@@ -166,19 +167,19 @@
# Read .repo files from directories specified by the reposdir option
# (typically /etc/yum.repos.d and /etc/yum/repos.d)
- parser = config.IncludedDirConfigParser(vars=self.yumvar)
+ parser = ConfigParser()
for reposdir in self.conf.reposdir:
if os.path.exists(self.conf.installroot+'/'+reposdir):
reposdir = self.conf.installroot + '/' + reposdir
if os.path.isdir(reposdir):
- #XXX: why can't we just pass the list of files?
- files = ' '.join(glob.glob('%s/*.repo' % reposdir))
- try:
- parser.read(files)
- except ParsingError, e:
- msg = str(e)
- raise Errors.ConfigError, msg
+ for repofn in glob.glob('%s/*.repo' % reposdir):
+ confpp_obj = ConfigPreProcessor(repofn, vars=self.yumvar)
+ try:
+ parser.readfp(confpp_obj)
+ except ParsingError, e:
+ msg = str(e)
+ raise Errors.ConfigError, msg
# Check sections in the .repo files that were just slurped up
for section in parser.sections():
Index: config.py
===================================================================
RCS file: /home/groups/yum/cvs/yum/yum/config.py,v
retrieving revision 1.103
retrieving revision 1.104
diff -u -r1.103 -r1.104
--- config.py 29 Sep 2006 15:44:58 -0000 1.103
+++ config.py 2 Oct 2006 03:46:57 -0000 1.104
@@ -20,8 +20,8 @@
import rpm
import copy
import urlparse
-from parser import IncludingConfigParser, IncludedDirConfigParser
-from ConfigParser import NoSectionError, NoOptionError
+from parser import ConfigPreProcessor
+from ConfigParser import NoSectionError, NoOptionError, ConfigParser, ParsingError
import rpmUtils.transaction
import rpmUtils.arch
import Errors
@@ -560,14 +560,16 @@
May raise Errors.ConfigError if a problem is detected with while parsing.
'''
- if not os.path.exists(configfile):
- raise Errors.ConfigError, 'No such config file %s' % configfile
StartupConf.installroot.default = root
startupconf = StartupConf()
- parser = IncludingConfigParser()
- parser.read(configfile)
+ parser = ConfigParser()
+ confpp_obj = ConfigPreProcessor(configfile)
+ try:
+ parser.readfp(confpp_obj)
+ except ParsingError, e:
+ raise Errors.ConfigError("Parsing file failed: %s" % e)
startupconf.populate(parser, 'main')
# Check that plugin paths are all absolute
Index: parser.py
===================================================================
RCS file: /home/groups/yum/cvs/yum/yum/parser.py,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- parser.py 5 Jul 2006 14:32:49 -0000 1.7
+++ parser.py 2 Oct 2006 03:46:57 -0000 1.8
@@ -7,6 +7,8 @@
import os.path
from ConfigParser import ConfigParser, NoSectionError, NoOptionError
+import Errors
+
#TODO: better handling of recursion
#TODO: ability to handle bare includes (ie. before first [section])
#TODO: avoid include line reordering on write
@@ -276,6 +278,188 @@
return ''.join(done)
+class ConfigPreProcessor:
+ """
+ ConfigParser Include Pre-Processor
+
+ File-like Object capable of pre-processing include= lines for
+ a ConfigParser.
+
+ The readline function expands lines matching include=(url)
+ into lines from the url specified. Includes may occur in
+ included files as well.
+
+ Suggested Usage:
+ cfg = ConfigParser.ConfigParser()
+ fileobj = confpp( fileorurl )
+ cfg.readfp(fileobj)
+ """
+
+
+ def __init__(self, configfile, vars=None):
+ # put the vars away in a helpful place
+ self._vars = vars
+
+ # set some file-like object attributes for ConfigParser
+ # these just make confpp look more like a real file object.
+ self.mode = 'r'
+
+ # establish whether to use urlgrabber or urllib
+ # we want to use urlgrabber if it supports urlopen
+ if hasattr(urlgrabber.grabber, 'urlopen'):
+ self._urlresolver = urlgrabber.grabber
+ else:
+ self._urlresolver = urllib
+
+
+ # first make configfile a url even if it points to
+ # a local file
+ scheme = urlparse.urlparse(configfile)[0]
+ if scheme == '':
+ # check it to make sure it's not a relative file url
+ if configfile[0] != '/':
+ configfile = os.getcwd() + '/' + configfile
+ url = 'file://' + configfile
+ else:
+ url = configfile
+
+ # these are used to maintain the include stack and check
+ # for recursive/duplicate includes
+ self._incstack = []
+ self._alreadyincluded = []
+
+ # _pushfile will return None if he couldn't open the file
+ fo = self._pushfile( url )
+ if fo is None:
+ raise Errors.ConfigError, 'Error accessing file: %s' % url
+
+ def readline( self, size=0 ):
+ """
+ Implementation of File-Like Object readline function. This should be
+ the only function called by ConfigParser according to the python docs.
+ We maintain a stack of real FLOs and delegate readline calls to the
+ FLO on top of the stack. When EOF occurs on the topmost FLO, it is
+ popped off the stack and the next FLO takes over. include= lines
+ found anywhere cause a new FLO to be opened and pushed onto the top
+ of the stack. Finally, we return EOF when the bottom-most (configfile
+ arg to __init__) FLO returns EOF.
+
+ Very Technical Pseudo Code:
+
+ def confpp.readline() [this is called by ConfigParser]
+ open configfile, push on stack
+ while stack has some stuff on it
+ line = readline from file on top of stack
+ pop and continue if line is EOF
+ if line starts with 'include=' then
+ error if file is recursive or duplicate
+ otherwise open file, push on stack
+ continue
+ else
+ return line
+
+ return EOF
+ """
+
+ # set line to EOF initially.
+ line=''
+ while len(self._incstack) > 0:
+ # peek at the file like object on top of the stack
+ fo = self._incstack[-1]
+ line = fo.readline()
+ if len(line) > 0:
+ m = re.match( r'\s*include\s*=\s*(?P<url>.*)', line )
+ if m:
+ url = m.group('url')
+ if len(url) == 0:
+ raise Errors.ConfigError, \
+ 'Error parsing config %s: include must specify file to include.' % (self.name)
+ else:
+ # whooohoo a valid include line.. push it on the stack
+ fo = self._pushfile( url )
+ else:
+ # line didn't match include=, just return it as is
+ # for the ConfigParser
+ break
+ else:
+ # the current file returned EOF, pop it off the stack.
+ self._popfile()
+
+ # at this point we have a line from the topmost file on the stack
+ # or EOF if the stack is empty
+ if vars:
+ return varReplace(line, self._vars)
+ return line
+
+
+ def _absurl( self, url ):
+ """
+ Returns an absolute url for the (possibly) relative
+ url specified. The base url used to resolve the
+ missing bits of url is the url of the file currently
+ being included (i.e. the top of the stack).
+ """
+
+ if len(self._incstack) == 0:
+ # it's the initial config file. No base url to resolve against.
+ return url
+ else:
+ return urlparse.urljoin( self.geturl(), url )
+
+
+ def _pushfile( self, url ):
+ """
+ Opens the url specified, pushes it on the stack, and
+ returns a file like object. Returns None if the url
+ has previously been included.
+ If the file can not be opened this function exits.
+ """
+
+ # absolutize this url using the including files url
+ # as a base url.
+ absurl = self._absurl(url)
+ # check if this has previously been included.
+ if self._urlalreadyincluded(absurl):
+ return None
+ try:
+ fo = self._urlresolver.urlopen(absurl)
+ except urlgrabber.grabber.URLGrabError, e:
+ fo = None
+ if fo is not None:
+ self.name = absurl
+ self._incstack.append( fo )
+ self._alreadyincluded.append(absurl)
+ else:
+ raise Errors.ConfigError, \
+ 'Error accessing file for config %s' % (absurl)
+
+ return fo
+
+
+ def _popfile( self ):
+ """
+ Pop a file off the stack signaling completion of including that file.
+ """
+ fo = self._incstack.pop()
+ fo.close()
+ if len(self._incstack) > 0:
+ self.name = self._incstack[-1].geturl()
+ else:
+ self.name = None
+
+
+ def _urlalreadyincluded( self, url ):
+ """
+ Checks if the url has already been included at all.. this
+ does not necessarily have to be recursive
+ """
+ for eurl in self._alreadyincluded:
+ if eurl == url: return 1
+ return 0
+
+
+ def geturl(self): return self.name
+
def _test():
import sys
More information about the Yum-cvs-commits
mailing list