[rtems-tools commit] rtemstoolkit: Add Python INI configuration support.

Chris Johns chrisj at rtems.org
Mon May 15 01:49:33 UTC 2017


Module:    rtems-tools
Branch:    master
Commit:    ef38b5d7c22b163a557172b50497af6eec624127
Changeset: http://git.rtems.org/rtems-tools/commit/?id=ef38b5d7c22b163a557172b50497af6eec624127

Author:    Chris Johns <chrisj at rtems.org>
Date:      Mon May 15 11:48:44 2017 +1000

rtemstoolkit: Add Python INI configuration support.

---

 rtemstoolkit/configuration.py | 137 ++++++++++++++++++++++++++++++++++++++++++
 tester/rt/check.py            | 133 ++++++++--------------------------------
 2 files changed, 161 insertions(+), 109 deletions(-)

diff --git a/rtemstoolkit/configuration.py b/rtemstoolkit/configuration.py
new file mode 100644
index 0000000..71ab3ca
--- /dev/null
+++ b/rtemstoolkit/configuration.py
@@ -0,0 +1,137 @@
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2017 Chris Johns (chrisj at rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# Host specifics.
+#
+
+from __future__ import print_function
+
+import os
+import re
+
+try:
+    import configparser
+except:
+    import ConfigParser as configparser
+
+from rtemstoolkit import error
+from rtemstoolkit import path
+
+class configuration:
+
+    def __init__(self):
+        self.config = configparser.ConfigParser()
+        self.ini = None
+        self.macro_filter = re.compile('\$\{.+\}')
+
+    def get_item(self, section, label, err = True):
+        try:
+            rec = self.config.get(section, label).replace(os.linesep, ' ')
+        except:
+            if err:
+                raise error.general('config: no "%s" found in "%s"' % (label, section))
+            return None
+        #
+        # On Python 2.7 there is no extended interpolation so add support here.
+        # On Python 3 this should happen automatically and so the findall
+        # should find nothing.
+        #
+        for m in self.macro_filter.findall(rec):
+            if ':' not in m:
+                raise error.general('config: interpolation is ${section:value}: %s' % (m))
+            section_value = m[2:-1].split(':')
+            if len(section_value) != 2:
+                raise error.general('config: interpolation is ${section:value}: %s' % (m))
+            try:
+                ref = self.config.get(section_value[0],
+                                      section_value[1]).replace(os.linesep, ' ')
+                rec = rec.replace(m, ref)
+            except:
+                pass
+        return rec
+
+    def get_items(self, section, err = True):
+        try:
+            items = [(name, key.replace(os.linesep, ' ')) \
+                     for name, key in self.config.items(section)]
+            return items
+        except:
+            if err:
+                raise error.general('config: section "%s" not found' % (section))
+        return []
+
+    def comma_list(self, section, label, err = True):
+        items = self.get_item(section, label, err)
+        if items is None:
+            return []
+        return sorted(set([a.strip() for a in items.split(',')]))
+
+    def get_item_names(self, section, err = True):
+        try:
+            return [item[0] for item in self.config.items(section)]
+        except:
+            if err:
+                raise error.general('config: section "%s" not found' % (section))
+        return []
+
+    def load(self, name):
+        #
+        # Load all the files.
+        #
+        self.ini = { 'base'     : path.dirname(name),
+                     'files'    : [] }
+        includes = [name]
+        still_loading = True
+        while still_loading:
+            still_loading = False
+            for include in includes:
+                if not path.exists(include):
+                    rebased_inc = path.join(self.ini['base'],
+                                            path.basename(include))
+                    if not path.exists(rebased_inc):
+                        e = 'config: cannot find configuration: %s' % (include)
+                        raise error.general(e)
+                    include = rebased_inc
+                if include not in self.ini['files']:
+                    try:
+                        self.config.read(include)
+                    except configparser.ParsingError as ce:
+                        raise error.general('config: %s' % (ce))
+                    still_loading = True
+                    self.ini['files'] += [include]
+            includes = []
+            if still_loading:
+                for section in self.config.sections():
+                    includes += self.comma_list(section, 'include', err = False)
+
+
+    def files(self):
+        return self.ini['files']
diff --git a/tester/rt/check.py b/tester/rt/check.py
index 31a3e7e..581f246 100755
--- a/tester/rt/check.py
+++ b/tester/rt/check.py
@@ -41,11 +41,7 @@ import textwrap
 
 import pprint
 
-try:
-    import configparser
-except:
-    import ConfigParser as configparser
-
+from rtemstoolkit import configuration
 from rtemstoolkit import execute
 from rtemstoolkit import error
 from rtemstoolkit import host
@@ -440,17 +436,13 @@ class results:
                 log.output(' %s (%5d):' % (self._arch_bsp(f[0], f[1]), f[3]))
                 log.output(wrap([' ' * 6, config_cmd], lineend = '\\', width = 75))
 
-class configuration:
+class configuration_:
 
     def __init__(self):
-        self.config = configparser.ConfigParser()
-        self.name = None
-        self.ini = None
+        self.config = configuration.configuration()
         self.archs = { }
         self.builds_ = { }
         self.profiles = { }
-        self.configurations = { }
-        self.macro_filter = re.compile('\$\{.+\}')
 
     def __str__(self):
         import pprint
@@ -463,90 +455,10 @@ class configuration:
              pprint.pformat(self.profiles, indent = 1, width = 80) + os.linesep
         return s
 
-    def _get_item(self, section, label, err = True):
-        try:
-            rec = self.config.get(section, label).replace(os.linesep, ' ')
-        except:
-            if err:
-                raise error.general('config: no "%s" found in "%s"' % (label, section))
-            return None
-        #
-        # On Python 2.7 there is no extended interpolation so add support here.
-        # On Python 3 this should happen automatically and so the findall
-        # should find nothing.
-        #
-        for m in self.macro_filter.findall(rec):
-            if ':' not in m:
-                raise error.general('config: interpolation is ${section:value}: %s' % (m))
-            section_value = m[2:-1].split(':')
-            if len(section_value) != 2:
-                raise error.general('config: interpolation is ${section:value}: %s' % (m))
-            try:
-                ref = self.config.get(section_value[0],
-                                      section_value[1]).replace(os.linesep, ' ')
-                rec = rec.replace(m, ref)
-            except:
-                pass
-        return rec
-
-    def _get_items(self, section, err = True):
-        try:
-            items = [(name, key.replace(os.linesep, ' ')) \
-                     for name, key in self.config.items(section)]
-            return items
-        except:
-            if err:
-                raise error.general('config: section "%s" not found' % (section))
-        return []
-
-    def _comma_list(self, section, label, err = True):
-        items = self._get_item(section, label, err)
-        if items is None:
-            return []
-        return sorted(set([a.strip() for a in items.split(',')]))
-
-    def _get_item_names(self, section, err = True):
-        try:
-            return [item[0] for item in self.config.items(section)]
-        except:
-            if err:
-                raise error.general('config: section "%s" not found' % (section))
-        return []
-
-    def _load(self, name):
-        #
-        # Load all the files.
-        #
-        self.ini = { 'base'     : path.dirname(name),
-                     'files'    : [] }
-        includes = [name]
-        still_loading = True
-        while still_loading:
-            still_loading = False
-            for include in includes:
-                if not path.exists(include):
-                    rebased_inc = path.join(self.ini['base'],
-                                            path.basename(include))
-                    if not path.exists(rebased_inc):
-                        e = 'config: cannot find configuration: %s' % (include)
-                        raise error.general(e)
-                    include = rebased_inc
-                if include not in self.ini['files']:
-                    try:
-                        self.config.read(include)
-                    except configparser.ParsingError as ce:
-                        raise error.general('config: %s' % (ce))
-                    still_loading = True
-                    self.ini['files'] += [include]
-            includes = []
-            if still_loading:
-                for section in self.config.sections():
-                    includes += self._comma_list(section, 'include', err = False)
-
     def _build_options(self, build, nesting = 0):
         if ':' in build:
             section, name = build.split(':', 1)
-            opts = [self._get_item(section, name)]
+            opts = [self.config.get_item(section, name)]
             return opts
         builds = self.builds_['builds']
         if build not in builds:
@@ -557,57 +469,60 @@ class configuration:
         for option in self.builds_['builds'][build]:
             if ':' in option:
                 section, name = option.split(':', 1)
-                opts = [self._get_item(section, name)]
+                opts = [self.config.get_item(section, name)]
             else:
-                opts = self._options(option, nesting + 1)
+                opts = self._build_options(option, nesting + 1)
             for opt in opts:
                 if opt not in options:
                     options += [opt]
         return options
 
     def load(self, name, build):
-        self._load(name)
+        self.config.load(name)
         archs = []
-        self.profiles['profiles'] = self._comma_list('profiles', 'profiles', err = False)
+        self.profiles['profiles'] = \
+            self.config.comma_list('profiles', 'profiles', err = False)
         if len(self.profiles['profiles']) == 0:
             self.profiles['profiles'] = ['tier-%d' % (t) for t in range(1,4)]
         for p in self.profiles['profiles']:
             profile = {}
             profile['name'] = p
-            profile['archs'] = self._comma_list(profile['name'], 'archs')
+            profile['archs'] = self.config.comma_list(profile['name'], 'archs')
             archs += profile['archs']
             for arch in profile['archs']:
                 bsps = 'bsps_%s' % (arch)
-                profile[bsps] = self._comma_list(profile['name'], bsps)
+                profile[bsps] = self.config.comma_list(profile['name'], bsps)
             self.profiles[profile['name']] = profile
         for a in set(archs):
             arch = {}
             arch['excludes'] = {}
-            for exclude in self._comma_list(a, 'exclude', err = False):
+            for exclude in self.config.comma_list(a, 'exclude', err = False):
                 arch['excludes'][exclude] = ['all']
-            for i in self._get_items(a, False):
+            for i in self.config.get_items(a, False):
                 if i[0].startswith('exclude-'):
                     exclude = i[0][len('exclude-'):]
                     if exclude not in arch['excludes']:
                         arch['excludes'][exclude] = []
-                    arch['excludes'][exclude] += sorted(set([b.strip() for b in i[1].split(',')]))
-            arch['bsps'] = self._comma_list(a, 'bsps', err = False)
+                    arch['excludes'][exclude] += \
+                        sorted(set([b.strip() for b in i[1].split(',')]))
+            arch['bsps'] = self.config.comma_list(a, 'bsps', err = False)
             for b in arch['bsps']:
                 arch[b] = {}
-                arch[b]['bspopts'] = self._comma_list(a, 'bspopts_%s' % (b), err = False)
+                arch[b]['bspopts'] = \
+                    self.config.comma_list(a, 'bspopts_%s' % (b), err = False)
             self.archs[a] = arch
         builds = {}
-        builds['default'] = self._get_item('builds', 'default')
+        builds['default'] = self.config.get_item('builds', 'default')
         if build is None:
             build = builds['default']
         builds['config'] = { }
-        for config in self._get_items('config'):
+        for config in self.config.get_items('config'):
             builds['config'][config[0]] = config[1]
         builds['build'] = build
-        builds_ = self._get_item_names('builds')
+        builds_ = self.config.get_item_names('builds')
         builds['builds'] = {}
         for build in builds_:
-            build_builds = self._comma_list('builds', build)
+            build_builds = self.config.comma_list('builds', build)
             has_config = False
             has_build = False
             for b in build_builds:
@@ -681,7 +596,7 @@ class configuration:
         cols_2 = [10, width - 10]
         s = textbox.line(cols_1, line = '=', marker = '+', indent = 1)
         s1 = ' File(s)'
-        for f in self.ini['files']:
+        for f in self.config.files():
             colon = ':'
             for l in textwrap.wrap(f, width = cols_2[1] - 3):
                 s += textbox.row(cols_2, [s1, ' ' + l], marker = colon, indent = 1)
@@ -1161,7 +1076,7 @@ def run_args(args):
         log.notice(title())
         log.output(command_line())
 
-        config = configuration()
+        config = configuration_()
         config.load(config_file, opts.build)
 
         if opts.config_report:



More information about the vc mailing list