[PATCH 0/8] qemu-replies-tool: Improvements for .replies comparison

Add few more stable dumps to help comparing two .replies files (especially useful when updating to new git versions of qemu) Peter Krempa (8): scripts: qemu-replies-tool: Convert the QMP conversation to list of dicts scripts: qemu-replies-tool: Drop specific invocation of marginally useful dump modes scripts: qemu-replies-tool: Dump machine types in --dump-all scripts: qemu-replies-tool: List also data from 'qom-list-properties' scripts: qemu-replies-tool: Prefix output with filename when dumping data for multiple files scripts: qemu-replies-tool: Dump data from query-version/query-target/query-kvm scripts: qemu-replies-tool: Add stable dump of 'query-command-line-options' scripts: qemu-replies-tool: Add option to dump JSON commands that weren't processed by --dump-all scripts/qemu-replies-tool.py | 271 ++++++++++++++++++++++++++--------- 1 file changed, 207 insertions(+), 64 deletions(-) -- 2.51.0

From: Peter Krempa <pkrempa@redhat.com> Currently the conversation was a list of tuples. Since upcoming patches will want to store some additional flags with the processed commands convert it to a list of dicts, so that we can name the individual fields. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- scripts/qemu-replies-tool.py | 54 ++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/scripts/qemu-replies-tool.py b/scripts/qemu-replies-tool.py index 6d474a83f2..4ec06ee95d 100755 --- a/scripts/qemu-replies-tool.py +++ b/scripts/qemu-replies-tool.py @@ -36,13 +36,13 @@ def qemu_replies_load(filename): if command is None: command = json.loads(jsonstr) else: - conv.append((command, json.loads(jsonstr))) + conv.append({'cmd': command, 'rep': json.loads(jsonstr)}) command = None jsonstr = '' if command is not None and jsonstr != '': - conv.append((command, json.loads(jsonstr))) + conv.append({'cmd': command, 'rep': json.loads(jsonstr)}) command = None jsonstr = '' @@ -67,14 +67,14 @@ def qemu_replies_compare_or_replace(filename, conv, regenerate_on_error): seq = 9999 # poison the initial counter state # possibly fix mis-ordererd 'id' fields - for (cmd, rep) in conv: + for c in conv: # 'qmp_capabilities' command restarts the numbering sequence - if cmd['execute'] == 'qmp_capabilities': + if c['cmd']['execute'] == 'qmp_capabilities': seq = 1 newid = 'libvirt-%d' % seq - cmd['id'] = newid - rep['id'] = newid + c['cmd']['id'] = newid + c['rep']['id'] = newid seq += 1 @@ -82,7 +82,7 @@ def qemu_replies_compare_or_replace(filename, conv, regenerate_on_error): if len(actual) != 0: actual += '\n\n' - actual += json.dumps(cmd, indent=2) + '\n\n' + json.dumps(rep, indent=2) + actual += json.dumps(c['cmd'], indent=2) + '\n\n' + json.dumps(c['rep'], indent=2) expect = '' actual += '\n' @@ -114,9 +114,9 @@ def modify_replies(conv): version = None # filled with a dictionary with 'major', 'minor', 'micro' keys # find version of current qemu for later use - for (cmd, rep) in conv: - if cmd['execute'] == 'query-version': - version = rep['return']['qemu'] + for c in conv: + if c['cmd']['execute'] == 'query-version': + version = c['rep']['return']['qemu'] break if version is None: @@ -126,9 +126,9 @@ def modify_replies(conv): # Find index of a command, in this case we're looking for the last # invocation of given command for i in range(len(conv)): - (cmd, rep) = conv[i] + c = conv[i] - if cmd['execute'] == 'device-list-properties': + if c['cmd']['execute'] == 'device-list-properties': idx = i if idx == -1: @@ -161,9 +161,9 @@ def modify_replies(conv): # insert command into the QMP conversation based on version of qemu if version['major'] >= 8 and version['minor'] > 0: - conv.insert(idx, (cmd, reply)) + conv.insert(idx, {'cmd': cmd, 'rep': reply}) else: - conv.insert(idx, (cmd, reply_unsupp)) + conv.insert(idx, {'cmd': cmd, 'rep': reply_unsupp}) # Validates that 'entry' (an member of the QMP schema): @@ -389,9 +389,9 @@ def dump_qmp_probe_strings(schemalist): def dump_qom_list_types(conv): types = [] - for (cmd, rep) in conv: - if cmd['execute'] == 'qom-list-types': - for qomtype in rep['return']: + for c in conv: + if c['cmd']['execute'] == 'qom-list-types': + for qomtype in c['rep']['return']: # validate known fields: # 'parent' is ignored below as it causes output churn for k in qomtype: @@ -411,20 +411,20 @@ def dump_qom_list_types(conv): def dump_device_list_properties(conv): devices = [] - for (cmd, rep) in conv: - if cmd['execute'] == 'device-list-properties': - if 'return' in rep: - for arg in rep['return']: + for c in conv: + if c['cmd']['execute'] == 'device-list-properties': + if 'return' in c['rep']: + for arg in c['rep']['return']: for k in arg: if k not in ['name', 'type', 'description', 'default-value']: - raise Exception("Unhandled 'device-list-properties' typename '%s' field '%s'" % (cmd['arguments']['typename'], k)) + raise Exception("Unhandled 'device-list-properties' typename '%s' field '%s'" % (c['cmd']['arguments']['typename'], k)) if 'default-value' in arg: defval = ' (%s)' % str(arg['default-value']) else: defval = '' - devices.append('%s %s %s%s' % (cmd['arguments']['typename'], + devices.append('%s %s %s%s' % (c['cmd']['arguments']['typename'], arg['name'], arg['type'], defval)) @@ -441,12 +441,12 @@ def process_one(filename, args): modify_replies(conv) - for (cmd, rep) in conv: - if cmd['execute'] == 'query-qmp-schema': - validate_qmp_schema(rep['return']) + for c in conv: + if c['cmd']['execute'] == 'query-qmp-schema': + validate_qmp_schema(c['rep']['return']) if args.dump_all or args.dump_qmp_query_strings: - dump_qmp_probe_strings(rep['return']) + dump_qmp_probe_strings(c['rep']['return']) dumped = True if args.dump_all or args.dump_qom_list_types: -- 2.51.0

From: Peter Krempa <pkrempa@redhat.com> While '--dump-qmp-query-strings' is useful by itself because it's a simple way to generate the QMP schema query strings for libvirt, the other modes aren't useful besides comparing two .replies files by the dumped output. Remove specific options for '--dump-qom-list-types' and '--dump-device-list-properties', so that upcoming additions which will be useful only for comparisons aren't forced to add these options. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- scripts/qemu-replies-tool.py | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/scripts/qemu-replies-tool.py b/scripts/qemu-replies-tool.py index 4ec06ee95d..b5e4ae46ca 100755 --- a/scripts/qemu-replies-tool.py +++ b/scripts/qemu-replies-tool.py @@ -449,11 +449,8 @@ def process_one(filename, args): dump_qmp_probe_strings(c['rep']['return']) dumped = True - if args.dump_all or args.dump_qom_list_types: + if args.dump_all: dump_qom_list_types(conv) - dumped = True - - if args.dump_all or args.dump_device_list_properties: dump_device_list_properties(conv) dumped = True @@ -492,7 +489,8 @@ In 'dump' mode if '-dump-all' or one of the specific '-dump-*' flags (below) is selected the script outputs information gathered from the given '.replies' file. The data is also usable for comparing two '.replies' files in a "diffable" fashion as many of the query commands may change ordering or naming without -functional impact on libvirt. +functional impact on libvirt. The following specific dump options are useful +on it's own: --dump-qmp-query-strings @@ -501,16 +499,6 @@ functional impact on libvirt. virQEMUCapsQMPSchemaQueries. It's useful to find specific query string without having to piece the information together from 'query-qmp-schema' - --dump-qom-list-types - - Dumps all types returned by 'qom-list-types' in a stable order with the - 'parent' property dropped as it's not relevant for libvirt. - - --dump-device-list-properties - - Dumps all properties of all devices queried by libvirt in stable order - along with types and default values. - The tool can be also used to programmaticaly modify the '.replies' file by editing the 'modify_replies' method directly in the source, or for re-formatting and re-numbering the '.replies' file to conform with the required @@ -541,12 +529,6 @@ parser.add_argument('--dump-all', action='store_true', parser.add_argument('--dump-qmp-query-strings', action='store_true', help='dump QMP schema in form of query strings used to probe capabilities') -parser.add_argument('--dump-qom-list-types', action='store_true', - help='dump data from qom-list-types in a stable order') - -parser.add_argument('--dump-device-list-properties', action='store_true', - help='dump all devices and their properties') - args = parser.parse_args() files = [] -- 2.51.0

From: Peter Krempa <pkrempa@redhat.com> Dumps the supported machine types and their deprecation state in stable human-sort order. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- scripts/qemu-replies-tool.py | 57 ++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/scripts/qemu-replies-tool.py b/scripts/qemu-replies-tool.py index b5e4ae46ca..211c448482 100755 --- a/scripts/qemu-replies-tool.py +++ b/scripts/qemu-replies-tool.py @@ -10,6 +10,7 @@ import argparse import json import os import sys +import re class qrtException(Exception): @@ -434,6 +435,61 @@ def dump_device_list_properties(conv): print('(dev) ' + d) +# Sort helper for version string e.g. '11.0', '1.2' etc. Tolerates empty version. +def machine_type_sorter(item): + key = item[0] + + if key == '': + return [0] + + return list(map(int, key.split('.'))) + + +def dump_machine_types(conv): + machines = dict() + aliases = [] + + for c in conv: + if c['cmd']['execute'] == 'query-machines': + for machine in c['rep']['return']: + deprecated = False + name = machine['name'] + version = '' + match = re.fullmatch(r'(.+)-(\d+\.\d+)', name) + + if match is not None: + name = match.group(1) + version = match.group(2) + + if 'deprecated' in machine: + deprecated = machine['deprecated'] + + if 'alias' in machine: + aliases.append('%s -> %s' % (machine['alias'], machine['name'])) + + if name not in machines: + machines[name] = {} + + machines[name][version] = deprecated + break + + for (machine, versions) in sorted(machines.items()): + for (version, deprecated) in sorted(versions.items(), key=machine_type_sorter): + d = '' + if deprecated: + d = ' (deprecated)' + + if len(version) > 0: + version = '-' + version + + print('(machine) %s%s%s' % (machine, version, d)) + + aliases.sort() + + for a in aliases: + print('(machine alias) ' + a) + + def process_one(filename, args): try: conv = qemu_replies_load(filename) @@ -452,6 +508,7 @@ def process_one(filename, args): if args.dump_all: dump_qom_list_types(conv) dump_device_list_properties(conv) + dump_machine_types(conv) dumped = True if dumped: -- 2.51.0

From: Peter Krempa <pkrempa@redhat.com> In addition to 'device-list-properties' libvirt probes also some properties of qom types. Since the format is identical make the dumping function for 'device-list-properties' universal and make it accept also 'qom-list-types'. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- scripts/qemu-replies-tool.py | 50 +++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/scripts/qemu-replies-tool.py b/scripts/qemu-replies-tool.py index 211c448482..77d96f625d 100755 --- a/scripts/qemu-replies-tool.py +++ b/scripts/qemu-replies-tool.py @@ -409,30 +409,40 @@ def dump_qom_list_types(conv): print('(qom) ' + t) -def dump_device_list_properties(conv): - devices = [] +def dump_device_and_object_properties(conv): + ent = [] for c in conv: + prefix = None + if c['cmd']['execute'] == 'device-list-properties': - if 'return' in c['rep']: - for arg in c['rep']['return']: - for k in arg: - if k not in ['name', 'type', 'description', 'default-value']: - raise Exception("Unhandled 'device-list-properties' typename '%s' field '%s'" % (c['cmd']['arguments']['typename'], k)) - - if 'default-value' in arg: - defval = ' (%s)' % str(arg['default-value']) - else: - defval = '' + prefix = '(dev-prop)' + + if c['cmd']['execute'] == 'qom-list-properties': + prefix = '(qom-prop)' + + if prefix is None or 'return' not in c['rep']: + continue + + for arg in c['rep']['return']: + for k in arg: + if k not in ['name', 'type', 'description', 'default-value']: + raise Exception("Unhandled 'device-list-properties'/'qom-list-properties' typename '%s' field '%s'" % (c['cmd']['arguments']['typename'], k)) + + if 'default-value' in arg: + defval = ' (%s)' % str(arg['default-value']) + else: + defval = '' - devices.append('%s %s %s%s' % (c['cmd']['arguments']['typename'], - arg['name'], - arg['type'], - defval)) - devices.sort() + ent.append('%s %s %s %s%s' % (prefix, + c['cmd']['arguments']['typename'], + arg['name'], + arg['type'], + defval)) + ent.sort() - for d in devices: - print('(dev) ' + d) + for e in ent: + print(e) # Sort helper for version string e.g. '11.0', '1.2' etc. Tolerates empty version. @@ -507,7 +517,7 @@ def process_one(filename, args): if args.dump_all: dump_qom_list_types(conv) - dump_device_list_properties(conv) + dump_device_and_object_properties(conv) dump_machine_types(conv) dumped = True -- 2.51.0

From: Peter Krempa <pkrempa@redhat.com> The --dump-* mode can be used together with --repliesdir which iterates over all '.replies' files in the directory. Make this useful by outputing the filename so the user can associate the data with the file it was dumped from. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- scripts/qemu-replies-tool.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/scripts/qemu-replies-tool.py b/scripts/qemu-replies-tool.py index 77d96f625d..8e48268456 100755 --- a/scripts/qemu-replies-tool.py +++ b/scripts/qemu-replies-tool.py @@ -371,7 +371,7 @@ def dump_qmp_probe_strings_iter(name, cur, trace, schema): dump_qmp_probe_strings_iter(var['type'], cur, trace, schema) -def dump_qmp_probe_strings(schemalist): +def dump_qmp_probe_strings(schemalist, dumpprefix): schemadict = {} toplevel = [] @@ -384,10 +384,10 @@ def dump_qmp_probe_strings(schemalist): toplevel.sort() for c in toplevel: - dump_qmp_probe_strings_iter(c, '(qmp) ' + c, [], schemadict) + dump_qmp_probe_strings_iter(c, dumpprefix + '(qmp) ' + c, [], schemadict) -def dump_qom_list_types(conv): +def dump_qom_list_types(conv, dumpprefix): types = [] for c in conv: @@ -406,10 +406,10 @@ def dump_qom_list_types(conv): types.sort() for t in types: - print('(qom) ' + t) + print(dumpprefix + '(qom) ' + t) -def dump_device_and_object_properties(conv): +def dump_device_and_object_properties(conv, dumpprefix): ent = [] for c in conv: @@ -442,7 +442,7 @@ def dump_device_and_object_properties(conv): ent.sort() for e in ent: - print(e) + print(dumpprefix + e) # Sort helper for version string e.g. '11.0', '1.2' etc. Tolerates empty version. @@ -455,7 +455,7 @@ def machine_type_sorter(item): return list(map(int, key.split('.'))) -def dump_machine_types(conv): +def dump_machine_types(conv, dumpprefix): machines = dict() aliases = [] @@ -497,13 +497,17 @@ def dump_machine_types(conv): aliases.sort() for a in aliases: - print('(machine alias) ' + a) + print(dumpprefix + '(machine alias) ' + a) def process_one(filename, args): try: conv = qemu_replies_load(filename) dumped = False + dumpprefix = '' + + if args.repliesdir: + dumpprefix = filename + ': ' modify_replies(conv) @@ -512,13 +516,13 @@ def process_one(filename, args): validate_qmp_schema(c['rep']['return']) if args.dump_all or args.dump_qmp_query_strings: - dump_qmp_probe_strings(c['rep']['return']) + dump_qmp_probe_strings(c['rep']['return'], dumpprefix) dumped = True if args.dump_all: - dump_qom_list_types(conv) - dump_device_and_object_properties(conv) - dump_machine_types(conv) + dump_qom_list_types(conv, dumpprefix) + dump_device_and_object_properties(conv, dumpprefix) + dump_machine_types(conv, dumpprefix) dumped = True if dumped: -- 2.51.0

From: Peter Krempa <pkrempa@redhat.com> Process few other simple commands. While this output doesn't change places it's useful to see it when comparing the dumps of two .replies files. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- scripts/qemu-replies-tool.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/scripts/qemu-replies-tool.py b/scripts/qemu-replies-tool.py index 8e48268456..7cda1d57ad 100755 --- a/scripts/qemu-replies-tool.py +++ b/scripts/qemu-replies-tool.py @@ -500,6 +500,24 @@ def dump_machine_types(conv, dumpprefix): print(dumpprefix + '(machine alias) ' + a) +def dump_other(conv, dumpprefix): + for c in conv: + if c['cmd']['execute'] == 'query-version': + print('%s(version) %s.%s.%s %s' % (dumpprefix, + c['rep']['return']['qemu']['major'], + c['rep']['return']['qemu']['minor'], + c['rep']['return']['qemu']['micro'], + c['rep']['return']['package'])) + + if c['cmd']['execute'] == 'query-target': + print('%s(target) %s' % (dumpprefix, c['rep']['return']['arch'])) + + if c['cmd']['execute'] == 'query-kvm': + print('%s(kvm) present:%s enabled:%s' % (dumpprefix, + c['rep']['return']['present'], + c['rep']['return']['enabled'])) + + def process_one(filename, args): try: conv = qemu_replies_load(filename) @@ -520,6 +538,7 @@ def process_one(filename, args): dumped = True if args.dump_all: + dump_other(conv, dumpprefix) dump_qom_list_types(conv, dumpprefix) dump_device_and_object_properties(conv, dumpprefix) dump_machine_types(conv, dumpprefix) -- 2.51.0

From: Peter Krempa <pkrempa@redhat.com> While 'query-command-line-options' is usually fairly stable (for comparing between two .replies files) it's simpler to compare it in the dumped variant. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- scripts/qemu-replies-tool.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/scripts/qemu-replies-tool.py b/scripts/qemu-replies-tool.py index 7cda1d57ad..e5a1b2fb3e 100755 --- a/scripts/qemu-replies-tool.py +++ b/scripts/qemu-replies-tool.py @@ -500,6 +500,19 @@ def dump_machine_types(conv, dumpprefix): print(dumpprefix + '(machine alias) ' + a) +def dump_command_line_options(c, dumpprefix): + optpar = [] + + for opt in c['rep']['return']: + for par in opt['parameters']: + optpar.append('%s %s' % (opt['option'], par['name'])) + + optpar.sort() + + for o in optpar: + print(dumpprefix + '(cl-opt) ' + o) + + def dump_other(conv, dumpprefix): for c in conv: if c['cmd']['execute'] == 'query-version': @@ -517,6 +530,9 @@ def dump_other(conv, dumpprefix): c['rep']['return']['present'], c['rep']['return']['enabled'])) + if c['cmd']['execute'] == 'query-command-line-options': + dump_command_line_options(c, dumpprefix) + def process_one(filename, args): try: -- 2.51.0

From: Peter Krempa <pkrempa@redhat.com> This is useful for checking that the script still covers everything when using it to compare two .replies files. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- scripts/qemu-replies-tool.py | 59 ++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/scripts/qemu-replies-tool.py b/scripts/qemu-replies-tool.py index e5a1b2fb3e..cf99ecd1f3 100755 --- a/scripts/qemu-replies-tool.py +++ b/scripts/qemu-replies-tool.py @@ -401,6 +401,8 @@ def dump_qom_list_types(conv, dumpprefix): types.append(qomtype['name']) + c['processed'] = True + break types.sort() @@ -421,7 +423,12 @@ def dump_device_and_object_properties(conv, dumpprefix): if c['cmd']['execute'] == 'qom-list-properties': prefix = '(qom-prop)' - if prefix is None or 'return' not in c['rep']: + if prefix is None: + continue + + c['processed'] = True + + if 'return' not in c['rep']: continue for arg in c['rep']['return']: @@ -458,9 +465,16 @@ def machine_type_sorter(item): def dump_machine_types(conv, dumpprefix): machines = dict() aliases = [] + dumped_kvm = False for c in conv: if c['cmd']['execute'] == 'query-machines': + + c['processed'] = True + + if dumped_kvm: + continue + for machine in c['rep']['return']: deprecated = False name = machine['name'] @@ -481,7 +495,9 @@ def dump_machine_types(conv, dumpprefix): machines[name] = {} machines[name][version] = deprecated - break + + # Dump only the machines for the first occurence of 'query-machines' + dumped_kvm = True for (machine, versions) in sorted(machines.items()): for (version, deprecated) in sorted(versions.items(), key=machine_type_sorter): @@ -521,17 +537,47 @@ def dump_other(conv, dumpprefix): c['rep']['return']['qemu']['minor'], c['rep']['return']['qemu']['micro'], c['rep']['return']['package'])) + c['processed'] = True if c['cmd']['execute'] == 'query-target': print('%s(target) %s' % (dumpprefix, c['rep']['return']['arch'])) + c['processed'] = True if c['cmd']['execute'] == 'query-kvm': print('%s(kvm) present:%s enabled:%s' % (dumpprefix, c['rep']['return']['present'], c['rep']['return']['enabled'])) + c['processed'] = True if c['cmd']['execute'] == 'query-command-line-options': dump_command_line_options(c, dumpprefix) + c['processed'] = True + + +# dumps the parts of the .replies file which are not handled by the various dump_ +# helpers +def dump_unprocessed(conv): + actual = '' + + for c in conv: + if 'processed' in c and c['processed'] is True: + continue + + # skip stuf not making sense to be processed: + # 'qmp_capabilities' - startup of QMP, no interesting data + # 'query-cpu-model-expansion' - too host dependant, nothing relevant + if c['cmd']['execute'] in ['qmp_capabilities', 'query-cpu-model-expansion']: + continue + + # skip commands not having successful return + if 'return' not in c['rep']: + continue + + actual += json.dumps(c['cmd'], indent=2) + '\n\n' + json.dumps(c['rep'], indent=2) + + if actual != '': + for line in actual.split('\n'): + print('(unprocessed) ' + line) def process_one(filename, args): @@ -551,6 +597,7 @@ def process_one(filename, args): if args.dump_all or args.dump_qmp_query_strings: dump_qmp_probe_strings(c['rep']['return'], dumpprefix) + c['processed'] = True dumped = True if args.dump_all: @@ -560,6 +607,10 @@ def process_one(filename, args): dump_machine_types(conv, dumpprefix) dumped = True + if args.dump_unprocessed: + dump_unprocessed(conv) + dumped = True + if dumped: return True @@ -635,6 +686,10 @@ parser.add_argument('--dump-all', action='store_true', parser.add_argument('--dump-qmp-query-strings', action='store_true', help='dump QMP schema in form of query strings used to probe capabilities') + +parser.add_argument('--dump-unprocessed', action='store_true', + help='dump JSON of commands unprocessed by any of the --dump-* options') + args = parser.parse_args() files = [] -- 2.51.0

On a Friday in 2025, Peter Krempa via Devel wrote:
Add few more stable dumps to help comparing two .replies files (especially useful when updating to new git versions of qemu)
Peter Krempa (8): scripts: qemu-replies-tool: Convert the QMP conversation to list of dicts scripts: qemu-replies-tool: Drop specific invocation of marginally useful dump modes scripts: qemu-replies-tool: Dump machine types in --dump-all scripts: qemu-replies-tool: List also data from 'qom-list-properties' scripts: qemu-replies-tool: Prefix output with filename when dumping data for multiple files scripts: qemu-replies-tool: Dump data from query-version/query-target/query-kvm scripts: qemu-replies-tool: Add stable dump of 'query-command-line-options' scripts: qemu-replies-tool: Add option to dump JSON commands that weren't processed by --dump-all
scripts/qemu-replies-tool.py | 271 ++++++++++++++++++++++++++--------- 1 file changed, 207 insertions(+), 64 deletions(-)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano
participants (2)
-
Ján Tomko
-
Peter Krempa