source: rtems-tools/rtemstoolkit/configuration.py @ 757578d

5
Last change on this file since 757578d was 757578d, checked in by Chris Johns <chrisj@…>, on 06/10/19 at 07:08:34

rtemstoolkit/configuration: Fix interpolation support.

  • It was disabled always. Now optional by the constructor.
  • Property mode set to 100644
File size: 6.9 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
40from rtemstoolkit import error
41from rtemstoolkit import path
42
43try:
44    import configparser
45    has_strict = True
46except:
47    # python2
48    import ConfigParser as configparser
49    has_strict = False
50
51class configuration:
52
53    def __init__(self, raw = True):
54        self.raw = raw
55        if has_strict:
56            self.config = configparser.ConfigParser(strict = False)
57        else:
58            self.config = configparser.ConfigParser()
59        self.ini = None
60        self.macro_filter = re.compile('\$\{[^\}]+\}')
61
62    def __str__(self):
63        if self.ini is None:
64            return 'empty'
65        s = ['Base: %s' % (self.ini['base'])]
66        s += ['Files:']
67        for f in self.ini['files']:
68            s += [' %s' % (f)]
69        s += ['Defaults:']
70        for default in self.config.defaults():
71            s += ' ' + default
72        s += ['Sections:']
73        for section in self.config.sections():
74            s += [' [%s]' % (section)]
75            for option in self.config.options(section):
76                rec = self.config.get(section,
77                                      option,
78                                      raw = True).replace(os.linesep, ' ')
79                s += ['  %s = %s' % (option, rec)]
80        return os.linesep.join(s)
81
82    def _interpolate(self, section, rec):
83        #
84        # On Python 2.7 there is no extended interpolation so add support here.
85        # On Python 3 we disable the built in support and also the code here.
86        #
87        if not self.raw:
88            not_found = []
89            while True:
90                macros = [m for m in self.macro_filter.findall(rec) if m not in not_found]
91                if len(macros) == 0:
92                    break
93                for m in macros:
94                    if m in not_found:
95                        continue
96                    if ':' in m:
97                        section_value = m[2:-1].split(':')
98                        if len(section_value) != 2:
99                            err = 'config: interpolation is ${section:item}: %s' % (m)
100                            raise error.general(err)
101                    else:
102                        section_value = [section, m[2:-1]]
103                    try:
104                        ref = self.config.get(section_value[0],
105                                              section_value[1],
106                                              raw = True).replace(os.linesep, ' ')
107                        rec = rec.replace(m, ref)
108                    except:
109                        not_found += [m]
110                        pass
111        return rec
112
113    def get_sections(self):
114        return self.config.sections()
115
116    def get_item(self, section, label, err = True):
117        try:
118            rec = self.config.get(section,
119                                  label,
120                                  raw = True).replace(os.linesep, ' ')
121        except:
122            if err:
123                raise error.general('config: no "%s" found in "%s"' % (label, section))
124            return None
125        return self._interpolate(section, rec)
126
127    def get_items(self, section, err = True, flatten = True):
128        try:
129            items = []
130            for name, value in self.config.items(section, raw = True):
131                if flatten:
132                    value = value.replace(os.linesep, ' ')
133                value = self._interpolate(section, value)
134                items += [(name, value)]
135            return items
136        except:
137            if err:
138                raise error.general('config: section "%s" not found' % (section))
139        return []
140
141    def comma_list(self, section, label, err = True):
142        items = self.get_item(section, label, err)
143        if items is None:
144            return []
145        return sorted(set([a.strip() for a in items.split(',')]))
146
147    def get_item_names(self, section, err = True):
148        try:
149            return [item[0] for item in self.config.items(section, raw = True)]
150        except:
151            if err:
152                raise error.general('config: section "%s" not found' % (section))
153        return []
154
155    def has_section(self, section):
156        return self.config.has_section(section)
157
158    def load(self, name):
159        #
160        # Load all the files.
161        #
162        self.ini = { 'base'     : path.dirname(name),
163                     'files'    : [] }
164        includes = [name]
165        still_loading = True
166        while still_loading:
167            still_loading = False
168            for include in includes:
169                if not path.exists(include):
170                    rebased_inc = path.join(self.ini['base'],
171                                            path.basename(include))
172                    if not path.exists(rebased_inc):
173                        e = 'config: cannot find configuration: %s' % (include)
174                        raise error.general(e)
175                    include = rebased_inc
176                if include not in self.ini['files']:
177                    try:
178                        self.config.read(include)
179                    except configparser.ParsingError as ce:
180                        raise error.general('config: %s' % (ce))
181                    still_loading = True
182                    self.ini['files'] += [include]
183            includes = []
184            if still_loading:
185                for section in self.config.sections():
186                    includes += self.comma_list(section, 'include', err = False)
187
188    def files(self):
189        return self.ini['files']
Note: See TracBrowser for help on using the repository browser.