QAPI patches for 2018-06-22

-----BEGIN PGP SIGNATURE-----
 
 iQIcBAABAgAGBQJbLQlmAAoJEDhwtADrkYZTSncQAK1jsP8crW+bgwRBPhwZgmv6
 IEWXQc9OBlVD3yrSnMsqJuFOo9vak0EThBFUPBUNSN5rQZhuwBrOyKJRcxTSEilh
 h0Wq/HxCARRdJpcPXWo7UIXgNXrk5qoUzowc6m/6ReogOoycrA4YeOLdOoy98dUv
 0a2U/EyKL/lWgioQhbnZWBEtFX1BFVztWUsG0AF6PGgbu7SZRGtw+IDQWzV7oRVN
 gsiKJYjTN7jjyxaM789TioiajMD1dFSN2V3BSqLv9LkaJ8dV69OVU5R6429EkzTF
 /BdahCtsTE7TTkXeqPqpOnrRXBYiCOeLTbi1Ub5De7wjtaLzfQW9ZolA1OxaSRWS
 AMvS92V2w6S97F0VkkfagGmqO6ypVXAjPr7a3yXHKig2DDMR5BWq10GXS7EHvn5a
 qVD4WbGxUFplxpyvbCAjZS/qV8hoDG8SsA58lUJP18z5Z6PJpCvk6bQl9XcOF+bc
 WqlcgW75Iu/ii1XZdzFylX1h9p4ox4roiZ9YBMKakb/oI8kfUHs4dL0Yz5A0aJKr
 /Vw/8TmokqkLI+PJX+6P4kGyrIVhB6x/iPDv1MXqjaEiO+tM6pMUfJvH8HtzTIay
 CJ0QNZQe2ksbV1gHZ4wGZwnGwOtOQVUmXChDVEcQbyOdlHAEGn9Zjbc1wq/wei8x
 VtA3kZn6CoIuih6vt6SO
 =Mo3y
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2018-06-22' into staging

QAPI patches for 2018-06-22

# gpg: Signature made Fri 22 Jun 2018 15:36:22 BST
# gpg:                using RSA key 3870B400EB918653
# gpg: Good signature from "Markus Armbruster <armbru@redhat.com>"
# gpg:                 aka "Markus Armbruster <armbru@pond.sub.org>"
# Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867  4E5F 3870 B400 EB91 8653

* remotes/armbru/tags/pull-qapi-2018-06-22:
  MAINTAINERS: Update QAPI stanza for commit fb0bc835e5
  qapi/introspect: Eliminate pointless variable in .visit_end()
  Revert commit d4e5ec877c
  qapi: Open files with encoding='utf-8'
  qapi: remove empty flat union branches and types
  qapi: allow empty branches in flat unions
  tests: Add QDict clone-flatten test
  qdict: Make qdict_flatten() shallow-clone-friendly
  qapi/events: generate event enum in main module
  qapi/visit: remove useless prefix argument

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2018-06-22 17:08:57 +01:00
commit 7ed14cbf3c
24 changed files with 116 additions and 190 deletions

View File

@ -1625,7 +1625,8 @@ F: tests/test-*-visitor.c
F: tests/test-qapi-*.c F: tests/test-qapi-*.c
F: tests/test-qmp-*.c F: tests/test-qmp-*.c
F: tests/test-visitor-serialization.c F: tests/test-visitor-serialization.c
F: scripts/qapi* F: scripts/qapi-gen.py
F: scripts/qapi/*
F: docs/devel/qapi* F: docs/devel/qapi*
T: git git://repo.or.cz/qemu/armbru.git qapi-next T: git git://repo.or.cz/qemu/armbru.git qapi-next

View File

@ -20,8 +20,6 @@ ifneq ($(wildcard config-host.mak),)
all: all:
include config-host.mak include config-host.mak
PYTHON_UTF8 = LC_ALL= LANG=C LC_CTYPE=en_US.UTF-8 $(PYTHON)
git-submodule-update: git-submodule-update:
.PHONY: git-submodule-update .PHONY: git-submodule-update
@ -576,7 +574,7 @@ qga/qapi-generated/qga-qapi-commands.h qga/qapi-generated/qga-qapi-commands.c \
qga/qapi-generated/qga-qapi-doc.texi: \ qga/qapi-generated/qga-qapi-doc.texi: \
qga/qapi-generated/qapi-gen-timestamp ; qga/qapi-generated/qapi-gen-timestamp ;
qga/qapi-generated/qapi-gen-timestamp: $(SRC_PATH)/qga/qapi-schema.json $(qapi-py) qga/qapi-generated/qapi-gen-timestamp: $(SRC_PATH)/qga/qapi-schema.json $(qapi-py)
$(call quiet-command,$(PYTHON_UTF8) $(SRC_PATH)/scripts/qapi-gen.py \ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-gen.py \
-o qga/qapi-generated -p "qga-" $<, \ -o qga/qapi-generated -p "qga-" $<, \
"GEN","$(@:%-timestamp=%)") "GEN","$(@:%-timestamp=%)")
@>$@ @>$@
@ -676,7 +674,7 @@ qapi/qapi-introspect.h qapi/qapi-introspect.c \
qapi/qapi-doc.texi: \ qapi/qapi-doc.texi: \
qapi-gen-timestamp ; qapi-gen-timestamp ;
qapi-gen-timestamp: $(qapi-modules) $(qapi-py) qapi-gen-timestamp: $(qapi-modules) $(qapi-py)
$(call quiet-command,$(PYTHON_UTF8) $(SRC_PATH)/scripts/qapi-gen.py \ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-gen.py \
-o "qapi" -b $<, \ -o "qapi" -b $<, \
"GEN","$(@:%-timestamp=%)") "GEN","$(@:%-timestamp=%)")
@>$@ @>$@

View File

@ -4166,7 +4166,6 @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs)
switch (encrypt_info->format) { switch (encrypt_info->format) {
case Q_CRYPTO_BLOCK_FORMAT_QCOW: case Q_CRYPTO_BLOCK_FORMAT_QCOW:
qencrypt->format = BLOCKDEV_QCOW2_ENCRYPTION_FORMAT_AES; qencrypt->format = BLOCKDEV_QCOW2_ENCRYPTION_FORMAT_AES;
qencrypt->u.aes = encrypt_info->u.qcow;
break; break;
case Q_CRYPTO_BLOCK_FORMAT_LUKS: case Q_CRYPTO_BLOCK_FORMAT_LUKS:
qencrypt->format = BLOCKDEV_QCOW2_ENCRYPTION_FORMAT_LUKS; qencrypt->format = BLOCKDEV_QCOW2_ENCRYPTION_FORMAT_LUKS;

2
cpus.c
View File

@ -2273,8 +2273,6 @@ CpuInfoFastList *qmp_query_cpus_fast(Error **errp)
info->value->target = target; info->value->target = target;
if (target == SYS_EMU_TARGET_S390X) { if (target == SYS_EMU_TARGET_S390X) {
cpustate_to_cpuinfo_s390(&info->value->u.s390x, cpu); cpustate_to_cpuinfo_s390(&info->value->u.s390x, cpu);
} else {
/* do nothing for @CpuInfoOther */
} }
if (!cur_item) { if (!cur_item) {

View File

@ -496,9 +496,11 @@ Resulting in these JSON objects:
Notice that in a flat union, the discriminator name is controlled by Notice that in a flat union, the discriminator name is controlled by
the user, but because it must map to a base member with enum type, the the user, but because it must map to a base member with enum type, the
code generator can ensure that branches exist for all values of the code generator ensures that branches match the existing values of the
enum (although the order of the keys need not match the declaration of enum. The order of the keys need not match the declaration of the enum.
the enum). In the resulting generated C data types, a flat union is The keys need not cover all possible enum values. Omitted enum values
are still valid branches that add no additional members to the data type.
In the resulting generated C data types, a flat union is
represented as a struct with the base members included directly, and represented as a struct with the base members included directly, and
then a union of structures for each branch of the struct. then a union of structures for each branch of the struct.

View File

@ -52,8 +52,7 @@
{ 'union': 'ImageInfoSpecificQCow2Encryption', { 'union': 'ImageInfoSpecificQCow2Encryption',
'base': 'ImageInfoSpecificQCow2EncryptionBase', 'base': 'ImageInfoSpecificQCow2EncryptionBase',
'discriminator': 'format', 'discriminator': 'format',
'data': { 'aes': 'QCryptoBlockInfoQCow', 'data': { 'luks': 'QCryptoBlockInfoLUKS' } }
'luks': 'QCryptoBlockInfoLUKS' } }
## ##
# @ImageInfoSpecificQCow2: # @ImageInfoSpecificQCow2:
@ -2877,16 +2876,6 @@
'data': { 'type': 'SshHostKeyCheckHashType', 'data': { 'type': 'SshHostKeyCheckHashType',
'hash': 'str' }} 'hash': 'str' }}
##
# @SshHostKeyDummy:
#
# For those union branches that don't need additional fields.
#
# Since: 2.12
##
{ 'struct': 'SshHostKeyDummy',
'data': {} }
## ##
# @SshHostKeyCheck: # @SshHostKeyCheck:
# #
@ -2895,9 +2884,7 @@
{ 'union': 'SshHostKeyCheck', { 'union': 'SshHostKeyCheck',
'base': { 'mode': 'SshHostKeyCheckMode' }, 'base': { 'mode': 'SshHostKeyCheckMode' },
'discriminator': 'mode', 'discriminator': 'mode',
'data': { 'none': 'SshHostKeyDummy', 'data': { 'hash': 'SshHostKeyHash' } }
'hash': 'SshHostKeyHash',
'known_hosts': 'SshHostKeyDummy' } }
## ##
# @BlockdevOptionsSsh: # @BlockdevOptionsSsh:
@ -4075,15 +4062,6 @@
'*subformat': 'BlockdevVpcSubformat', '*subformat': 'BlockdevVpcSubformat',
'*force-size': 'bool' } } '*force-size': 'bool' } }
##
# @BlockdevCreateNotSupported:
#
# This is used for all drivers that don't support creating images.
#
# Since: 2.12
##
{ 'struct': 'BlockdevCreateNotSupported', 'data': {}}
## ##
# @BlockdevCreateOptions: # @BlockdevCreateOptions:
# #
@ -4098,44 +4076,20 @@
'driver': 'BlockdevDriver' }, 'driver': 'BlockdevDriver' },
'discriminator': 'driver', 'discriminator': 'driver',
'data': { 'data': {
'blkdebug': 'BlockdevCreateNotSupported',
'blkverify': 'BlockdevCreateNotSupported',
'bochs': 'BlockdevCreateNotSupported',
'cloop': 'BlockdevCreateNotSupported',
'copy-on-read': 'BlockdevCreateNotSupported',
'dmg': 'BlockdevCreateNotSupported',
'file': 'BlockdevCreateOptionsFile', 'file': 'BlockdevCreateOptionsFile',
'ftp': 'BlockdevCreateNotSupported',
'ftps': 'BlockdevCreateNotSupported',
'gluster': 'BlockdevCreateOptionsGluster', 'gluster': 'BlockdevCreateOptionsGluster',
'host_cdrom': 'BlockdevCreateNotSupported',
'host_device': 'BlockdevCreateNotSupported',
'http': 'BlockdevCreateNotSupported',
'https': 'BlockdevCreateNotSupported',
'iscsi': 'BlockdevCreateNotSupported',
'luks': 'BlockdevCreateOptionsLUKS', 'luks': 'BlockdevCreateOptionsLUKS',
'nbd': 'BlockdevCreateNotSupported',
'nfs': 'BlockdevCreateOptionsNfs', 'nfs': 'BlockdevCreateOptionsNfs',
'null-aio': 'BlockdevCreateNotSupported',
'null-co': 'BlockdevCreateNotSupported',
'nvme': 'BlockdevCreateNotSupported',
'parallels': 'BlockdevCreateOptionsParallels', 'parallels': 'BlockdevCreateOptionsParallels',
'qcow': 'BlockdevCreateOptionsQcow', 'qcow': 'BlockdevCreateOptionsQcow',
'qcow2': 'BlockdevCreateOptionsQcow2', 'qcow2': 'BlockdevCreateOptionsQcow2',
'qed': 'BlockdevCreateOptionsQed', 'qed': 'BlockdevCreateOptionsQed',
'quorum': 'BlockdevCreateNotSupported',
'raw': 'BlockdevCreateNotSupported',
'rbd': 'BlockdevCreateOptionsRbd', 'rbd': 'BlockdevCreateOptionsRbd',
'replication': 'BlockdevCreateNotSupported',
'sheepdog': 'BlockdevCreateOptionsSheepdog', 'sheepdog': 'BlockdevCreateOptionsSheepdog',
'ssh': 'BlockdevCreateOptionsSsh', 'ssh': 'BlockdevCreateOptionsSsh',
'throttle': 'BlockdevCreateNotSupported',
'vdi': 'BlockdevCreateOptionsVdi', 'vdi': 'BlockdevCreateOptionsVdi',
'vhdx': 'BlockdevCreateOptionsVhdx', 'vhdx': 'BlockdevCreateOptionsVhdx',
'vmdk': 'BlockdevCreateNotSupported', 'vpc': 'BlockdevCreateOptionsVpc'
'vpc': 'BlockdevCreateOptionsVpc',
'vvfat': 'BlockdevCreateNotSupported',
'vxhs': 'BlockdevCreateNotSupported'
} } } }
## ##

View File

@ -297,16 +297,6 @@
'uuid': 'str', 'uuid': 'str',
'slots': [ 'QCryptoBlockInfoLUKSSlot' ] }} 'slots': [ 'QCryptoBlockInfoLUKSSlot' ] }}
##
# @QCryptoBlockInfoQCow:
#
# Information about the QCow block encryption options
#
# Since: 2.7
##
{ 'struct': 'QCryptoBlockInfoQCow',
'data': { }}
## ##
# @QCryptoBlockInfo: # @QCryptoBlockInfo:
@ -318,5 +308,4 @@
{ 'union': 'QCryptoBlockInfo', { 'union': 'QCryptoBlockInfo',
'base': 'QCryptoBlockInfoBase', 'base': 'QCryptoBlockInfoBase',
'discriminator': 'format', 'discriminator': 'format',
'data': { 'qcow': 'QCryptoBlockInfoQCow', 'data': { 'luks': 'QCryptoBlockInfoLUKS' } }
'luks': 'QCryptoBlockInfoLUKS' } }

View File

@ -396,8 +396,7 @@
'mips': 'CpuInfoMIPS', 'mips': 'CpuInfoMIPS',
'tricore': 'CpuInfoTricore', 'tricore': 'CpuInfoTricore',
's390': 'CpuInfoS390', 's390': 'CpuInfoS390',
'riscv': 'CpuInfoRISCV', 'riscv': 'CpuInfoRISCV' } }
'other': 'CpuInfoOther' } }
## ##
# @CpuInfoX86: # @CpuInfoX86:
@ -467,16 +466,6 @@
## ##
{ 'struct': 'CpuInfoRISCV', 'data': { 'pc': 'int' } } { 'struct': 'CpuInfoRISCV', 'data': { 'pc': 'int' } }
##
# @CpuInfoOther:
#
# No additional information is available about the virtual CPU
#
# Since: 2.6
#
##
{ 'struct': 'CpuInfoOther', 'data': { } }
## ##
# @CpuS390State: # @CpuS390State:
# #
@ -578,38 +567,7 @@
'arch' : 'CpuInfoArch', 'arch' : 'CpuInfoArch',
'target' : 'SysEmuTarget' }, 'target' : 'SysEmuTarget' },
'discriminator' : 'target', 'discriminator' : 'target',
'data' : { 'aarch64' : 'CpuInfoOther', 'data' : { 's390x' : 'CpuInfoS390' } }
'alpha' : 'CpuInfoOther',
'arm' : 'CpuInfoOther',
'cris' : 'CpuInfoOther',
'hppa' : 'CpuInfoOther',
'i386' : 'CpuInfoOther',
'lm32' : 'CpuInfoOther',
'm68k' : 'CpuInfoOther',
'microblaze' : 'CpuInfoOther',
'microblazeel' : 'CpuInfoOther',
'mips' : 'CpuInfoOther',
'mips64' : 'CpuInfoOther',
'mips64el' : 'CpuInfoOther',
'mipsel' : 'CpuInfoOther',
'moxie' : 'CpuInfoOther',
'nios2' : 'CpuInfoOther',
'or1k' : 'CpuInfoOther',
'ppc' : 'CpuInfoOther',
'ppc64' : 'CpuInfoOther',
'ppcemb' : 'CpuInfoOther',
'riscv32' : 'CpuInfoOther',
'riscv64' : 'CpuInfoOther',
's390x' : 'CpuInfoS390',
'sh4' : 'CpuInfoOther',
'sh4eb' : 'CpuInfoOther',
'sparc' : 'CpuInfoOther',
'sparc64' : 'CpuInfoOther',
'tricore' : 'CpuInfoOther',
'unicore32' : 'CpuInfoOther',
'x86_64' : 'CpuInfoOther',
'xtensa' : 'CpuInfoOther',
'xtensaeb' : 'CpuInfoOther' } }
## ##
# @query-cpus-fast: # @query-cpus-fast:

View File

@ -88,16 +88,6 @@
## ##
{ 'command': 'netdev_del', 'data': {'id': 'str'} } { 'command': 'netdev_del', 'data': {'id': 'str'} }
##
# @NetdevNoneOptions:
#
# Use it alone to have zero network devices.
#
# Since: 1.2
##
{ 'struct': 'NetdevNoneOptions',
'data': { } }
## ##
# @NetLegacyNicOptions: # @NetLegacyNicOptions:
# #
@ -477,7 +467,6 @@
'base': { 'id': 'str', 'type': 'NetClientDriver' }, 'base': { 'id': 'str', 'type': 'NetClientDriver' },
'discriminator': 'type', 'discriminator': 'type',
'data': { 'data': {
'none': 'NetdevNoneOptions',
'nic': 'NetLegacyNicOptions', 'nic': 'NetLegacyNicOptions',
'user': 'NetdevUserOptions', 'user': 'NetdevUserOptions',
'tap': 'NetdevTapOptions', 'tap': 'NetdevTapOptions',
@ -530,7 +519,6 @@
'base': { 'type': 'NetLegacyOptionsType' }, 'base': { 'type': 'NetLegacyOptionsType' },
'discriminator': 'type', 'discriminator': 'type',
'data': { 'data': {
'none': 'NetdevNoneOptions',
'nic': 'NetLegacyNicOptions', 'nic': 'NetLegacyNicOptions',
'user': 'NetdevUserOptions', 'user': 'NetdevUserOptions',
'tap': 'NetdevTapOptions', 'tap': 'NetdevTapOptions',

View File

@ -995,17 +995,6 @@
'events' : [ 'InputEvent' ] } } 'events' : [ 'InputEvent' ] } }
##
# @DisplayNoOpts:
#
# Empty struct for displays without config options.
#
# Since: 2.12
#
##
{ 'struct' : 'DisplayNoOpts',
'data' : { } }
## ##
# @DisplayGTK: # @DisplayGTK:
# #
@ -1068,10 +1057,4 @@
'*window-close' : 'bool', '*window-close' : 'bool',
'*gl' : 'DisplayGLMode' }, '*gl' : 'DisplayGLMode' },
'discriminator' : 'type', 'discriminator' : 'type',
'data' : { 'default' : 'DisplayNoOpts', 'data' : { 'gtk' : 'DisplayGTK' } }
'none' : 'DisplayNoOpts',
'gtk' : 'DisplayGTK',
'sdl' : 'DisplayNoOpts',
'egl-headless' : 'DisplayNoOpts',
'curses' : 'DisplayNoOpts',
'cocoa' : 'DisplayNoOpts' } }

View File

@ -114,19 +114,30 @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix)
/* /*
* Flatten non-empty QDict and QList recursively into @target, * Flatten non-empty QDict and QList recursively into @target,
* copy other objects to @target * copy other objects to @target.
* On the root level (if @qdict == @target), remove flattened
* nested QDicts and QLists from @qdict.
*
* (Note that we do not need to remove entries from nested
* dicts or lists. Their reference count is decremented on
* the root level, so there are no leaks. In fact, if they
* have a reference count greater than one, we are probably
* well advised not to modify them altogether.)
*/ */
if (dict_val && qdict_size(dict_val)) { if (dict_val && qdict_size(dict_val)) {
qdict_flatten_qdict(dict_val, target, qdict_flatten_qdict(dict_val, target,
new_key ? new_key : entry->key); new_key ? new_key : entry->key);
if (target == qdict) {
qdict_del(qdict, entry->key); qdict_del(qdict, entry->key);
}
} else if (list_val && !qlist_empty(list_val)) { } else if (list_val && !qlist_empty(list_val)) {
qdict_flatten_qlist(list_val, target, qdict_flatten_qlist(list_val, target,
new_key ? new_key : entry->key); new_key ? new_key : entry->key);
if (target == qdict) {
qdict_del(qdict, entry->key); qdict_del(qdict, entry->key);
}
} else if (target != qdict) { } else if (target != qdict) {
qdict_put_obj(target, new_key, qobject_ref(value)); qdict_put_obj(target, new_key, qobject_ref(value));
qdict_del(qdict, entry->key);
} }
g_free(new_key); g_free(new_key);

View File

@ -16,6 +16,7 @@ import errno
import os import os
import re import re
import string import string
import sys
from collections import OrderedDict from collections import OrderedDict
builtin_types = { builtin_types = {
@ -340,6 +341,9 @@ class QAPISchemaParser(object):
return None return None
try: try:
if sys.version_info[0] >= 3:
fobj = open(incl_fname, 'r', encoding='utf-8')
else:
fobj = open(incl_fname, 'r') fobj = open(incl_fname, 'r')
except IOError as e: except IOError as e:
raise QAPISemError(info, '%s: %s' % (e.strerror, incl_fname)) raise QAPISemError(info, '%s: %s' % (e.strerror, incl_fname))
@ -779,13 +783,6 @@ def check_union(expr, info):
"enum '%s'" "enum '%s'"
% (key, enum_define['enum'])) % (key, enum_define['enum']))
# If discriminator is user-defined, ensure all values are covered
if enum_define:
for value in enum_define['data']:
if value not in members.keys():
raise QAPISemError(info, "Union '%s' data missing '%s' branch"
% (name, value))
def check_alternate(expr, info): def check_alternate(expr, info):
name = expr['alternate'] name = expr['alternate']
@ -1357,6 +1354,14 @@ class QAPISchemaObjectTypeVariants(object):
self.tag_member = seen[c_name(self._tag_name)] self.tag_member = seen[c_name(self._tag_name)]
assert self._tag_name == self.tag_member.name assert self._tag_name == self.tag_member.name
assert isinstance(self.tag_member.type, QAPISchemaEnumType) assert isinstance(self.tag_member.type, QAPISchemaEnumType)
if self._tag_name: # flat union
# branches that are not explicitly covered get an empty type
cases = set([v.name for v in self.variants])
for val in self.tag_member.type.values:
if val.name not in cases:
v = QAPISchemaObjectTypeVariant(val.name, 'q_empty')
v.set_owner(self.tag_member.owner)
self.variants.append(v)
for v in self.variants: for v in self.variants:
v.check(schema) v.check(schema)
# Union names must match enum values; alternate names are # Union names must match enum values; alternate names are
@ -1492,7 +1497,11 @@ class QAPISchemaEvent(QAPISchemaEntity):
class QAPISchema(object): class QAPISchema(object):
def __init__(self, fname): def __init__(self, fname):
self._fname = fname self._fname = fname
parser = QAPISchemaParser(open(fname, 'r')) if sys.version_info[0] >= 3:
f = open(fname, 'r', encoding='utf-8')
else:
f = open(fname, 'r')
parser = QAPISchemaParser(f)
exprs = check_exprs(parser.exprs) exprs = check_exprs(parser.exprs)
self.docs = parser.docs self.docs = parser.docs
self._entity_list = [] self._entity_list = []
@ -2006,6 +2015,9 @@ class QAPIGen(object):
if e.errno != errno.EEXIST: if e.errno != errno.EEXIST:
raise raise
fd = os.open(pathname, os.O_RDWR | os.O_CREAT, 0o666) fd = os.open(pathname, os.O_RDWR | os.O_CREAT, 0o666)
if sys.version_info[0] >= 3:
f = open(fd, 'r+', encoding='utf-8')
else:
f = os.fdopen(fd, 'r+') f = os.fdopen(fd, 'r+')
text = (self._top(fname) + self._preamble + self._body text = (self._top(fname) + self._preamble + self._body
+ self._bottom(fname)) + self._bottom(fname))

View File

@ -180,8 +180,9 @@ class QAPISchemaGenEventVisitor(QAPISchemaModularCVisitor):
types=types)) types=types))
def visit_end(self): def visit_end(self):
self._genh.add(gen_enum(self._enum_name, self._event_names)) (genc, genh) = self._module[self._main_module]
self._genc.add(gen_enum_lookup(self._enum_name, self._event_names)) genh.add(gen_enum(self._enum_name, self._event_names))
genc.add(gen_enum_lookup(self._enum_name, self._event_names))
def visit_event(self, name, info, arg_type, boxed): def visit_event(self, name, info, arg_type, boxed):
self._genh.add(gen_event_send_decl(name, arg_type, boxed)) self._genh.add(gen_event_send_decl(name, arg_type, boxed))

View File

@ -75,13 +75,10 @@ class QAPISchemaGenIntrospectVisitor(QAPISchemaMonolithicCVisitor):
def visit_end(self): def visit_end(self):
# visit the types that are actually used # visit the types that are actually used
qlits = self._qlits
self._qlits = []
for typ in self._used_types: for typ in self._used_types:
typ.visit(self) typ.visit(self)
# generate C # generate C
# TODO can generate awfully long lines # TODO can generate awfully long lines
qlits.extend(self._qlits)
name = c_name(self._prefix, protect=False) + 'qmp_schema_qlit' name = c_name(self._prefix, protect=False) + 'qmp_schema_qlit'
self._genh.add(mcgen(''' self._genh.add(mcgen('''
#include "qapi/qmp/qlit.h" #include "qapi/qmp/qlit.h"
@ -93,7 +90,7 @@ extern const QLitObject %(c_name)s;
const QLitObject %(c_name)s = %(c_string)s; const QLitObject %(c_name)s = %(c_string)s;
''', ''',
c_name=c_name(name), c_name=c_name(name),
c_string=to_qlit(qlits))) c_string=to_qlit(self._qlits)))
self._schema = None self._schema = None
self._qlits = [] self._qlits = []
self._used_types = [] self._used_types = []

View File

@ -125,6 +125,8 @@ def gen_variants(variants):
c_name=c_name(variants.tag_member.name)) c_name=c_name(variants.tag_member.name))
for var in variants.variants: for var in variants.variants:
if var.type.name == 'q_empty':
continue
ret += mcgen(''' ret += mcgen('''
%(c_type)s %(c_name)s; %(c_type)s %(c_name)s;
''', ''',

View File

@ -81,14 +81,23 @@ void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
c_name=c_name(variants.tag_member.name)) c_name=c_name(variants.tag_member.name))
for var in variants.variants: for var in variants.variants:
case_str = c_enum_const(variants.tag_member.type.name,
var.name,
variants.tag_member.type.prefix)
if var.type.name == 'q_empty':
# valid variant and nothing to do
ret += mcgen('''
case %(case)s:
break;
''',
case=case_str)
else:
ret += mcgen(''' ret += mcgen('''
case %(case)s: case %(case)s:
visit_type_%(c_type)s_members(v, &obj->u.%(c_name)s, &err); visit_type_%(c_type)s_members(v, &obj->u.%(c_name)s, &err);
break; break;
''', ''',
case=c_enum_const(variants.tag_member.type.name, case=case_str,
var.name,
variants.tag_member.type.prefix),
c_type=var.type.c_name(), c_name=c_name(var.name)) c_type=var.type.c_name(), c_name=c_name(var.name))
ret += mcgen(''' ret += mcgen('''
@ -293,7 +302,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaModularCVisitor):
#include "qapi/qmp/qerror.h" #include "qapi/qmp/qerror.h"
#include "%(visit)s.h" #include "%(visit)s.h"
''', ''',
visit=visit, prefix=self._prefix)) visit=visit))
self._genh.preamble_add(mcgen(''' self._genh.preamble_add(mcgen('''
#include "qapi/qapi-builtin-visit.h" #include "qapi/qapi-builtin-visit.h"
#include "%(types)s.h" #include "%(types)s.h"

View File

@ -499,7 +499,6 @@ qapi-schema += flat-union-base-any.json
qapi-schema += flat-union-base-union.json qapi-schema += flat-union-base-union.json
qapi-schema += flat-union-clash-member.json qapi-schema += flat-union-clash-member.json
qapi-schema += flat-union-empty.json qapi-schema += flat-union-empty.json
qapi-schema += flat-union-incomplete-branch.json
qapi-schema += flat-union-inline.json qapi-schema += flat-union-inline.json
qapi-schema += flat-union-int-branch.json qapi-schema += flat-union-int-branch.json
qapi-schema += flat-union-invalid-branch-key.json qapi-schema += flat-union-invalid-branch-key.json
@ -679,13 +678,13 @@ tests/test-qapi-events.c tests/test-qapi-events.h \
tests/test-qapi-introspect.c tests/test-qapi-introspect.h: \ tests/test-qapi-introspect.c tests/test-qapi-introspect.h: \
tests/test-qapi-gen-timestamp ; tests/test-qapi-gen-timestamp ;
tests/test-qapi-gen-timestamp: $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(qapi-py) tests/test-qapi-gen-timestamp: $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(qapi-py)
$(call quiet-command,$(PYTHON_UTF8) $(SRC_PATH)/scripts/qapi-gen.py \ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-gen.py \
-o tests -p "test-" $<, \ -o tests -p "test-" $<, \
"GEN","$(@:%-timestamp=%)") "GEN","$(@:%-timestamp=%)")
@>$@ @>$@
tests/qapi-schema/doc-good.test.texi: $(SRC_PATH)/tests/qapi-schema/doc-good.json $(qapi-py) tests/qapi-schema/doc-good.test.texi: $(SRC_PATH)/tests/qapi-schema/doc-good.json $(qapi-py)
$(call quiet-command,$(PYTHON_UTF8) $(SRC_PATH)/scripts/qapi-gen.py \ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-gen.py \
-o tests/qapi-schema -p "doc-good-" $<, \ -o tests/qapi-schema -p "doc-good-" $<, \
"GEN","$@") "GEN","$@")
@mv tests/qapi-schema/doc-good-qapi-doc.texi $@ @mv tests/qapi-schema/doc-good-qapi-doc.texi $@
@ -979,7 +978,7 @@ check-tests/qemu-iotests-quick.sh: tests/qemu-iotests-quick.sh qemu-img$(EXESUF)
.PHONY: $(patsubst %, check-%, $(check-qapi-schema-y)) .PHONY: $(patsubst %, check-%, $(check-qapi-schema-y))
$(patsubst %, check-%, $(check-qapi-schema-y)): check-%.json: $(SRC_PATH)/%.json $(patsubst %, check-%, $(check-qapi-schema-y)): check-%.json: $(SRC_PATH)/%.json
$(call quiet-command, PYTHONPATH=$(SRC_PATH)/scripts \ $(call quiet-command, PYTHONPATH=$(SRC_PATH)/scripts \
$(PYTHON_UTF8) $(SRC_PATH)/tests/qapi-schema/test-qapi.py \ $(PYTHON) $(SRC_PATH)/tests/qapi-schema/test-qapi.py \
$^ >$*.test.out 2>$*.test.err; \ $^ >$*.test.out 2>$*.test.err; \
echo $$? >$*.test.exit, \ echo $$? >$*.test.exit, \
"TEST","$*.out") "TEST","$*.out")

View File

@ -125,6 +125,38 @@ static void qdict_flatten_test(void)
qobject_unref(root); qobject_unref(root);
} }
static void qdict_clone_flatten_test(void)
{
QDict *dict1 = qdict_new();
QDict *dict2 = qdict_new();
QDict *cloned_dict1;
/*
* Test that we can clone and flatten
* { "a": { "b": 42 } }
* without modifying the clone.
*/
qdict_put_int(dict2, "b", 42);
qdict_put(dict1, "a", dict2);
cloned_dict1 = qdict_clone_shallow(dict1);
qdict_flatten(dict1);
g_assert(qdict_size(dict1) == 1);
g_assert(qdict_get_int(dict1, "a.b") == 42);
g_assert(qdict_size(cloned_dict1) == 1);
g_assert(qdict_get_qdict(cloned_dict1, "a") == dict2);
g_assert(qdict_size(dict2) == 1);
g_assert(qdict_get_int(dict2, "b") == 42);
qobject_unref(dict1);
qobject_unref(cloned_dict1);
}
static void qdict_array_split_test(void) static void qdict_array_split_test(void)
{ {
QDict *test_dict = qdict_new(); QDict *test_dict = qdict_new();
@ -674,6 +706,7 @@ int main(int argc, char **argv)
g_test_add_func("/public/defaults", qdict_defaults_test); g_test_add_func("/public/defaults", qdict_defaults_test);
g_test_add_func("/public/flatten", qdict_flatten_test); g_test_add_func("/public/flatten", qdict_flatten_test);
g_test_add_func("/public/clone_flatten", qdict_clone_flatten_test);
g_test_add_func("/public/array_split", qdict_array_split_test); g_test_add_func("/public/array_split", qdict_array_split_test);
g_test_add_func("/public/array_entries", qdict_array_entries_test); g_test_add_func("/public/array_entries", qdict_array_entries_test);
g_test_add_func("/public/join", qdict_join_test); g_test_add_func("/public/join", qdict_join_test);

View File

@ -1 +0,0 @@
tests/qapi-schema/flat-union-incomplete-branch.json:6: Union 'TestUnion' data missing 'value2' branch

View File

@ -1,9 +0,0 @@
# we require all branches of the union to be covered
{ 'enum': 'TestEnum',
'data': [ 'value1', 'value2' ] }
{ 'struct': 'TestTypeA',
'data': { 'string': 'str' } }
{ 'union': 'TestUnion',
'base': { 'type': 'TestEnum' },
'discriminator': 'type',
'data': { 'value1': 'TestTypeA' } }

View File

@ -39,7 +39,7 @@
'*enum1': 'EnumOne' } } # intentional forward reference '*enum1': 'EnumOne' } } # intentional forward reference
{ 'enum': 'EnumOne', { 'enum': 'EnumOne',
'data': [ 'value1', 'value2', 'value3' ] } 'data': [ 'value1', 'value2', 'value3', 'value4' ] }
{ 'struct': 'UserDefZero', { 'struct': 'UserDefZero',
'data': { 'integer': 'int' } } 'data': { 'integer': 'int' } }
@ -76,7 +76,9 @@
'discriminator': 'enum1', 'discriminator': 'enum1',
'data': { 'value1' : 'UserDefA', 'data': { 'value1' : 'UserDefA',
'value2' : 'UserDefB', 'value2' : 'UserDefB',
'value3' : 'UserDefB' } } 'value3' : 'UserDefB'
# 'value4' defaults to empty
} }
{ 'struct': 'UserDefUnionBase', { 'struct': 'UserDefUnionBase',
'base': 'UserDefZero', 'base': 'UserDefZero',

View File

@ -23,7 +23,7 @@ object UserDefOne
base UserDefZero base UserDefZero
member string: str optional=False member string: str optional=False
member enum1: EnumOne optional=True member enum1: EnumOne optional=True
enum EnumOne ['value1', 'value2', 'value3'] enum EnumOne ['value1', 'value2', 'value3', 'value4']
object UserDefZero object UserDefZero
member integer: int optional=False member integer: int optional=False
object UserDefTwoDictDict object UserDefTwoDictDict
@ -52,6 +52,7 @@ object UserDefFlatUnion
case value1: UserDefA case value1: UserDefA
case value2: UserDefB case value2: UserDefB
case value3: UserDefB case value3: UserDefB
case value4: q_empty
object UserDefUnionBase object UserDefUnionBase
base UserDefZero base UserDefZero
member string: str optional=False member string: str optional=False