blob: eb44be9a59a26997682008965eb7aed98216669c [file] [log] [blame]
Ole Troan6a3064f2019-05-14 13:24:10 +02001#!/usr/bin/env python3
2
3import sys
4import os
5import ipaddress
6import yaml
7from pprint import pprint
8import re
9from jsonschema import validate
10import argparse
11from subprocess import run, PIPE
12
13# VPP feature JSON schema
14schema = {
15 "$schema": "http://json-schema.org/schema#",
16 "type": "object",
17 "properties": {
18 "name": {"type": "string"},
Paul Vinciguerraea1a6512019-11-01 02:34:32 -040019 "description": {"type": "string"},
20 "maintainer": {"type": "string"},
Ole Troan6a3064f2019-05-14 13:24:10 +020021 "state": {"type": "string",
22 "enum": ["production", "experimental"]},
Paul Vinciguerraea1a6512019-11-01 02:34:32 -040023 "features": {"$ref": "#/definitions/features"},
24 "missing": {"$ref": "#/definitions/features"},
25 "properties": {"type": "array",
26 "items": {"type": "string",
27 "enum": ["API", "CLI", "STATS",
28 "MULTITHREAD"]},
Ole Troan6a3064f2019-05-14 13:24:10 +020029 },
30 },
31 "additionalProperties": False,
32 "definitions": {
33 "featureobject": {
34 "type": "object",
35 "patternProperties": {
Paul Vinciguerraea1a6512019-11-01 02:34:32 -040036 "^.*$": {"$ref": "#/definitions/features"},
Ole Troan6a3064f2019-05-14 13:24:10 +020037 },
38 },
39 "features": {
40 "type": "array",
Paul Vinciguerraea1a6512019-11-01 02:34:32 -040041 "items": {"anyOf": [{"$ref": "#/definitions/featureobject"},
42 {"type": "string"},
43 ]},
Ole Troan6a3064f2019-05-14 13:24:10 +020044 "minItems": 1,
45 },
46 },
47}
48
49
Ole Troan6a3064f2019-05-14 13:24:10 +020050def filelist_from_git_status():
51 filelist = []
52 git_status = 'git status --porcelain */FEATURE.yaml'
53 rv = run(git_status.split(), stdout=PIPE, stderr=PIPE)
54 if rv.returncode != 0:
55 sys.exit(rv.returncode)
56
57 for l in rv.stdout.decode('ascii').split('\n'):
58 if len(l):
59 filelist.append(l.split()[1])
60 return filelist
61
Paul Vinciguerraea1a6512019-11-01 02:34:32 -040062
Ole Troan6a3064f2019-05-14 13:24:10 +020063def filelist_from_git_ls():
64 filelist = []
65 git_ls = 'git ls-files :(top)*/FEATURE.yaml'
66 rv = run(git_ls.split(), stdout=PIPE, stderr=PIPE)
67 if rv.returncode != 0:
68 sys.exit(rv.returncode)
69
70 for l in rv.stdout.decode('ascii').split('\n'):
71 if len(l):
72 filelist.append(l)
73 return filelist
74
Paul Vinciguerraea1a6512019-11-01 02:34:32 -040075
Ole Troan6a3064f2019-05-14 13:24:10 +020076def output_features(indent, fl):
77 for f in fl:
78 if type(f) is dict:
Paul Vinciguerraea1a6512019-11-01 02:34:32 -040079 for k, v in f.items():
Ole Troan6a3064f2019-05-14 13:24:10 +020080 print('{}- {}'.format(' ' * indent, k))
81 output_features(indent + 2, v)
82 else:
83 print('{}- {}'.format(' ' * indent, f))
84
Paul Vinciguerraea1a6512019-11-01 02:34:32 -040085
Ole Troan6a3064f2019-05-14 13:24:10 +020086def output_markdown(features):
Paul Vinciguerraea1a6512019-11-01 02:34:32 -040087 for k, v in features.items():
Ole Troan6a3064f2019-05-14 13:24:10 +020088 print('# {}'.format(v['name']))
89 print('Maintainer: {} '.format(v['maintainer']))
90 print('State: {}\n'.format(v['state']))
91 print('{}\n'.format(v['description']))
92 output_features(0, v['features'])
93 if 'missing' in v:
94 print('\n## Missing')
95 output_features(0, v['missing'])
96 print()
97
Paul Vinciguerraea1a6512019-11-01 02:34:32 -040098
Ole Troan6a3064f2019-05-14 13:24:10 +020099def main():
100 parser = argparse.ArgumentParser(description='VPP Feature List.')
101 parser.add_argument('--validate', dest='validate', action='store_true',
102 help='validate the FEATURE.yaml file')
103 parser.add_argument('--git-status', dest='git_status', action='store_true',
104 help='Get filelist from git status')
105 parser.add_argument('--all', dest='all', action='store_true',
106 help='Validate all files in repository')
107 parser.add_argument('--markdown', dest='markdown', action='store_true',
108 help='Output feature table in markdown')
109 parser.add_argument('infile', nargs='?', type=argparse.FileType('r'),
110 default=sys.stdin)
111 args = parser.parse_args()
112
113 features = {}
114
115 if args.git_status:
116 filelist = filelist_from_git_status()
117 elif args.all:
118 filelist = filelist_from_git_ls()
119 else:
120 filelist = args.infile
121
122 for featurefile in filelist:
123 featurefile = featurefile.rstrip()
124
125 # Load configuration file
126 with open(featurefile) as f:
Paul Vinciguerraea1a6512019-11-01 02:34:32 -0400127 cfg = yaml.load(f, Loader=yaml.SafeLoader)
Ole Troan6a3064f2019-05-14 13:24:10 +0200128 validate(instance=cfg, schema=schema)
129 features[featurefile] = cfg
130
131 if args.markdown:
132 output_markdown(features)
133
Paul Vinciguerraea1a6512019-11-01 02:34:32 -0400134
Ole Troan6a3064f2019-05-14 13:24:10 +0200135if __name__ == '__main__':
136 main()