source: rtems/rtems-bsps

Last change on this file was f767355d, checked in by Chris Johns <chrisj@…>, on May 1, 2020 at 7:52:42 AM

rtems-bsps: Add markdown support

  • Convert to python for better performance
  • Property mode set to 100755
File size: 12.3 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 = 5
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
266def run(args):
267    """Runs the command"""
268    argsp = argparse.ArgumentParser(
269        prog='rtems-bsps',
270        description='List the BSP and architectures in RTEMS')
271    argsp.add_argument('-a',
272                       '--arch',
273                       help='Output the BSPs in an architecture',
274                       type=str,
275                       default=None)
276    argsp.add_argument('-f',
277                       '--family',
278                       help='Output the BSPs in an architecture family',
279                       type=str,
280                       default=None)
281    argsp.add_argument('-p',
282                       '--paths',
283                       help='Show the BSP paths in the output',
284                       action='store_true')
285    argsp.add_argument('-m',
286                       '--markdown',
287                       help='Output list in markdown format',
288                       action='store_true')
289    argsp.add_argument('-T',
290                       '--title',
291                       help='Output a title in the markdown format',
292                       action='store_true')
293    argsp.add_argument('-v',
294                       '--trace',
295                       help='Verbose or trace for debugging',
296                       action='store_true')
297
298    argopts = argsp.parse_args(args[1:])
299
300    if argopts.arch is not None and argopts.family is not None:
301        print('error: arch or family, not both at once', file=sys.stderr)
302        sys.exit(1)
303
304    ab = ArchBsps(trace=argopts.trace)
305
306    if argopts.markdown:
307        ab.markdown(arch_selector=argopts.arch,
308                    family_selector=argopts.family,
309                    show_path=argopts.paths,
310                    show_title=argopts.title)
311    else:
312        ab.text(arch_selector=argopts.arch,
313                family_selector=argopts.family,
314                show_path=argopts.paths)
315
316    print(os.linesep.join(ab.output()))
317
318
319if __name__ == "__main__":
320    run(sys.argv)
Note: See TracBrowser for help on using the repository browser.