mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2025-11-16 12:34:45 +00:00
358 lines
14 KiB
Python
Executable File
358 lines
14 KiB
Python
Executable File
#! /usr/bin/env python
|
|
#
|
|
# RTEMS (http://www.rtems.org/)
|
|
# Copyright 2020 Chris Johns (chrisj@rtems.org)
|
|
# All rights reserved.
|
|
#
|
|
# 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.
|
|
#
|
|
|
|
from __future__ import print_function
|
|
|
|
import argparse
|
|
import os
|
|
import os.path
|
|
import sys
|
|
|
|
rtems_version = 5
|
|
|
|
|
|
class ArchBsps:
|
|
"""Collects and processes the BSPs for a range of architectures
|
|
creating output in text, markdown and HTML ir pandoc is installed"""
|
|
def __init__(self, path='.', trace=False):
|
|
self.trace = trace
|
|
self._output = []
|
|
self.top = os.path.realpath(path)
|
|
self.base = os.path.join(self.top, 'bsps')
|
|
self.configs = []
|
|
self.archs = {}
|
|
self._collect('.cfg')
|
|
self._process()
|
|
|
|
def _clear(self):
|
|
"""Clears the output."""
|
|
self._output = []
|
|
|
|
def _out(self, line=''):
|
|
"""Output a line to the output buffer."""
|
|
self._output += [line]
|
|
|
|
def _collect(self, ext):
|
|
"""Collect the config files from the source tree."""
|
|
self.configs = []
|
|
for root, dirs, files in os.walk(self.base, topdown=True):
|
|
for f in files:
|
|
if os.path.splitext(f)[1] == ext:
|
|
self.configs += [os.path.join(root, f)]
|
|
|
|
def _process(self):
|
|
"""Process the collected list of config files."""
|
|
self.archs = {}
|
|
for cfg in self.configs:
|
|
config_path = cfg[len(self.base) + 1:]
|
|
config_parts = config_path.split(os.sep)
|
|
if len(config_parts) == 4:
|
|
arch = config_parts[0]
|
|
family = config_parts[1]
|
|
bsp = os.path.splitext(config_parts[3])[0]
|
|
if arch not in self.archs:
|
|
self.archs[arch] = {}
|
|
if family not in self.archs[arch]:
|
|
self.archs[arch][family] = {}
|
|
self.archs[arch][family][bsp] = config_path
|
|
|
|
def _max_arch_len(self):
|
|
"""Finds the longest arch label"""
|
|
maxlen = 0
|
|
for arch in self.archs:
|
|
if len(arch) > maxlen:
|
|
maxlen = len(arch)
|
|
return maxlen
|
|
|
|
def _max_family_len(self):
|
|
"""Finds the longest family label"""
|
|
maxlen = 0
|
|
for arch in self.archs:
|
|
for family in self.archs[arch]:
|
|
if len(family) > maxlen:
|
|
maxlen = len(family)
|
|
return maxlen
|
|
|
|
def _max_bsp_len(self):
|
|
"""Finds the longest BSP label"""
|
|
maxlen = 0
|
|
for arch in self.archs:
|
|
for family in self.archs[arch]:
|
|
for bsp in self.archs[arch][family]:
|
|
if len(bsp) > maxlen:
|
|
maxlen = len(bsp)
|
|
return maxlen
|
|
|
|
def _max_bsp_path_len(self):
|
|
"""Finds the longest BSP path"""
|
|
maxlen = 0
|
|
for arch in self.archs:
|
|
for family in self.archs[arch]:
|
|
for bsp in self.archs[arch][family]:
|
|
if len(self.archs[arch][family][bsp]) > maxlen:
|
|
maxlen = len(self.archs[arch][family][bsp])
|
|
return maxlen
|
|
|
|
def title(self):
|
|
"""Returns the output's title"""
|
|
return 'RTEMS %d Board Support Packages' % (rtems_version)
|
|
|
|
def output(self):
|
|
"""Return the output"""
|
|
return self._output
|
|
|
|
def architectures(self):
|
|
"""Returns the number of architectures we have"""
|
|
return len(self.archs)
|
|
|
|
def families(self, arch=None):
|
|
"""Returns the number of BSP families we have for an architecture. If
|
|
you supply an architecture the count is the families in the
|
|
architure.
|
|
|
|
"""
|
|
if arch is not None:
|
|
return len(self.archs[arch])
|
|
count = 0
|
|
for arch in self.archs:
|
|
count += len(self.archs[arch])
|
|
return count
|
|
|
|
def bsps(self, arch=None, family=None):
|
|
"""Returns the number of BSPs we have for an architecture or a family"""
|
|
count = 0
|
|
if arch is not None and family is not None:
|
|
count = len(self.archs[arch][family])
|
|
elif arch is None and family is not None:
|
|
for arch in self.archs:
|
|
if family in self.archs[arch]:
|
|
count = len(self.archs[arch][family])
|
|
break
|
|
elif arch is not None and family is None:
|
|
count = 0
|
|
for family in self.archs[arch]:
|
|
count += len(self.archs[arch][family])
|
|
else:
|
|
for arch in self.archs:
|
|
for family in self.archs[arch]:
|
|
count += len(self.archs[arch][family])
|
|
return count
|
|
|
|
def text(self, arch_selector=None, family_selector=None, show_path=False):
|
|
"""Generate plain text output"""
|
|
self._clear()
|
|
self._out(self.title())
|
|
self._out()
|
|
self._out('Architectures: %d' % (self.architectures()))
|
|
self._out('BSP Families: %d' % (self.families()))
|
|
self._out('BSPs: %d' % (self.bsps()))
|
|
max_family = self._max_family_len()
|
|
max_bsp = self._max_bsp_len()
|
|
if arch_selector is None:
|
|
archs_matcher = []
|
|
else:
|
|
archs_matcher = [a.strip() for a in arch_selector.split(',')]
|
|
if family_selector is None:
|
|
family_matcher = []
|
|
else:
|
|
family_matcher = [f.strip() for f in family_selector.split(',')]
|
|
for arch in sorted(self.archs.keys()):
|
|
if arch_selector is None or arch in archs_matcher:
|
|
first = True
|
|
for family in sorted(self.archs[arch].keys()):
|
|
if family_selector is None or family in family_matcher:
|
|
if first:
|
|
self._out()
|
|
self._out('%s: (families:%d bsps:%d)' % \
|
|
(arch,
|
|
self.families(arch=arch),
|
|
self.bsps(arch=arch)))
|
|
first = False
|
|
for bsp in sorted(self.archs[arch][family].keys()):
|
|
if show_path:
|
|
p = os.path.join('bsps',
|
|
self.archs[arch][family][bsp])
|
|
self._out(' %-*s %-*s %s' % \
|
|
(max_bsp, bsp, max_family, family, p))
|
|
else:
|
|
self._out(' %-*s %s' % (max_bsp, bsp, family))
|
|
|
|
def markdown(self,
|
|
arch_selector=None,
|
|
family_selector=None,
|
|
show_path=False,
|
|
show_title=False):
|
|
"""Generates markdown output"""
|
|
self._clear()
|
|
if show_title:
|
|
self._out('# ' + self.title())
|
|
self._out()
|
|
self._out('**Architectures:** %d ' % (self.architectures()))
|
|
self._out('**BSP Families:** %d ' % (self.families()))
|
|
self._out('**BSPs:** %d ' % (self.bsps()))
|
|
max_arch = self._max_arch_len()
|
|
max_family = self._max_family_len()
|
|
max_bsp = self._max_bsp_len()
|
|
max_bsp_path = self._max_bsp_path_len() + 4
|
|
if arch_selector is None:
|
|
archs_matcher = []
|
|
else:
|
|
archs_matcher = [a.strip() for a in arch_selector.split(',')]
|
|
if family_selector is None:
|
|
family_matcher = []
|
|
else:
|
|
family_matcher = [f.strip() for f in family_selector.split(',')]
|
|
for arch in sorted(self.archs.keys()):
|
|
if arch_selector is None or arch in archs_matcher:
|
|
first = True
|
|
for family in sorted(self.archs[arch].keys()):
|
|
if family_selector is None or family in family_matcher:
|
|
if first:
|
|
fbs = 'families:%-2d bsps:%-3d' % \
|
|
(self.families(arch=arch),
|
|
self.bsps(arch=arch))
|
|
if max_family < len(fbs):
|
|
max_fb = len(fbs)
|
|
else:
|
|
max_fb = max_family
|
|
self._out()
|
|
if show_path:
|
|
self._out('%-*s |%-*s |' %
|
|
(max_bsp, arch, max_fb, fbs))
|
|
self._out('%s-|%s-|-%s' %
|
|
('-' * max_bsp, '-' * max_fb,
|
|
'-' * max_bsp_path))
|
|
else:
|
|
self._out('%-*s |%s' % (max_bsp, arch, fbs))
|
|
self._out('%s-|-%s' %
|
|
('-' * max_bsp, '-' * max_fb))
|
|
first = False
|
|
for bsp in sorted(self.archs[arch][family].keys()):
|
|
if show_path:
|
|
p = os.path.join('bsps',
|
|
self.archs[arch][family][bsp])
|
|
self._out('%-*s |%-*s |%s' % \
|
|
(max_bsp, bsp, max_fb, family, p))
|
|
else:
|
|
self._out('%-*s |%s' % (max_bsp, bsp, family))
|
|
|
|
def pairs(self, arch_selector=None, family_selector=None, show_path=False):
|
|
"""Generate output as pairs"""
|
|
self._clear()
|
|
max_arch = self._max_arch_len()
|
|
max_bsp = self._max_bsp_len()
|
|
if arch_selector is None:
|
|
arch_matcher = []
|
|
else:
|
|
arch_matcher = [a.strip() for a in arch_selector.split(',')]
|
|
if family_selector is None:
|
|
family_matcher = []
|
|
else:
|
|
family_matcher = [f.strip() for f in family_selector.split(',')]
|
|
for arch in sorted(self.archs.keys()):
|
|
if arch_selector is None or arch in arch_matcher:
|
|
for family in sorted(self.archs[arch].keys()):
|
|
if family_selector is None or family in family_matcher:
|
|
for bsp in sorted(self.archs[arch][family].keys()):
|
|
if show_path:
|
|
p = os.path.join('bsps',
|
|
self.archs[arch][family][bsp])
|
|
pair = arch + '/' + bsp
|
|
pair = '%-*s %s' % (max_arch + max_bsp + 1, pair, p)
|
|
|
|
self._out(pair)
|
|
else:
|
|
self._out('%s/%s' % (arch, bsp))
|
|
|
|
|
|
def run(args):
|
|
"""Runs the command"""
|
|
argsp = argparse.ArgumentParser(
|
|
prog='rtems-bsps',
|
|
description='List the BSP and architectures in RTEMS')
|
|
argsp.add_argument('-a',
|
|
'--arch',
|
|
help='Output the BSPs in an architecture',
|
|
type=str,
|
|
default=None)
|
|
argsp.add_argument('-f',
|
|
'--family',
|
|
help='Output the BSPs in an architecture family',
|
|
type=str,
|
|
default=None)
|
|
argsp.add_argument('-p',
|
|
'--paths',
|
|
help='Show the BSP paths in the output',
|
|
action='store_true')
|
|
argsp.add_argument('-m',
|
|
'--markdown',
|
|
help='Output list in markdown format',
|
|
action='store_true')
|
|
argsp.add_argument('-T',
|
|
'--title',
|
|
help='Output a title in the markdown format',
|
|
action='store_true')
|
|
argsp.add_argument('-v',
|
|
'--trace',
|
|
help='Verbose or trace for debugging',
|
|
action='store_true')
|
|
argsp.add_argument('-P',
|
|
'--pairs',
|
|
help='Output architectures and BSPs in CPU/BSP format',
|
|
action='store_true')
|
|
|
|
argopts = argsp.parse_args(args[1:])
|
|
|
|
if argopts.arch is not None and argopts.family is not None:
|
|
print('error: arch or family, not both at once', file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
ab = ArchBsps(trace=argopts.trace)
|
|
|
|
if argopts.markdown:
|
|
ab.markdown(arch_selector=argopts.arch,
|
|
family_selector=argopts.family,
|
|
show_path=argopts.paths,
|
|
show_title=argopts.title)
|
|
else:
|
|
if argopts.pairs:
|
|
ab.pairs(arch_selector=argopts.arch,
|
|
family_selector=argopts.family,
|
|
show_path=argopts.paths)
|
|
else:
|
|
ab.text(arch_selector=argopts.arch,
|
|
family_selector=argopts.family,
|
|
show_path=argopts.paths)
|
|
|
|
print(os.linesep.join(ab.output()))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
run(sys.argv)
|