source: rtems/rtems-bsps @ dbb7c956

Last change on this file since dbb7c956 was 4cd885c, checked in by Sebastian Huber <sebastian.huber@…>, on 11/02/20 at 18:43:20

rtems-bsps: Use build specification items

Close #4123.

  • Property mode set to 100755
File size: 14.2 KB
Line 
1#! /usr/bin/env python
2#
3# RTEMS (http://www.rtems.org/)
4# Copyright 2020 Chris Johns (chrisj@rtems.org)
5# All rights reserved.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions are met:
9#
10# 1. Redistributions of source code must retain the above copyright notice,
11# this list of conditions and the following disclaimer.
12#
13# 2. Redistributions in binary form must reproduce the above copyright notice,
14# this list of conditions and the following disclaimer in the documentation
15# and/or other materials provided with the distribution.
16#
17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27# POSSIBILITY OF SUCH DAMAGE.
28#
29
30from __future__ import print_function
31
32import argparse
33import os
34import os.path
35import re
36import sys
37
38rtems_version = 6
39
40
41_BUILD_TYPE_BSP = re.compile(r"build-type:\s*bsp\n")
42_ARCH = re.compile(r"arch:\s*(\S+)\n")
43_FAMILY = re.compile(r"family:\s*(\S+)\n")
44_BSP = re.compile(r"bsp:\s*(\S+)\n")
45
46
47class ArchBsps:
48    """Collects and processes the BSPs for a range of architectures
49    creating output in text, markdown and HTML ir pandoc is installed"""
50    def __init__(self, path='.', trace=False):
51        self.trace = trace
52        self._output = []
53        self.top = os.path.realpath(path)
54        self.base = os.path.join(self.top, 'spec', 'build', 'bsps')
55        self.configs = []
56        self.archs = {}
57        self._collect('.yml')
58        self._process()
59
60    def _clear(self):
61        """Clears the output."""
62        self._output = []
63
64    def _out(self, line=''):
65        """Output a line to the output buffer."""
66        self._output += [line]
67
68    def _collect(self, ext):
69        """Collect the config files from the source tree."""
70        self.configs = []
71        for root, dirs, files in os.walk(self.base, topdown=True):
72            for f in files:
73                if os.path.splitext(f)[1] == ext:
74                    self.configs += [os.path.join(root, f)]
75
76    def _process(self):
77        """Process the collected list of config files."""
78        self.archs = {}
79        for cfg in self.configs:
80            with open(cfg, 'r') as cfg_file:
81                content = cfg_file.read()
82                if _BUILD_TYPE_BSP.search(content):
83                    arch = _ARCH.search(content).group(1)
84                    family = _FAMILY.search(content).group(1)
85                    bsp = _BSP.search(content).group(1)
86                    self.archs.setdefault(arch, {})
87                    self.archs[arch].setdefault(family, {})
88                    self.archs[arch][family][bsp] = cfg[len(self.base) + 1:]
89
90    def _max_arch_len(self):
91        """Finds the longest arch label"""
92        maxlen = 0
93        for arch in self.archs:
94            if len(arch) > maxlen:
95                maxlen = len(arch)
96        return maxlen
97
98    def _max_family_len(self):
99        """Finds the longest family label"""
100        maxlen = 0
101        for arch in self.archs:
102            for family in self.archs[arch]:
103                if len(family) > maxlen:
104                    maxlen = len(family)
105        return maxlen
106
107    def _max_bsp_len(self):
108        """Finds the longest BSP label"""
109        maxlen = 0
110        for arch in self.archs:
111            for family in self.archs[arch]:
112                for bsp in self.archs[arch][family]:
113                    if len(bsp) > maxlen:
114                        maxlen = len(bsp)
115        return maxlen
116
117    def _max_bsp_path_len(self):
118        """Finds the longest BSP path"""
119        maxlen = 0
120        for arch in self.archs:
121            for family in self.archs[arch]:
122                for bsp in self.archs[arch][family]:
123                    if len(self.archs[arch][family][bsp]) > maxlen:
124                        maxlen = len(self.archs[arch][family][bsp])
125        return maxlen
126
127    def title(self):
128        """Returns the output's title"""
129        return 'RTEMS %d Board Support Packages' % (rtems_version)
130
131    def output(self):
132        """Return the output"""
133        return self._output
134
135    def architectures(self):
136        """Returns the number of architectures we have"""
137        return len(self.archs)
138
139    def families(self, arch=None):
140        """Returns the number of BSP families we have for an architecture. If
141        you supply an architecture the count is the families in the
142        architure.
143
144        """
145        if arch is not None:
146            return len(self.archs[arch])
147        count = 0
148        for arch in self.archs:
149            count += len(self.archs[arch])
150        return count
151
152    def bsps(self, arch=None, family=None):
153        """Returns the number of BSPs we have for an architecture or a family"""
154        count = 0
155        if arch is not None and family is not None:
156            count = len(self.archs[arch][family])
157        elif arch is None and family is not None:
158            for arch in self.archs:
159                if family in self.archs[arch]:
160                    count = len(self.archs[arch][family])
161                    break
162        elif arch is not None and family is None:
163            count = 0
164            for family in self.archs[arch]:
165                count += len(self.archs[arch][family])
166        else:
167            for arch in self.archs:
168                for family in self.archs[arch]:
169                    count += len(self.archs[arch][family])
170        return count
171
172    def text(self, arch_selector=None, family_selector=None, show_path=False):
173        """Generate plain text output"""
174        self._clear()
175        self._out(self.title())
176        self._out()
177        self._out('Architectures: %d' % (self.architectures()))
178        self._out('BSP Families: %d' % (self.families()))
179        self._out('BSPs: %d' % (self.bsps()))
180        max_family = self._max_family_len()
181        max_bsp = self._max_bsp_len()
182        if arch_selector is None:
183            archs_matcher = []
184        else:
185            archs_matcher = [a.strip() for a in arch_selector.split(',')]
186        if family_selector is None:
187            family_matcher = []
188        else:
189            family_matcher = [f.strip() for f in family_selector.split(',')]
190        for arch in sorted(self.archs.keys()):
191            if arch_selector is None or arch in archs_matcher:
192                first = True
193                for family in sorted(self.archs[arch].keys()):
194                    if family_selector is None or family in family_matcher:
195                        if first:
196                            self._out()
197                            self._out('%s: (families:%d bsps:%d)' % \
198                                      (arch,
199                                       self.families(arch=arch),
200                                       self.bsps(arch=arch)))
201                            first = False
202                        for bsp in sorted(self.archs[arch][family].keys()):
203                            if show_path:
204                                p = os.path.join('bsps',
205                                                 self.archs[arch][family][bsp])
206                                self._out(' %-*s %-*s %s' % \
207                                          (max_bsp, bsp, max_family, family, p))
208                            else:
209                                self._out(' %-*s %s' % (max_bsp, bsp, family))
210
211    def markdown(self,
212                 arch_selector=None,
213                 family_selector=None,
214                 show_path=False,
215                 show_title=False):
216        """Generates markdown output"""
217        self._clear()
218        if show_title:
219            self._out('# ' + self.title())
220            self._out()
221        self._out('**Architectures:** %d  ' % (self.architectures()))
222        self._out('**BSP Families:** %d  ' % (self.families()))
223        self._out('**BSPs:** %d  ' % (self.bsps()))
224        max_arch = self._max_arch_len()
225        max_family = self._max_family_len()
226        max_bsp = self._max_bsp_len()
227        max_bsp_path = self._max_bsp_path_len() + 4
228        if arch_selector is None:
229            archs_matcher = []
230        else:
231            archs_matcher = [a.strip() for a in arch_selector.split(',')]
232        if family_selector is None:
233            family_matcher = []
234        else:
235            family_matcher = [f.strip() for f in family_selector.split(',')]
236        for arch in sorted(self.archs.keys()):
237            if arch_selector is None or arch in archs_matcher:
238                first = True
239                for family in sorted(self.archs[arch].keys()):
240                    if family_selector is None or family in family_matcher:
241                        if first:
242                            fbs = 'families:%-2d bsps:%-3d' % \
243                                (self.families(arch=arch),
244                                 self.bsps(arch=arch))
245                            if max_family < len(fbs):
246                                max_fb = len(fbs)
247                            else:
248                                max_fb = max_family
249                            self._out()
250                            if show_path:
251                                self._out('%-*s |%-*s |' %
252                                          (max_bsp, arch, max_fb, fbs))
253                                self._out('%s-|%s-|-%s' %
254                                          ('-' * max_bsp, '-' * max_fb,
255                                           '-' * max_bsp_path))
256                            else:
257                                self._out('%-*s |%s' % (max_bsp, arch, fbs))
258                                self._out('%s-|-%s' %
259                                          ('-' * max_bsp, '-' * max_fb))
260                            first = False
261                        for bsp in sorted(self.archs[arch][family].keys()):
262                            if show_path:
263                                p = os.path.join('bsps',
264                                                 self.archs[arch][family][bsp])
265                                self._out('%-*s |%-*s |%s' % \
266                                          (max_bsp, bsp, max_fb, family, p))
267                            else:
268                                self._out('%-*s |%s' % (max_bsp, bsp, family))
269                               
270    def pairs(self, arch_selector=None, family_selector=None, show_path=False):
271        """Generate output as pairs"""
272        self._clear()
273        max_arch = self._max_arch_len()
274        max_bsp = self._max_bsp_len()
275        if arch_selector is None:
276            arch_matcher = []
277        else:
278            arch_matcher = [a.strip() for a in arch_selector.split(',')]
279        if family_selector is None:
280            family_matcher = []
281        else:
282            family_matcher = [f.strip() for f in family_selector.split(',')]
283        for arch in sorted(self.archs.keys()):
284            if arch_selector is None or arch in arch_matcher:
285                for family in sorted(self.archs[arch].keys()):
286                    if family_selector is None or family in family_matcher:
287                        for bsp in sorted(self.archs[arch][family].keys()):
288                            if show_path:
289                                p = os.path.join('bsps',
290                                                 self.archs[arch][family][bsp])
291                                pair = arch + '/' + bsp
292                                pair = '%-*s %s' % (max_arch + max_bsp + 1, pair, p)
293                               
294                                self._out(pair)
295                            else:
296                                self._out('%s/%s' % (arch, bsp))
297
298
299def run(args):
300    """Runs the command"""
301    argsp = argparse.ArgumentParser(
302        prog='rtems-bsps',
303        description='List the BSP and architectures in RTEMS')
304    argsp.add_argument('-a',
305                       '--arch',
306                       help='Output the BSPs in an architecture',
307                       type=str,
308                       default=None)
309    argsp.add_argument('-f',
310                       '--family',
311                       help='Output the BSPs in an architecture family',
312                       type=str,
313                       default=None)
314    argsp.add_argument('-p',
315                       '--paths',
316                       help='Show the BSP paths in the output',
317                       action='store_true')
318    argsp.add_argument('-m',
319                       '--markdown',
320                       help='Output list in markdown format',
321                       action='store_true')
322    argsp.add_argument('-T',
323                       '--title',
324                       help='Output a title in the markdown format',
325                       action='store_true')
326    argsp.add_argument('-v',
327                       '--trace',
328                       help='Verbose or trace for debugging',
329                       action='store_true')
330    argsp.add_argument('-P',
331                       '--pairs',
332                       help='Output architectures and BSPs in CPU/BSP format',
333                       action='store_true')
334
335    argopts = argsp.parse_args(args[1:])
336
337    if argopts.arch is not None and argopts.family is not None:
338        print('error: arch or family, not both at once', file=sys.stderr)
339        sys.exit(1)
340
341    ab = ArchBsps(trace=argopts.trace)
342
343    if argopts.markdown:
344        ab.markdown(arch_selector=argopts.arch,
345                    family_selector=argopts.family,
346                    show_path=argopts.paths,
347                    show_title=argopts.title)
348    else:
349        if argopts.pairs:
350            ab.pairs(arch_selector=argopts.arch,
351                     family_selector=argopts.family,
352                     show_path=argopts.paths)
353        else:
354            ab.text(arch_selector=argopts.arch,
355                    family_selector=argopts.family,
356                    show_path=argopts.paths)
357
358    print(os.linesep.join(ab.output()))
359
360
361if __name__ == "__main__":
362    run(sys.argv)
Note: See TracBrowser for help on using the repository browser.