Commit c615550d authored by Markus Armbruster's avatar Markus Armbruster
Browse files

qapi: Improve source file read error handling



qapi-gen.py crashes when it can't open the main schema file, and when
it can't read from any schema file.  Lazy.

Change QAPISchema.__init__() to take a file name instead of a file
object.  Move the open code from _include() to __init__(), so it's
used for the main schema file, too.

Move the read into the try for good measure, and rephrase the error
message.

Reporting open or read failure for the main schema file needs a
QAPISourceInfo representing "no source".  Make QAPISourceInfo cope
with fname=None.

Signed-off-by: default avatarMarkus Armbruster <armbru@redhat.com>
Reviewed-by: default avatarEric Blake <eblake@redhat.com>
Message-Id: <20190927134639.4284-27-armbru@redhat.com>
parent 56d2df5e
Loading
Loading
Loading
Loading
+26 −20
Original line number Diff line number Diff line
@@ -53,7 +53,12 @@ class QAPISourceInfo(object):
        return info

    def loc(self):
        return '%s:%d' % (self.fname, self.line)
        if self.fname is None:
            return sys.argv[0]
        ret = self.fname
        if self.line is not None:
            ret += ':%d' % self.line
        return ret

    def in_defn(self):
        if self.defn_name:
@@ -383,14 +388,26 @@ class QAPIDoc(object):

class QAPISchemaParser(object):

    def __init__(self, fp, previously_included=[], incl_info=None):
        self.fname = fp.name
        previously_included.append(os.path.abspath(fp.name))
    def __init__(self, fname, previously_included=[], incl_info=None):
        previously_included.append(os.path.abspath(fname))

        try:
            if sys.version_info[0] >= 3:
                fp = open(fname, 'r', encoding='utf-8')
            else:
                fp = open(fname, 'r')
            self.src = fp.read()
        except IOError as e:
            raise QAPISemError(incl_info or QAPISourceInfo(None, None, None),
                               "can't read %s file '%s': %s"
                               % ("include" if incl_info else "schema",
                                  fname,
                                  e.strerror))

        if self.src == '' or self.src[-1] != '\n':
            self.src += '\n'
        self.cursor = 0
        self.info = QAPISourceInfo(self.fname, 1, incl_info)
        self.info = QAPISourceInfo(fname, 1, incl_info)
        self.line_pos = 0
        self.exprs = []
        self.docs = []
@@ -414,7 +431,7 @@ class QAPISchemaParser(object):
                if not isinstance(include, str):
                    raise QAPISemError(info,
                                       "value of 'include' must be a string")
                incl_fname = os.path.join(os.path.dirname(self.fname),
                incl_fname = os.path.join(os.path.dirname(fname),
                                          include)
                self.exprs.append({'expr': {'include': incl_fname},
                                   'info': info})
@@ -466,14 +483,7 @@ class QAPISchemaParser(object):
        if incl_abs_fname in previously_included:
            return None

        try:
            if sys.version_info[0] >= 3:
                fobj = open(incl_fname, 'r', encoding='utf-8')
            else:
                fobj = open(incl_fname, 'r')
        except IOError as e:
            raise QAPISemError(info, "%s: %s" % (e.strerror, incl_fname))
        return QAPISchemaParser(fobj, previously_included, info)
        return QAPISchemaParser(incl_fname, previously_included, info)

    def _pragma(self, name, value, info):
        global doc_required, returns_whitelist, name_case_whitelist
@@ -1734,11 +1744,7 @@ class QAPISchemaEvent(QAPISchemaEntity):
class QAPISchema(object):
    def __init__(self, fname):
        self.fname = fname
        if sys.version_info[0] >= 3:
            f = open(fname, 'r', encoding='utf-8')
        else:
            f = open(fname, 'r')
        parser = QAPISchemaParser(f)
        parser = QAPISchemaParser(fname)
        exprs = check_exprs(parser.exprs)
        self.docs = parser.docs
        self._entity_list = []
+1 −1
Original line number Diff line number Diff line
tests/qapi-schema/include-no-file.json:1: No such file or directory: tests/qapi-schema/include-no-file-sub.json
tests/qapi-schema/include-no-file.json:1: can't read include file 'tests/qapi-schema/include-no-file-sub.json': No such file or directory