blob: 13182421f8fca241ce636cde0a81717863735751 [file] [log] [blame]
Matteo Scandolod2044a42017-08-07 16:08:28 -07001# Copyright 2017-present Open Networking Foundation
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15
Matteo Scandolo67654fa2017-06-09 09:33:17 -070016#!/usr/bin/python
17
Zack Williams045b63d2019-01-22 16:30:57 -070018from __future__ import print_function
Matteo Scandolo67654fa2017-06-09 09:33:17 -070019import argparse
20from generator import *
Scott Bakerd0d35662018-03-26 09:58:07 -070021from version import __version__
Matteo Scandolo67654fa2017-06-09 09:33:17 -070022
Zack Williams045b63d2019-01-22 16:30:57 -070023parse = argparse.ArgumentParser(description="XOS Generative Toolchain")
24parse.add_argument(
25 "--rev",
26 dest="rev",
27 action="store_true",
28 default=XOSProcessorArgs.default_rev,
29 help="Convert proto to xproto",
30)
31parse.add_argument(
32 "--output",
33 dest="output",
34 action="store",
35 default=XOSProcessorArgs.default_output,
36 help="Destination dir",
37)
38parse.add_argument(
39 "--attic",
40 dest="attic",
41 action="store",
42 default=XOSProcessorArgs.default_attic,
43 help="The location at which static files are stored",
44)
45parse.add_argument(
46 "--kvpairs",
47 dest="kv",
48 action="store",
49 default=XOSProcessorArgs.default_kvpairs,
50 help="Key value pairs to make available to the target",
51)
52parse.add_argument(
53 "--write-to-file",
54 dest="write_to_file",
55 choices=["single", "model", "target"],
56 action="store",
57 default=XOSProcessorArgs.default_write_to_file,
58 help="Single output file (single) or output file per model (model) or let target decide (target)",
59)
60parse.add_argument("--version", action="version", version=__version__)
61parse.add_argument(
62 "-v",
63 "--verbosity",
64 action="count",
65 default=XOSProcessorArgs.default_verbosity,
66 help="increase output verbosity",
67)
68parse.add_argument(
69 "--include-models",
70 dest="include_models",
71 action="append",
72 default=XOSProcessorArgs.default_include_models,
73 help="list of models to include",
74)
75parse.add_argument(
76 "--include-apps",
77 dest="include_apps",
78 action="append",
79 default=XOSProcessorArgs.default_include_apps,
80 help="list of models to include",
81)
Matteo Scandolo67654fa2017-06-09 09:33:17 -070082
83group = parse.add_mutually_exclusive_group()
Zack Williams045b63d2019-01-22 16:30:57 -070084group.add_argument(
85 "--dest-file",
86 dest="dest_file",
87 action="store",
88 default=XOSProcessorArgs.default_dest_file,
89 help="Output file name (if write-to-file is set to single)",
90)
91group.add_argument(
92 "--dest-extension",
93 dest="dest_extension",
94 action="store",
95 default=XOSProcessorArgs.default_dest_extension,
96 help="Output file extension (if write-to-file is set to single)",
97)
Matteo Scandolo67654fa2017-06-09 09:33:17 -070098
Sapan Bhatiabfb233a2018-02-09 14:53:09 -080099group = parse.add_mutually_exclusive_group(required=True)
Zack Williams045b63d2019-01-22 16:30:57 -0700100group.add_argument(
101 "--target",
102 dest="target",
103 action="store",
104 default=XOSProcessorArgs.default_target,
105 help="Output format, corresponding to <output>.yaml file",
106)
107group.add_argument(
108 "--checkers",
109 dest="checkers",
110 action="store",
111 default=XOSProcessorArgs.default_checkers,
112 help="Comma-separated list of static checkers",
113)
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800114
Zack Williams045b63d2019-01-22 16:30:57 -0700115parse.add_argument(
116 "files",
117 metavar="<input file>",
118 nargs="+",
119 action="store",
120 help="xproto files to compile",
121)
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700122
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800123CHECK = 1
124GEN = 2
125
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700126
Zack Williams045b63d2019-01-22 16:30:57 -0700127class XosGen:
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700128 @staticmethod
129 def init(args=None):
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700130 if not args:
131 args = parse.parse_args()
132
133 args.quiet = False
134
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800135 if args.target:
136 op = GEN
Zack Williams045b63d2019-01-22 16:30:57 -0700137 subdir = "/targets/"
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800138 elif args.checkers:
139 op = CHECK
Zack Williams045b63d2019-01-22 16:30:57 -0700140 subdir = "/checkers/"
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800141 else:
142 parse.error("At least one of --target and --checkers is required")
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700143
Zack Williams045b63d2019-01-22 16:30:57 -0700144 operators = (
145 args.checkers.split(",")
146 if hasattr(args, "checkers") and args.checkers
147 else [args.target]
148 )
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700149
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800150 for i in xrange(len(operators)):
Zack Williams045b63d2019-01-22 16:30:57 -0700151 if "/" not in operators[i]:
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800152 # if the target is not a path, it refer to a library included one
Zack Williams045b63d2019-01-22 16:30:57 -0700153 operators[i] = os.path.abspath(
154 os.path.dirname(os.path.realpath(__file__)) + subdir + operators[i]
155 )
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700156
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800157 if not os.path.isabs(operators[i]):
Zack Williams045b63d2019-01-22 16:30:57 -0700158 operators[i] = os.path.abspath(os.getcwd() + "/" + operators[i])
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700159
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800160 if op == GEN:
161 # convert output to absolute path
162 if args.output is not None and not os.path.isabs(args.output):
Zack Williams045b63d2019-01-22 16:30:57 -0700163 args.output = os.path.abspath(os.getcwd() + "/" + args.output)
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700164
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800165 operator = operators[0]
Zack Williams045b63d2019-01-22 16:30:57 -0700166
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800167 # check if there's a line that starts with +++ in the target
168 # if so, then the output file names are left to the target to decide
169 # also, if dest-file or dest-extension are supplied, then an error is generated.
Zack Williams045b63d2019-01-22 16:30:57 -0700170 plusplusplus = reduce(
171 lambda acc, line: True if line.startswith("+++") else acc,
172 open(operator).read().splitlines(),
173 False,
174 )
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800175
Zack Williams045b63d2019-01-22 16:30:57 -0700176 if plusplusplus and args.write_to_file != "target":
177 parse.error(
178 '%s chooses the names of the files that it generates, you must set --write-to-file to "target"'
179 % operator
180 )
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800181
Zack Williams045b63d2019-01-22 16:30:57 -0700182 if args.write_to_file != "single" and (args.dest_file):
183 parse.error(
184 '--dest-file requires --write-to-file to be set to "single"'
185 )
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800186
Zack Williams045b63d2019-01-22 16:30:57 -0700187 if args.write_to_file != "model" and (args.dest_extension):
188 parse.error(
189 '--dest-extension requires --write-to-file to be set to "model"'
190 )
191
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800192 else:
193 if args.write_to_file or args.dest_extension:
Zack Williams045b63d2019-01-22 16:30:57 -0700194 parse.error("Checkers cannot write to files")
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700195
196 inputs = []
197
198 for fname in args.files:
199 if not os.path.isabs(fname):
Zack Williams045b63d2019-01-22 16:30:57 -0700200 inputs.append(os.path.abspath(os.getcwd() + "/" + fname))
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700201 else:
202 inputs.append(fname)
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800203
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700204 args.files = inputs
205
Zack Williams045b63d2019-01-22 16:30:57 -0700206 if op == GEN:
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800207 generated = XOSProcessor.process(args, operators[0])
208 if not args.output and not args.write_to_file:
Zack Williams045b63d2019-01-22 16:30:57 -0700209 print(generated)
210 elif op == CHECK:
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800211 for o in operators:
212 verdict_str = XOSProcessor.process(args, o)
Zack Williams045b63d2019-01-22 16:30:57 -0700213 vlst = verdict_str.split("\n")
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700214
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800215 try:
216 verdict = next(v for v in vlst if v.strip())
Zack Williams045b63d2019-01-22 16:30:57 -0700217 status_code, status_string = verdict.split(" ", 1)
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800218 status_code = int(status_code)
Zack Williams045b63d2019-01-22 16:30:57 -0700219 except BaseException:
220 print("Checker %s returned mangled output" % o)
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800221 exit(1)
222
223 if status_code != 200:
Zack Williams045b63d2019-01-22 16:30:57 -0700224 print("%s: %s - %s" % (o, status_code, status_string))
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800225 exit(1)
226 else:
Zack Williams045b63d2019-01-22 16:30:57 -0700227 print("%s: OK" % o)