source: rtems/rtems-bsps @ d7a48e1

Last change on this file since d7a48e1 was 0805930, checked in by Ryan Long <ryan.long@…>, on 09/28/20 at 22:49:57

rtems-bsps: add ability to print architecture/bsp list

Closes #4099.

  • Property mode set to 100755
File size: 14.1 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 sys
36
37rtems_version = 6
38
39
40class ArchBsps:
41    """Collects and processes the BSPs for a range of architectures
42    creating output in text, markdown and HTML ir pandoc is installed"""
43    def __init__(self, path='.', trace=False):
44        self.trace = trace
45        self._output = []
46        self.top = os.path.realpath(path)
47        self.base = os.path.join(self.top, 'bsps')
48        self.configs = []
49        self.archs = {}
50        self._collect('.cfg')
51        self._process()
52
53    def _clear(self):
54        """Clears the output."""
55        self._output = []
56
57    def _out(self, line=''):
58        """Output a line to the output buffer."""
59        self._output += [line]
60
61    def _collect(self, ext):
62        """Collect the config files from the source tree."""
63        self.configs = []
64        for root, dirs, files in os.walk(self.base, topdown=True):
65            for f in files:
66                if os.path.splitext(f)[1] == ext:
67                    self.configs += [os.path.join(root, f)]
68
69    def _process(self):
70        """Process the collected list of config files."""
71        self.archs = {}
72        for cfg in self.configs:
73            config_path = cfg[len(self.base) + 1:]
74            config_parts = config_path.split(os.sep)
75            if len(config_parts) == 4:
76                arch = config_parts[0]
77                family = config_parts[1]
78                bsp = os.path.splitext(config_parts[3])[0]
79                if arch not in self.archs:
80                    self.archs[arch] = {}
81                if family not in self.archs[arch]:
82                    self.archs[arch][family] = {}
83                self.archs[arch][family][bsp] = config_path
84
85    def _max_arch_len(self):
86        """Finds the longest arch label"""
87        maxlen = 0
88        for arch in self.archs:
89            if len(arch) > maxlen:
90                maxlen = len(arch)
91        return maxlen
92
93    def _max_family_len(self):
94        """Finds the longest family label"""
95        maxlen = 0
96        for arch in self.archs:
97            for family in self.archs[arch]:
98                if len(family) > maxlen:
99                    maxlen = len(family)
100        return maxlen
101
102    def _max_bsp_len(self):
103        """Finds the longest BSP label"""
104        maxlen = 0
105        for arch in self.archs:
106            for family in self.archs[arch]:
107                for bsp in self.archs[arch][family]:
108                    if len(bsp) > maxlen:
109                        maxlen = len(bsp)
110        return maxlen
111
112    def _max_bsp_path_len(self):
113        """Finds the longest BSP path"""
114        maxlen = 0
115        for arch in self.archs:
116            for family in self.archs[arch]:
117                for bsp in self.archs[arch][family]:
118                    if len(self.archs[arch][family][bsp]) > maxlen:
119                        maxlen = len(self.archs[arch][family][bsp])
120        return maxlen
121
122    def title(self):
123        """Returns the output's title"""
124        return 'RTEMS %d Board Support Packages' % (rtems_version)
125
126    def output(self):
127        """Return the output"""
128        return self._output
129
130    def architectures(self):
131        """Returns the number of architectures we have"""
132        return len(self.archs)
133
134    def families(self, arch=None):
135        """Returns the number of BSP families we have for an architecture. If
136        you supply an architecture the count is the families in the
137        architure.
138
139        """
140        if arch is not None:
141            return len(self.archs[arch])
142        count = 0
143        for arch in self.archs:
144            count += len(self.archs[arch])
145        return count
146
147    def bsps(self, arch=None, family=None):
148        """Returns the number of BSPs we have for an architecture or a family"""
149        count = 0
150        if arch is not None and family is not None:
151            count = len(self.archs[arch][family])
152        elif arch is None and family is not None:
153            for arch in self.archs:
154                if family in self.archs[arch]:
155                    count = len(self.archs[arch][family])
156                    break
157        elif arch is not None and family is None:
158            count = 0
159            for family in self.archs[arch]:
160                count += len(self.archs[arch][family])
161        else:
162            for arch in self.archs:
163                for family in self.archs[arch]:
164                    count += len(self.archs[arch][family])
165        return count
166
167    def text(self, arch_selector=None, family_selector=None, show_path=False):
168        """Generate plain text output"""
169        self._clear()
170        self._out(self.title())
171        self._out()
172        self._out('Architectures: %d' % (self.architectures()))
173        self._out('BSP Families: %d' % (self.families()))
174        self._out('BSPs: %d' % (self.bsps()))
175        max_family = self._max_family_len()
176        max_bsp = self._max_bsp_len()
177        if arch_selector is None:
178            archs_matcher = []
179        else:
180            archs_matcher = [a.strip() for a in arch_selector.split(',')]
181        if family_selector is None:
182            family_matcher = []
183        else:
184            family_matcher = [f.strip() for f in family_selector.split(',')]
185        for arch in sorted(self.archs.keys()):
186            if arch_selector is None or arch in archs_matcher:
187                first = True
188                for family in sorted(self.archs[arch].keys()):
189                    if family_selector is None or family in family_matcher:
190                        if first:
191                            self._out()
192                            self._out('%s: (families:%d bsps:%d)' % \
193                                      (arch,
194                                       self.families(arch=arch),
195                                       self.bsps(arch=arch)))
196                            first = False
197                        for bsp in sorted(self.archs[arch][family].keys()):
198                            if show_path:
199                                p = os.path.join('bsps',
200                                                 self.archs[arch][family][bsp])
201                                self._out(' %-*s %-*s %s' % \
202                                          (max_bsp, bsp, max_family, family, p))
203                            else:
204                                self._out(' %-*s %s' % (max_bsp, bsp, family))
205
206    def markdown(self,
207                 arch_selector=None,
208                 family_selector=None,
209                 show_path=False,
210                 show_title=False):
211        """Generates markdown output"""
212        self._clear()
213        if show_title:
214            self._out('# ' + self.title())
215            self._out()
216        self._out('**Architectures:** %d  ' % (self.architectures()))
217        self._out('**BSP Families:** %d  ' % (self.families()))
218        self._out('**BSPs:** %d  ' % (self.bsps()))
219        max_arch = self._max_arch_len()
220        max_family = self._max_family_len()
221        max_bsp = self._max_bsp_len()
222        max_bsp_path = self._max_bsp_path_len() + 4
223        if arch_selector is None:
224            archs_matcher = []
225        else:
226            archs_matcher = [a.strip() for a in arch_selector.split(',')]
227        if family_selector is None:
228            family_matcher = []
229        else:
230            family_matcher = [f.strip() for f in family_selector.split(',')]
231        for arch in sorted(self.archs.keys()):
232            if arch_selector is None or arch in archs_matcher:
233                first = True
234                for family in sorted(self.archs[arch].keys()):
235                    if family_selector is None or family in family_matcher:
236                        if first:
237                            fbs = 'families:%-2d bsps:%-3d' % \
238                                (self.families(arch=arch),
239                                 self.bsps(arch=arch))
240                            if max_family < len(fbs):
241                                max_fb = len(fbs)
242                            else:
243                                max_fb = max_family
244                            self._out()
245                            if show_path:
246                                self._out('%-*s |%-*s |' %
247                                          (max_bsp, arch, max_fb, fbs))
248                                self._out('%s-|%s-|-%s' %
249                                          ('-' * max_bsp, '-' * max_fb,
250                                           '-' * max_bsp_path))
251                            else:
252                                self._out('%-*s |%s' % (max_bsp, arch, fbs))
253                                self._out('%s-|-%s' %
254                                          ('-' * max_bsp, '-' * max_fb))
255                            first = False
256                        for bsp in sorted(self.archs[arch][family].keys()):
257                            if show_path:
258                                p = os.path.join('bsps',
259                                                 self.archs[arch][family][bsp])
260                                self._out('%-*s |%-*s |%s' % \
261                                          (max_bsp, bsp, max_fb, family, p))
262                            else:
263                                self._out('%-*s |%s' % (max_bsp, bsp, family))
264                               
265    def pairs(self, arch_selector=None, family_selector=None, show_path=False):
266        """Generate output as pairs"""
267        self._clear()
268        max_arch = self._max_arch_len()
269        max_bsp = self._max_bsp_len()
270        if arch_selector is None:
271            arch_matcher = []
272        else:
273            arch_matcher = [a.strip() for a in arch_selector.split(',')]
274        if family_selector is None:
275            family_matcher = []
276        else:
277            family_matcher = [f.strip() for f in family_selector.split(',')]
278        for arch in sorted(self.archs.keys()):
279            if arch_selector is None or arch in arch_matcher:
280                for family in sorted(self.archs[arch].keys()):
281                    if family_selector is None or family in family_matcher:
282                        for bsp in sorted(self.archs[arch][family].keys()):
283                            if show_path:
284                                p = os.path.join('bsps',
285                                                 self.archs[arch][family][bsp])
286                                pair = arch + '/' + bsp
287                                pair = '%-*s %s' % (max_arch + max_bsp + 1, pair, p)
288                               
289                                self._out(pair)
290                            else:
291                                self._out('%s/%s' % (arch, bsp))
292
293
294def run(args):
295    """Runs the command"""
296    argsp = argparse.ArgumentParser(
297        prog='rtems-bsps',
298        description='List the BSP and architectures in RTEMS')
299    argsp.add_argument('-a',
300                       '--arch',
301                       help='Output the BSPs in an architecture',
302                       type=str,
303                       default=None)
304    argsp.add_argument('-f',
305                       '--family',
306                       help='Output the BSPs in an architecture family',
307                       type=str,
308                       default=None)
309    argsp.add_argument('-p',
310                       '--paths',
311                       help='Show the BSP paths in the output',
312                       action='store_true')
313    argsp.add_argument('-m',
314                       '--markdown',
315                       help='Output list in markdown format',
316                       action='store_true')
317    argsp.add_argument('-T',
318                       '--title',
319                       help='Output a title in the markdown format',
320                       action='store_true')
321    argsp.add_argument('-v',
322                       '--trace',
323                       help='Verbose or trace for debugging',
324                       action='store_true')
325    argsp.add_argument('-P',
326                       '--pairs',
327                       help='Output architectures and BSPs in CPU/BSP format',
328                       action='store_true')
329
330    argopts = argsp.parse_args(args[1:])
331
332    if argopts.arch is not None and argopts.family is not None:
333        print('error: arch or family, not both at once', file=sys.stderr)
334        sys.exit(1)
335
336    ab = ArchBsps(trace=argopts.trace)
337
338    if argopts.markdown:
339        ab.markdown(arch_selector=argopts.arch,
340                    family_selector=argopts.family,
341                    show_path=argopts.paths,
342                    show_title=argopts.title)
343    else:
344        if argopts.pairs:
345            ab.pairs(arch_selector=argopts.arch,
346                     family_selector=argopts.family,
347                     show_path=argopts.paths)
348        else:
349            ab.text(arch_selector=argopts.arch,
350                    family_selector=argopts.family,
351                    show_path=argopts.paths)
352
353    print(os.linesep.join(ab.output()))
354
355
356if __name__ == "__main__":
357    run(sys.argv)
Note: See TracBrowser for help on using the repository browser.