aboutsummaryrefslogtreecommitdiffstats
path: root/src/scripts/fts.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/scripts/fts.py')
-rwxr-xr-xsrc/scripts/fts.py224
1 files changed, 136 insertions, 88 deletions
diff --git a/src/scripts/fts.py b/src/scripts/fts.py
index b579190e433..e8ff477c788 100755
--- a/src/scripts/fts.py
+++ b/src/scripts/fts.py
@@ -2,6 +2,7 @@
import sys
import os
+import os.path
import ipaddress
import yaml
from pprint import pprint
@@ -10,6 +11,7 @@ from jsonschema import validate, exceptions
import argparse
from subprocess import run, PIPE
from io import StringIO
+import urllib.parse
# VPP feature JSON schema
schema = {
@@ -19,25 +21,28 @@ schema = {
"name": {"type": "string"},
"description": {"type": "string"},
"maintainer": {"$ref": "#/definitions/maintainers"},
- "state": {"type": "string",
- "enum": ["production", "experimental", "development"]},
+ "state": {
+ "type": "string",
+ "enum": ["production", "experimental", "development"],
+ },
"features": {"$ref": "#/definitions/features"},
"missing": {"$ref": "#/definitions/features"},
- "properties": {"type": "array",
- "items": {"type": "string",
- "enum": ["API", "CLI", "STATS",
- "MULTITHREAD"]},
- },
+ "properties": {
+ "type": "array",
+ "items": {"type": "string", "enum": ["API", "CLI", "STATS", "MULTITHREAD"]},
+ },
},
"additionalProperties": False,
"definitions": {
"maintainers": {
- "anyof": [{
- "type": "array",
- "items": {"type": "string"},
- "minItems": 1,
- },
- {"type": "string"}],
+ "anyof": [
+ {
+ "type": "array",
+ "items": {"type": "string"},
+ "minItems": 1,
+ },
+ {"type": "string"},
+ ],
},
"featureobject": {
"type": "object",
@@ -47,23 +52,28 @@ schema = {
},
"features": {
"type": "array",
- "items": {"anyOf": [{"$ref": "#/definitions/featureobject"},
- {"type": "string"},
- ]},
+ "items": {
+ "anyOf": [
+ {"$ref": "#/definitions/featureobject"},
+ {"type": "string"},
+ ]
+ },
"minItems": 1,
},
},
}
+DEFAULT_REPO_LINK = "https://github.com/FDio/vpp/blob/master/"
+
def filelist_from_git_status():
filelist = []
- git_status = 'git status --porcelain */FEATURE*.yaml'
+ git_status = "git status --porcelain */FEATURE*.yaml"
rv = run(git_status.split(), stdout=PIPE, stderr=PIPE)
if rv.returncode != 0:
sys.exit(rv.returncode)
- for l in rv.stdout.decode('ascii').split('\n'):
+ for l in rv.stdout.decode("ascii").split("\n"):
if len(l):
filelist.append(l.split()[1])
return filelist
@@ -71,24 +81,26 @@ def filelist_from_git_status():
def filelist_from_git_ls():
filelist = []
- git_ls = 'git ls-files :(top)*/FEATURE*.yaml'
+ git_ls = "git ls-files :(top)*/FEATURE*.yaml"
rv = run(git_ls.split(), stdout=PIPE, stderr=PIPE)
if rv.returncode != 0:
sys.exit(rv.returncode)
- for l in rv.stdout.decode('ascii').split('\n'):
+ for l in rv.stdout.decode("ascii").split("\n"):
if len(l):
filelist.append(l)
return filelist
+
def version_from_git():
- git_describe = 'git describe'
+ git_describe = "git describe"
rv = run(git_describe.split(), stdout=PIPE, stderr=PIPE)
if rv.returncode != 0:
sys.exit(rv.returncode)
- return rv.stdout.decode('ascii').split('\n')[0]
+ return rv.stdout.decode("ascii").split("\n")[0]
+
-class MarkDown():
+class MarkDown:
_dispatch = {}
def __init__(self, stream):
@@ -98,105 +110,115 @@ class MarkDown():
def print_maintainer(self, o):
write = self.stream.write
if type(o) is list:
- write('Maintainers: ' +
- ', '.join('{m}'.format(m=m) for m in
- o) + ' \n')
+ write("Maintainers: " + ", ".join("{m}".format(m=m) for m in o) + " \n")
else:
- write('Maintainer: {o} \n'.format(o=o))
+ write("Maintainer: {o} \n".format(o=o))
- _dispatch['maintainer'] = print_maintainer
+ _dispatch["maintainer"] = print_maintainer
def print_features(self, o, indent=0):
write = self.stream.write
for f in o:
- indentstr = ' ' * indent
+ indentstr = " " * indent
if type(f) is dict:
for k, v in f.items():
- write('{indentstr}- {k}\n'.format(indentstr=indentstr, k=k))
+ write("{indentstr}- {k}\n".format(indentstr=indentstr, k=k))
self.print_features(v, indent + 2)
else:
- write('{indentstr}- {f}\n'.format(indentstr=indentstr, f=f))
- write('\n')
- _dispatch['features'] = print_features
+ write("{indentstr}- {f}\n".format(indentstr=indentstr, f=f))
+ write("\n")
+
+ _dispatch["features"] = print_features
def print_markdown_header(self, o):
write = self.stream.write
- write('## {o}\n'.format(o=o))
- version = version_from_git()
- write('VPP version: {version}\n\n'.format(version=version))
- _dispatch['markdown_header'] = print_markdown_header
+ write("## {o}\n".format(o=o))
+
+ _dispatch["markdown_header"] = print_markdown_header
def print_name(self, o):
write = self.stream.write
- write('### {o}\n'.format(o=o))
+ write("### {o}\n".format(o=o))
self.toc.append(o)
- _dispatch['name'] = print_name
+
+ _dispatch["name"] = print_name
def print_description(self, o):
write = self.stream.write
- write('\n{o}\n\n'.format(o=o))
- _dispatch['description'] = print_description
+ write("\n{o}\n\n".format(o=o))
+
+ _dispatch["description"] = print_description
def print_state(self, o):
write = self.stream.write
- write('Feature maturity level: {o} \n'.format(o=o))
- _dispatch['state'] = print_state
+ write("Feature maturity level: {o} \n".format(o=o))
+
+ _dispatch["state"] = print_state
def print_properties(self, o):
write = self.stream.write
- write('Supports: {s} \n'.format(s=" ".join(o)))
- _dispatch['properties'] = print_properties
+ write("Supports: {s} \n".format(s=" ".join(o)))
+
+ _dispatch["properties"] = print_properties
def print_missing(self, o):
write = self.stream.write
- write('\nNot yet implemented: \n')
+ write("\nNot yet implemented: \n")
self.print_features(o)
- _dispatch['missing'] = print_missing
+
+ _dispatch["missing"] = print_missing
def print_code(self, o):
write = self.stream.write
- write('Source Code: [{o}]({o}) \n'.format(o=o))
- _dispatch['code'] = print_code
+ write("Source Code: [{o}]({o}) \n".format(o=o))
+
+ _dispatch["code"] = print_code
def print(self, t, o):
write = self.stream.write
if t in self._dispatch:
- self._dispatch[t](self, o,)
+ self._dispatch[t](
+ self,
+ o,
+ )
else:
- write('NOT IMPLEMENTED: {t}\n')
+ write("NOT IMPLEMENTED: {t}\n")
+
def output_toc(toc, stream):
write = stream.write
- write('## VPP Feature list:\n')
+ write("# VPP Supported Features\n")
for t in toc:
- ref = t.lower().replace(' ', '-')
- write('[{t}](#{ref}) \n'.format(t=t, ref=ref))
+ ref = t.lower().replace(" ", "-")
+ write("[{t}](#{ref}) \n".format(t=t, ref=ref))
+
def featuresort(k):
- return k[1]['name']
+ return k[1]["name"]
+
def featurelistsort(k):
orderedfields = {
- 'name': 0,
- 'maintainer': 1,
- 'description': 2,
- 'features': 3,
- 'state': 4,
- 'properties': 5,
- 'missing': 6,
- 'code': 7,
+ "name": 0,
+ "maintainer": 1,
+ "description": 2,
+ "features": 3,
+ "state": 4,
+ "properties": 5,
+ "missing": 6,
+ "code": 7,
}
return orderedfields[k[0]]
-def output_markdown(features, fields, notfields):
+
+def output_markdown(features, fields, notfields, repository_url):
stream = StringIO()
m = MarkDown(stream)
- m.print('markdown_header', 'Feature Details:')
+ m.print("markdown_header", "Feature Details:")
for path, featuredef in sorted(features.items(), key=featuresort):
- codeurl = 'https://git.fd.io/vpp/tree/src/' + \
- '/'.join(os.path.normpath(path).split('/')[1:-1])
- featuredef['code'] = codeurl
+ codeurl = urllib.parse.urljoin(repository_url, os.path.dirname(path))
+ featuredef["code"] = codeurl
for k, v in sorted(featuredef.items(), key=featurelistsort):
if notfields:
if k not in notfields:
@@ -211,21 +233,45 @@ def output_markdown(features, fields, notfields):
output_toc(m.toc, tocstream)
return tocstream, stream
+
def main():
- parser = argparse.ArgumentParser(description='VPP Feature List.')
- parser.add_argument('--validate', dest='validate', action='store_true',
- help='validate the FEATURE.yaml file')
- parser.add_argument('--git-status', dest='git_status', action='store_true',
- help='Get filelist from git status')
- parser.add_argument('--all', dest='all', action='store_true',
- help='Validate all files in repository')
- parser.add_argument('--markdown', dest='markdown', action='store_true',
- help='Output feature table in markdown')
- parser.add_argument('infile', nargs='?', type=argparse.FileType('r'),
- default=sys.stdin)
+ parser = argparse.ArgumentParser(description="VPP Feature List.")
+ parser.add_argument(
+ "--validate",
+ dest="validate",
+ action="store_true",
+ help="validate the FEATURE.yaml file",
+ )
+ parser.add_argument(
+ "--repolink",
+ metavar="repolink",
+ default=DEFAULT_REPO_LINK,
+ help="Link to public repository [%s]" % DEFAULT_REPO_LINK,
+ )
+ parser.add_argument(
+ "--git-status",
+ dest="git_status",
+ action="store_true",
+ help="Get filelist from git status",
+ )
+ parser.add_argument(
+ "--all",
+ dest="all",
+ action="store_true",
+ help="Validate all files in repository",
+ )
+ parser.add_argument(
+ "--markdown",
+ dest="markdown",
+ action="store_true",
+ help="Output feature table in markdown",
+ )
+ parser.add_argument(
+ "infile", nargs="?", type=argparse.FileType("r"), default=sys.stdin
+ )
group = parser.add_mutually_exclusive_group()
- group.add_argument('--include', help='List of fields to include')
- group.add_argument('--exclude', help='List of fields to exclude')
+ group.add_argument("--include", help="List of fields to include")
+ group.add_argument("--exclude", help="List of fields to exclude")
args = parser.parse_args()
features = {}
@@ -237,11 +283,11 @@ def main():
filelist = args.infile
if args.include:
- fields = args.include.split(',')
+ fields = args.include.split(",")
else:
fields = []
if args.exclude:
- notfields = args.exclude.split(',')
+ notfields = args.exclude.split(",")
else:
notfields = []
@@ -249,23 +295,25 @@ def main():
featurefile = featurefile.rstrip()
# Load configuration file
- with open(featurefile, encoding='utf-8') as f:
+ with open(featurefile, encoding="utf-8") as f:
cfg = yaml.load(f, Loader=yaml.SafeLoader)
try:
validate(instance=cfg, schema=schema)
except exceptions.ValidationError:
- print('File does not validate: {featurefile}' \
- .format(featurefile=featurefile), file=sys.stderr)
+ print(
+ "File does not validate: {featurefile}".format(featurefile=featurefile),
+ file=sys.stderr,
+ )
raise
features[featurefile] = cfg
if args.markdown:
stream = StringIO()
- tocstream, stream = output_markdown(features, fields, notfields)
+ tocstream, stream = output_markdown(features, fields, notfields, args.repolink)
print(tocstream.getvalue())
print(stream.getvalue())
stream.close()
-if __name__ == '__main__':
+if __name__ == "__main__":
main()