source: rtems-tools/rtemstoolkit/rtems.py @ 5416cfa

Last change on this file since 5416cfa was 5416cfa, checked in by Chris Johns <chrisj@…>, on Oct 2, 2018 at 6:49:54 AM

config: Create a config directory and move the RTEMS arch/bsp data to it.

Closes #3536

  • Property mode set to 100755
File size: 16.0 KB
Line 
1#
2# RTEMS Tools Project (http://www.rtems.org/)
3# Copyright 20162018 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
31from __future__ import print_function
32
33import copy
34import os
35import re
36import textwrap
37
38from rtemstoolkit import configuration as configuration_
39from rtemstoolkit import error
40from rtemstoolkit import textbox
41from rtemstoolkit import version
42
43
44def clean_windows_path():
45    #
46    # On Windows MSYS2 prepends a path to itself to the environment
47    # path. This means the RTEMS specific automake is not found and which
48    # breaks the bootstrap. We need to remove the prepended path. Also
49    # remove any ACLOCAL paths from the environment.
50    #
51    if os.name == 'nt':
52        cspath = os.environ['PATH'].split(os.pathsep)
53        if 'msys' in cspath[0] and cspath[0].endswith('bin'):
54            os.environ['PATH'] = os.pathsep.join(cspath[1:])
55
56class configuration:
57
58    def __init__(self):
59        self.config = configuration_.configuration()
60        self.archs = { }
61        self.profiles = { }
62
63    def __str__(self):
64        s = self.name + os.linesep
65        s += 'Archs:' + os.linesep + \
66             pprint.pformat(self.archs, indent = 1, width = 80) + os.linesep
67        s += 'Profiles:' + os.linesep + \
68             pprint.pformat(self.profiles, indent = 1, width = 80) + os.linesep
69        return s
70
71    def _build_options(self, build, nesting = 0):
72        if ':' in build:
73            section, name = build.split(':', 1)
74            opts = [self.config.get_item(section, name)]
75            return opts
76        builds = self.builds_['builds']
77        if build not in builds:
78            raise error.general('build %s not found' % (build))
79        if nesting > 20:
80            raise error.general('nesting build %s' % (build))
81        options = []
82        for option in self.builds_['builds'][build]:
83            if ':' in option:
84                section, name = option.split(':', 1)
85                opts = [self.config.get_item(section, name)]
86            else:
87                opts = self._build_options(option, nesting + 1)
88            for opt in opts:
89                if opt not in options:
90                    options += [opt]
91        return options
92
93    def load(self, name, build):
94        self.config.load(name)
95        archs = []
96        self.profiles['profiles'] = \
97            self.config.comma_list('profiles', 'profiles', err = False)
98        if len(self.profiles['profiles']) == 0:
99            self.profiles['profiles'] = ['tier-%d' % (t) for t in range(1,4)]
100        for p in self.profiles['profiles']:
101            profile = {}
102            profile['name'] = p
103            profile['archs'] = self.config.comma_list(profile['name'], 'archs', err = False)
104            archs += profile['archs']
105            for arch in profile['archs']:
106                bsps = 'bsps_%s' % (arch)
107                profile[bsps] = self.config.comma_list(profile['name'], bsps)
108            self.profiles[profile['name']] = profile
109        invalid_chars = re.compile(r'[^a-zA-Z0-9_-]')
110        for a in set(archs):
111            if len(invalid_chars.findall(a)) != 0:
112                raise error.general('invalid character(s) in arch name: %s' % (a))
113            arch = {}
114            arch['excludes'] = {}
115            for exclude in self.config.comma_list(a, 'exclude', err = False):
116                arch['excludes'][exclude] = ['all']
117            for i in self.config.get_items(a, False):
118                if i[0].startswith('exclude-'):
119                    exclude = i[0][len('exclude-'):]
120                    if exclude not in arch['excludes']:
121                        arch['excludes'][exclude] = []
122                    arch['excludes'][exclude] += \
123                        sorted(set([b.strip() for b in i[1].split(',')]))
124            arch['bsps'] = self.config.comma_list(a, 'bsps', err = False)
125            for b in arch['bsps']:
126                if len(invalid_chars.findall(b)) != 0:
127                    raise error.general('invalid character(s) in BSP name: %s' % (b))
128                arch[b] = {}
129                arch[b]['bspopts'] = \
130                    self.config.comma_list(a, 'bspopts_%s' % (b), err = False)
131            self.archs[a] = arch
132        builds = {}
133        builds['default'] = self.config.get_item('builds', 'default')
134        if build is None:
135            build = builds['default']
136        builds['config'] = { }
137        for config in self.config.get_items('config'):
138            builds['config'][config[0]] = config[1]
139        builds['build'] = build
140        builds_ = self.config.get_item_names('builds')
141        builds['builds'] = {}
142        for build in builds_:
143            build_builds = self.config.comma_list('builds', build)
144            has_config = False
145            has_build = False
146            for b in build_builds:
147                if ':' in b:
148                    if has_build:
149                        raise error.general('config and build in build: %s' % (build))
150                    has_config = True
151                else:
152                    if has_config:
153                        raise error.general('config and build in build: %s' % (build))
154                    has_build = True
155            builds['builds'][build] = build_builds
156        self.builds_ = builds
157
158    def configs(self):
159        return sorted(list(self.builds_['config'].keys()))
160
161    def config_flags(self, config):
162        if config not in self.builds_['config']:
163            raise error.general('config entry not found: %s' % (config))
164        return self.builds_['config'][config]
165
166    def build(self):
167        return self.builds_['build']
168
169    def builds(self):
170        if self.builds_['build'] in self.builds_['builds']:
171            build = copy.copy(self.builds_['builds'][self.builds_['build']])
172            if ':' in build[0]:
173                return [self.builds_['build']]
174            return build
175        return None
176
177    def build_options(self, build):
178        return ' '.join(self._build_options(build))
179
180    def excludes(self, arch, bsp):
181        return list(set(self.arch_excludes(arch) + self.bsp_excludes(arch, bsp)))
182
183    def exclude_options(self, arch, bsp):
184        return ' '.join([self.config_flags('no-' + e) for e in self.excludes(arch, bsp)])
185
186    def archs(self):
187        return sorted(self.archs.keys())
188
189    def arch_present(self, arch):
190        return arch in self.archs
191
192    def arch_excludes(self, arch):
193        excludes = self.archs[arch]['excludes'].keys()
194        for exclude in self.archs[arch]['excludes']:
195            if 'all' not in self.archs[arch]['excludes'][exclude]:
196                excludes.remove(exclude)
197        return sorted(excludes)
198
199    def arch_bsps(self, arch):
200        return sorted(self.archs[arch]['bsps'])
201
202    def bsp_present(self, arch, bsp):
203        return bsp in self.archs[arch]['bsps']
204
205    def bsp_excludes(self, arch, bsp):
206        excludes = self.archs[arch]['excludes'].keys()
207        for exclude in self.archs[arch]['excludes']:
208            if 'all' not in self.archs[arch]['excludes'][exclude] and \
209               bsp not in self.archs[arch]['excludes'][exclude]:
210                excludes.remove(exclude)
211        return sorted(excludes)
212
213    def bspopts(self, arch, bsp):
214        if arch not in self.archs:
215            raise error.general('invalid architecture: %s' % (arch))
216        if bsp not in self.archs[arch]:
217            raise error.general('invalid BSP: %s' % (bsp))
218        return self.archs[arch][bsp]['bspopts']
219
220    def profile_present(self, profile):
221        return profile in self.profiles
222
223    def profile_archs(self, profile):
224        if profile not in self.profiles:
225            raise error.general('invalid profile: %s' % (profile))
226        return self.profiles[profile]['archs']
227
228    def profile_arch_bsps(self, profile, arch):
229        if profile not in self.profiles:
230            raise error.general('invalid profile: %s' % (profile))
231        if 'bsps_%s' % (arch) not in self.profiles[profile]:
232            raise error.general('invalid profile arch: %s' % (arch))
233        return ['%s/%s' % (arch, bsp) for bsp in self.profiles[profile]['bsps_%s' % (arch)]]
234
235    def report(self, profiles = True, builds = True, architectures = True):
236        width = 70
237        cols_1 = [width]
238        cols_2 = [10, width - 10]
239        s = textbox.line(cols_1, line = '=', marker = '+', indent = 1)
240        s1 = ' File(s)'
241        for f in self.config.files():
242            colon = ':'
243            for l in textwrap.wrap(f, width = cols_2[1] - 3):
244                s += textbox.row(cols_2, [s1, ' ' + l], marker = colon, indent = 1)
245                colon = ' '
246                s1 = ' ' * len(s1)
247        s += textbox.line(cols_1, marker = '+', indent = 1)
248        s += os.linesep
249        if profiles:
250            s += textbox.line(cols_1, line = '=', marker = '+', indent = 1)
251            profiles = sorted(self.profiles['profiles'])
252            archs = []
253            bsps = []
254            for profile in profiles:
255                archs += self.profiles[profile]['archs']
256                for arch in sorted(self.profiles[profile]['archs']):
257                    bsps += self.profiles[profile]['bsps_%s' % (arch)]
258            archs = len(set(archs))
259            bsps = len(set(bsps))
260            s += textbox.row(cols_1,
261                             [' Profiles : %d (archs:%d, bsps:%d)' % \
262                              (len(profiles), archs, bsps)],
263                             indent = 1)
264            for profile in profiles:
265                textbox.row(cols_2,
266                            [profile, self.profiles[profile]['name']],
267                            indent = 1)
268            s += textbox.line(cols_1, marker = '+', indent = 1)
269            for profile in profiles:
270                s += textbox.row(cols_1, [' %s' % (profile)], indent = 1)
271                profile = self.profiles[profile]
272                archs = sorted(profile['archs'])
273                for arch in archs:
274                    arch_bsps = ', '.join(profile['bsps_%s' % (arch)])
275                    if len(arch_bsps) > 0:
276                        s += textbox.line(cols_2, marker = '+', indent = 1)
277                        s1 = ' ' + arch
278                        for l in textwrap.wrap(arch_bsps,
279                                               width = cols_2[1] - 3):
280                            s += textbox.row(cols_2, [s1, ' ' + l], indent = 1)
281                            s1 = ' ' * len(s1)
282                s += textbox.line(cols_2, marker = '+', indent = 1)
283            s += os.linesep
284        if builds:
285            s += textbox.line(cols_1, line = '=', marker = '+', indent = 1)
286            s += textbox.row(cols_1,
287                             [' Builds:  %s (default)' % (self.builds_['default'])],
288                             indent = 1)
289            builds = self.builds_['builds']
290            bsize = 0
291            for build in builds:
292                if len(build) > bsize:
293                    bsize = len(build)
294            cols_b = [bsize + 2, width - bsize - 2]
295            s += textbox.line(cols_b, marker = '+', indent = 1)
296            for build in builds:
297                s1 = ' ' + build
298                for l in textwrap.wrap(', '.join(builds[build]),
299                                       width = cols_b[1] - 3):
300                    s += textbox.row(cols_b, [s1, ' ' + l], indent = 1)
301                    s1 = ' ' * len(s1)
302                s += textbox.line(cols_b, marker = '+', indent = 1)
303            configs = self.builds_['config']
304            s += textbox.row(cols_1,
305                             [' Configure Options: %d' % (len(configs))],
306                             indent = 1)
307            csize = 0
308            for config in configs:
309                if len(config) > csize:
310                    csize = len(config)
311            cols_c = [csize + 3, width - csize - 3]
312            s += textbox.line(cols_c, marker = '+', indent = 1)
313            for config in configs:
314                s1 = ' ' + config
315                for l in textwrap.wrap(configs[config], width = cols_c[1] - 3):
316                    s += textbox.row(cols_c, [s1, ' ' + l], indent = 1)
317                    s1 = ' ' * len(s1)
318                s += textbox.line(cols_c, marker = '+', indent = 1)
319            s += os.linesep
320        if architectures:
321            s += textbox.line(cols_1, line = '=', marker = '+', indent = 1)
322            archs = sorted(self.archs.keys())
323            bsps = 0
324            asize = 0
325            for arch in archs:
326                if len(arch) > asize:
327                    asize = len(arch)
328                bsps += len(self.archs[arch]['bsps'])
329            s += textbox.row(cols_1,
330                             [' Architectures : %d (bsps: %d)' % (len(archs), bsps)],
331                             indent = 1)
332            cols_a = [asize + 2, width - asize - 2]
333            s += textbox.line(cols_a, marker = '+', indent = 1)
334            for arch in archs:
335                s += textbox.row(cols_a,
336                                 [' ' + arch, ' %d' % (len(self.archs[arch]['bsps']))],
337                                 indent = 1)
338            s += textbox.line(cols_a, marker = '+', indent = 1)
339            for archn in archs:
340                arch = self.archs[archn]
341                if len(arch['bsps']) > 0:
342                    bsize = 0
343                    for bsp in arch['bsps']:
344                        if len(bsp) > bsize:
345                            bsize = len(bsp)
346                    cols_b = [bsize + 3, width - bsize - 3]
347                    s += textbox.row(cols_1, [' ' + archn + ':'], indent = 1)
348                    s += textbox.line(cols_b, marker = '+', indent = 1)
349                    for bsp in arch['bsps']:
350                        s1 = ' ' + bsp
351                        bspopts = ' '.join(arch[bsp]['bspopts'])
352                        if len(bspopts):
353                            for l in textwrap.wrap('bopt: ' + bspopts,
354                                                   width = cols_b[1] - 3):
355                                s += textbox.row(cols_b, [s1, ' ' + l], indent = 1)
356                                s1 = ' ' * len(s1)
357                        excludes = []
358                        for exclude in arch['excludes']:
359                            if 'all' in arch['excludes'][exclude] or \
360                               bsp in arch['excludes'][exclude]:
361                                excludes += [exclude]
362                        excludes = ', '.join(excludes)
363                        if len(excludes):
364                            for l in textwrap.wrap('ex: ' + excludes,
365                                                   width = cols_b[1] - 3):
366                                s += textbox.row(cols_b, [s1, ' ' + l], indent = 1)
367                                s1 = ' ' * len(s1)
368                        if len(bspopts) == 0 and len(excludes) == 0:
369                            s += textbox.row(cols_b, [s1, ' '], indent = 1)
370                    s += textbox.line(cols_b, marker = '+', indent = 1)
371            s += os.linesep
372        return s
Note: See TracBrowser for help on using the repository browser.