blob: 2da8962d3bdc2a657bcb90bf926d08290964d82f [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
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800128CHECK = 1
129GEN = 2
130
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700131
Zack Williams045b63d2019-01-22 16:30:57 -0700132class XosGen:
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700133 @staticmethod
134 def init(args=None):
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700135 if not args:
136 args = parse.parse_args()
137
138 args.quiet = False
139
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800140 if args.target:
141 op = GEN
Zack Williams045b63d2019-01-22 16:30:57 -0700142 subdir = "/targets/"
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800143 elif args.checkers:
144 op = CHECK
Zack Williams045b63d2019-01-22 16:30:57 -0700145 subdir = "/checkers/"
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800146 else:
147 parse.error("At least one of --target and --checkers is required")
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700148
Zack Williams045b63d2019-01-22 16:30:57 -0700149 operators = (
150 args.checkers.split(",")
151 if hasattr(args, "checkers") and args.checkers
152 else [args.target]
153 )
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700154
Zack Williams9a42f872019-02-15 17:56:04 -0700155 for i in range(len(operators)):
Zack Williams045b63d2019-01-22 16:30:57 -0700156 if "/" not in operators[i]:
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800157 # if the target is not a path, it refer to a library included one
Zack Williams045b63d2019-01-22 16:30:57 -0700158 operators[i] = os.path.abspath(
159 os.path.dirname(os.path.realpath(__file__)) + subdir + operators[i]
160 )
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700161
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800162 if not os.path.isabs(operators[i]):
Zack Williams045b63d2019-01-22 16:30:57 -0700163 operators[i] = os.path.abspath(os.getcwd() + "/" + operators[i])
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700164
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800165 if op == GEN:
166 # convert output to absolute path
167 if args.output is not None and not os.path.isabs(args.output):
Zack Williams045b63d2019-01-22 16:30:57 -0700168 args.output = os.path.abspath(os.getcwd() + "/" + args.output)
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700169
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800170 operator = operators[0]
Zack Williams045b63d2019-01-22 16:30:57 -0700171
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800172 # check if there's a line that starts with +++ in the target
173 # if so, then the output file names are left to the target to decide
174 # also, if dest-file or dest-extension are supplied, then an error is generated.
Zack Williams045b63d2019-01-22 16:30:57 -0700175 plusplusplus = reduce(
176 lambda acc, line: True if line.startswith("+++") else acc,
177 open(operator).read().splitlines(),
178 False,
179 )
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800180
Zack Williams045b63d2019-01-22 16:30:57 -0700181 if plusplusplus and args.write_to_file != "target":
182 parse.error(
183 '%s chooses the names of the files that it generates, you must set --write-to-file to "target"'
184 % operator
185 )
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800186
Zack Williams045b63d2019-01-22 16:30:57 -0700187 if args.write_to_file != "single" and (args.dest_file):
188 parse.error(
189 '--dest-file requires --write-to-file to be set to "single"'
190 )
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800191
Zack Williams045b63d2019-01-22 16:30:57 -0700192 if args.write_to_file != "model" and (args.dest_extension):
193 parse.error(
194 '--dest-extension requires --write-to-file to be set to "model"'
195 )
196
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800197 else:
198 if args.write_to_file or args.dest_extension:
Zack Williams045b63d2019-01-22 16:30:57 -0700199 parse.error("Checkers cannot write to files")
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700200
201 inputs = []
202
203 for fname in args.files:
204 if not os.path.isabs(fname):
Zack Williams045b63d2019-01-22 16:30:57 -0700205 inputs.append(os.path.abspath(os.getcwd() + "/" + fname))
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700206 else:
207 inputs.append(fname)
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800208
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700209 args.files = inputs
210
Zack Williams045b63d2019-01-22 16:30:57 -0700211 if op == GEN:
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800212 generated = XOSProcessor.process(args, operators[0])
213 if not args.output and not args.write_to_file:
Zack Williams045b63d2019-01-22 16:30:57 -0700214 print(generated)
215 elif op == CHECK:
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800216 for o in operators:
217 verdict_str = XOSProcessor.process(args, o)
Zack Williams045b63d2019-01-22 16:30:57 -0700218 vlst = verdict_str.split("\n")
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700219
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800220 try:
221 verdict = next(v for v in vlst if v.strip())
Zack Williams045b63d2019-01-22 16:30:57 -0700222 status_code, status_string = verdict.split(" ", 1)
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800223 status_code = int(status_code)
Zack Williams045b63d2019-01-22 16:30:57 -0700224 except BaseException:
225 print("Checker %s returned mangled output" % o)
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800226 exit(1)
227
228 if status_code != 200:
Zack Williams045b63d2019-01-22 16:30:57 -0700229 print("%s: %s - %s" % (o, status_code, status_string))
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800230 exit(1)
231 else:
Zack Williams045b63d2019-01-22 16:30:57 -0700232 print("%s: OK" % o)