mirror of
https://github.com/mii443/qemu.git
synced 2025-12-03 11:08:25 +00:00
Merge tag 'python-pull-request' of https://gitlab.com/jsnow/qemu into staging
Python Pullreq Python PR: - Use socketpair for all machine.py connections - Support Python 3.12 - Switch iotests over to using raise-on-error QMP command interface (Thank you very much, Vladimir!) # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCAAdFiEE+ber27ys35W+dsvQfe+BBqr8OQ4FAmUpldkACgkQfe+BBqr8 # OQ4NtRAAnkEmXsECAxQ2ewvf3yK8PTFm4Oq5nqMIw+KB94ATrsGzk3z1rLvatSl3 # 6VLsV2+FWoOEyKrsfu5DIfbuo4d3TZTU7N2DIZpVpvO166K+fXbzp8skAg+n3BMC # tWkSOcnsT6+8aqyxxyASdHvbbE7pvPw8OA3oIIstsYeZ5/HHpOWXNj1kjCsnL0lW # 7y5h6UUKGmnCPdixyk042+AvKkT7GAKVjFnjUF5JHv0iR2KpQ+O9H7OEalqQT5w5 # eab4oMGuIYhzYe+MNpyybAB3Xd2pxhcppk+sl4dCE8qmMn7KRoTNw1iu+qhsNQfQ # JILZoCPtYMhpef4X0ulH8PFBMweBptqOjo4lpz9QIdMWTf86IE0yIT9DCy3aSjpp # ywwxhFKJS43gz4WHkEJlrY9PHwLsULaV/Cz6HKJAU6h9aFtcNdT4pkCOERnZ8X4C # yHlNReTG5Dz1sYzKJ/k9LTjAaVDasumR8/yadaUCwalj5zexQ27qlIM6oc5wdIRQ # up1VHi7odF5KHb6GeqdniuuEF6NBCYRAV5nz+dbd6exfKOaxYRrr48yh9SUm8QS6 # JCvMMFFAZCIrI/nkRVajbLi9L5O3fg5abtlzSzh9o4iyf8Rf/1gtKNxZRK1NZIjQ # cTYBJXpMulNx7bM2CPNsPWGqCTAjAcu10svqTA8luGj4fqdTNyU= # =02Bd # -----END PGP SIGNATURE----- # gpg: Signature made Fri 13 Oct 2023 15:09:13 EDT # gpg: using RSA key F9B7ABDBBCACDF95BE76CBD07DEF8106AAFC390E # gpg: Good signature from "John Snow (John Huston) <jsnow@redhat.com>" [full] # Primary key fingerprint: FAEB 9711 A12C F475 812F 18F2 88A9 064D 1835 61EB # Subkey fingerprint: F9B7 ABDB BCAC DF95 BE76 CBD0 7DEF 8106 AAFC 390E * tag 'python-pull-request' of https://gitlab.com/jsnow/qemu: (25 commits) python: use vm.cmd() instead of vm.qmp() where appropriate scripts: add python_qmp_updater.py tests/vm/basevm.py: use cmd() instead of qmp() iotests.py: pause_job(): drop return value iotests: drop some extra ** in qmp() call iotests: drop some extra semicolons iotests: refactor some common qmp result checks into generic pattern iotests: add some missed checks of qmp result iotests: QemuStorageDaemon: add cmd() method like in QEMUMachine. python/machine.py: upgrade vm.cmd() method python/qemu: rename command() to cmd() python: rename QEMUMonitorProtocol.cmd() to cmd_raw() scripts/cpu-x86-uarch-abi.py: use .command() instead of .cmd() qmp_shell.py: _fill_completion() use .command() instead of .cmd() python/qemu/qmp/legacy: cmd(): drop cmd_id unused argument Python: Enable python3.12 support configure: fix error message to say Python 3.8 python/qmp: remove Server.wait_closed() call for Python 3.12 Python/iotests: Add type hint for nbd module python/machine: remove unused sock_dir argument ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
@@ -85,7 +85,7 @@ skip = [
|
||||
|
||||
names = []
|
||||
|
||||
for model in models["return"]:
|
||||
for model in models:
|
||||
if "alias-of" in model:
|
||||
continue
|
||||
names.append(model["name"])
|
||||
@@ -94,11 +94,11 @@ models = {}
|
||||
|
||||
for name in sorted(names):
|
||||
cpu = shell.cmd("query-cpu-model-expansion",
|
||||
{ "type": "static",
|
||||
"model": { "name": name }})
|
||||
{ "type": "static",
|
||||
"model": { "name": name }})
|
||||
|
||||
got = {}
|
||||
for (feature, present) in cpu["return"]["model"]["props"].items():
|
||||
for (feature, present) in cpu["model"]["props"].items():
|
||||
if present and feature not in skip:
|
||||
got[feature] = True
|
||||
|
||||
|
||||
@@ -269,14 +269,14 @@ def formatTestCase(t):
|
||||
|
||||
def qomListTypeNames(vm, **kwargs):
|
||||
"""Run qom-list-types QMP command, return type names"""
|
||||
types = vm.command('qom-list-types', **kwargs)
|
||||
types = vm.cmd('qom-list-types', **kwargs)
|
||||
return [t['name'] for t in types]
|
||||
|
||||
|
||||
def infoQDM(vm):
|
||||
"""Parse 'info qdm' output"""
|
||||
args = {'command-line': 'info qdm'}
|
||||
devhelp = vm.command('human-monitor-command', **args)
|
||||
devhelp = vm.cmd('human-monitor-command', **args)
|
||||
for l in devhelp.split('\n'):
|
||||
l = l.strip()
|
||||
if l == '' or l.endswith(':'):
|
||||
@@ -304,9 +304,9 @@ class QemuBinaryInfo(object):
|
||||
# there's no way to query DeviceClass::user_creatable using QMP,
|
||||
# so use 'info qdm':
|
||||
self.no_user_devs = set([d['name'] for d in infoQDM(vm, ) if d['no-user']])
|
||||
self.machines = list(m['name'] for m in vm.command('query-machines'))
|
||||
self.machines = list(m['name'] for m in vm.cmd('query-machines'))
|
||||
self.user_devs = self.alldevs.difference(self.no_user_devs)
|
||||
self.kvm_available = vm.command('query-kvm')['enabled']
|
||||
self.kvm_available = vm.cmd('query-kvm')['enabled']
|
||||
finally:
|
||||
vm.shutdown()
|
||||
|
||||
|
||||
136
scripts/python_qmp_updater.py
Executable file
136
scripts/python_qmp_updater.py
Executable file
@@ -0,0 +1,136 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Intended usage:
|
||||
#
|
||||
# git grep -l '\.qmp(' | xargs ./scripts/python_qmp_updater.py
|
||||
#
|
||||
|
||||
import re
|
||||
import sys
|
||||
from typing import Optional
|
||||
|
||||
start_reg = re.compile(r'^(?P<padding> *)(?P<res>\w+) = (?P<vm>.*).qmp\(',
|
||||
flags=re.MULTILINE)
|
||||
|
||||
success_reg_templ = re.sub('\n *', '', r"""
|
||||
(\n*{padding}(?P<comment>\#.*$))?
|
||||
\n*{padding}
|
||||
(
|
||||
self.assert_qmp\({res},\ 'return',\ {{}}\)
|
||||
|
|
||||
assert\ {res}\['return'\]\ ==\ {{}}
|
||||
|
|
||||
assert\ {res}\ ==\ {{'return':\ {{}}}}
|
||||
|
|
||||
self.assertEqual\({res}\['return'\],\ {{}}\)
|
||||
)""")
|
||||
|
||||
some_check_templ = re.sub('\n *', '', r"""
|
||||
(\n*{padding}(?P<comment>\#.*$))?
|
||||
\s*self.assert_qmp\({res},""")
|
||||
|
||||
|
||||
def tmatch(template: str, text: str,
|
||||
padding: str, res: str) -> Optional[re.Match[str]]:
|
||||
return re.match(template.format(padding=padding, res=res), text,
|
||||
flags=re.MULTILINE)
|
||||
|
||||
|
||||
def find_closing_brace(text: str, start: int) -> int:
|
||||
"""
|
||||
Having '(' at text[start] search for pairing ')' and return its index.
|
||||
"""
|
||||
assert text[start] == '('
|
||||
|
||||
height = 1
|
||||
|
||||
for i in range(start + 1, len(text)):
|
||||
if text[i] == '(':
|
||||
height += 1
|
||||
elif text[i] == ')':
|
||||
height -= 1
|
||||
if height == 0:
|
||||
return i
|
||||
|
||||
raise ValueError
|
||||
|
||||
|
||||
def update(text: str) -> str:
|
||||
result = ''
|
||||
|
||||
while True:
|
||||
m = start_reg.search(text)
|
||||
if m is None:
|
||||
result += text
|
||||
break
|
||||
|
||||
result += text[:m.start()]
|
||||
|
||||
args_ind = m.end()
|
||||
args_end = find_closing_brace(text, args_ind - 1)
|
||||
|
||||
all_args = text[args_ind:args_end].split(',', 1)
|
||||
|
||||
name = all_args[0]
|
||||
args = None if len(all_args) == 1 else all_args[1]
|
||||
|
||||
unchanged_call = text[m.start():args_end+1]
|
||||
text = text[args_end+1:]
|
||||
|
||||
padding, res, vm = m.group('padding', 'res', 'vm')
|
||||
|
||||
m = tmatch(success_reg_templ, text, padding, res)
|
||||
|
||||
if m is None:
|
||||
result += unchanged_call
|
||||
|
||||
if ('query-' not in name and
|
||||
'x-debug-block-dirty-bitmap-sha256' not in name and
|
||||
not tmatch(some_check_templ, text, padding, res)):
|
||||
print(unchanged_call + text[:200] + '...\n\n')
|
||||
|
||||
continue
|
||||
|
||||
if m.group('comment'):
|
||||
result += f'{padding}{m.group("comment")}\n'
|
||||
|
||||
result += f'{padding}{vm}.cmd({name}'
|
||||
|
||||
if args:
|
||||
result += ','
|
||||
|
||||
if '\n' in args:
|
||||
m_args = re.search('(?P<pad> *).*$', args)
|
||||
assert m_args is not None
|
||||
|
||||
cur_padding = len(m_args.group('pad'))
|
||||
expected = len(f'{padding}{res} = {vm}.qmp(')
|
||||
drop = len(f'{res} = ')
|
||||
if cur_padding == expected - 1:
|
||||
# tolerate this bad style
|
||||
drop -= 1
|
||||
elif cur_padding < expected - 1:
|
||||
# assume nothing to do
|
||||
drop = 0
|
||||
|
||||
if drop:
|
||||
args = re.sub('\n' + ' ' * drop, '\n', args)
|
||||
|
||||
result += args
|
||||
|
||||
result += ')'
|
||||
|
||||
text = text[m.end():]
|
||||
|
||||
return result
|
||||
|
||||
|
||||
for fname in sys.argv[1:]:
|
||||
print(fname)
|
||||
with open(fname) as f:
|
||||
t = f.read()
|
||||
|
||||
t = update(t)
|
||||
|
||||
with open(fname, 'w') as f:
|
||||
f.write(t)
|
||||
@@ -43,13 +43,13 @@ def render_block_graph(qmp, filename, format='png'):
|
||||
representation in @format into "@filename.@format"
|
||||
'''
|
||||
|
||||
bds_nodes = qmp.command('query-named-block-nodes')
|
||||
bds_nodes = qmp.cmd('query-named-block-nodes')
|
||||
bds_nodes = {n['node-name']: n for n in bds_nodes}
|
||||
|
||||
job_nodes = qmp.command('query-block-jobs')
|
||||
job_nodes = qmp.cmd('query-block-jobs')
|
||||
job_nodes = {n['device']: n for n in job_nodes}
|
||||
|
||||
block_graph = qmp.command('x-debug-query-block-graph')
|
||||
block_graph = qmp.cmd('x-debug-query-block-graph')
|
||||
|
||||
graph = Digraph(comment='Block Nodes Graph')
|
||||
graph.format = format
|
||||
@@ -94,7 +94,7 @@ class LibvirtGuest():
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def command(self, cmd):
|
||||
def cmd(self, cmd):
|
||||
# only supports qmp commands without parameters
|
||||
m = {'execute': cmd}
|
||||
ar = ['virsh', 'qemu-monitor-command', self.name, json.dumps(m)]
|
||||
|
||||
Reference in New Issue
Block a user