blob: 608cae7aa35b2064ef5d414ab7e553414a5a5658 [file] [log] [blame]
Zack Williams9a42f872019-02-15 17:56:04 -07001#!/usr/bin/env python
2
Matteo Scandolod2044a42017-08-07 16:08:28 -07003# Copyright 2017-present Open Networking Foundation
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
Zack Williams9a42f872019-02-15 17:56:04 -070017from __future__ import absolute_import, print_function
Matteo Scandolod2044a42017-08-07 16:08:28 -070018
Matteo Scandolo67654fa2017-06-09 09:33:17 -070019import argparse
Zack Williams9a42f872019-02-15 17:56:04 -070020import os
21from functools import reduce
22
23from six.moves import range
24
25from .generator import XOSProcessor, XOSProcessorArgs
26from .version import __version__
Matteo Scandolo67654fa2017-06-09 09:33:17 -070027
Zack Williams045b63d2019-01-22 16:30:57 -070028parse = argparse.ArgumentParser(description="XOS Generative Toolchain")
29parse.add_argument(
30 "--rev",
31 dest="rev",
32 action="store_true",
33 default=XOSProcessorArgs.default_rev,
34 help="Convert proto to xproto",
35)
36parse.add_argument(
37 "--output",
38 dest="output",
39 action="store",
40 default=XOSProcessorArgs.default_output,
41 help="Destination dir",
42)
43parse.add_argument(
44 "--attic",
45 dest="attic",
46 action="store",
47 default=XOSProcessorArgs.default_attic,
48 help="The location at which static files are stored",
49)
50parse.add_argument(
51 "--kvpairs",
52 dest="kv",
53 action="store",
54 default=XOSProcessorArgs.default_kvpairs,
55 help="Key value pairs to make available to the target",
56)
57parse.add_argument(
58 "--write-to-file",
59 dest="write_to_file",
60 choices=["single", "model", "target"],
61 action="store",
62 default=XOSProcessorArgs.default_write_to_file,
63 help="Single output file (single) or output file per model (model) or let target decide (target)",
64)
65parse.add_argument("--version", action="version", version=__version__)
66parse.add_argument(
67 "-v",
68 "--verbosity",
69 action="count",
70 default=XOSProcessorArgs.default_verbosity,
71 help="increase output verbosity",
72)
73parse.add_argument(
74 "--include-models",
75 dest="include_models",
76 action="append",
77 default=XOSProcessorArgs.default_include_models,
78 help="list of models to include",
79)
80parse.add_argument(
81 "--include-apps",
82 dest="include_apps",
83 action="append",
84 default=XOSProcessorArgs.default_include_apps,
85 help="list of models to include",
86)
Matteo Scandolo67654fa2017-06-09 09:33:17 -070087
88group = parse.add_mutually_exclusive_group()
Zack Williams045b63d2019-01-22 16:30:57 -070089group.add_argument(
90 "--dest-file",
91 dest="dest_file",
92 action="store",
93 default=XOSProcessorArgs.default_dest_file,
94 help="Output file name (if write-to-file is set to single)",
95)
96group.add_argument(
97 "--dest-extension",
98 dest="dest_extension",
99 action="store",
100 default=XOSProcessorArgs.default_dest_extension,
101 help="Output file extension (if write-to-file is set to single)",
102)
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700103
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800104group = parse.add_mutually_exclusive_group(required=True)
Zack Williams045b63d2019-01-22 16:30:57 -0700105group.add_argument(
106 "--target",
107 dest="target",
108 action="store",
109 default=XOSProcessorArgs.default_target,
110 help="Output format, corresponding to <output>.yaml file",
111)
112group.add_argument(
113 "--checkers",
114 dest="checkers",
115 action="store",
116 default=XOSProcessorArgs.default_checkers,
117 help="Comma-separated list of static checkers",
118)
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800119
Zack Williams045b63d2019-01-22 16:30:57 -0700120parse.add_argument(
121 "files",
122 metavar="<input file>",
123 nargs="+",
124 action="store",
125 help="xproto files to compile",
126)
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700127
Scott Baker7ae3a8f2019-03-05 16:24:14 -0800128parse.add_argument(
129 "--strict-validation",
130 dest="strict_validation",
131 action="store_true",
132 default=XOSProcessorArgs.default_strict_validation,
133 help="Exit if validation fails",
134)
135
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800136CHECK = 1
137GEN = 2
138
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700139
Zack Williams045b63d2019-01-22 16:30:57 -0700140class XosGen:
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700141 @staticmethod
142 def init(args=None):
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700143 if not args:
144 args = parse.parse_args()
145
146 args.quiet = False
147
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800148 if args.target:
149 op = GEN
Zack Williams045b63d2019-01-22 16:30:57 -0700150 subdir = "/targets/"
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800151 elif args.checkers:
152 op = CHECK
Zack Williams045b63d2019-01-22 16:30:57 -0700153 subdir = "/checkers/"
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800154 else:
155 parse.error("At least one of --target and --checkers is required")
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700156
Zack Williams045b63d2019-01-22 16:30:57 -0700157 operators = (
158 args.checkers.split(",")
159 if hasattr(args, "checkers") and args.checkers
160 else [args.target]
161 )
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700162
Zack Williams9a42f872019-02-15 17:56:04 -0700163 for i in range(len(operators)):
Zack Williams045b63d2019-01-22 16:30:57 -0700164 if "/" not in operators[i]:
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800165 # if the target is not a path, it refer to a library included one
Zack Williams045b63d2019-01-22 16:30:57 -0700166 operators[i] = os.path.abspath(
167 os.path.dirname(os.path.realpath(__file__)) + subdir + operators[i]
168 )
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700169
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800170 if not os.path.isabs(operators[i]):
Zack Williams045b63d2019-01-22 16:30:57 -0700171 operators[i] = os.path.abspath(os.getcwd() + "/" + operators[i])
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700172
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800173 if op == GEN:
174 # convert output to absolute path
175 if args.output is not None and not os.path.isabs(args.output):
Zack Williams045b63d2019-01-22 16:30:57 -0700176 args.output = os.path.abspath(os.getcwd() + "/" + args.output)
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700177
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800178 operator = operators[0]
Zack Williams045b63d2019-01-22 16:30:57 -0700179
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800180 # check if there's a line that starts with +++ in the target
181 # if so, then the output file names are left to the target to decide
182 # also, if dest-file or dest-extension are supplied, then an error is generated.
Zack Williams045b63d2019-01-22 16:30:57 -0700183 plusplusplus = reduce(
184 lambda acc, line: True if line.startswith("+++") else acc,
185 open(operator).read().splitlines(),
186 False,
187 )
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800188
Zack Williams045b63d2019-01-22 16:30:57 -0700189 if plusplusplus and args.write_to_file != "target":
190 parse.error(
191 '%s chooses the names of the files that it generates, you must set --write-to-file to "target"'
192 % operator
193 )
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800194
Zack Williams045b63d2019-01-22 16:30:57 -0700195 if args.write_to_file != "single" and (args.dest_file):
196 parse.error(
197 '--dest-file requires --write-to-file to be set to "single"'
198 )
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800199
Zack Williams045b63d2019-01-22 16:30:57 -0700200 if args.write_to_file != "model" and (args.dest_extension):
201 parse.error(
202 '--dest-extension requires --write-to-file to be set to "model"'
203 )
204
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800205 else:
206 if args.write_to_file or args.dest_extension:
Zack Williams045b63d2019-01-22 16:30:57 -0700207 parse.error("Checkers cannot write to files")
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700208
209 inputs = []
210
211 for fname in args.files:
212 if not os.path.isabs(fname):
Zack Williams045b63d2019-01-22 16:30:57 -0700213 inputs.append(os.path.abspath(os.getcwd() + "/" + fname))
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700214 else:
215 inputs.append(fname)
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800216
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700217 args.files = inputs
218
Zack Williams045b63d2019-01-22 16:30:57 -0700219 if op == GEN:
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800220 generated = XOSProcessor.process(args, operators[0])
221 if not args.output and not args.write_to_file:
Zack Williams045b63d2019-01-22 16:30:57 -0700222 print(generated)
223 elif op == CHECK:
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800224 for o in operators:
225 verdict_str = XOSProcessor.process(args, o)
Zack Williams045b63d2019-01-22 16:30:57 -0700226 vlst = verdict_str.split("\n")
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700227
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800228 try:
229 verdict = next(v for v in vlst if v.strip())
Zack Williams045b63d2019-01-22 16:30:57 -0700230 status_code, status_string = verdict.split(" ", 1)
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800231 status_code = int(status_code)
Zack Williams045b63d2019-01-22 16:30:57 -0700232 except BaseException:
233 print("Checker %s returned mangled output" % o)
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800234 exit(1)
235
236 if status_code != 200:
Zack Williams045b63d2019-01-22 16:30:57 -0700237 print("%s: %s - %s" % (o, status_code, status_string))
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800238 exit(1)
239 else:
Zack Williams045b63d2019-01-22 16:30:57 -0700240 print("%s: OK" % o)