Commit 23394b4c authored by Peter Krempa's avatar Peter Krempa Committed by Markus Armbruster
Browse files

qapi: Add feature flags to commands



Similarly to features for struct types introduce the feature flags also
for commands. This will allow notifying management layers of fixes and
compatible changes in the behaviour of a command which may not be
detectable any other way.

The changes were heavily inspired by commit 6a8c0b51.

Signed-off-by: default avatarPeter Krempa <pkrempa@redhat.com>
Reviewed-by: default avatarMarkus Armbruster <armbru@redhat.com>
Signed-off-by: default avatarMarkus Armbruster <armbru@redhat.com>
Message-Id: <20191018081454.21369-3-armbru@redhat.com>
parent 758f272b
Loading
Loading
Loading
Loading
+6 −4
Original line number Diff line number Diff line
@@ -457,7 +457,8 @@ Syntax:
                '*gen': false,
                '*allow-oob': true,
                '*allow-preconfig': true,
                '*if': COND }
                '*if': COND,
                '*features': FEATURES }

Member 'command' names the command.

@@ -640,9 +641,10 @@ change in the QMP syntax (usually by allowing values or operations
that previously resulted in an error).  QMP clients may still need to
know whether the extension is available.

For this purpose, a list of features can be specified for a struct type.
This is exposed to the client as a list of string, where each string
signals that this build of QEMU shows a certain behaviour.
For this purpose, a list of features can be specified for a command or
struct type.  This is exposed to the client as a list of strings,
where each string signals that this build of QEMU shows a certain
behaviour.

Each member of the 'features' array defines a feature.  It can either
be { 'name': STRING, '*if': COND }, or STRING, which is shorthand for
+5 −1
Original line number Diff line number Diff line
@@ -266,13 +266,17 @@
# @allow-oob: whether the command allows out-of-band execution,
#             defaults to false (Since: 2.12)
#
# @features: names of features associated with the command, in no particular
#            order. (since 4.2)
#
# TODO: @success-response (currently irrelevant, because it's QGA, not QMP)
#
# Since: 2.5
##
{ 'struct': 'SchemaInfoCommand',
  'data': { 'arg-type': 'str', 'ret-type': 'str',
            '*allow-oob': 'bool' } }
            '*allow-oob': 'bool',
            '*features': [ 'str' ] } }

##
# @SchemaInfoEvent:
+2 −1
Original line number Diff line number Diff line
@@ -277,7 +277,8 @@ void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds);
        genc.add(gen_registry(self._regy.get_content(), self._prefix))

    def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
                      success_response, boxed, allow_oob, allow_preconfig):
                      success_response, boxed, allow_oob, allow_preconfig,
                      features):
        if not gen:
            return
        # FIXME: If T is a user-defined type, the user is responsible
+3 −1
Original line number Diff line number Diff line
@@ -249,12 +249,14 @@ class QAPISchemaGenDocVisitor(QAPISchemaVisitor):
                               body=texi_entity(doc, 'Members', ifcond)))

    def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
                      success_response, boxed, allow_oob, allow_preconfig):
                      success_response, boxed, allow_oob, allow_preconfig,
                      features):
        doc = self.cur_doc
        if boxed:
            body = texi_body(doc)
            body += ('\n@b{Arguments:} the members of @code{%s}\n'
                     % arg_type.name)
            body += texi_features(doc)
            body += texi_sections(doc, ifcond)
        else:
            body = texi_entity(doc, 'Arguments', ifcond)
+20 −15
Original line number Diff line number Diff line
@@ -185,6 +185,22 @@ def normalize_features(features):
                       for f in features]


def check_features(features, info):
    if features is None:
        return
    if not isinstance(features, list):
        raise QAPISemError(info, "'features' must be an array")
    for f in features:
        source = "'features' member"
        assert isinstance(f, dict)
        check_keys(f, info, source, ['name'], ['if'])
        check_name_is_str(f['name'], info, source)
        source = "%s '%s'" % (source, f['name'])
        check_name_str(f['name'], info, source)
        check_if(f, info, source)
        normalize_if(f)


def normalize_enum(expr):
    if isinstance(expr['data'], list):
        expr['data'] = [m if isinstance(m, dict) else {'name': m}
@@ -217,23 +233,10 @@ def check_enum(expr, info):
def check_struct(expr, info):
    name = expr['struct']
    members = expr['data']
    features = expr.get('features')

    check_type(members, info, "'data'", allow_dict=name)
    check_type(expr.get('base'), info, "'base'")

    if features:
        if not isinstance(features, list):
            raise QAPISemError(info, "'features' must be an array")
        for f in features:
            source = "'features' member"
            assert isinstance(f, dict)
            check_keys(f, info, source, ['name'], ['if'])
            check_name_is_str(f['name'], info, source)
            source = "%s '%s'" % (source, f['name'])
            check_name_str(f['name'], info, source)
            check_if(f, info, source)
            normalize_if(f)
    check_features(expr.get('features'), info)


def check_union(expr, info):
@@ -283,6 +286,7 @@ def check_command(expr, info):
        raise QAPISemError(info, "'boxed': true requires 'data'")
    check_type(args, info, "'data'", allow_dict=not boxed)
    check_type(rets, info, "'returns'", allow_array=True)
    check_features(expr.get('features'), info)


def check_event(expr, info):
@@ -358,10 +362,11 @@ def check_exprs(exprs):
        elif meta == 'command':
            check_keys(expr, info, meta,
                       ['command'],
                       ['data', 'returns', 'boxed', 'if',
                       ['data', 'returns', 'boxed', 'if', 'features',
                        'gen', 'success-response', 'allow-oob',
                        'allow-preconfig'])
            normalize_members(expr.get('data'))
            normalize_features(expr.get('features'))
            check_command(expr, info)
        elif meta == 'event':
            check_keys(expr, info, meta,
Loading