Package yum :: Module parser
[hide private]
[frames] | no frames]

Source Code for Module yum.parser

  1  import re 
  2  import urlparse 
  3  import urlgrabber 
  4  import os.path 
  5   
  6  import Errors 
  7   
  8   
  9  _KEYCRE = re.compile(r"\$(\w+)") 
 10   
11 -def varReplace(raw, vars):
12 '''Perform variable replacement 13 14 @param raw: String to perform substitution on. 15 @param vars: Dictionary of variables to replace. Key is variable name 16 (without $ prefix). Value is replacement string. 17 @return: Input raw string with substituted values. 18 ''' 19 20 done = [] # Completed chunks to return 21 22 while raw: 23 m = _KEYCRE.search(raw) 24 if not m: 25 done.append(raw) 26 break 27 28 # Determine replacement value (if unknown variable then preserve 29 # original) 30 varname = m.group(1).lower() 31 replacement = vars.get(varname, m.group()) 32 33 start, end = m.span() 34 done.append(raw[:start]) # Keep stuff leading up to token 35 done.append(replacement) # Append replacement value 36 raw = raw[end:] # Continue with remainder of string 37 38 return ''.join(done)
39
40 -class ConfigPreProcessor:
41 """ 42 ConfigParser Include Pre-Processor 43 44 File-like Object capable of pre-processing include= lines for 45 a ConfigParser. 46 47 The readline function expands lines matching include=(url) 48 into lines from the url specified. Includes may occur in 49 included files as well. 50 51 Suggested Usage:: 52 cfg = ConfigParser.ConfigParser() 53 fileobj = confpp( fileorurl ) 54 cfg.readfp(fileobj) 55 """ 56 57
58 - def __init__(self, configfile, vars=None):
59 # put the vars away in a helpful place 60 self._vars = vars 61 62 # used to track the current ini-section 63 self._section = None 64 65 # set some file-like object attributes for ConfigParser 66 # these just make confpp look more like a real file object. 67 self.mode = 'r' 68 69 # first make configfile a url even if it points to 70 # a local file 71 scheme = urlparse.urlparse(configfile)[0] 72 if scheme == '': 73 # check it to make sure it's not a relative file url 74 if configfile[0] != '/': 75 configfile = os.getcwd() + '/' + configfile 76 url = 'file://' + configfile 77 else: 78 url = configfile 79 80 # these are used to maintain the include stack and check 81 # for recursive/duplicate includes 82 self._incstack = [] 83 self._alreadyincluded = [] 84 85 # _pushfile will return None if he couldn't open the file 86 fo = self._pushfile( url ) 87 if fo is None: 88 raise Errors.ConfigError, 'Error accessing file: %s' % url
89
90 - def readline( self, size=0 ):
91 """ 92 Implementation of File-Like Object readline function. This should be 93 the only function called by ConfigParser according to the python docs. 94 We maintain a stack of real FLOs and delegate readline calls to the 95 FLO on top of the stack. When EOF occurs on the topmost FLO, it is 96 popped off the stack and the next FLO takes over. include= lines 97 found anywhere cause a new FLO to be opened and pushed onto the top 98 of the stack. Finally, we return EOF when the bottom-most (configfile 99 arg to __init__) FLO returns EOF. 100 101 Very Technical Pseudo Code:: 102 103 def confpp.readline() [this is called by ConfigParser] 104 open configfile, push on stack 105 while stack has some stuff on it 106 line = readline from file on top of stack 107 pop and continue if line is EOF 108 if line starts with 'include=' then 109 error if file is recursive or duplicate 110 otherwise open file, push on stack 111 continue 112 else 113 return line 114 115 return EOF 116 """ 117 118 # set line to EOF initially. 119 line='' 120 while len(self._incstack) > 0: 121 # peek at the file like object on top of the stack 122 fo = self._incstack[-1] 123 line = fo.readline() 124 if len(line) > 0: 125 m = re.match( r'\s*include\s*=\s*(?P<url>.*)', line ) 126 if m: 127 url = m.group('url') 128 if len(url) == 0: 129 raise Errors.ConfigError, \ 130 'Error parsing config %s: include must specify file to include.' % (self.name) 131 else: 132 # whooohoo a valid include line.. push it on the stack 133 fo = self._pushfile( url ) 134 else: 135 # check if the current line starts a new section 136 secmatch = re.match( r'\s*\[(?P<section>.*)\]', line ) 137 if secmatch: 138 self._section = secmatch.group('section') 139 # line didn't match include=, just return it as is 140 # for the ConfigParser 141 break 142 else: 143 # the current file returned EOF, pop it off the stack. 144 self._popfile() 145 146 # at this point we have a line from the topmost file on the stack 147 # or EOF if the stack is empty 148 if self._vars: 149 return varReplace(line, self._vars) 150 return line
151 152
153 - def _absurl( self, url ):
154 """ 155 Returns an absolute url for the (possibly) relative 156 url specified. The base url used to resolve the 157 missing bits of url is the url of the file currently 158 being included (i.e. the top of the stack). 159 """ 160 161 if len(self._incstack) == 0: 162 # it's the initial config file. No base url to resolve against. 163 return url 164 else: 165 return urlparse.urljoin( self.geturl(), url )
166
167 - def _pushfile( self, url ):
168 """ 169 Opens the url specified, pushes it on the stack, and 170 returns a file like object. Returns None if the url 171 has previously been included. 172 If the file can not be opened this function exits. 173 """ 174 175 # absolutize this url using the including files url 176 # as a base url. 177 absurl = self._absurl(url) 178 179 # get the current section to add it to the included 180 # url's name. 181 includetuple = (absurl, self._section) 182 # check if this has previously been included. 183 if self._isalreadyincluded(includetuple): 184 return None 185 try: 186 fo = urlgrabber.grabber.urlopen(absurl) 187 except urlgrabber.grabber.URLGrabError, e: 188 fo = None 189 if fo is not None: 190 self.name = absurl 191 self._incstack.append( fo ) 192 self._alreadyincluded.append(includetuple) 193 else: 194 raise Errors.ConfigError, \ 195 'Error accessing file for config %s' % (absurl) 196 197 return fo
198 199
200 - def _popfile( self ):
201 """ 202 Pop a file off the stack signaling completion of including that file. 203 """ 204 fo = self._incstack.pop() 205 fo.close() 206 if len(self._incstack) > 0: 207 self.name = self._incstack[-1].geturl() 208 else: 209 self.name = None
210 211
212 - def _isalreadyincluded( self, tuple ):
213 """ 214 Checks if the tuple describes an include that was already done. 215 This does not necessarily have to be recursive 216 """ 217 for etuple in self._alreadyincluded: 218 if etuple == tuple: return 1 219 return 0
220 221
222 - def geturl(self): return self.name
223