@@ -236,24 +236,24 @@ gen-out-type = $(subst .,-,$(suffix $@))
qapi-py = $(SRC_PATH)/scripts/qapi.py $(SRC_PATH)/scripts/ordereddict.py
qga/qapi-generated/qga-qapi-types.c qga/qapi-generated/qga-qapi-types.h :\
-$(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
- $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, " GEN $@")
+$(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
+ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(SRC_PATH)/qga/qapi-schema.json $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, " GEN $@")
qga/qapi-generated/qga-qapi-visit.c qga/qapi-generated/qga-qapi-visit.h :\
-$(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
- $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, " GEN $@")
+$(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
+ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(SRC_PATH)/qga/qapi-schema.json $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, " GEN $@")
qga/qapi-generated/qga-qmp-commands.h qga/qapi-generated/qga-qmp-marshal.c :\
-$(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
- $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, " GEN $@")
+$(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
+ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(SRC_PATH)/qga/qapi-schema.json $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, " GEN $@")
qapi-types.c qapi-types.h :\
-$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
- $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o "." -b < $<, " GEN $@")
+$(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
+ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(SRC_PATH)/qapi-schema.json $(gen-out-type) -o "." -b < $<, " GEN $@")
qapi-visit.c qapi-visit.h :\
-$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
- $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o "." -b < $<, " GEN $@")
+$(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
+ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(SRC_PATH)/qapi-schema.json $(gen-out-type) -o "." -b < $<, " GEN $@")
qmp-commands.h qmp-marshal.c :\
-$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
- $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -m -o "." < $<, " GEN $@")
+$(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
+ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(SRC_PATH)/qapi-schema.json $(gen-out-type) -m -o "." < $<, " GEN $@")
QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
$(qga-obj-y) qemu-ga.o: $(QGALIB_GEN)
@@ -369,13 +369,17 @@ def gen_command_def_prologue(prefix="", proxy=False):
try:
- opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:o:m",
+ opts, args = getopt.gnu_getopt(sys.argv[2:], "chp:o:m",
["source", "header", "prefix=",
"output-dir=", "type=", "middle"])
except getopt.GetoptError, err:
print str(err)
sys.exit(1)
+if len(sys.argv) < 2:
+ print "The first argument must be the file name to parse"
+ sys.exit(1)
+
output_dir = ""
prefix = ""
dispatch_type = "sync"
@@ -420,7 +424,7 @@ except os.error, e:
if e.errno != errno.EEXIST:
raise
-exprs = parse_schema(sys.stdin)
+exprs = parse_schema(sys.argv[1])
commands = filter(lambda expr: expr.has_key('command'), exprs)
commands = filter(lambda expr: not expr.has_key('gen'), commands)
@@ -279,13 +279,17 @@ void qapi_free_%(type)s(%(c_type)s obj)
try:
- opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:o:",
+ opts, args = getopt.gnu_getopt(sys.argv[2:], "chbp:o:",
["source", "header", "builtins",
"prefix=", "output-dir="])
except getopt.GetoptError, err:
print str(err)
sys.exit(1)
+if len(sys.argv) < 2:
+ print "The first argument must be the file name to parse"
+ sys.exit(1)
+
output_dir = ""
prefix = ""
c_file = 'qapi-types.c'
@@ -378,7 +382,7 @@ fdecl.write(mcgen('''
''',
guard=guardname(h_file)))
-exprs = parse_schema(sys.stdin)
+exprs = parse_schema(sys.argv[1])
exprs = filter(lambda expr: not expr.has_key('gen'), exprs)
fdecl.write(guardstart("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
@@ -397,13 +397,17 @@ void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **e
name=name)
try:
- opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:o:",
+ opts, args = getopt.gnu_getopt(sys.argv[2:], "chbp:o:",
["source", "header", "builtins", "prefix=",
"output-dir="])
except getopt.GetoptError, err:
print str(err)
sys.exit(1)
+if len(sys.argv) < 2:
+ print "The first argument must be the file name to parse"
+ sys.exit(1)
+
output_dir = ""
prefix = ""
c_file = 'qapi-visit.c'
@@ -494,7 +498,7 @@ fdecl.write(mcgen('''
''',
prefix=prefix, guard=guardname(h_file)))
-exprs = parse_schema(sys.stdin)
+exprs = parse_schema(sys.argv[1])
# to avoid header dependency hell, we always generate declarations
# for built-in types in our header files and simply guard them
@@ -12,6 +12,7 @@
# See the COPYING file in the top-level directory.
from ordereddict import OrderedDict
+import os
import sys
builtin_types = [
@@ -35,6 +36,9 @@ builtin_type_qtypes = {
'uint64': 'QTYPE_QINT',
}
+def get_filename(path):
+ return os.path.split(path)[1]
+
class QAPISchemaError(Exception):
def __init__(self, schema, msg):
self.fp = schema.fp
@@ -48,7 +52,8 @@ class QAPISchemaError(Exception):
self.col += 1
def __str__(self):
- return "%s:%s:%s: %s" % (self.fp.name, self.line, self.col, self.msg)
+ return "%s:%s:%s: %s" % (get_filename(self.fp.name),
+ self.line, self.col, self.msg)
class QAPIExprError(Exception):
def __init__(self, expr_info, msg):
@@ -57,7 +62,8 @@ class QAPIExprError(Exception):
self.msg = msg
def __str__(self):
- return "%s:%s: %s" % (self.fp.name, self.line, self.msg)
+ return "%s:%s: %s" % (get_filename(self.fp.name),
+ self.line, self.msg)
class QAPISchema:
@@ -263,18 +269,40 @@ def check_exprs(schema):
if expr.has_key('union'):
check_union(expr, expr_elem['info'])
-def parse_schema(fp):
- try:
- schema = QAPISchema(fp)
- except QAPISchemaError, e:
- print >>sys.stderr, e
- exit(1)
+modules = []
+
+def build_schema(path):
+ with open(path, "r") as fp:
+ try:
+ schema = QAPISchema(fp)
+ except QAPISchemaError, e:
+ print >>sys.stderr, e
+ exit(1)
+ return schema
+
+def parse_schema(path):
+ path = os.path.abspath(path)
+
+ if path in modules:
+ print "Module inclusion loop detected with module: %s" %\
+ get_filename(path)
+ sys.exit(1)
+
+ modules.append(path)
+
+ schema = build_schema(path)
exprs = []
for expr_elem in schema.exprs:
expr = expr_elem['expr']
- if expr.has_key('enum'):
+ if expr.has_key('include'):
+ prefix = os.path.split(path)[0]
+ sub_path = os.path.join(prefix, expr['include'])
+ sub_exprs = parse_schema(sub_path)
+ exprs += sub_exprs
+ continue
+ elif expr.has_key('enum'):
add_enum(expr['enum'], expr['data'])
elif expr.has_key('union'):
add_union(expr)
@@ -164,7 +164,7 @@ check-qapi-schema-y := $(addprefix tests/qapi-schema/, \
duplicate-key.json union-invalid-base.json flat-union-no-base.json \
flat-union-invalid-discriminator.json \
flat-union-invalid-branch-key.json flat-union-reverse-define.json \
- flat-union-string-discriminator.json)
+ flat-union-string-discriminator.json include.json include_loop.json)
GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h
@@ -215,14 +215,14 @@ tests/test-vmstate$(EXESUF): tests/test-vmstate.o \
libqemuutil.a
tests/test-qapi-types.c tests/test-qapi-types.h :\
-$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py
- $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o tests -p "test-" < $<, " GEN $@")
+$(SRC_PATH)/scripts/qapi-types.py
+ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(gen-out-type) -o tests -p "test-" < $<, " GEN $@")
tests/test-qapi-visit.c tests/test-qapi-visit.h :\
-$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py
- $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o tests -p "test-" < $<, " GEN $@")
+$(SRC_PATH)/scripts/qapi-visit.py
+ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(gen-out-type) -o tests -p "test-" < $<, " GEN $@")
tests/test-qmp-commands.h tests/test-qmp-marshal.c :\
-$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py
- $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o tests -p "test-" < $<, " GEN $@")
+$(SRC_PATH)/scripts/qapi-commands.py
+ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(gen-out-type) -o tests -p "test-" < $<, " GEN $@")
tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a
tests/test-string-input-visitor$(EXESUF): tests/test-string-input-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a
@@ -362,7 +362,7 @@ check-tests/test-qapi.py: tests/test-qapi.py
.PHONY: $(patsubst %, check-%, $(check-qapi-schema-y))
$(patsubst %, check-%, $(check-qapi-schema-y)): check-%.json: $(SRC_PATH)/%.json
- $(call quiet-command, PYTHONPATH=$(SRC_PATH)/scripts $(PYTHON) $(SRC_PATH)/tests/qapi-schema/test-qapi.py <$^ >$*.test.out 2>$*.test.err; echo $$? >$*.test.exit, " TEST $*.out")
+ $(call quiet-command, PYTHONPATH=$(SRC_PATH)/scripts $(PYTHON) $(SRC_PATH)/tests/qapi-schema/test-qapi.py $^ >$*.test.out 2>$*.test.err; echo $$? >$*.test.exit, " TEST $*.out")
@diff -q $(SRC_PATH)/$*.out $*.test.out
@diff -q $(SRC_PATH)/$*.err $*.test.err
@diff -q $(SRC_PATH)/$*.exit $*.test.exit
@@ -1 +1 @@
-<stdin>:2:10: Duplicate key "key"
+duplicate-key.json:2:10: Duplicate key "key"
@@ -1 +1 @@
-<stdin>:13: Discriminator value 'value_wrong' is not found in enum 'TestEnum'
+flat-union-invalid-branch-key.json:13: Discriminator value 'value_wrong' is not found in enum 'TestEnum'
@@ -1 +1 @@
-<stdin>:13: Discriminator 'enum_wrong' is not a member of base type 'TestBase'
+flat-union-invalid-discriminator.json:13: Discriminator 'enum_wrong' is not a member of base type 'TestBase'
@@ -1 +1 @@
-<stdin>:7: Flat union 'TestUnion' must have a base field
+flat-union-no-base.json:7: Flat union 'TestUnion' must have a base field
@@ -1 +1 @@
-<stdin>:13: Discriminator 'kind' must be of enumeration type
+flat-union-string-discriminator.json:13: Discriminator 'kind' must be of enumeration type
@@ -1 +1 @@
-<stdin>:2:36: Stray ";"
+funny-char.json:2:36: Stray ";"
new file mode 100644
new file mode 100644
@@ -0,0 +1 @@
+0
new file mode 100644
@@ -0,0 +1,4 @@
+{ 'enum': 'Status',
+ 'data': [ 'good', 'bad', 'ugly' ] }
+{ 'include': './include/include.json' }
+{ 'foo': '42' }
new file mode 100644
@@ -0,0 +1,8 @@
+[OrderedDict([('enum', 'Status'), ('data', ['good', 'bad', 'ugly'])]),
+ OrderedDict([('bar', '33')]),
+ OrderedDict([('enum', 'Fruits'), ('data', ['orange', 'apple', 'gooseberry'])]),
+ OrderedDict([('baz', '54')]),
+ OrderedDict([('foo', '42')])]
+[{'enum_name': 'Status', 'enum_values': ['good', 'bad', 'ugly']},
+ {'enum_name': 'Fruits', 'enum_values': ['orange', 'apple', 'gooseberry']}]
+[]
new file mode 100644
@@ -0,0 +1,7 @@
+
+{ 'bar': '33' }
+
+{ 'enum': 'Fruits',
+ 'data': [ 'orange', 'apple', 'gooseberry' ] }
+
+{ 'baz': '54' }
new file mode 100644
new file mode 100644
@@ -0,0 +1 @@
+1
new file mode 100644
@@ -0,0 +1 @@
+{ 'include': 'include_loop.json' }
new file mode 100644
@@ -0,0 +1 @@
+Module inclusion loop detected with module: include_loop.json
@@ -1 +1 @@
-<stdin>:1:10: Expected ":"
+missing-colon.json:1:10: Expected ":"
@@ -1 +1 @@
-<stdin>:2:20: Expected "," or "]"
+missing-comma-list.json:2:20: Expected "," or "]"
@@ -1 +1 @@
-<stdin>:2:3: Expected "," or "}"
+missing-comma-object.json:2:3: Expected "," or "}"
@@ -1 +1 @@
-<stdin>:1:1: Expected "{"
+non-objects.json:1:1: Expected "{"
@@ -1 +1 @@
-<stdin>:1:1: Expected "{"
+quoted-structural-chars.json:1:1: Expected "{"
@@ -15,7 +15,7 @@ from pprint import pprint
import sys
try:
- exprs = parse_schema(sys.stdin)
+ exprs = parse_schema(sys.argv[1])
except SystemExit:
raise
except Exception, e:
@@ -1 +1 @@
-<stdin>:2:36: Expected "{", "[" or string
+trailing-comma-list.json:2:36: Expected "{", "[" or string
@@ -1 +1 @@
-<stdin>:2:38: Expected string
+trailing-comma-object.json:2:38: Expected string
@@ -1 +1 @@
-<stdin>:1:20: Expected "," or "]"
+unclosed-list.json:1:20: Expected "," or "]"
@@ -1 +1 @@
-<stdin>:1:21: Expected "," or "}"
+unclosed-object.json:1:21: Expected "," or "}"
@@ -1 +1 @@
-<stdin>:1:11: Missing terminating "'"
+unclosed-string.json:1:11: Missing terminating "'"
@@ -1 +1 @@
-<stdin>:7: Base 'TestBaseWrong' is not a valid type
+union-invalid-base.json:7: Base 'TestBaseWrong' is not a valid type
The new directive in the form { 'include': 'path/to/file.json' } will trigger the parsing of path/to/file.json. The directive will be replaced by the result of the parsing. This will allow for easy modularisation of qapi JSON descriptions files. The qapi commands now takes the input file path as first argument to make it easier to detect include loops: stdin would not allow to do this. Signed-off-by: Benoit Canet <benoit@irqsave.net> --- Makefile | 24 +++++------ scripts/qapi-commands.py | 8 +++- scripts/qapi-types.py | 8 +++- scripts/qapi-visit.py | 8 +++- scripts/qapi.py | 46 +++++++++++++++++----- tests/Makefile | 16 ++++---- tests/qapi-schema/duplicate-key.err | 2 +- .../qapi-schema/flat-union-invalid-branch-key.err | 2 +- .../flat-union-invalid-discriminator.err | 2 +- tests/qapi-schema/flat-union-no-base.err | 2 +- .../flat-union-string-discriminator.err | 2 +- tests/qapi-schema/funny-char.err | 2 +- tests/qapi-schema/include.err | 0 tests/qapi-schema/include.exit | 1 + tests/qapi-schema/include.json | 4 ++ tests/qapi-schema/include.out | 8 ++++ tests/qapi-schema/include/include.json | 7 ++++ tests/qapi-schema/include_loop.err | 0 tests/qapi-schema/include_loop.exit | 1 + tests/qapi-schema/include_loop.json | 1 + tests/qapi-schema/include_loop.out | 1 + tests/qapi-schema/missing-colon.err | 2 +- tests/qapi-schema/missing-comma-list.err | 2 +- tests/qapi-schema/missing-comma-object.err | 2 +- tests/qapi-schema/non-objects.err | 2 +- tests/qapi-schema/quoted-structural-chars.err | 2 +- tests/qapi-schema/test-qapi.py | 2 +- tests/qapi-schema/trailing-comma-list.err | 2 +- tests/qapi-schema/trailing-comma-object.err | 2 +- tests/qapi-schema/unclosed-list.err | 2 +- tests/qapi-schema/unclosed-object.err | 2 +- tests/qapi-schema/unclosed-string.err | 2 +- tests/qapi-schema/union-invalid-base.err | 2 +- 33 files changed, 116 insertions(+), 53 deletions(-) create mode 100644 tests/qapi-schema/include.err create mode 100644 tests/qapi-schema/include.exit create mode 100644 tests/qapi-schema/include.json create mode 100644 tests/qapi-schema/include.out create mode 100644 tests/qapi-schema/include/include.json create mode 100644 tests/qapi-schema/include_loop.err create mode 100644 tests/qapi-schema/include_loop.exit create mode 100644 tests/qapi-schema/include_loop.json create mode 100644 tests/qapi-schema/include_loop.out