source: rtems-tools/rtemstoolkit/configuration.py @ a248471

Last change on this file since a248471 was a248471, checked in by Chris Johns <chrisj@…>, on Oct 24, 2017 at 9:53:27 PM

rtemstoolkit: Remove test import for YAML.

Closes #3204.

  • Property mode set to 100644
File size: 5.8 KB
Line 
1#
2# RTEMS Tools Project (http://www.rtems.org/)
3# Copyright 2017 Chris Johns (chrisj@rtems.org)
4# All rights reserved.
5#
6# This file is part of the RTEMS Tools package in 'rtems-tools'.
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions are met:
10#
11# 1. Redistributions of source code must retain the above copyright notice,
12# this list of conditions and the following disclaimer.
13#
14# 2. Redistributions in binary form must reproduce the above copyright notice,
15# this list of conditions and the following disclaimer in the documentation
16# and/or other materials provided with the distribution.
17#
18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28# POSSIBILITY OF SUCH DAMAGE.
29#
30
31#
32# Host specifics.
33#
34
35from __future__ import print_function
36
37import os
38import re
39
40try:
41    import configparser
42except:
43    import ConfigParser as configparser
44
45from rtemstoolkit import error
46from rtemstoolkit import path
47
48class configuration:
49
50    def __init__(self):
51        self.config = configparser.ConfigParser()
52        self.ini = None
53        self.macro_filter = re.compile('\$\{.+\}')
54
55    def __str__(self):
56        if self.ini is None:
57            return 'empty'
58        s = ['Base: %s' % (self.ini['base'])]
59        s += ['Files:']
60        for f in self.ini['files']:
61            s += [' %s' % (f)]
62        s += ['Defaults:']
63        for default in self.config.defaults():
64            s += ' ' + default
65        s += ['Sections:']
66        for section in self.config.sections():
67            s += [' [%s]' % (section)]
68            for option in self.config.options(section):
69                s += [%s = %s' % (option, self.config.get(section, option))]
70        return os.linesep.join(s)
71
72    def get_item(self, section, label, err = True):
73        try:
74            rec = self.config.get(section, label).replace(os.linesep, ' ')
75        except:
76            if err:
77                raise error.general('config: no "%s" found in "%s"' % (label, section))
78            return None
79        #
80        # On Python 2.7 there is no extended interpolation so add support here.
81        # On Python 3 this should happen automatically and so the findall
82        # should find nothing.
83        #
84        for m in self.macro_filter.findall(rec):
85            if ':' not in m:
86                raise error.general('config: interpolation is ${section:value}: %s' % (m))
87            section_value = m[2:-1].split(':')
88            if len(section_value) != 2:
89                raise error.general('config: interpolation is ${section:value}: %s' % (m))
90            try:
91                ref = self.config.get(section_value[0],
92                                      section_value[1]).replace(os.linesep, ' ')
93                rec = rec.replace(m, ref)
94            except:
95                pass
96        return rec
97
98    def get_items(self, section, err = True, flatten = True):
99        try:
100            items = []
101            for name, key in self.config.items(section):
102                if flatten:
103                    items += [(name, key.replace(os.linesep, ' '))]
104                else:
105                    items += [(name, key)]
106            return items
107        except:
108            if err:
109                raise error.general('config: section "%s" not found' % (section))
110        return []
111
112    def comma_list(self, section, label, err = True):
113        items = self.get_item(section, label, err)
114        if items is None:
115            return []
116        return sorted(set([a.strip() for a in items.split(',')]))
117
118    def get_item_names(self, section, err = True):
119        try:
120            return [item[0] for item in self.config.items(section)]
121        except:
122            if err:
123                raise error.general('config: section "%s" not found' % (section))
124        return []
125
126    def has_section(self, section):
127        return self.config.has_section(section)
128
129    def load(self, name):
130        #
131        # Load all the files.
132        #
133        self.ini = { 'base'     : path.dirname(name),
134                     'files'    : [] }
135        includes = [name]
136        still_loading = True
137        while still_loading:
138            still_loading = False
139            for include in includes:
140                if not path.exists(include):
141                    rebased_inc = path.join(self.ini['base'],
142                                            path.basename(include))
143                    if not path.exists(rebased_inc):
144                        e = 'config: cannot find configuration: %s' % (include)
145                        raise error.general(e)
146                    include = rebased_inc
147                if include not in self.ini['files']:
148                    try:
149                        self.config.read(include)
150                    except configparser.ParsingError as ce:
151                        raise error.general('config: %s' % (ce))
152                    still_loading = True
153                    self.ini['files'] += [include]
154            includes = []
155            if still_loading:
156                for section in self.config.sections():
157                    includes += self.comma_list(section, 'include', err = False)
158
159    def files(self):
160        return self.ini['files']
Note: See TracBrowser for help on using the repository browser.