qapi: skip redundant includes

The purpose of this change is to help create a json file containing
common definitions; each bit of generated C code must be emitted
only one time.

A second history global to all QAPISchema instances has been added
to detect when a file is included more than one time and skip these
includes.
It does not act as a stack and the changes made to it by the
__init__ function are propagated back to the caller so it's really
a global state.

Signed-off-by: Benoit Canet <benoit@irqsave.net>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
This commit is contained in:
Benoît Canet 2014-05-16 12:51:56 +02:00 committed by Luiz Capitulino
parent 11b389f21e
commit 24fd848950
8 changed files with 23 additions and 5 deletions

View File

@ -48,7 +48,7 @@ The QAPI schema definitions can be modularized using the 'include' directive:
{ 'include': 'path/to/file.json'} { 'include': 'path/to/file.json'}
The directive is evaluated recursively, and include paths are relative to the The directive is evaluated recursively, and include paths are relative to the
file using the directive. file using the directive. Multiple includes of the same file are safe.
=== Complex types === === Complex types ===

View File

@ -73,13 +73,18 @@ class QAPIExprError(Exception):
class QAPISchema: class QAPISchema:
def __init__(self, fp, input_relname=None, include_hist=[], parent_info=None): def __init__(self, fp, input_relname=None, include_hist=[],
previously_included=[], parent_info=None):
""" include_hist is a stack used to detect inclusion cycles
previously_included is a global state used to avoid multiple
inclusions of the same file"""
input_fname = os.path.abspath(fp.name) input_fname = os.path.abspath(fp.name)
if input_relname is None: if input_relname is None:
input_relname = fp.name input_relname = fp.name
self.input_dir = os.path.dirname(input_fname) self.input_dir = os.path.dirname(input_fname)
self.input_file = input_relname self.input_file = input_relname
self.include_hist = include_hist + [(input_relname, input_fname)] self.include_hist = include_hist + [(input_relname, input_fname)]
previously_included.append(input_fname)
self.parent_info = parent_info self.parent_info = parent_info
self.src = fp.read() self.src = fp.read()
if self.src == '' or self.src[-1] != '\n': if self.src == '' or self.src[-1] != '\n':
@ -106,13 +111,16 @@ class QAPISchema:
for elem in self.include_hist): for elem in self.include_hist):
raise QAPIExprError(expr_info, "Inclusion loop for %s" raise QAPIExprError(expr_info, "Inclusion loop for %s"
% include) % include)
# skip multiple include of the same file
if include_path in previously_included:
continue
try: try:
fobj = open(include_path, 'r') fobj = open(include_path, 'r')
except IOError as e: except IOError as e:
raise QAPIExprError(expr_info, raise QAPIExprError(expr_info,
'%s: %s' % (e.strerror, include)) '%s: %s' % (e.strerror, include))
exprs_include = QAPISchema(fobj, include, exprs_include = QAPISchema(fobj, include, self.include_hist,
self.include_hist, expr_info) previously_included, expr_info)
self.exprs.extend(exprs_include.exprs) self.exprs.extend(exprs_include.exprs)
else: else:
expr_elem = {'expr': expr, expr_elem = {'expr': expr,

View File

@ -193,7 +193,8 @@ check-qapi-schema-y := $(addprefix tests/qapi-schema/, \
flat-union-string-discriminator.json \ flat-union-string-discriminator.json \
include-simple.json include-relpath.json include-format-err.json \ include-simple.json include-relpath.json include-format-err.json \
include-non-file.json include-no-file.json include-before-err.json \ include-non-file.json include-no-file.json include-before-err.json \
include-nested-err.json include-self-cycle.json include-cycle.json) include-nested-err.json include-self-cycle.json include-cycle.json \
include-repetition.json)
GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h

View File

@ -0,0 +1,2 @@
{ 'include': 'comments.json' }
{ 'include': 'comments.json' }

View File

View File

@ -0,0 +1 @@
0

View File

@ -0,0 +1,3 @@
{ 'include': 'comments.json' }
{ 'include': 'include-repetition-sub.json' }
{ 'include': 'comments.json' }

View File

@ -0,0 +1,3 @@
[OrderedDict([('enum', 'Status'), ('data', ['good', 'bad', 'ugly'])])]
[{'enum_name': 'Status', 'enum_values': ['good', 'bad', 'ugly']}]
[]