source: soft/build_system/build_system/repsys/tags/V1_6_10/RepSys/ConfigParser.py @ 1

Last change on this file since 1 was 1, checked in by fasma, 12 years ago

Initial Import from Mandriva's soft revision 224062 and package revision 45733

File size: 13.8 KB
Line 
1"""
2This is a heavily hacked version of ConfigParser to keep the order in
3which options and sections are read, and allow multiple options with
4the same key.
5"""
6from __future__ import generators
7import string, types
8import re
9
10__all__ = ["NoSectionError","DuplicateSectionError","NoOptionError",
11           "InterpolationError","InterpolationDepthError","ParsingError",
12           "MissingSectionHeaderError","ConfigParser",
13           "MAX_INTERPOLATION_DEPTH"]
14
15DEFAULTSECT = "DEFAULT"
16
17MAX_INTERPOLATION_DEPTH = 10
18
19# exception classes
20class Error(Exception):
21    def __init__(self, msg=''):
22        self._msg = msg
23        Exception.__init__(self, msg)
24    def __repr__(self):
25        return self._msg
26    __str__ = __repr__
27
28class NoSectionError(Error):
29    def __init__(self, section):
30        Error.__init__(self, 'No section: %s' % section)
31        self.section = section
32
33class DuplicateSectionError(Error):
34    def __init__(self, section):
35        Error.__init__(self, "Section %s already exists" % section)
36        self.section = section
37
38class NoOptionError(Error):
39    def __init__(self, option, section):
40        Error.__init__(self, "No option `%s' in section: %s" %
41                       (option, section))
42        self.option = option
43        self.section = section
44
45class InterpolationError(Error):
46    def __init__(self, reference, option, section, rawval):
47        Error.__init__(self,
48                       "Bad value substitution:\n"
49                       "\tsection: [%s]\n"
50                       "\toption : %s\n"
51                       "\tkey    : %s\n"
52                       "\trawval : %s\n"
53                       % (section, option, reference, rawval))
54        self.reference = reference
55        self.option = option
56        self.section = section
57
58class InterpolationDepthError(Error):
59    def __init__(self, option, section, rawval):
60        Error.__init__(self,
61                       "Value interpolation too deeply recursive:\n"
62                       "\tsection: [%s]\n"
63                       "\toption : %s\n"
64                       "\trawval : %s\n"
65                       % (section, option, rawval))
66        self.option = option
67        self.section = section
68
69class ParsingError(Error):
70    def __init__(self, filename):
71        Error.__init__(self, 'File contains parsing errors: %s' % filename)
72        self.filename = filename
73        self.errors = []
74
75    def append(self, lineno, line):
76        self.errors.append((lineno, line))
77        self._msg = self._msg + '\n\t[line %2d]: %s' % (lineno, line)
78
79class MissingSectionHeaderError(ParsingError):
80    def __init__(self, filename, lineno, line):
81        Error.__init__(
82            self,
83            'File contains no section headers.\nfile: %s, line: %d\n%s' %
84            (filename, lineno, line))
85        self.filename = filename
86        self.lineno = lineno
87        self.line = line
88
89class ConfigParser:
90    def __init__(self, defaults=None):
91        # Options are stored in __sections_list like this:
92        # [(sectname, [(optname, optval), ...]), ...]
93        self.__sections_list = []
94        self.__sections_dict = {}
95        if defaults is None:
96            self.__defaults = {}
97        else:
98            self.__defaults = defaults
99
100    def defaults(self):
101        return self.__defaults
102
103    def sections(self):
104        return self.__sections_dict.keys()
105
106    def has_section(self, section):
107        return self.__sections_dict.has_key(section)
108
109    def options(self, section):
110        self.__sections_dict[section]
111        try:
112            opts = self.__sections_dict[section].keys()
113        except KeyError:
114            raise NoSectionError(section)
115        return self.__defaults.keys()+opts
116
117    def read(self, filenames):
118        if type(filenames) in types.StringTypes:
119            filenames = [filenames]
120        for filename in filenames:
121            try:
122                fp = open(filename)
123            except IOError:
124                continue
125            self.__read(fp, filename)
126            fp.close()
127
128    def readfp(self, fp, filename=None):
129        if filename is None:
130            try:
131                filename = fp.name
132            except AttributeError:
133                filename = '<???>'
134        self.__read(fp, filename)
135
136    def set(self, section, option, value):
137        if self.__sections_dict.has_key(section):
138            sectdict = self.__sections_dict[section]
139            sectlist = []
140            self.__sections_list.append((section, sectlist))
141        elif section == DEFAULTSECT:
142            sectdict = self.__defaults
143            sectlist = None
144        else:
145            sectdict = {}
146            self.__sections_dict[section] = sectdict
147            sectlist = []
148            self.__sections_list.append((section, sectlist))
149        xform = self.optionxform(option)
150        sectdict[xform] = value
151        if sectlist is not None:
152            sectlist.append([xform, value])
153
154    def get(self, section, option, raw=0, vars=None):
155        d = self.__defaults.copy()
156        try:
157            d.update(self.__sections_dict[section])
158        except KeyError:
159            if section != DEFAULTSECT:
160                raise NoSectionError(section)
161        if vars:
162            d.update(vars)
163        option = self.optionxform(option)
164        try:
165            rawval = d[option]
166        except KeyError:
167            raise NoOptionError(option, section)
168        if raw:
169            return rawval
170        return self.__interpolate(rawval, d)
171
172    def getall(self, section, option, raw=0, vars=None):
173        option = self.optionxform(option)
174        values = []
175        d = self.__defaults.copy()
176        if section != DEFAULTSECT:
177            for sectname, options in self.__sections_list:
178                if sectname == section:
179                    for optname, value in options:
180                        if optname == option:
181                            values.append(value)
182                        d[optname] = value
183        if raw:
184            return values
185        if vars:
186            d.update(vars)
187        for i in len(values):
188            values[i] = self.__interpolate(values[i], d)
189        return values
190
191    def walk(self, section, option=None, raw=0, vars=None):
192        # Build dictionary for interpolation
193        try:
194            d = self.__sections_dict[section].copy()
195        except KeyError:
196            if section == DEFAULTSECT:
197                d = {}
198            else:
199                raise NoSectionError(section)
200        d.update(self.__defaults)
201        if vars:
202            d.update(vars)
203
204        # Start walking
205        if option:
206            option = self.optionxform(option)
207        if section != DEFAULTSECT:
208            for sectname, options in self.__sections_list:
209                if sectname == section:
210                    for optname, value in options:
211                        if not option or optname == option:
212                            if not raw:
213                                value = self.__interpolate(value, d)
214                            yield (optname, value)
215
216    def __interpolate(self, value, vars):
217        rawval = value
218        depth = 0
219        while depth < 10:
220            depth = depth + 1
221            if value.find("%(") >= 0:
222                try:
223                    value = value % vars
224                except KeyError, key:
225                    raise InterpolationError(key, option, section, rawval)
226            else:
227                break
228        if value.find("%(") >= 0:
229            raise InterpolationDepthError(option, section, rawval)
230        return value
231
232    def __get(self, section, conv, option):
233        return conv(self.get(section, option))
234
235    def getint(self, section, option):
236        return self.__get(section, string.atoi, option)
237
238    def getfloat(self, section, option):
239        return self.__get(section, string.atof, option)
240
241    def getboolean(self, section, option):
242        states = {'1': 1, 'yes': 1, 'true': 1, 'on': 1,
243                  '0': 0, 'no': 0, 'false': 0, 'off': 0}
244        v = self.get(section, option)
245        if not states.has_key(v.lower()):
246            raise ValueError, 'Not a boolean: %s' % v
247        return states[v.lower()]
248
249    def optionxform(self, optionstr):
250        #return optionstr.lower()
251        return optionstr
252
253    def has_option(self, section, option):
254        """Check for the existence of a given option in a given section."""
255        if not section or section == "DEFAULT":
256            return self.__defaults.has_key(option)
257        elif not self.has_section(section):
258            return 0
259        else:
260            option = self.optionxform(option)
261            return self.__sections_dict[section].has_key(option)
262
263    SECTCRE = re.compile(r'\[(?P<header>[^]]+)\]')
264    OPTCRE = re.compile(r'(?P<option>\S+)\s*(?P<vi>[:=])\s*(?P<value>.*)$')
265
266    def __read(self, fp, fpname):
267        cursectdict = None                            # None, or a dictionary
268        optname = None
269        lineno = 0
270        e = None                                  # None, or an exception
271        while 1:
272            line = fp.readline()
273            if not line:
274                break
275            lineno = lineno + 1
276            # comment or blank line?
277            if line.strip() == '' or line[0] in '#;':
278                continue
279            if line.split()[0].lower() == 'rem' \
280               and line[0] in "rR":      # no leading whitespace
281                continue
282            # continuation line?
283            if line[0] in ' \t' and cursectdict is not None and optname:
284                value = line.strip()
285                if value:
286                    k = self.optionxform(optname)
287                    cursectdict[k] = "%s\n%s" % (cursectdict[k], value)
288                    cursectlist[-1][1] = "%s\n%s" % (cursectlist[-1][1], value)
289            # a section header or option header?
290            else:
291                # is it a section header?
292                mo = self.SECTCRE.match(line)
293                if mo:
294                    sectname = mo.group('header')
295                    if self.__sections_dict.has_key(sectname):
296                        cursectdict = self.__sections_dict[sectname]
297                        cursectlist = []
298                        self.__sections_list.append((sectname, cursectlist))
299                    elif sectname == DEFAULTSECT:
300                        cursectdict = self.__defaults
301                        cursectlist = None
302                    else:
303                        cursectdict = {}
304                        self.__sections_dict[sectname] = cursectdict
305                        cursectlist = []
306                        self.__sections_list.append((sectname, cursectlist))
307                    # So sections can't start with a continuation line
308                    optname = None
309                # no section header in the file?
310                elif cursectdict is None:
311                    raise MissingSectionHeaderError(fpname, lineno, `line`)
312                # an option line?
313                else:
314                    mo = self.OPTCRE.match(line)
315                    if mo:
316                        optname, vi, optval = mo.group('option', 'vi', 'value')
317                        if vi in ('=', ':') and ';' in optval:
318                            # ';' is a comment delimiter only if it follows
319                            # a spacing character
320                            pos = optval.find(';')
321                            if pos and optval[pos-1] in string.whitespace:
322                                optval = optval[:pos]
323                        optval = optval.strip()
324                        # allow empty values
325                        if optval == '""':
326                            optval = ''
327                        xform = self.optionxform(optname)
328                        cursectdict[xform] = optval
329                        if cursectlist is not None:
330                            cursectlist.append([xform, optval])
331                    else:
332                        # a non-fatal parsing error occurred.  set up the
333                        # exception but keep going. the exception will be
334                        # raised at the end of the file and will contain a
335                        # list of all bogus lines
336                        if not e:
337                            e = ParsingError(fpname)
338                        e.append(lineno, `line`)
339        # if any parsing errors occurred, raise an exception
340        if e:
341            raise e
342
343# Here we wrap this hacked ConfigParser into something more useful
344# for us.
345
346import os
347
348class Config:
349    def __init__(self):
350        self._config = ConfigParser()
351        conffiles = []
352        conffiles.append("/etc/repsys.conf")
353        repsys_conf = os.environ.get("REPSYS_CONF")
354        if repsys_conf:
355            conffiles.append(repsys_conf)
356        conffiles.append(os.path.expanduser("~/.repsys/config"))
357        for file in conffiles:
358            if os.path.isfile(file):
359                self._config.read(file)
360
361    def sections(self):
362        try:
363            return self._config.sections()
364        except Error:
365            return []
366
367    def options(self, section):
368        try:
369            return self._config.options(section)
370        except Error:
371            return []
372
373    def set(self, section, option, value):
374        return self._config.set(section, option, value)
375   
376    def walk(self, section):
377        return self._config.walk(section)
378
379    def get(self, section, option, default=None):
380        try:
381            return self._config.get(section, option)
382        except Error:
383            return default
384   
385    def getint(self, section, option, default=None):
386        ret = self.get(section, option, default)
387        if type(ret) == type(""):
388            return int(ret)
389           
390    def getbool(self, section, option, default=None):
391        ret = self.get(section, option, default)
392        states = {'1': 1, 'yes': 1, 'true': 1, 'on': 1,
393                  '0': 0, 'no': 0, 'false': 0, 'off': 0}
394        if type(ret) == type("") and states.has_key(ret.lower()):
395            return states[ret.lower()]
396        return default
397
398# vim:ts=4:sw=4:et
Note: See TracBrowser for help on using the repository browser.