QAPI patches patches for 2020-09-29
-----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEENUvIs9frKmtoZ05fOHC0AOuRhlMFAl9zkQsSHGFybWJydUBy ZWRoYXQuY29tAAoJEDhwtADrkYZT5O8QAIDcYCifFstBX2P07kz6gT2GKeJdCZl6 uijRTfV/srckkRa1aecrnPr/Tp9bjqZuBtd3O60X/mAHtsoaiALheWlbLyhIGFOr bY4DwNYVpaOpnl2XzQoav8dkftfkH3rxpJa8SvYSRZ7FZWZBo91/84Lts4d5IzDo h3HWNlaSOr4g9lwQSBmze/fhJldehqe9kS+2t8LyzzzJ2HDCj/Y7TqRjIsvM5HQn Vcp18988O2OYHagZVDHs87w6S3bBTfC0kaM5y6NqzyvQxia/ygvjE7mx4p651HgO bgU/cVLFqJMACsEHyOJV4H+hAX7P8Huw6/OH7w9PoHNi7SKGpP36WhSoiciPYxcz lIlY8DoRdZZwxzlbJ+DTJwLgDPhZcRlHvR6ScoyDdbTRA5nZGf6yCAcnA/qnN32B IlaXBIcKWSOid92YSNv7i5olhcMvqy9Z7fXubmmgzyM9kSAONBnxkn30CI4p8ZL1 poK2gH5De/VUcy4dtx0Sq0khwFbuVHMbrF3abLlsM/rj7c03XX7Nc0WB9MPkMuxI LWpQF9JDIIYvR+Xi7x9ZyLmqL8DRmQVAof8YQtfG9F1ALeieWww1ELvsWDHwVyAB KgqB2So6AeFosNVigv7slf25IbTwcg3kIgspoBrsgQ2pUavzp6ruOqzkkz7BvfcE DZhNUXeAQPGx =SKm6 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2020-09-29' into staging QAPI patches patches for 2020-09-29 # gpg: Signature made Tue 29 Sep 2020 20:54:51 BST # gpg: using RSA key 354BC8B3D7EB2A6B68674E5F3870B400EB918653 # gpg: issuer "armbru@redhat.com" # gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" [full] # gpg: aka "Markus Armbruster <armbru@pond.sub.org>" [full] # Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867 4E5F 3870 B400 EB91 8653 * remotes/armbru/tags/pull-qapi-2020-09-29: (29 commits) Remove texinfo dependency from docker and CI configs configure: Drop texinfo requirement Remove Texinfo related line from git.orderfile scripts/texi2pod: Delete unused script docs/devel/qapi-code-gen.txt: Update to new rST backend conventions scripts/qapi: Remove texinfo generation support tests/qapi-schema: Add test of the rST QAPI doc-comment output meson.build: Make manuals depend on source to Sphinx extensions meson.build: Move SPHINX_ARGS to top level meson.build file tests/qapi-schema: Convert doc-good.json to rST-style strong/emphasis qga/qapi-schema.json: Add some headings qapi: Use rST markup for literal blocks docs/interop: Convert qemu-qmp-ref to rST docs/interop: Convert qemu-ga-ref to rST docs/sphinx: Add new qapi-doc Sphinx extension qapi/machine.json: Escape a literal '*' in doc comment scripts/qapi/parser.py: improve doc comment indent handling scripts/qapi: Move doc-comment whitespace stripping to doc.py tests/qapi/doc-good.json: Prepare for qapi-doc Sphinx extension qapi/block.json: Add newline after "Example:" for block-latency-histogram-set ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
e344ffe73b
|
@ -192,7 +192,6 @@ jobs:
|
|||
apt:
|
||||
packages:
|
||||
- python3-sphinx
|
||||
- texinfo
|
||||
- perl
|
||||
|
||||
|
||||
|
|
|
@ -1617,6 +1617,7 @@ F: include/hw/pci/*
|
|||
F: hw/misc/pci-testdev.c
|
||||
F: hw/pci/*
|
||||
F: hw/pci-bridge/*
|
||||
F: qapi/pci.json
|
||||
F: docs/pci*
|
||||
F: docs/specs/*pci*
|
||||
F: default-configs/pci.mak
|
||||
|
@ -1632,6 +1633,7 @@ F: hw/acpi/*
|
|||
F: hw/smbios/*
|
||||
F: hw/i386/acpi-build.[hc]
|
||||
F: hw/arm/virt-acpi-build.c
|
||||
F: qapi/acpi.json
|
||||
F: tests/qtest/bios-tables-test*
|
||||
F: tests/qtest/acpi-utils.[hc]
|
||||
F: tests/data/acpi/
|
||||
|
@ -2385,6 +2387,7 @@ F: tests/test-qmp-*.c
|
|||
F: tests/test-visitor-serialization.c
|
||||
F: scripts/qapi-gen.py
|
||||
F: scripts/qapi/*
|
||||
F: docs/sphinx/qapidoc.py
|
||||
F: docs/devel/qapi*
|
||||
T: git https://repo.or.cz/qemu/armbru.git qapi-next
|
||||
|
||||
|
@ -2418,9 +2421,9 @@ M: Michael Roth <mdroth@linux.vnet.ibm.com>
|
|||
S: Maintained
|
||||
F: qga/
|
||||
F: docs/interop/qemu-ga.rst
|
||||
F: docs/interop/qemu-ga-ref.rst
|
||||
F: scripts/qemu-guest-agent/
|
||||
F: tests/test-qga.c
|
||||
F: docs/interop/qemu-ga-ref.texi
|
||||
T: git https://github.com/mdroth/qemu.git qga
|
||||
|
||||
QOM
|
||||
|
@ -3149,6 +3152,7 @@ M: Peter Maydell <peter.maydell@linaro.org>
|
|||
S: Maintained
|
||||
F: docs/conf.py
|
||||
F: docs/*/conf.py
|
||||
F: docs/sphinx/
|
||||
|
||||
Miscellaneous
|
||||
-------------
|
||||
|
|
2
Makefile
2
Makefile
|
@ -280,7 +280,7 @@ endif
|
|||
$(call print-help,vm-help,Help about targets running tests inside VM)
|
||||
@echo ''
|
||||
@echo 'Documentation targets:'
|
||||
$(call print-help,html info pdf txt man,Build documentation in specified format)
|
||||
$(call print-help,html man,Build documentation in specified format)
|
||||
@echo ''
|
||||
ifdef CONFIG_WIN32
|
||||
@echo 'Windows targets:'
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
#include "qemu/uuid.h"
|
||||
#include "sysemu/replay.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qapi-commands-misc.h"
|
||||
#include "qapi/qapi-commands-machine.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "crypto/secret.h"
|
||||
|
|
12
configure
vendored
12
configure
vendored
|
@ -4874,14 +4874,14 @@ if test "$docs" != "no" ; then
|
|||
else
|
||||
sphinx_ok=no
|
||||
fi
|
||||
if has makeinfo && has pod2man && test "$sphinx_ok" = "yes"; then
|
||||
if test "$sphinx_ok" = "yes"; then
|
||||
docs=yes
|
||||
else
|
||||
if test "$docs" = "yes" ; then
|
||||
if has $sphinx_build && test "$sphinx_ok" != "yes"; then
|
||||
echo "Warning: $sphinx_build exists but it is either too old or uses too old a Python version" >&2
|
||||
fi
|
||||
feature_not_found "docs" "Install texinfo, Perl/perl-podlators and a Python 3 version of python-sphinx"
|
||||
feature_not_found "docs" "Install a Python 3 version of python-sphinx"
|
||||
fi
|
||||
docs=no
|
||||
fi
|
||||
|
@ -6301,13 +6301,6 @@ if test "$solaris" = "no" && test "$tsan" = "no"; then
|
|||
fi
|
||||
fi
|
||||
|
||||
# test if pod2man has --utf8 option
|
||||
if pod2man --help | grep -q utf8; then
|
||||
POD2MAN="pod2man --utf8"
|
||||
else
|
||||
POD2MAN="pod2man"
|
||||
fi
|
||||
|
||||
# Use ASLR, no-SEH and DEP if available
|
||||
if test "$mingw32" = "yes" ; then
|
||||
for flag in --dynamicbase --no-seh --nxcompat; do
|
||||
|
@ -7456,7 +7449,6 @@ echo "HOST_DSOSUF=$HOST_DSOSUF" >> $config_host_mak
|
|||
echo "LIBS_QGA=$libs_qga" >> $config_host_mak
|
||||
echo "TASN1_LIBS=$tasn1_libs" >> $config_host_mak
|
||||
echo "TASN1_CFLAGS=$tasn1_cflags" >> $config_host_mak
|
||||
echo "POD2MAN=$POD2MAN" >> $config_host_mak
|
||||
if test "$gcov" = "yes" ; then
|
||||
echo "CONFIG_GCOV=y" >> $config_host_mak
|
||||
fi
|
||||
|
|
|
@ -52,7 +52,10 @@ except NameError:
|
|||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use an absolute path starting from qemu_docdir.
|
||||
#
|
||||
# Our extensions are in docs/sphinx; the qapidoc extension requires
|
||||
# the QAPI modules from scripts/.
|
||||
sys.path.insert(0, os.path.join(qemu_docdir, "sphinx"))
|
||||
sys.path.insert(0, os.path.join(qemu_docdir, "../scripts"))
|
||||
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
@ -67,7 +70,7 @@ needs_sphinx = '1.6'
|
|||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = ['kerneldoc', 'qmp_lexer', 'hxtool', 'depfile']
|
||||
extensions = ['kerneldoc', 'qmp_lexer', 'hxtool', 'depfile', 'qapidoc']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
@ -241,3 +244,4 @@ texinfo_documents = [
|
|||
kerneldoc_bin = os.path.join(qemu_docdir, '../scripts/kernel-doc')
|
||||
kerneldoc_srctree = os.path.join(qemu_docdir, '..')
|
||||
hxtool_srctree = os.path.join(qemu_docdir, '..')
|
||||
qapidoc_srctree = os.path.join(qemu_docdir, '..')
|
||||
|
|
|
@ -824,23 +824,37 @@ See below for more on definition documentation.
|
|||
Free-form documentation may be used to provide additional text and
|
||||
structuring content.
|
||||
|
||||
==== Headings and subheadings ====
|
||||
|
||||
A free-form documentation comment containing a line which starts with
|
||||
some '=' symbols and then a space defines a section heading:
|
||||
|
||||
##
|
||||
# = This is a top level heading
|
||||
#
|
||||
# This is a free-form comment which will go under the
|
||||
# top level heading.
|
||||
##
|
||||
|
||||
##
|
||||
# == This is a second level heading
|
||||
##
|
||||
|
||||
A heading line must be the first line of the documentation
|
||||
comment block.
|
||||
|
||||
Section headings must always be correctly nested, so you can only
|
||||
define a third-level heading inside a second-level heading, and so on.
|
||||
|
||||
==== Documentation markup ====
|
||||
|
||||
Comment text starting with '=' is a section title:
|
||||
Documentation comments can use most rST markup. In particular,
|
||||
a '::' literal block can be used for examples:
|
||||
|
||||
# = Section title
|
||||
|
||||
Double the '=' for a subsection title:
|
||||
|
||||
# == Subsection title
|
||||
|
||||
Both are only permitted in free-form documentation.
|
||||
|
||||
'|' denotes examples:
|
||||
|
||||
# | Text of the example, may span
|
||||
# | multiple lines
|
||||
# ::
|
||||
#
|
||||
# Text of the example, may span
|
||||
# multiple lines
|
||||
|
||||
'*' starts an itemized list:
|
||||
|
||||
|
@ -856,34 +870,33 @@ A decimal number followed by '.' starts a numbered list:
|
|||
# multiple lines
|
||||
# 2. Second item
|
||||
|
||||
The actual number doesn't matter. You could even use '*' instead of
|
||||
'2.' for the second item.
|
||||
The actual number doesn't matter.
|
||||
|
||||
Lists can't be nested. Blank lines are currently not supported within
|
||||
lists.
|
||||
Lists of either kind must be preceded and followed by a blank line.
|
||||
If a list item's text spans multiple lines, then the second and
|
||||
subsequent lines must be correctly indented to line up with the
|
||||
first character of the first line.
|
||||
|
||||
Additional whitespace between the initial '#' and the comment text is
|
||||
permitted.
|
||||
|
||||
*foo* and _foo_ are for strong and emphasis styles respectively (they
|
||||
do not work over multiple lines). @foo is used to reference a name in
|
||||
the schema.
|
||||
The usual '**strong**', '*emphasised*' and '``literal``' markup should
|
||||
be used. If you need a single literal '*' you will need to
|
||||
backslash-escape it. As an extension beyond the usual rST syntax, you
|
||||
can also use '@foo' to reference a name in the schema; this is
|
||||
rendered the same way as '``foo``'.
|
||||
|
||||
Example:
|
||||
|
||||
##
|
||||
# = Section
|
||||
# == Subsection
|
||||
#
|
||||
# Some text foo with *strong* and _emphasis_
|
||||
# Some text foo with **bold** and *emphasis*
|
||||
# 1. with a list
|
||||
# 2. like that
|
||||
#
|
||||
# And some code:
|
||||
# | $ echo foo
|
||||
# | -> do this
|
||||
# | <- get that
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# $ echo foo
|
||||
# -> do this
|
||||
# <- get that
|
||||
##
|
||||
|
||||
|
||||
|
@ -901,6 +914,22 @@ commands and events), member (for structs and unions), branch (for
|
|||
alternates), or value (for enums), and finally optional tagged
|
||||
sections.
|
||||
|
||||
Descriptions of arguments can span multiple lines. The description
|
||||
text can start on the line following the '@argname:', in which case it
|
||||
must not be indented at all. It can also start on the same line as
|
||||
the '@argname:'. In this case if it spans multiple lines then second
|
||||
and subsequent lines must be indented to line up with the first
|
||||
character of the first line of the description:
|
||||
|
||||
# @argone:
|
||||
# This is a two line description
|
||||
# in the first style.
|
||||
#
|
||||
# @argtwo: This is a two line description
|
||||
# in the second style.
|
||||
|
||||
The number of spaces between the ':' and the text is not significant.
|
||||
|
||||
FIXME: the parser accepts these things in almost any order.
|
||||
FIXME: union branches should be described, too.
|
||||
|
||||
|
@ -911,9 +940,26 @@ A tagged section starts with one of the following words:
|
|||
"Note:"/"Notes:", "Since:", "Example"/"Examples", "Returns:", "TODO:".
|
||||
The section ends with the start of a new section.
|
||||
|
||||
The text of a section can start on a new line, in
|
||||
which case it must not be indented at all. It can also start
|
||||
on the same line as the 'Note:', 'Returns:', etc tag. In this
|
||||
case if it spans multiple lines then second and subsequent
|
||||
lines must be indented to match the first, in the same way as
|
||||
multiline argument descriptions.
|
||||
|
||||
A 'Since: x.y.z' tagged section lists the release that introduced the
|
||||
definition.
|
||||
|
||||
The text of a section can start on a new line, in
|
||||
which case it must not be indented at all. It can also start
|
||||
on the same line as the 'Note:', 'Returns:', etc tag. In this
|
||||
case if it spans multiple lines then second and subsequent
|
||||
lines must be indented to match the first.
|
||||
|
||||
An 'Example' or 'Examples' section is automatically rendered
|
||||
entirely as literal fixed-width text. In other sections,
|
||||
the text is formatted, and rST markup can be used.
|
||||
|
||||
For example:
|
||||
|
||||
##
|
||||
|
|
|
@ -12,8 +12,6 @@
|
|||
<li><a href="tools/index.html">Tools Guide</a></li>
|
||||
<li><a href="interop/index.html">System Emulation Management and Interoperability Guide</a></li>
|
||||
<li><a href="specs/index.html">System Emulation Guest Hardware Specifications</a></li>
|
||||
<li><a href="interop/qemu-qmp-ref.html">QMP Reference Manual</a></li>
|
||||
<li><a href="interop/qemu-ga-ref.html">Guest Agent Protocol Reference</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -19,4 +19,8 @@ html_theme_options['description'] = u'System Emulation Management and Interopera
|
|||
man_pages = [
|
||||
('qemu-ga', 'qemu-ga', u'QEMU Guest Agent',
|
||||
['Michael Roth <mdroth@linux.vnet.ibm.com>'], 8),
|
||||
('qemu-ga-ref', 'qemu-ga-ref', 'QEMU Guest Agent Protocol Reference',
|
||||
[], 7),
|
||||
('qemu-qmp-ref', 'qemu-qmp-ref', 'QEMU QMP Reference Manual',
|
||||
[], 7),
|
||||
]
|
||||
|
|
|
@ -18,6 +18,8 @@ Contents:
|
|||
live-block-operations
|
||||
pr-helper
|
||||
qemu-ga
|
||||
qemu-ga-ref
|
||||
qemu-qmp-ref
|
||||
vhost-user
|
||||
vhost-user-gpu
|
||||
vhost-vdpa
|
||||
|
|
13
docs/interop/qemu-ga-ref.rst
Normal file
13
docs/interop/qemu-ga-ref.rst
Normal file
|
@ -0,0 +1,13 @@
|
|||
QEMU Guest Agent Protocol Reference
|
||||
===================================
|
||||
|
||||
..
|
||||
TODO: the old Texinfo manual used to note that this manual
|
||||
is GPL-v2-or-later. We should make that reader-visible
|
||||
both here and in our Sphinx manuals more generally.
|
||||
|
||||
..
|
||||
TODO: display the QEMU version, both here and in our Sphinx manuals
|
||||
more generally.
|
||||
|
||||
.. qapi-doc:: qga/qapi-schema.json
|
|
@ -1,80 +0,0 @@
|
|||
\input texinfo
|
||||
@setfilename qemu-ga-ref.info
|
||||
|
||||
@include version.texi
|
||||
|
||||
@exampleindent 0
|
||||
@paragraphindent 0
|
||||
|
||||
@settitle QEMU Guest Agent Protocol Reference
|
||||
|
||||
@iftex
|
||||
@center @image{docs/qemu_logo}
|
||||
@end iftex
|
||||
|
||||
@copying
|
||||
This is the QEMU Guest Agent Protocol reference manual.
|
||||
|
||||
Copyright @copyright{} 2016 The QEMU Project developers
|
||||
|
||||
@quotation
|
||||
This manual is free documentation: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This manual is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this manual. If not, see http://www.gnu.org/licenses/.
|
||||
@end quotation
|
||||
@end copying
|
||||
|
||||
@dircategory QEMU
|
||||
@direntry
|
||||
* QEMU-GA-Ref: (qemu-ga-ref). QEMU Guest Agent Protocol Reference
|
||||
@end direntry
|
||||
|
||||
@titlepage
|
||||
@title Guest Agent Protocol Reference Manual
|
||||
@subtitle QEMU version @value{VERSION}
|
||||
@page
|
||||
@vskip 0pt plus 1filll
|
||||
@insertcopying
|
||||
@end titlepage
|
||||
|
||||
@contents
|
||||
|
||||
@ifnottex
|
||||
@node Top
|
||||
@top QEMU Guest Agent protocol reference
|
||||
@end ifnottex
|
||||
|
||||
@menu
|
||||
* API Reference::
|
||||
* Commands and Events Index::
|
||||
* Data Types Index::
|
||||
@end menu
|
||||
|
||||
@node API Reference
|
||||
@chapter API Reference
|
||||
|
||||
@c for texi2pod:
|
||||
@c man begin DESCRIPTION
|
||||
|
||||
@include qga/qga-qapi-doc.texi
|
||||
|
||||
@c man end
|
||||
|
||||
@node Commands and Events Index
|
||||
@unnumbered Commands and Events Index
|
||||
@printindex fn
|
||||
|
||||
@node Data Types Index
|
||||
@unnumbered Data Types Index
|
||||
@printindex tp
|
||||
|
||||
@bye
|
13
docs/interop/qemu-qmp-ref.rst
Normal file
13
docs/interop/qemu-qmp-ref.rst
Normal file
|
@ -0,0 +1,13 @@
|
|||
QEMU QMP Reference Manual
|
||||
=========================
|
||||
|
||||
..
|
||||
TODO: the old Texinfo manual used to note that this manual
|
||||
is GPL-v2-or-later. We should make that reader-visible
|
||||
both here and in our Sphinx manuals more generally.
|
||||
|
||||
..
|
||||
TODO: display the QEMU version, both here and in our Sphinx manuals
|
||||
more generally.
|
||||
|
||||
.. qapi-doc:: qapi/qapi-schema.json
|
|
@ -1,80 +0,0 @@
|
|||
\input texinfo
|
||||
@setfilename qemu-qmp-ref.info
|
||||
|
||||
@include version.texi
|
||||
|
||||
@exampleindent 0
|
||||
@paragraphindent 0
|
||||
|
||||
@settitle QEMU QMP Reference Manual
|
||||
|
||||
@iftex
|
||||
@center @image{docs/qemu_logo}
|
||||
@end iftex
|
||||
|
||||
@copying
|
||||
This is the QEMU QMP reference manual.
|
||||
|
||||
Copyright @copyright{} 2016 The QEMU Project developers
|
||||
|
||||
@quotation
|
||||
This manual is free documentation: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This manual is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this manual. If not, see http://www.gnu.org/licenses/.
|
||||
@end quotation
|
||||
@end copying
|
||||
|
||||
@dircategory QEMU
|
||||
@direntry
|
||||
* QEMU-QMP-Ref: (qemu-qmp-ref). QEMU QMP Reference Manual
|
||||
@end direntry
|
||||
|
||||
@titlepage
|
||||
@title QMP Reference Manual
|
||||
@subtitle QEMU version @value{VERSION}
|
||||
@page
|
||||
@vskip 0pt plus 1filll
|
||||
@insertcopying
|
||||
@end titlepage
|
||||
|
||||
@contents
|
||||
|
||||
@ifnottex
|
||||
@node Top
|
||||
@top QEMU QMP reference
|
||||
@end ifnottex
|
||||
|
||||
@menu
|
||||
* API Reference::
|
||||
* Commands and Events Index::
|
||||
* Data Types Index::
|
||||
@end menu
|
||||
|
||||
@node API Reference
|
||||
@chapter API Reference
|
||||
|
||||
@c for texi2pod:
|
||||
@c man begin DESCRIPTION
|
||||
|
||||
@include qapi/qapi-doc.texi
|
||||
|
||||
@c man end
|
||||
|
||||
@node Commands and Events Index
|
||||
@unnumbered Commands and Events Index
|
||||
@printindex fn
|
||||
|
||||
@node Data Types Index
|
||||
@unnumbered Data Types Index
|
||||
@printindex tp
|
||||
|
||||
@bye
|
|
@ -1,11 +1,3 @@
|
|||
SPHINX_ARGS = [config_host['SPHINX_BUILD'],
|
||||
'-Dversion=' + meson.project_version(),
|
||||
'-Drelease=' + config_host['PKGVERSION']]
|
||||
|
||||
if get_option('werror')
|
||||
SPHINX_ARGS += [ '-W' ]
|
||||
endif
|
||||
|
||||
if build_docs
|
||||
configure_file(output: 'index.html',
|
||||
input: files('index.html.in'),
|
||||
|
@ -15,6 +7,8 @@ if build_docs
|
|||
man_pages = {
|
||||
'interop' : {
|
||||
'qemu-ga.8': (have_tools ? 'man8' : ''),
|
||||
'qemu-ga-ref.7': 'man7',
|
||||
'qemu-qmp-ref.7': 'man7',
|
||||
},
|
||||
'tools': {
|
||||
'qemu-img.1': (have_tools ? 'man1' : ''),
|
||||
|
@ -42,6 +36,7 @@ if build_docs
|
|||
output: [manual + '.stamp'],
|
||||
input: [files('conf.py'), files(manual / 'conf.py')],
|
||||
depfile: manual + '.d',
|
||||
depend_files: sphinx_extn_depends,
|
||||
command: [SPHINX_ARGS, '-Ddepfile=@DEPFILE@',
|
||||
'-Ddepfile_stamp=@OUTPUT0@',
|
||||
'-b', 'html', '-d', private_dir,
|
||||
|
@ -69,5 +64,6 @@ if build_docs
|
|||
endif
|
||||
endforeach
|
||||
alias_target('sphinxdocs', sphinxdocs)
|
||||
alias_target('html', sphinxdocs)
|
||||
alias_target('man', sphinxmans)
|
||||
endif
|
||||
|
|
549
docs/sphinx/qapidoc.py
Normal file
549
docs/sphinx/qapidoc.py
Normal file
|
@ -0,0 +1,549 @@
|
|||
# coding=utf-8
|
||||
#
|
||||
# QEMU qapidoc QAPI file parsing extension
|
||||
#
|
||||
# Copyright (c) 2020 Linaro
|
||||
#
|
||||
# This work is licensed under the terms of the GNU GPLv2 or later.
|
||||
# See the COPYING file in the top-level directory.
|
||||
|
||||
"""
|
||||
qapidoc is a Sphinx extension that implements the qapi-doc directive
|
||||
|
||||
The purpose of this extension is to read the documentation comments
|
||||
in QAPI schema files, and insert them all into the current document.
|
||||
|
||||
It implements one new rST directive, "qapi-doc::".
|
||||
Each qapi-doc:: directive takes one argument, which is the
|
||||
pathname of the schema file to process, relative to the source tree.
|
||||
|
||||
The docs/conf.py file must set the qapidoc_srctree config value to
|
||||
the root of the QEMU source tree.
|
||||
|
||||
The Sphinx documentation on writing extensions is at:
|
||||
https://www.sphinx-doc.org/en/master/development/index.html
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.statemachine import ViewList
|
||||
from docutils.parsers.rst import directives, Directive
|
||||
from sphinx.errors import ExtensionError
|
||||
from sphinx.util.nodes import nested_parse_with_titles
|
||||
import sphinx
|
||||
from qapi.gen import QAPISchemaVisitor
|
||||
from qapi.schema import QAPIError, QAPISemError, QAPISchema
|
||||
|
||||
|
||||
# Sphinx up to 1.6 uses AutodocReporter; 1.7 and later
|
||||
# use switch_source_input. Check borrowed from kerneldoc.py.
|
||||
Use_SSI = sphinx.__version__[:3] >= '1.7'
|
||||
if Use_SSI:
|
||||
from sphinx.util.docutils import switch_source_input
|
||||
else:
|
||||
from sphinx.ext.autodoc import AutodocReporter
|
||||
|
||||
|
||||
__version__ = '1.0'
|
||||
|
||||
|
||||
# Function borrowed from pydash, which is under the MIT license
|
||||
def intersperse(iterable, separator):
|
||||
"""Yield the members of *iterable* interspersed with *separator*."""
|
||||
iterable = iter(iterable)
|
||||
yield next(iterable)
|
||||
for item in iterable:
|
||||
yield separator
|
||||
yield item
|
||||
|
||||
|
||||
class QAPISchemaGenRSTVisitor(QAPISchemaVisitor):
|
||||
"""A QAPI schema visitor which generates docutils/Sphinx nodes
|
||||
|
||||
This class builds up a tree of docutils/Sphinx nodes corresponding
|
||||
to documentation for the various QAPI objects. To use it, first
|
||||
create a QAPISchemaGenRSTVisitor object, and call its
|
||||
visit_begin() method. Then you can call one of the two methods
|
||||
'freeform' (to add documentation for a freeform documentation
|
||||
chunk) or 'symbol' (to add documentation for a QAPI symbol). These
|
||||
will cause the visitor to build up the tree of document
|
||||
nodes. Once you've added all the documentation via 'freeform' and
|
||||
'symbol' method calls, you can call 'get_document_nodes' to get
|
||||
the final list of document nodes (in a form suitable for returning
|
||||
from a Sphinx directive's 'run' method).
|
||||
"""
|
||||
def __init__(self, sphinx_directive):
|
||||
self._cur_doc = None
|
||||
self._sphinx_directive = sphinx_directive
|
||||
self._top_node = nodes.section()
|
||||
self._active_headings = [self._top_node]
|
||||
|
||||
def _make_dlitem(self, term, defn):
|
||||
"""Return a dlitem node with the specified term and definition.
|
||||
|
||||
term should be a list of Text and literal nodes.
|
||||
defn should be one of:
|
||||
- a string, which will be handed to _parse_text_into_node
|
||||
- a list of Text and literal nodes, which will be put into
|
||||
a paragraph node
|
||||
"""
|
||||
dlitem = nodes.definition_list_item()
|
||||
dlterm = nodes.term('', '', *term)
|
||||
dlitem += dlterm
|
||||
if defn:
|
||||
dldef = nodes.definition()
|
||||
if isinstance(defn, list):
|
||||
dldef += nodes.paragraph('', '', *defn)
|
||||
else:
|
||||
self._parse_text_into_node(defn, dldef)
|
||||
dlitem += dldef
|
||||
return dlitem
|
||||
|
||||
def _make_section(self, title):
|
||||
"""Return a section node with optional title"""
|
||||
section = nodes.section(ids=[self._sphinx_directive.new_serialno()])
|
||||
if title:
|
||||
section += nodes.title(title, title)
|
||||
return section
|
||||
|
||||
def _nodes_for_ifcond(self, ifcond, with_if=True):
|
||||
"""Return list of Text, literal nodes for the ifcond
|
||||
|
||||
Return a list which gives text like ' (If: cond1, cond2, cond3)', where
|
||||
the conditions are in literal-text and the commas are not.
|
||||
If with_if is False, we don't return the "(If: " and ")".
|
||||
"""
|
||||
condlist = intersperse([nodes.literal('', c) for c in ifcond],
|
||||
nodes.Text(', '))
|
||||
if not with_if:
|
||||
return condlist
|
||||
|
||||
nodelist = [nodes.Text(' ('), nodes.strong('', 'If: ')]
|
||||
nodelist.extend(condlist)
|
||||
nodelist.append(nodes.Text(')'))
|
||||
return nodelist
|
||||
|
||||
def _nodes_for_one_member(self, member):
|
||||
"""Return list of Text, literal nodes for this member
|
||||
|
||||
Return a list of doctree nodes which give text like
|
||||
'name: type (optional) (If: ...)' suitable for use as the
|
||||
'term' part of a definition list item.
|
||||
"""
|
||||
term = [nodes.literal('', member.name)]
|
||||
if member.type.doc_type():
|
||||
term.append(nodes.Text(': '))
|
||||
term.append(nodes.literal('', member.type.doc_type()))
|
||||
if member.optional:
|
||||
term.append(nodes.Text(' (optional)'))
|
||||
if member.ifcond:
|
||||
term.extend(self._nodes_for_ifcond(member.ifcond))
|
||||
return term
|
||||
|
||||
def _nodes_for_variant_when(self, variants, variant):
|
||||
"""Return list of Text, literal nodes for variant 'when' clause
|
||||
|
||||
Return a list of doctree nodes which give text like
|
||||
'when tagname is variant (If: ...)' suitable for use in
|
||||
the 'variants' part of a definition list.
|
||||
"""
|
||||
term = [nodes.Text(' when '),
|
||||
nodes.literal('', variants.tag_member.name),
|
||||
nodes.Text(' is '),
|
||||
nodes.literal('', '"%s"' % variant.name)]
|
||||
if variant.ifcond:
|
||||
term.extend(self._nodes_for_ifcond(variant.ifcond))
|
||||
return term
|
||||
|
||||
def _nodes_for_members(self, doc, what, base=None, variants=None):
|
||||
"""Return list of doctree nodes for the table of members"""
|
||||
dlnode = nodes.definition_list()
|
||||
for section in doc.args.values():
|
||||
term = self._nodes_for_one_member(section.member)
|
||||
# TODO drop fallbacks when undocumented members are outlawed
|
||||
if section.text:
|
||||
defn = section.text
|
||||
elif (variants and variants.tag_member == section.member
|
||||
and not section.member.type.doc_type()):
|
||||
values = section.member.type.member_names()
|
||||
defn = [nodes.Text('One of ')]
|
||||
defn.extend(intersperse([nodes.literal('', v) for v in values],
|
||||
nodes.Text(', ')))
|
||||
else:
|
||||
defn = [nodes.Text('Not documented')]
|
||||
|
||||
dlnode += self._make_dlitem(term, defn)
|
||||
|
||||
if base:
|
||||
dlnode += self._make_dlitem([nodes.Text('The members of '),
|
||||
nodes.literal('', base.doc_type())],
|
||||
None)
|
||||
|
||||
if variants:
|
||||
for v in variants.variants:
|
||||
if v.type.is_implicit():
|
||||
assert not v.type.base and not v.type.variants
|
||||
for m in v.type.local_members:
|
||||
term = self._nodes_for_one_member(m)
|
||||
term.extend(self._nodes_for_variant_when(variants, v))
|
||||
dlnode += self._make_dlitem(term, None)
|
||||
else:
|
||||
term = [nodes.Text('The members of '),
|
||||
nodes.literal('', v.type.doc_type())]
|
||||
term.extend(self._nodes_for_variant_when(variants, v))
|
||||
dlnode += self._make_dlitem(term, None)
|
||||
|
||||
if not dlnode.children:
|
||||
return []
|
||||
|
||||
section = self._make_section(what)
|
||||
section += dlnode
|
||||
return [section]
|
||||
|
||||
def _nodes_for_enum_values(self, doc):
|
||||
"""Return list of doctree nodes for the table of enum values"""
|
||||
seen_item = False
|
||||
dlnode = nodes.definition_list()
|
||||
for section in doc.args.values():
|
||||
termtext = [nodes.literal('', section.member.name)]
|
||||
if section.member.ifcond:
|
||||
termtext.extend(self._nodes_for_ifcond(section.member.ifcond))
|
||||
# TODO drop fallbacks when undocumented members are outlawed
|
||||
if section.text:
|
||||
defn = section.text
|
||||
else:
|
||||
defn = [nodes.Text('Not documented')]
|
||||
|
||||
dlnode += self._make_dlitem(termtext, defn)
|
||||
seen_item = True
|
||||
|
||||
if not seen_item:
|
||||
return []
|
||||
|
||||
section = self._make_section('Values')
|
||||
section += dlnode
|
||||
return [section]
|
||||
|
||||
def _nodes_for_arguments(self, doc, boxed_arg_type):
|
||||
"""Return list of doctree nodes for the arguments section"""
|
||||
if boxed_arg_type:
|
||||
assert not doc.args
|
||||
section = self._make_section('Arguments')
|
||||
dlnode = nodes.definition_list()
|
||||
dlnode += self._make_dlitem(
|
||||
[nodes.Text('The members of '),
|
||||
nodes.literal('', boxed_arg_type.name)],
|
||||
None)
|
||||
section += dlnode
|
||||
return [section]
|
||||
|
||||
return self._nodes_for_members(doc, 'Arguments')
|
||||
|
||||
def _nodes_for_features(self, doc):
|
||||
"""Return list of doctree nodes for the table of features"""
|
||||
seen_item = False
|
||||
dlnode = nodes.definition_list()
|
||||
for section in doc.features.values():
|
||||
dlnode += self._make_dlitem([nodes.literal('', section.name)],
|
||||
section.text)
|
||||
seen_item = True
|
||||
|
||||
if not seen_item:
|
||||
return []
|
||||
|
||||
section = self._make_section('Features')
|
||||
section += dlnode
|
||||
return [section]
|
||||
|
||||
def _nodes_for_example(self, exampletext):
|
||||
"""Return list of doctree nodes for a code example snippet"""
|
||||
return [nodes.literal_block(exampletext, exampletext)]
|
||||
|
||||
def _nodes_for_sections(self, doc):
|
||||
"""Return list of doctree nodes for additional sections"""
|
||||
nodelist = []
|
||||
for section in doc.sections:
|
||||
snode = self._make_section(section.name)
|
||||
if section.name and section.name.startswith('Example'):
|
||||
snode += self._nodes_for_example(section.text)
|
||||
else:
|
||||
self._parse_text_into_node(section.text, snode)
|
||||
nodelist.append(snode)
|
||||
return nodelist
|
||||
|
||||
def _nodes_for_if_section(self, ifcond):
|
||||
"""Return list of doctree nodes for the "If" section"""
|
||||
nodelist = []
|
||||
if ifcond:
|
||||
snode = self._make_section('If')
|
||||
snode += self._nodes_for_ifcond(ifcond, with_if=False)
|
||||
nodelist.append(snode)
|
||||
return nodelist
|
||||
|
||||
def _add_doc(self, typ, sections):
|
||||
"""Add documentation for a command/object/enum...
|
||||
|
||||
We assume we're documenting the thing defined in self._cur_doc.
|
||||
typ is the type of thing being added ("Command", "Object", etc)
|
||||
|
||||
sections is a list of nodes for sections to add to the definition.
|
||||
"""
|
||||
|
||||
doc = self._cur_doc
|
||||
snode = nodes.section(ids=[self._sphinx_directive.new_serialno()])
|
||||
snode += nodes.title('', '', *[nodes.literal(doc.symbol, doc.symbol),
|
||||
nodes.Text(' (' + typ + ')')])
|
||||
self._parse_text_into_node(doc.body.text, snode)
|
||||
for s in sections:
|
||||
if s is not None:
|
||||
snode += s
|
||||
self._add_node_to_current_heading(snode)
|
||||
|
||||
def visit_enum_type(self, name, info, ifcond, features, members, prefix):
|
||||
doc = self._cur_doc
|
||||
self._add_doc('Enum',
|
||||
self._nodes_for_enum_values(doc)
|
||||
+ self._nodes_for_features(doc)
|
||||
+ self._nodes_for_sections(doc)
|
||||
+ self._nodes_for_if_section(ifcond))
|
||||
|
||||
def visit_object_type(self, name, info, ifcond, features,
|
||||
base, members, variants):
|
||||
doc = self._cur_doc
|
||||
if base and base.is_implicit():
|
||||
base = None
|
||||
self._add_doc('Object',
|
||||
self._nodes_for_members(doc, 'Members', base, variants)
|
||||
+ self._nodes_for_features(doc)
|
||||
+ self._nodes_for_sections(doc)
|
||||
+ self._nodes_for_if_section(ifcond))
|
||||
|
||||
def visit_alternate_type(self, name, info, ifcond, features, variants):
|
||||
doc = self._cur_doc
|
||||
self._add_doc('Alternate',
|
||||
self._nodes_for_members(doc, 'Members')
|
||||
+ self._nodes_for_features(doc)
|
||||
+ self._nodes_for_sections(doc)
|
||||
+ self._nodes_for_if_section(ifcond))
|
||||
|
||||
def visit_command(self, name, info, ifcond, features, arg_type,
|
||||
ret_type, gen, success_response, boxed, allow_oob,
|
||||
allow_preconfig):
|
||||
doc = self._cur_doc
|
||||
self._add_doc('Command',
|
||||
self._nodes_for_arguments(doc,
|
||||
arg_type if boxed else None)
|
||||
+ self._nodes_for_features(doc)
|
||||
+ self._nodes_for_sections(doc)
|
||||
+ self._nodes_for_if_section(ifcond))
|
||||
|
||||
def visit_event(self, name, info, ifcond, features, arg_type, boxed):
|
||||
doc = self._cur_doc
|
||||
self._add_doc('Event',
|
||||
self._nodes_for_arguments(doc,
|
||||
arg_type if boxed else None)
|
||||
+ self._nodes_for_features(doc)
|
||||
+ self._nodes_for_sections(doc)
|
||||
+ self._nodes_for_if_section(ifcond))
|
||||
|
||||
def symbol(self, doc, entity):
|
||||
"""Add documentation for one symbol to the document tree
|
||||
|
||||
This is the main entry point which causes us to add documentation
|
||||
nodes for a symbol (which could be a 'command', 'object', 'event',
|
||||
etc). We do this by calling 'visit' on the schema entity, which
|
||||
will then call back into one of our visit_* methods, depending
|
||||
on what kind of thing this symbol is.
|
||||
"""
|
||||
self._cur_doc = doc
|
||||
entity.visit(self)
|
||||
self._cur_doc = None
|
||||
|
||||
def _start_new_heading(self, heading, level):
|
||||
"""Start a new heading at the specified heading level
|
||||
|
||||
Create a new section whose title is 'heading' and which is placed
|
||||
in the docutils node tree as a child of the most recent level-1
|
||||
heading. Subsequent document sections (commands, freeform doc chunks,
|
||||
etc) will be placed as children of this new heading section.
|
||||
"""
|
||||
if len(self._active_headings) < level:
|
||||
raise QAPISemError(self._cur_doc.info,
|
||||
'Level %d subheading found outside a '
|
||||
'level %d heading'
|
||||
% (level, level - 1))
|
||||
snode = self._make_section(heading)
|
||||
self._active_headings[level - 1] += snode
|
||||
self._active_headings = self._active_headings[:level]
|
||||
self._active_headings.append(snode)
|
||||
|
||||
def _add_node_to_current_heading(self, node):
|
||||
"""Add the node to whatever the current active heading is"""
|
||||
self._active_headings[-1] += node
|
||||
|
||||
def freeform(self, doc):
|
||||
"""Add a piece of 'freeform' documentation to the document tree
|
||||
|
||||
A 'freeform' document chunk doesn't relate to any particular
|
||||
symbol (for instance, it could be an introduction).
|
||||
|
||||
If the freeform document starts with a line of the form
|
||||
'= Heading text', this is a section or subsection heading, with
|
||||
the heading level indicated by the number of '=' signs.
|
||||
"""
|
||||
|
||||
# QAPIDoc documentation says free-form documentation blocks
|
||||
# must have only a body section, nothing else.
|
||||
assert not doc.sections
|
||||
assert not doc.args
|
||||
assert not doc.features
|
||||
self._cur_doc = doc
|
||||
|
||||
text = doc.body.text
|
||||
if re.match(r'=+ ', text):
|
||||
# Section/subsection heading (if present, will always be
|
||||
# the first line of the block)
|
||||
(heading, _, text) = text.partition('\n')
|
||||
(leader, _, heading) = heading.partition(' ')
|
||||
self._start_new_heading(heading, len(leader))
|
||||
if text == '':
|
||||
return
|
||||
|
||||
node = self._make_section(None)
|
||||
self._parse_text_into_node(text, node)
|
||||
self._add_node_to_current_heading(node)
|
||||
self._cur_doc = None
|
||||
|
||||
def _parse_text_into_node(self, doctext, node):
|
||||
"""Parse a chunk of QAPI-doc-format text into the node
|
||||
|
||||
The doc comment can contain most inline rST markup, including
|
||||
bulleted and enumerated lists.
|
||||
As an extra permitted piece of markup, @var will be turned
|
||||
into ``var``.
|
||||
"""
|
||||
|
||||
# Handle the "@var means ``var`` case
|
||||
doctext = re.sub(r'@([\w-]+)', r'``\1``', doctext)
|
||||
|
||||
rstlist = ViewList()
|
||||
for line in doctext.splitlines():
|
||||
# The reported line number will always be that of the start line
|
||||
# of the doc comment, rather than the actual location of the error.
|
||||
# Being more precise would require overhaul of the QAPIDoc class
|
||||
# to track lines more exactly within all the sub-parts of the doc
|
||||
# comment, as well as counting lines here.
|
||||
rstlist.append(line, self._cur_doc.info.fname,
|
||||
self._cur_doc.info.line)
|
||||
# Append a blank line -- in some cases rST syntax errors get
|
||||
# attributed to the line after one with actual text, and if there
|
||||
# isn't anything in the ViewList corresponding to that then Sphinx
|
||||
# 1.6's AutodocReporter will then misidentify the source/line location
|
||||
# in the error message (usually attributing it to the top-level
|
||||
# .rst file rather than the offending .json file). The extra blank
|
||||
# line won't affect the rendered output.
|
||||
rstlist.append("", self._cur_doc.info.fname, self._cur_doc.info.line)
|
||||
self._sphinx_directive.do_parse(rstlist, node)
|
||||
|
||||
def get_document_nodes(self):
|
||||
"""Return the list of docutils nodes which make up the document"""
|
||||
return self._top_node.children
|
||||
|
||||
|
||||
class QAPISchemaGenDepVisitor(QAPISchemaVisitor):
|
||||
"""A QAPI schema visitor which adds Sphinx dependencies each module
|
||||
|
||||
This class calls the Sphinx note_dependency() function to tell Sphinx
|
||||
that the generated documentation output depends on the input
|
||||
schema file associated with each module in the QAPI input.
|
||||
"""
|
||||
def __init__(self, env, qapidir):
|
||||
self._env = env
|
||||
self._qapidir = qapidir
|
||||
|
||||
def visit_module(self, name):
|
||||
if name is not None:
|
||||
qapifile = self._qapidir + '/' + name
|
||||
self._env.note_dependency(os.path.abspath(qapifile))
|
||||
super().visit_module(name)
|
||||
|
||||
|
||||
class QAPIDocDirective(Directive):
|
||||
"""Extract documentation from the specified QAPI .json file"""
|
||||
required_argument = 1
|
||||
optional_arguments = 1
|
||||
option_spec = {
|
||||
'qapifile': directives.unchanged_required
|
||||
}
|
||||
has_content = False
|
||||
|
||||
def new_serialno(self):
|
||||
"""Return a unique new ID string suitable for use as a node's ID"""
|
||||
env = self.state.document.settings.env
|
||||
return 'qapidoc-%d' % env.new_serialno('qapidoc')
|
||||
|
||||
def run(self):
|
||||
env = self.state.document.settings.env
|
||||
qapifile = env.config.qapidoc_srctree + '/' + self.arguments[0]
|
||||
qapidir = os.path.dirname(qapifile)
|
||||
|
||||
try:
|
||||
schema = QAPISchema(qapifile)
|
||||
|
||||
# First tell Sphinx about all the schema files that the
|
||||
# output documentation depends on (including 'qapifile' itself)
|
||||
schema.visit(QAPISchemaGenDepVisitor(env, qapidir))
|
||||
|
||||
vis = QAPISchemaGenRSTVisitor(self)
|
||||
vis.visit_begin(schema)
|
||||
for doc in schema.docs:
|
||||
if doc.symbol:
|
||||
vis.symbol(doc, schema.lookup_entity(doc.symbol))
|
||||
else:
|
||||
vis.freeform(doc)
|
||||
return vis.get_document_nodes()
|
||||
except QAPIError as err:
|
||||
# Launder QAPI parse errors into Sphinx extension errors
|
||||
# so they are displayed nicely to the user
|
||||
raise ExtensionError(str(err))
|
||||
|
||||
def do_parse(self, rstlist, node):
|
||||
"""Parse rST source lines and add them to the specified node
|
||||
|
||||
Take the list of rST source lines rstlist, parse them as
|
||||
rST, and add the resulting docutils nodes as children of node.
|
||||
The nodes are parsed in a way that allows them to include
|
||||
subheadings (titles) without confusing the rendering of
|
||||
anything else.
|
||||
"""
|
||||
# This is from kerneldoc.py -- it works around an API change in
|
||||
# Sphinx between 1.6 and 1.7. Unlike kerneldoc.py, we use
|
||||
# sphinx.util.nodes.nested_parse_with_titles() rather than the
|
||||
# plain self.state.nested_parse(), and so we can drop the saving
|
||||
# of title_styles and section_level that kerneldoc.py does,
|
||||
# because nested_parse_with_titles() does that for us.
|
||||
if Use_SSI:
|
||||
with switch_source_input(self.state, rstlist):
|
||||
nested_parse_with_titles(self.state, rstlist, node)
|
||||
else:
|
||||
save = self.state.memo.reporter
|
||||
self.state.memo.reporter = AutodocReporter(
|
||||
rstlist, self.state.memo.reporter)
|
||||
try:
|
||||
nested_parse_with_titles(self.state, rstlist, node)
|
||||
finally:
|
||||
self.state.memo.reporter = save
|
||||
|
||||
|
||||
def setup(app):
|
||||
""" Register qapi-doc directive with Sphinx"""
|
||||
app.add_config_value('qapidoc_srctree', None, 'env')
|
||||
app.add_directive('qapi-doc', QAPIDocDirective)
|
||||
|
||||
return dict(
|
||||
version=__version__,
|
||||
parallel_read_safe=True,
|
||||
parallel_write_safe=True
|
||||
)
|
|
@ -27,7 +27,7 @@
|
|||
#include "qapi/error.h"
|
||||
#include "qapi/opts-visitor.h"
|
||||
#include "qapi/qapi-events-run-state.h"
|
||||
#include "qapi/qapi-visit-misc.h"
|
||||
#include "qapi/qapi-visit-acpi.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/option.h"
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include "migration/vmstate.h"
|
||||
#include "hw/acpi/cpu.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qapi-events-misc.h"
|
||||
#include "qapi/qapi-events-acpi.h"
|
||||
#include "trace.h"
|
||||
#include "sysemu/numa.h"
|
||||
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
#include "migration/vmstate.h"
|
||||
#include "trace.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qapi-events-misc.h"
|
||||
#include "qapi/qapi-events-acpi.h"
|
||||
#include "qapi/qapi-events-machine.h"
|
||||
|
||||
#define MEMORY_SLOTS_NUMBER "MDNR"
|
||||
#define MEMORY_HOTPLUG_IO_REGION "HPMR"
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qapi-commands-misc.h"
|
||||
#include "qapi/qapi-commands-machine.h"
|
||||
#include "qemu/module.h"
|
||||
#include "hw/acpi/acpi.h"
|
||||
#include "hw/acpi/aml-build.h"
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "qapi/error.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "qapi/qapi-types-block.h"
|
||||
#include "qapi/qapi-types-machine.h"
|
||||
#include "qapi/qapi-types-misc.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qemu/ctype.h"
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
#include "qemu/osdep.h"
|
||||
#include <linux/kvm.h>
|
||||
#include "qapi/qapi-types-misc.h"
|
||||
#include "qapi/qapi-types-machine.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/timer.h"
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "sysemu/sysemu.h"
|
||||
#include "monitor/monitor.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qapi-commands-misc.h"
|
||||
#include "qapi/qapi-commands-pci.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/pci/msi.h"
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
#include "hw/hotplug.h"
|
||||
#include "hw/boards.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qapi-commands-misc.h"
|
||||
#include "qapi/qapi-commands-pci.h"
|
||||
#include "qemu/cutils.h"
|
||||
|
||||
//#define DEBUG_PCI
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include "hw/virtio/virtio-balloon.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qapi-events-misc.h"
|
||||
#include "qapi/qapi-events-machine.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "trace.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "virtio-mem-pci.h"
|
||||
#include "hw/mem/memory-device.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qapi-events-machine.h"
|
||||
#include "qapi/qapi-events-misc.h"
|
||||
|
||||
static void virtio_mem_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef ACPI_DEV_INTERFACE_H
|
||||
#define ACPI_DEV_INTERFACE_H
|
||||
|
||||
#include "qapi/qapi-types-misc.h"
|
||||
#include "qapi/qapi-types-acpi.h"
|
||||
#include "qom/object.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/qdev-core.h"
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#define MEMORY_DEVICE_H
|
||||
|
||||
#include "hw/qdev-core.h"
|
||||
#include "qapi/qapi-types-misc.h"
|
||||
#include "qapi/qapi-types-machine.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TYPE_MEMORY_DEVICE "memory-device"
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#ifndef HW_RTC_MC146818RTC_H
|
||||
#define HW_RTC_MC146818RTC_H
|
||||
|
||||
#include "qapi/qapi-types-misc.h"
|
||||
#include "qapi/qapi-types-machine.h"
|
||||
#include "qemu/queue.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "hw/isa/isa.h"
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#define HW_VIRTIO_PMEM_H
|
||||
|
||||
#include "hw/virtio/virtio.h"
|
||||
#include "qapi/qapi-types-misc.h"
|
||||
#include "qapi/qapi-types-machine.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TYPE_VIRTIO_PMEM "virtio-pmem"
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#define QEMU_BALLOON_H
|
||||
|
||||
#include "exec/cpu-common.h"
|
||||
#include "qapi/qapi-types-misc.h"
|
||||
#include "qapi/qapi-types-machine.h"
|
||||
|
||||
typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target);
|
||||
typedef void (QEMUBalloonStatus)(void *opaque, BalloonInfo *info);
|
||||
|
|
103
meson.build
103
meson.build
|
@ -619,7 +619,6 @@ qapi_gen = find_program('scripts/qapi-gen.py')
|
|||
qapi_gen_depends = [ meson.source_root() / 'scripts/qapi/__init__.py',
|
||||
meson.source_root() / 'scripts/qapi/commands.py',
|
||||
meson.source_root() / 'scripts/qapi/common.py',
|
||||
meson.source_root() / 'scripts/qapi/doc.py',
|
||||
meson.source_root() / 'scripts/qapi/error.py',
|
||||
meson.source_root() / 'scripts/qapi/events.py',
|
||||
meson.source_root() / 'scripts/qapi/expr.py',
|
||||
|
@ -631,7 +630,6 @@ qapi_gen_depends = [ meson.source_root() / 'scripts/qapi/__init__.py',
|
|||
meson.source_root() / 'scripts/qapi/types.py',
|
||||
meson.source_root() / 'scripts/qapi/visit.py',
|
||||
meson.source_root() / 'scripts/qapi/common.py',
|
||||
meson.source_root() / 'scripts/qapi/doc.py',
|
||||
meson.source_root() / 'scripts/qapi-gen.py'
|
||||
]
|
||||
|
||||
|
@ -672,6 +670,22 @@ foreach d : hx_headers
|
|||
endforeach
|
||||
genh += hxdep
|
||||
|
||||
SPHINX_ARGS = [config_host['SPHINX_BUILD'],
|
||||
'-Dversion=' + meson.project_version(),
|
||||
'-Drelease=' + config_host['PKGVERSION']]
|
||||
|
||||
if get_option('werror')
|
||||
SPHINX_ARGS += [ '-W' ]
|
||||
endif
|
||||
|
||||
sphinx_extn_depends = [ meson.source_root() / 'docs/sphinx/depfile.py',
|
||||
meson.source_root() / 'docs/sphinx/hxtool.py',
|
||||
meson.source_root() / 'docs/sphinx/kerneldoc.py',
|
||||
meson.source_root() / 'docs/sphinx/kernellog.py',
|
||||
meson.source_root() / 'docs/sphinx/qapidoc.py',
|
||||
meson.source_root() / 'docs/sphinx/qmp_lexer.py',
|
||||
qapi_gen_depends ]
|
||||
|
||||
# Collect sourcesets.
|
||||
|
||||
util_ss = ss.source_set()
|
||||
|
@ -1204,91 +1218,6 @@ if 'CONFIG_GTK' in config_host
|
|||
subdir('po')
|
||||
endif
|
||||
|
||||
if build_docs
|
||||
makeinfo = find_program('makeinfo', required: build_docs)
|
||||
|
||||
docs_inc = [
|
||||
'-I', meson.current_source_dir(),
|
||||
'-I', meson.current_build_dir() / 'docs',
|
||||
'-I', '@OUTDIR@',
|
||||
]
|
||||
|
||||
version_texi = configure_file(output: 'version.texi',
|
||||
input: 'version.texi.in',
|
||||
configuration: {'VERSION': meson.project_version(),
|
||||
'qemu_confdir': config_host['qemu_confdir']})
|
||||
|
||||
texi = {
|
||||
'qemu-qmp-ref': ['docs/interop/qemu-qmp-ref.texi', qapi_doc_texi, version_texi],
|
||||
}
|
||||
if 'CONFIG_GUEST_AGENT' in config_host
|
||||
texi += {'qemu-ga-ref': ['docs/interop/qemu-ga-ref.texi', qga_qapi_doc_texi, version_texi]}
|
||||
endif
|
||||
|
||||
if makeinfo.found()
|
||||
cmd = [
|
||||
'env', 'LC_ALL=C', makeinfo, '--no-split', '--number-sections', docs_inc,
|
||||
'@INPUT0@', '-o', '@OUTPUT@',
|
||||
]
|
||||
foreach ext, args: {
|
||||
'info': [],
|
||||
'html': ['--no-headers', '--html'],
|
||||
'txt': ['--no-headers', '--plaintext'],
|
||||
}
|
||||
t = []
|
||||
foreach doc, input: texi
|
||||
output = doc + '.' + ext
|
||||
t += custom_target(output,
|
||||
input: input,
|
||||
output: output,
|
||||
install: true,
|
||||
install_dir: qemu_docdir / 'interop',
|
||||
command: cmd + args)
|
||||
endforeach
|
||||
alias_target(ext, t)
|
||||
endforeach
|
||||
endif
|
||||
|
||||
texi2pdf = find_program('texi2pdf', required: false)
|
||||
|
||||
if texi2pdf.found()
|
||||
pdfs = []
|
||||
foreach doc, input: texi
|
||||
output = doc + '.pdf'
|
||||
pdfs += custom_target(output,
|
||||
input: input,
|
||||
output: output,
|
||||
command: [texi2pdf, '-q', docs_inc, '@INPUT0@', '-o', '@OUTPUT@'],
|
||||
build_by_default: false)
|
||||
endforeach
|
||||
alias_target('pdf', pdfs)
|
||||
endif
|
||||
|
||||
texi2pod = find_program('scripts/texi2pod.pl')
|
||||
pod2man = find_program('pod2man', required: build_docs)
|
||||
|
||||
if pod2man.found()
|
||||
foreach doc, input: texi
|
||||
man = doc + '.7'
|
||||
pod = custom_target(man + '.pod',
|
||||
input: input,
|
||||
output: man + '.pod',
|
||||
command: [texi2pod,
|
||||
'-DVERSION="' + meson.project_version() + '"',
|
||||
'-DCONFDIR="' + config_host['qemu_confdir'] + '"',
|
||||
'@INPUT0@', '@OUTPUT@'])
|
||||
man = custom_target(man,
|
||||
input: pod,
|
||||
output: man,
|
||||
capture: true,
|
||||
install: true,
|
||||
install_dir: get_option('mandir') / 'man7',
|
||||
command: [pod2man, '--utf8', '--section=7', '--center=" "',
|
||||
'--release=" "', '@INPUT@'])
|
||||
endforeach
|
||||
endif
|
||||
endif
|
||||
|
||||
if host_machine.system() == 'windows'
|
||||
nsis_cmd = [
|
||||
find_program('scripts/nsis.py'),
|
||||
|
|
|
@ -32,9 +32,11 @@
|
|||
#include "qapi/qapi-commands-block.h"
|
||||
#include "qapi/qapi-commands-char.h"
|
||||
#include "qapi/qapi-commands-control.h"
|
||||
#include "qapi/qapi-commands-machine.h"
|
||||
#include "qapi/qapi-commands-migration.h"
|
||||
#include "qapi/qapi-commands-misc.h"
|
||||
#include "qapi/qapi-commands-net.h"
|
||||
#include "qapi/qapi-commands-pci.h"
|
||||
#include "qapi/qapi-commands-rocker.h"
|
||||
#include "qapi/qapi-commands-run-state.h"
|
||||
#include "qapi/qapi-commands-tpm.h"
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "sysemu/blockdev.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qapi-commands-acpi.h"
|
||||
#include "qapi/qapi-commands-block.h"
|
||||
#include "qapi/qapi-commands-control.h"
|
||||
#include "qapi/qapi-commands-machine.h"
|
||||
|
|
141
qapi/acpi.json
Normal file
141
qapi/acpi.json
Normal file
|
@ -0,0 +1,141 @@
|
|||
# -*- Mode: Python -*-
|
||||
# vim: filetype=python
|
||||
#
|
||||
# This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
# See the COPYING file in the top-level directory.
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
##
|
||||
# = ACPI
|
||||
##
|
||||
|
||||
##
|
||||
# @AcpiTableOptions:
|
||||
#
|
||||
# Specify an ACPI table on the command line to load.
|
||||
#
|
||||
# At most one of @file and @data can be specified. The list of files specified
|
||||
# by any one of them is loaded and concatenated in order. If both are omitted,
|
||||
# @data is implied.
|
||||
#
|
||||
# Other fields / optargs can be used to override fields of the generic ACPI
|
||||
# table header; refer to the ACPI specification 5.0, section 5.2.6 System
|
||||
# Description Table Header. If a header field is not overridden, then the
|
||||
# corresponding value from the concatenated blob is used (in case of @file), or
|
||||
# it is filled in with a hard-coded value (in case of @data).
|
||||
#
|
||||
# String fields are copied into the matching ACPI member from lowest address
|
||||
# upwards, and silently truncated / NUL-padded to length.
|
||||
#
|
||||
# @sig: table signature / identifier (4 bytes)
|
||||
#
|
||||
# @rev: table revision number (dependent on signature, 1 byte)
|
||||
#
|
||||
# @oem_id: OEM identifier (6 bytes)
|
||||
#
|
||||
# @oem_table_id: OEM table identifier (8 bytes)
|
||||
#
|
||||
# @oem_rev: OEM-supplied revision number (4 bytes)
|
||||
#
|
||||
# @asl_compiler_id: identifier of the utility that created the table
|
||||
# (4 bytes)
|
||||
#
|
||||
# @asl_compiler_rev: revision number of the utility that created the
|
||||
# table (4 bytes)
|
||||
#
|
||||
# @file: colon (:) separated list of pathnames to load and
|
||||
# concatenate as table data. The resultant binary blob is expected to
|
||||
# have an ACPI table header. At least one file is required. This field
|
||||
# excludes @data.
|
||||
#
|
||||
# @data: colon (:) separated list of pathnames to load and
|
||||
# concatenate as table data. The resultant binary blob must not have an
|
||||
# ACPI table header. At least one file is required. This field excludes
|
||||
# @file.
|
||||
#
|
||||
# Since: 1.5
|
||||
##
|
||||
{ 'struct': 'AcpiTableOptions',
|
||||
'data': {
|
||||
'*sig': 'str',
|
||||
'*rev': 'uint8',
|
||||
'*oem_id': 'str',
|
||||
'*oem_table_id': 'str',
|
||||
'*oem_rev': 'uint32',
|
||||
'*asl_compiler_id': 'str',
|
||||
'*asl_compiler_rev': 'uint32',
|
||||
'*file': 'str',
|
||||
'*data': 'str' }}
|
||||
|
||||
##
|
||||
# @ACPISlotType:
|
||||
#
|
||||
# @DIMM: memory slot
|
||||
# @CPU: logical CPU slot (since 2.7)
|
||||
##
|
||||
{ 'enum': 'ACPISlotType', 'data': [ 'DIMM', 'CPU' ] }
|
||||
|
||||
##
|
||||
# @ACPIOSTInfo:
|
||||
#
|
||||
# OSPM Status Indication for a device
|
||||
# For description of possible values of @source and @status fields
|
||||
# see "_OST (OSPM Status Indication)" chapter of ACPI5.0 spec.
|
||||
#
|
||||
# @device: device ID associated with slot
|
||||
#
|
||||
# @slot: slot ID, unique per slot of a given @slot-type
|
||||
#
|
||||
# @slot-type: type of the slot
|
||||
#
|
||||
# @source: an integer containing the source event
|
||||
#
|
||||
# @status: an integer containing the status code
|
||||
#
|
||||
# Since: 2.1
|
||||
##
|
||||
{ 'struct': 'ACPIOSTInfo',
|
||||
'data' : { '*device': 'str',
|
||||
'slot': 'str',
|
||||
'slot-type': 'ACPISlotType',
|
||||
'source': 'int',
|
||||
'status': 'int' } }
|
||||
|
||||
##
|
||||
# @query-acpi-ospm-status:
|
||||
#
|
||||
# Return a list of ACPIOSTInfo for devices that support status
|
||||
# reporting via ACPI _OST method.
|
||||
#
|
||||
# Since: 2.1
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# -> { "execute": "query-acpi-ospm-status" }
|
||||
# <- { "return": [ { "device": "d1", "slot": "0", "slot-type": "DIMM", "source": 1, "status": 0},
|
||||
# { "slot": "1", "slot-type": "DIMM", "source": 0, "status": 0},
|
||||
# { "slot": "2", "slot-type": "DIMM", "source": 0, "status": 0},
|
||||
# { "slot": "3", "slot-type": "DIMM", "source": 0, "status": 0}
|
||||
# ]}
|
||||
#
|
||||
##
|
||||
{ 'command': 'query-acpi-ospm-status', 'returns': ['ACPIOSTInfo'] }
|
||||
|
||||
##
|
||||
# @ACPI_DEVICE_OST:
|
||||
#
|
||||
# Emitted when guest executes ACPI _OST method.
|
||||
#
|
||||
# @info: OSPM Status Indication
|
||||
#
|
||||
# Since: 2.1
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# <- { "event": "ACPI_DEVICE_OST",
|
||||
# "data": { "device": "d1", "slot": "0",
|
||||
# "slot-type": "DIMM", "source": 1, "status": 0 } }
|
||||
#
|
||||
##
|
||||
{ 'event': 'ACPI_DEVICE_OST',
|
||||
'data': { 'info': 'ACPIOSTInfo' } }
|
|
@ -570,13 +570,15 @@
|
|||
# For the example above, @bins may be something like [3, 1, 5, 2],
|
||||
# and corresponding histogram looks like:
|
||||
#
|
||||
# | 5| *
|
||||
# | 4| *
|
||||
# | 3| * *
|
||||
# | 2| * * *
|
||||
# | 1| * * * *
|
||||
# | +------------------
|
||||
# | 10 50 100
|
||||
# ::
|
||||
#
|
||||
# 5| *
|
||||
# 4| *
|
||||
# 3| * *
|
||||
# 2| * * *
|
||||
# 1| * * * *
|
||||
# +------------------
|
||||
# 10 50 100
|
||||
#
|
||||
# Since: 4.0
|
||||
##
|
||||
|
@ -4316,8 +4318,8 @@
|
|||
# @data-file-raw: True if the external data file must stay valid as a
|
||||
# standalone (read-only) raw image without looking at qcow2
|
||||
# metadata (default: false; since: 4.0)
|
||||
# @extended-l2 True to make the image have extended L2 entries
|
||||
# (default: false; since 5.2)
|
||||
# @extended-l2: True to make the image have extended L2 entries
|
||||
# (default: false; since 5.2)
|
||||
# @size: Size of the virtual disk in bytes
|
||||
# @version: Compatibility level (default: v3)
|
||||
# @backing-file: File name of the backing file if a backing file
|
||||
|
|
|
@ -528,7 +528,8 @@
|
|||
#
|
||||
# Since: 4.0
|
||||
#
|
||||
# Example: set new histograms for all io types with intervals
|
||||
# Example:
|
||||
# set new histograms for all io types with intervals
|
||||
# [0, 10), [10, 50), [50, 100), [100, +inf):
|
||||
#
|
||||
# -> { "execute": "block-latency-histogram-set",
|
||||
|
@ -536,7 +537,8 @@
|
|||
# "boundaries": [10, 50, 100] } }
|
||||
# <- { "return": {} }
|
||||
#
|
||||
# Example: set new histogram only for write, other histograms will remain
|
||||
# Example:
|
||||
# set new histogram only for write, other histograms will remain
|
||||
# not changed (or not created):
|
||||
#
|
||||
# -> { "execute": "block-latency-histogram-set",
|
||||
|
@ -544,7 +546,8 @@
|
|||
# "boundaries-write": [10, 50, 100] } }
|
||||
# <- { "return": {} }
|
||||
#
|
||||
# Example: set new histograms with the following intervals:
|
||||
# Example:
|
||||
# set new histograms with the following intervals:
|
||||
# read, flush: [0, 10), [10, 50), [50, 100), [100, +inf)
|
||||
# write: [0, 1000), [1000, 5000), [5000, +inf)
|
||||
#
|
||||
|
@ -554,7 +557,8 @@
|
|||
# "boundaries-write": [1000, 5000] } }
|
||||
# <- { "return": {} }
|
||||
#
|
||||
# Example: remove all latency histograms:
|
||||
# Example:
|
||||
# remove all latency histograms:
|
||||
#
|
||||
# -> { "execute": "block-latency-histogram-set",
|
||||
# "arguments": { "id": "drive0" } }
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#
|
||||
# The comprehensive enumeration of QEMU system emulation ("softmmu")
|
||||
# targets. Run "./configure --help" in the project root directory, and
|
||||
# look for the *-softmmu targets near the "--target-list" option. The
|
||||
# look for the \*-softmmu targets near the "--target-list" option. The
|
||||
# individual target constants are not documented here, for the time
|
||||
# being.
|
||||
#
|
||||
|
@ -402,6 +402,88 @@
|
|||
##
|
||||
{ 'command': 'query-target', 'returns': 'TargetInfo' }
|
||||
|
||||
##
|
||||
# @UuidInfo:
|
||||
#
|
||||
# Guest UUID information (Universally Unique Identifier).
|
||||
#
|
||||
# @UUID: the UUID of the guest
|
||||
#
|
||||
# Since: 0.14.0
|
||||
#
|
||||
# Notes: If no UUID was specified for the guest, a null UUID is returned.
|
||||
##
|
||||
{ 'struct': 'UuidInfo', 'data': {'UUID': 'str'} }
|
||||
|
||||
##
|
||||
# @query-uuid:
|
||||
#
|
||||
# Query the guest UUID information.
|
||||
#
|
||||
# Returns: The @UuidInfo for the guest
|
||||
#
|
||||
# Since: 0.14.0
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# -> { "execute": "query-uuid" }
|
||||
# <- { "return": { "UUID": "550e8400-e29b-41d4-a716-446655440000" } }
|
||||
#
|
||||
##
|
||||
{ 'command': 'query-uuid', 'returns': 'UuidInfo', 'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @GuidInfo:
|
||||
#
|
||||
# GUID information.
|
||||
#
|
||||
# @guid: the globally unique identifier
|
||||
#
|
||||
# Since: 2.9
|
||||
##
|
||||
{ 'struct': 'GuidInfo', 'data': {'guid': 'str'} }
|
||||
|
||||
##
|
||||
# @query-vm-generation-id:
|
||||
#
|
||||
# Show Virtual Machine Generation ID
|
||||
#
|
||||
# Since: 2.9
|
||||
##
|
||||
{ 'command': 'query-vm-generation-id', 'returns': 'GuidInfo' }
|
||||
|
||||
##
|
||||
# @LostTickPolicy:
|
||||
#
|
||||
# Policy for handling lost ticks in timer devices. Ticks end up getting
|
||||
# lost when, for example, the guest is paused.
|
||||
#
|
||||
# @discard: throw away the missed ticks and continue with future injection
|
||||
# normally. The guest OS will see the timer jump ahead by a
|
||||
# potentially quite significant amount all at once, as if the
|
||||
# intervening chunk of time had simply not existed; needless to
|
||||
# say, such a sudden jump can easily confuse a guest OS which is
|
||||
# not specifically prepared to deal with it. Assuming the guest
|
||||
# OS can deal correctly with the time jump, the time in the guest
|
||||
# and in the host should now match.
|
||||
#
|
||||
# @delay: continue to deliver ticks at the normal rate. The guest OS will
|
||||
# not notice anything is amiss, as from its point of view time will
|
||||
# have continued to flow normally. The time in the guest should now
|
||||
# be behind the time in the host by exactly the amount of time during
|
||||
# which ticks have been missed.
|
||||
#
|
||||
# @slew: deliver ticks at a higher rate to catch up with the missed ticks.
|
||||
# The guest OS will not notice anything is amiss, as from its point
|
||||
# of view time will have continued to flow normally. Once the timer
|
||||
# has managed to catch up with all the missing ticks, the time in
|
||||
# the guest and in the host should match.
|
||||
#
|
||||
# Since: 2.0
|
||||
##
|
||||
{ 'enum': 'LostTickPolicy',
|
||||
'data': ['discard', 'delay', 'slew' ] }
|
||||
|
||||
##
|
||||
# @NumaOptionsType:
|
||||
#
|
||||
|
@ -913,3 +995,311 @@
|
|||
'data': 'NumaOptions',
|
||||
'allow-preconfig': true
|
||||
}
|
||||
|
||||
##
|
||||
# @balloon:
|
||||
#
|
||||
# Request the balloon driver to change its balloon size.
|
||||
#
|
||||
# @value: the target logical size of the VM in bytes.
|
||||
# We can deduce the size of the balloon using this formula:
|
||||
#
|
||||
# logical_vm_size = vm_ram_size - balloon_size
|
||||
#
|
||||
# From it we have: balloon_size = vm_ram_size - @value
|
||||
#
|
||||
# Returns: - Nothing on success
|
||||
# - If the balloon driver is enabled but not functional because the KVM
|
||||
# kernel module cannot support it, KvmMissingCap
|
||||
# - If no balloon device is present, DeviceNotActive
|
||||
#
|
||||
# Notes: This command just issues a request to the guest. When it returns,
|
||||
# the balloon size may not have changed. A guest can change the balloon
|
||||
# size independent of this command.
|
||||
#
|
||||
# Since: 0.14.0
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# -> { "execute": "balloon", "arguments": { "value": 536870912 } }
|
||||
# <- { "return": {} }
|
||||
#
|
||||
# With a 2.5GiB guest this command inflated the ballon to 3GiB.
|
||||
#
|
||||
##
|
||||
{ 'command': 'balloon', 'data': {'value': 'int'} }
|
||||
|
||||
##
|
||||
# @BalloonInfo:
|
||||
#
|
||||
# Information about the guest balloon device.
|
||||
#
|
||||
# @actual: the logical size of the VM in bytes
|
||||
# Formula used: logical_vm_size = vm_ram_size - balloon_size
|
||||
#
|
||||
# Since: 0.14.0
|
||||
#
|
||||
##
|
||||
{ 'struct': 'BalloonInfo', 'data': {'actual': 'int' } }
|
||||
|
||||
##
|
||||
# @query-balloon:
|
||||
#
|
||||
# Return information about the balloon device.
|
||||
#
|
||||
# Returns: - @BalloonInfo on success
|
||||
# - If the balloon driver is enabled but not functional because the KVM
|
||||
# kernel module cannot support it, KvmMissingCap
|
||||
# - If no balloon device is present, DeviceNotActive
|
||||
#
|
||||
# Since: 0.14.0
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# -> { "execute": "query-balloon" }
|
||||
# <- { "return": {
|
||||
# "actual": 1073741824,
|
||||
# }
|
||||
# }
|
||||
#
|
||||
##
|
||||
{ 'command': 'query-balloon', 'returns': 'BalloonInfo' }
|
||||
|
||||
##
|
||||
# @BALLOON_CHANGE:
|
||||
#
|
||||
# Emitted when the guest changes the actual BALLOON level. This value is
|
||||
# equivalent to the @actual field return by the 'query-balloon' command
|
||||
#
|
||||
# @actual: the logical size of the VM in bytes
|
||||
# Formula used: logical_vm_size = vm_ram_size - balloon_size
|
||||
#
|
||||
# Note: this event is rate-limited.
|
||||
#
|
||||
# Since: 1.2
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# <- { "event": "BALLOON_CHANGE",
|
||||
# "data": { "actual": 944766976 },
|
||||
# "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
|
||||
#
|
||||
##
|
||||
{ 'event': 'BALLOON_CHANGE',
|
||||
'data': { 'actual': 'int' } }
|
||||
|
||||
##
|
||||
# @MemoryInfo:
|
||||
#
|
||||
# Actual memory information in bytes.
|
||||
#
|
||||
# @base-memory: size of "base" memory specified with command line
|
||||
# option -m.
|
||||
#
|
||||
# @plugged-memory: size of memory that can be hot-unplugged. This field
|
||||
# is omitted if target doesn't support memory hotplug
|
||||
# (i.e. CONFIG_MEM_DEVICE not defined at build time).
|
||||
#
|
||||
# Since: 2.11.0
|
||||
##
|
||||
{ 'struct': 'MemoryInfo',
|
||||
'data' : { 'base-memory': 'size', '*plugged-memory': 'size' } }
|
||||
|
||||
##
|
||||
# @query-memory-size-summary:
|
||||
#
|
||||
# Return the amount of initially allocated and present hotpluggable (if
|
||||
# enabled) memory in bytes.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# -> { "execute": "query-memory-size-summary" }
|
||||
# <- { "return": { "base-memory": 4294967296, "plugged-memory": 0 } }
|
||||
#
|
||||
# Since: 2.11.0
|
||||
##
|
||||
{ 'command': 'query-memory-size-summary', 'returns': 'MemoryInfo' }
|
||||
|
||||
##
|
||||
# @PCDIMMDeviceInfo:
|
||||
#
|
||||
# PCDIMMDevice state information
|
||||
#
|
||||
# @id: device's ID
|
||||
#
|
||||
# @addr: physical address, where device is mapped
|
||||
#
|
||||
# @size: size of memory that the device provides
|
||||
#
|
||||
# @slot: slot number at which device is plugged in
|
||||
#
|
||||
# @node: NUMA node number where device is plugged in
|
||||
#
|
||||
# @memdev: memory backend linked with device
|
||||
#
|
||||
# @hotplugged: true if device was hotplugged
|
||||
#
|
||||
# @hotpluggable: true if device if could be added/removed while machine is running
|
||||
#
|
||||
# Since: 2.1
|
||||
##
|
||||
{ 'struct': 'PCDIMMDeviceInfo',
|
||||
'data': { '*id': 'str',
|
||||
'addr': 'int',
|
||||
'size': 'int',
|
||||
'slot': 'int',
|
||||
'node': 'int',
|
||||
'memdev': 'str',
|
||||
'hotplugged': 'bool',
|
||||
'hotpluggable': 'bool'
|
||||
}
|
||||
}
|
||||
|
||||
##
|
||||
# @VirtioPMEMDeviceInfo:
|
||||
#
|
||||
# VirtioPMEM state information
|
||||
#
|
||||
# @id: device's ID
|
||||
#
|
||||
# @memaddr: physical address in memory, where device is mapped
|
||||
#
|
||||
# @size: size of memory that the device provides
|
||||
#
|
||||
# @memdev: memory backend linked with device
|
||||
#
|
||||
# Since: 4.1
|
||||
##
|
||||
{ 'struct': 'VirtioPMEMDeviceInfo',
|
||||
'data': { '*id': 'str',
|
||||
'memaddr': 'size',
|
||||
'size': 'size',
|
||||
'memdev': 'str'
|
||||
}
|
||||
}
|
||||
|
||||
##
|
||||
# @VirtioMEMDeviceInfo:
|
||||
#
|
||||
# VirtioMEMDevice state information
|
||||
#
|
||||
# @id: device's ID
|
||||
#
|
||||
# @memaddr: physical address in memory, where device is mapped
|
||||
#
|
||||
# @requested-size: the user requested size of the device
|
||||
#
|
||||
# @size: the (current) size of memory that the device provides
|
||||
#
|
||||
# @max-size: the maximum size of memory that the device can provide
|
||||
#
|
||||
# @block-size: the block size of memory that the device provides
|
||||
#
|
||||
# @node: NUMA node number where device is assigned to
|
||||
#
|
||||
# @memdev: memory backend linked with the region
|
||||
#
|
||||
# Since: 5.1
|
||||
##
|
||||
{ 'struct': 'VirtioMEMDeviceInfo',
|
||||
'data': { '*id': 'str',
|
||||
'memaddr': 'size',
|
||||
'requested-size': 'size',
|
||||
'size': 'size',
|
||||
'max-size': 'size',
|
||||
'block-size': 'size',
|
||||
'node': 'int',
|
||||
'memdev': 'str'
|
||||
}
|
||||
}
|
||||
|
||||
##
|
||||
# @MemoryDeviceInfo:
|
||||
#
|
||||
# Union containing information about a memory device
|
||||
#
|
||||
# nvdimm is included since 2.12. virtio-pmem is included since 4.1.
|
||||
# virtio-mem is included since 5.1.
|
||||
#
|
||||
# Since: 2.1
|
||||
##
|
||||
{ 'union': 'MemoryDeviceInfo',
|
||||
'data': { 'dimm': 'PCDIMMDeviceInfo',
|
||||
'nvdimm': 'PCDIMMDeviceInfo',
|
||||
'virtio-pmem': 'VirtioPMEMDeviceInfo',
|
||||
'virtio-mem': 'VirtioMEMDeviceInfo'
|
||||
}
|
||||
}
|
||||
|
||||
##
|
||||
# @query-memory-devices:
|
||||
#
|
||||
# Lists available memory devices and their state
|
||||
#
|
||||
# Since: 2.1
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# -> { "execute": "query-memory-devices" }
|
||||
# <- { "return": [ { "data":
|
||||
# { "addr": 5368709120,
|
||||
# "hotpluggable": true,
|
||||
# "hotplugged": true,
|
||||
# "id": "d1",
|
||||
# "memdev": "/objects/memX",
|
||||
# "node": 0,
|
||||
# "size": 1073741824,
|
||||
# "slot": 0},
|
||||
# "type": "dimm"
|
||||
# } ] }
|
||||
#
|
||||
##
|
||||
{ 'command': 'query-memory-devices', 'returns': ['MemoryDeviceInfo'] }
|
||||
|
||||
##
|
||||
# @MEMORY_DEVICE_SIZE_CHANGE:
|
||||
#
|
||||
# Emitted when the size of a memory device changes. Only emitted for memory
|
||||
# devices that can actually change the size (e.g., virtio-mem due to guest
|
||||
# action).
|
||||
#
|
||||
# @id: device's ID
|
||||
# @size: the new size of memory that the device provides
|
||||
#
|
||||
# Note: this event is rate-limited.
|
||||
#
|
||||
# Since: 5.1
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# <- { "event": "MEMORY_DEVICE_SIZE_CHANGE",
|
||||
# "data": { "id": "vm0", "size": 1073741824},
|
||||
# "timestamp": { "seconds": 1588168529, "microseconds": 201316 } }
|
||||
#
|
||||
##
|
||||
{ 'event': 'MEMORY_DEVICE_SIZE_CHANGE',
|
||||
'data': { '*id': 'str', 'size': 'size' } }
|
||||
|
||||
|
||||
##
|
||||
# @MEM_UNPLUG_ERROR:
|
||||
#
|
||||
# Emitted when memory hot unplug error occurs.
|
||||
#
|
||||
# @device: device name
|
||||
#
|
||||
# @msg: Informative message
|
||||
#
|
||||
# Since: 2.4
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# <- { "event": "MEM_UNPLUG_ERROR"
|
||||
# "data": { "device": "dimm1",
|
||||
# "msg": "acpi: device unplug for unsupported device"
|
||||
# },
|
||||
# "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
|
||||
#
|
||||
##
|
||||
{ 'event': 'MEM_UNPLUG_ERROR',
|
||||
'data': { 'device': 'str', 'msg': 'str' } }
|
||||
|
|
|
@ -14,6 +14,7 @@ util_ss.add(files(
|
|||
))
|
||||
|
||||
qapi_all_modules = [
|
||||
'acpi',
|
||||
'audio',
|
||||
'authz',
|
||||
'block-core',
|
||||
|
@ -34,6 +35,7 @@ qapi_all_modules = [
|
|||
'net',
|
||||
'pragma',
|
||||
'qdev',
|
||||
'pci',
|
||||
'qom',
|
||||
'rdma',
|
||||
'rocker',
|
||||
|
@ -97,7 +99,7 @@ foreach module : qapi_all_modules
|
|||
endforeach
|
||||
|
||||
qapi_files = custom_target('shared QAPI source files',
|
||||
output: qapi_util_outputs + qapi_specific_outputs + qapi_nonmodule_outputs + ['qapi-doc.texi'],
|
||||
output: qapi_util_outputs + qapi_specific_outputs + qapi_nonmodule_outputs,
|
||||
input: [ files('qapi-schema.json') ],
|
||||
command: [ qapi_gen, '-o', 'qapi', '-b', '@INPUT0@' ],
|
||||
depend_files: [ qapi_inputs, qapi_gen_depends ])
|
||||
|
@ -121,5 +123,3 @@ foreach output : qapi_specific_outputs + qapi_nonmodule_outputs
|
|||
specific_ss.add(when: 'CONFIG_SOFTMMU', if_true: qapi_files[i])
|
||||
i = i + 1
|
||||
endforeach
|
||||
|
||||
qapi_doc_texi = qapi_files[i]
|
||||
|
|
|
@ -681,23 +681,23 @@
|
|||
# Defaults to 1. (Since 5.0)
|
||||
#
|
||||
# @block-bitmap-mapping: Maps block nodes and bitmaps on them to
|
||||
# aliases for the purpose of dirty bitmap migration. Such
|
||||
# aliases may for example be the corresponding names on the
|
||||
# opposite site.
|
||||
# The mapping must be one-to-one, but not necessarily
|
||||
# complete: On the source, unmapped bitmaps and all bitmaps
|
||||
# on unmapped nodes will be ignored. On the destination,
|
||||
# encountering an unmapped alias in the incoming migration
|
||||
# stream will result in a report, and all further bitmap
|
||||
# migration data will then be discarded.
|
||||
# Note that the destination does not know about bitmaps it
|
||||
# does not receive, so there is no limitation or requirement
|
||||
# regarding the number of bitmaps received, or how they are
|
||||
# named, or on which nodes they are placed.
|
||||
# By default (when this parameter has never been set), bitmap
|
||||
# names are mapped to themselves. Nodes are mapped to their
|
||||
# block device name if there is one, and to their node name
|
||||
# otherwise. (Since 5.2)
|
||||
# aliases for the purpose of dirty bitmap migration. Such
|
||||
# aliases may for example be the corresponding names on the
|
||||
# opposite site.
|
||||
# The mapping must be one-to-one, but not necessarily
|
||||
# complete: On the source, unmapped bitmaps and all bitmaps
|
||||
# on unmapped nodes will be ignored. On the destination,
|
||||
# encountering an unmapped alias in the incoming migration
|
||||
# stream will result in a report, and all further bitmap
|
||||
# migration data will then be discarded.
|
||||
# Note that the destination does not know about bitmaps it
|
||||
# does not receive, so there is no limitation or requirement
|
||||
# regarding the number of bitmaps received, or how they are
|
||||
# named, or on which nodes they are placed.
|
||||
# By default (when this parameter has never been set), bitmap
|
||||
# names are mapped to themselves. Nodes are mapped to their
|
||||
# block device name if there is one, and to their node name
|
||||
# otherwise. (Since 5.2)
|
||||
#
|
||||
# Since: 2.4
|
||||
##
|
||||
|
@ -841,23 +841,23 @@
|
|||
# Defaults to 1. (Since 5.0)
|
||||
#
|
||||
# @block-bitmap-mapping: Maps block nodes and bitmaps on them to
|
||||
# aliases for the purpose of dirty bitmap migration. Such
|
||||
# aliases may for example be the corresponding names on the
|
||||
# opposite site.
|
||||
# The mapping must be one-to-one, but not necessarily
|
||||
# complete: On the source, unmapped bitmaps and all bitmaps
|
||||
# on unmapped nodes will be ignored. On the destination,
|
||||
# encountering an unmapped alias in the incoming migration
|
||||
# stream will result in a report, and all further bitmap
|
||||
# migration data will then be discarded.
|
||||
# Note that the destination does not know about bitmaps it
|
||||
# does not receive, so there is no limitation or requirement
|
||||
# regarding the number of bitmaps received, or how they are
|
||||
# named, or on which nodes they are placed.
|
||||
# By default (when this parameter has never been set), bitmap
|
||||
# names are mapped to themselves. Nodes are mapped to their
|
||||
# block device name if there is one, and to their node name
|
||||
# otherwise. (Since 5.2)
|
||||
# aliases for the purpose of dirty bitmap migration. Such
|
||||
# aliases may for example be the corresponding names on the
|
||||
# opposite site.
|
||||
# The mapping must be one-to-one, but not necessarily
|
||||
# complete: On the source, unmapped bitmaps and all bitmaps
|
||||
# on unmapped nodes will be ignored. On the destination,
|
||||
# encountering an unmapped alias in the incoming migration
|
||||
# stream will result in a report, and all further bitmap
|
||||
# migration data will then be discarded.
|
||||
# Note that the destination does not know about bitmaps it
|
||||
# does not receive, so there is no limitation or requirement
|
||||
# regarding the number of bitmaps received, or how they are
|
||||
# named, or on which nodes they are placed.
|
||||
# By default (when this parameter has never been set), bitmap
|
||||
# names are mapped to themselves. Nodes are mapped to their
|
||||
# block device name if there is one, and to their node name
|
||||
# otherwise. (Since 5.2)
|
||||
#
|
||||
# Since: 2.4
|
||||
##
|
||||
|
@ -1037,23 +1037,23 @@
|
|||
# Defaults to 1. (Since 5.0)
|
||||
#
|
||||
# @block-bitmap-mapping: Maps block nodes and bitmaps on them to
|
||||
# aliases for the purpose of dirty bitmap migration. Such
|
||||
# aliases may for example be the corresponding names on the
|
||||
# opposite site.
|
||||
# The mapping must be one-to-one, but not necessarily
|
||||
# complete: On the source, unmapped bitmaps and all bitmaps
|
||||
# on unmapped nodes will be ignored. On the destination,
|
||||
# encountering an unmapped alias in the incoming migration
|
||||
# stream will result in a report, and all further bitmap
|
||||
# migration data will then be discarded.
|
||||
# Note that the destination does not know about bitmaps it
|
||||
# does not receive, so there is no limitation or requirement
|
||||
# regarding the number of bitmaps received, or how they are
|
||||
# named, or on which nodes they are placed.
|
||||
# By default (when this parameter has never been set), bitmap
|
||||
# names are mapped to themselves. Nodes are mapped to their
|
||||
# block device name if there is one, and to their node name
|
||||
# otherwise. (Since 5.2)
|
||||
# aliases for the purpose of dirty bitmap migration. Such
|
||||
# aliases may for example be the corresponding names on the
|
||||
# opposite site.
|
||||
# The mapping must be one-to-one, but not necessarily
|
||||
# complete: On the source, unmapped bitmaps and all bitmaps
|
||||
# on unmapped nodes will be ignored. On the destination,
|
||||
# encountering an unmapped alias in the incoming migration
|
||||
# stream will result in a report, and all further bitmap
|
||||
# migration data will then be discarded.
|
||||
# Note that the destination does not know about bitmaps it
|
||||
# does not receive, so there is no limitation or requirement
|
||||
# regarding the number of bitmaps received, or how they are
|
||||
# named, or on which nodes they are placed.
|
||||
# By default (when this parameter has never been set), bitmap
|
||||
# names are mapped to themselves. Nodes are mapped to their
|
||||
# block device name if there is one, and to their node name
|
||||
# otherwise. (Since 5.2)
|
||||
#
|
||||
# Since: 2.4
|
||||
##
|
||||
|
@ -1744,9 +1744,9 @@
|
|||
# Information about current dirty page rate of vm.
|
||||
#
|
||||
# @dirty-rate: @dirtyrate describing the dirty page rate of vm
|
||||
# in units of MB/s.
|
||||
# If this field returns '-1', it means querying has not
|
||||
# yet started or completed.
|
||||
# in units of MB/s.
|
||||
# If this field returns '-1', it means querying has not
|
||||
# yet started or completed.
|
||||
#
|
||||
# @status: status containing dirtyrate query status includes
|
||||
# 'unstarted' or 'measuring' or 'measured'
|
||||
|
|
820
qapi/misc.json
820
qapi/misc.json
|
@ -8,38 +8,6 @@
|
|||
|
||||
{ 'include': 'common.json' }
|
||||
|
||||
##
|
||||
# @LostTickPolicy:
|
||||
#
|
||||
# Policy for handling lost ticks in timer devices. Ticks end up getting
|
||||
# lost when, for example, the guest is paused.
|
||||
#
|
||||
# @discard: throw away the missed ticks and continue with future injection
|
||||
# normally. The guest OS will see the timer jump ahead by a
|
||||
# potentially quite significant amount all at once, as if the
|
||||
# intervening chunk of time had simply not existed; needless to
|
||||
# say, such a sudden jump can easily confuse a guest OS which is
|
||||
# not specifically prepared to deal with it. Assuming the guest
|
||||
# OS can deal correctly with the time jump, the time in the guest
|
||||
# and in the host should now match.
|
||||
#
|
||||
# @delay: continue to deliver ticks at the normal rate. The guest OS will
|
||||
# not notice anything is amiss, as from its point of view time will
|
||||
# have continued to flow normally. The time in the guest should now
|
||||
# be behind the time in the host by exactly the amount of time during
|
||||
# which ticks have been missed.
|
||||
#
|
||||
# @slew: deliver ticks at a higher rate to catch up with the missed ticks.
|
||||
# The guest OS will not notice anything is amiss, as from its point
|
||||
# of view time will have continued to flow normally. Once the timer
|
||||
# has managed to catch up with all the missing ticks, the time in
|
||||
# the guest and in the host should match.
|
||||
#
|
||||
# Since: 2.0
|
||||
##
|
||||
{ 'enum': 'LostTickPolicy',
|
||||
'data': ['discard', 'delay', 'slew' ] }
|
||||
|
||||
##
|
||||
# @add_client:
|
||||
#
|
||||
|
@ -130,36 +98,6 @@
|
|||
##
|
||||
{ 'command': 'query-kvm', 'returns': 'KvmInfo' }
|
||||
|
||||
##
|
||||
# @UuidInfo:
|
||||
#
|
||||
# Guest UUID information (Universally Unique Identifier).
|
||||
#
|
||||
# @UUID: the UUID of the guest
|
||||
#
|
||||
# Since: 0.14.0
|
||||
#
|
||||
# Notes: If no UUID was specified for the guest, a null UUID is returned.
|
||||
##
|
||||
{ 'struct': 'UuidInfo', 'data': {'UUID': 'str'} }
|
||||
|
||||
##
|
||||
# @query-uuid:
|
||||
#
|
||||
# Query the guest UUID information.
|
||||
#
|
||||
# Returns: The @UuidInfo for the guest
|
||||
#
|
||||
# Since: 0.14.0
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# -> { "execute": "query-uuid" }
|
||||
# <- { "return": { "UUID": "550e8400-e29b-41d4-a716-446655440000" } }
|
||||
#
|
||||
##
|
||||
{ 'command': 'query-uuid', 'returns': 'UuidInfo', 'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @IOThreadInfo:
|
||||
#
|
||||
|
@ -219,369 +157,6 @@
|
|||
{ 'command': 'query-iothreads', 'returns': ['IOThreadInfo'],
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @BalloonInfo:
|
||||
#
|
||||
# Information about the guest balloon device.
|
||||
#
|
||||
# @actual: the number of bytes the balloon currently contains
|
||||
#
|
||||
# Since: 0.14.0
|
||||
#
|
||||
##
|
||||
{ 'struct': 'BalloonInfo', 'data': {'actual': 'int' } }
|
||||
|
||||
##
|
||||
# @query-balloon:
|
||||
#
|
||||
# Return information about the balloon device.
|
||||
#
|
||||
# Returns: - @BalloonInfo on success
|
||||
# - If the balloon driver is enabled but not functional because the KVM
|
||||
# kernel module cannot support it, KvmMissingCap
|
||||
# - If no balloon device is present, DeviceNotActive
|
||||
#
|
||||
# Since: 0.14.0
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# -> { "execute": "query-balloon" }
|
||||
# <- { "return": {
|
||||
# "actual": 1073741824,
|
||||
# }
|
||||
# }
|
||||
#
|
||||
##
|
||||
{ 'command': 'query-balloon', 'returns': 'BalloonInfo' }
|
||||
|
||||
##
|
||||
# @BALLOON_CHANGE:
|
||||
#
|
||||
# Emitted when the guest changes the actual BALLOON level. This value is
|
||||
# equivalent to the @actual field return by the 'query-balloon' command
|
||||
#
|
||||
# @actual: actual level of the guest memory balloon in bytes
|
||||
#
|
||||
# Note: this event is rate-limited.
|
||||
#
|
||||
# Since: 1.2
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# <- { "event": "BALLOON_CHANGE",
|
||||
# "data": { "actual": 944766976 },
|
||||
# "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
|
||||
#
|
||||
##
|
||||
{ 'event': 'BALLOON_CHANGE',
|
||||
'data': { 'actual': 'int' } }
|
||||
|
||||
##
|
||||
# @PciMemoryRange:
|
||||
#
|
||||
# A PCI device memory region
|
||||
#
|
||||
# @base: the starting address (guest physical)
|
||||
#
|
||||
# @limit: the ending address (guest physical)
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'struct': 'PciMemoryRange', 'data': {'base': 'int', 'limit': 'int'} }
|
||||
|
||||
##
|
||||
# @PciMemoryRegion:
|
||||
#
|
||||
# Information about a PCI device I/O region.
|
||||
#
|
||||
# @bar: the index of the Base Address Register for this region
|
||||
#
|
||||
# @type: - 'io' if the region is a PIO region
|
||||
# - 'memory' if the region is a MMIO region
|
||||
#
|
||||
# @size: memory size
|
||||
#
|
||||
# @prefetch: if @type is 'memory', true if the memory is prefetchable
|
||||
#
|
||||
# @mem_type_64: if @type is 'memory', true if the BAR is 64-bit
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'struct': 'PciMemoryRegion',
|
||||
'data': {'bar': 'int', 'type': 'str', 'address': 'int', 'size': 'int',
|
||||
'*prefetch': 'bool', '*mem_type_64': 'bool' } }
|
||||
|
||||
##
|
||||
# @PciBusInfo:
|
||||
#
|
||||
# Information about a bus of a PCI Bridge device
|
||||
#
|
||||
# @number: primary bus interface number. This should be the number of the
|
||||
# bus the device resides on.
|
||||
#
|
||||
# @secondary: secondary bus interface number. This is the number of the
|
||||
# main bus for the bridge
|
||||
#
|
||||
# @subordinate: This is the highest number bus that resides below the
|
||||
# bridge.
|
||||
#
|
||||
# @io_range: The PIO range for all devices on this bridge
|
||||
#
|
||||
# @memory_range: The MMIO range for all devices on this bridge
|
||||
#
|
||||
# @prefetchable_range: The range of prefetchable MMIO for all devices on
|
||||
# this bridge
|
||||
#
|
||||
# Since: 2.4
|
||||
##
|
||||
{ 'struct': 'PciBusInfo',
|
||||
'data': {'number': 'int', 'secondary': 'int', 'subordinate': 'int',
|
||||
'io_range': 'PciMemoryRange',
|
||||
'memory_range': 'PciMemoryRange',
|
||||
'prefetchable_range': 'PciMemoryRange' } }
|
||||
|
||||
##
|
||||
# @PciBridgeInfo:
|
||||
#
|
||||
# Information about a PCI Bridge device
|
||||
#
|
||||
# @bus: information about the bus the device resides on
|
||||
#
|
||||
# @devices: a list of @PciDeviceInfo for each device on this bridge
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'struct': 'PciBridgeInfo',
|
||||
'data': {'bus': 'PciBusInfo', '*devices': ['PciDeviceInfo']} }
|
||||
|
||||
##
|
||||
# @PciDeviceClass:
|
||||
#
|
||||
# Information about the Class of a PCI device
|
||||
#
|
||||
# @desc: a string description of the device's class
|
||||
#
|
||||
# @class: the class code of the device
|
||||
#
|
||||
# Since: 2.4
|
||||
##
|
||||
{ 'struct': 'PciDeviceClass',
|
||||
'data': {'*desc': 'str', 'class': 'int'} }
|
||||
|
||||
##
|
||||
# @PciDeviceId:
|
||||
#
|
||||
# Information about the Id of a PCI device
|
||||
#
|
||||
# @device: the PCI device id
|
||||
#
|
||||
# @vendor: the PCI vendor id
|
||||
#
|
||||
# @subsystem: the PCI subsystem id (since 3.1)
|
||||
#
|
||||
# @subsystem-vendor: the PCI subsystem vendor id (since 3.1)
|
||||
#
|
||||
# Since: 2.4
|
||||
##
|
||||
{ 'struct': 'PciDeviceId',
|
||||
'data': {'device': 'int', 'vendor': 'int', '*subsystem': 'int',
|
||||
'*subsystem-vendor': 'int'} }
|
||||
|
||||
##
|
||||
# @PciDeviceInfo:
|
||||
#
|
||||
# Information about a PCI device
|
||||
#
|
||||
# @bus: the bus number of the device
|
||||
#
|
||||
# @slot: the slot the device is located in
|
||||
#
|
||||
# @function: the function of the slot used by the device
|
||||
#
|
||||
# @class_info: the class of the device
|
||||
#
|
||||
# @id: the PCI device id
|
||||
#
|
||||
# @irq: if an IRQ is assigned to the device, the IRQ number
|
||||
#
|
||||
# @irq_pin: the IRQ pin, zero means no IRQ (since 5.1)
|
||||
#
|
||||
# @qdev_id: the device name of the PCI device
|
||||
#
|
||||
# @pci_bridge: if the device is a PCI bridge, the bridge information
|
||||
#
|
||||
# @regions: a list of the PCI I/O regions associated with the device
|
||||
#
|
||||
# Notes: the contents of @class_info.desc are not stable and should only be
|
||||
# treated as informational.
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'struct': 'PciDeviceInfo',
|
||||
'data': {'bus': 'int', 'slot': 'int', 'function': 'int',
|
||||
'class_info': 'PciDeviceClass', 'id': 'PciDeviceId',
|
||||
'*irq': 'int', 'irq_pin': 'int', 'qdev_id': 'str',
|
||||
'*pci_bridge': 'PciBridgeInfo', 'regions': ['PciMemoryRegion'] }}
|
||||
|
||||
##
|
||||
# @PciInfo:
|
||||
#
|
||||
# Information about a PCI bus
|
||||
#
|
||||
# @bus: the bus index
|
||||
#
|
||||
# @devices: a list of devices on this bus
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'struct': 'PciInfo', 'data': {'bus': 'int', 'devices': ['PciDeviceInfo']} }
|
||||
|
||||
##
|
||||
# @query-pci:
|
||||
#
|
||||
# Return information about the PCI bus topology of the guest.
|
||||
#
|
||||
# Returns: a list of @PciInfo for each PCI bus. Each bus is
|
||||
# represented by a json-object, which has a key with a json-array of
|
||||
# all PCI devices attached to it. Each device is represented by a
|
||||
# json-object.
|
||||
#
|
||||
# Since: 0.14.0
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# -> { "execute": "query-pci" }
|
||||
# <- { "return": [
|
||||
# {
|
||||
# "bus": 0,
|
||||
# "devices": [
|
||||
# {
|
||||
# "bus": 0,
|
||||
# "qdev_id": "",
|
||||
# "slot": 0,
|
||||
# "class_info": {
|
||||
# "class": 1536,
|
||||
# "desc": "Host bridge"
|
||||
# },
|
||||
# "id": {
|
||||
# "device": 32902,
|
||||
# "vendor": 4663
|
||||
# },
|
||||
# "function": 0,
|
||||
# "regions": [
|
||||
# ]
|
||||
# },
|
||||
# {
|
||||
# "bus": 0,
|
||||
# "qdev_id": "",
|
||||
# "slot": 1,
|
||||
# "class_info": {
|
||||
# "class": 1537,
|
||||
# "desc": "ISA bridge"
|
||||
# },
|
||||
# "id": {
|
||||
# "device": 32902,
|
||||
# "vendor": 28672
|
||||
# },
|
||||
# "function": 0,
|
||||
# "regions": [
|
||||
# ]
|
||||
# },
|
||||
# {
|
||||
# "bus": 0,
|
||||
# "qdev_id": "",
|
||||
# "slot": 1,
|
||||
# "class_info": {
|
||||
# "class": 257,
|
||||
# "desc": "IDE controller"
|
||||
# },
|
||||
# "id": {
|
||||
# "device": 32902,
|
||||
# "vendor": 28688
|
||||
# },
|
||||
# "function": 1,
|
||||
# "regions": [
|
||||
# {
|
||||
# "bar": 4,
|
||||
# "size": 16,
|
||||
# "address": 49152,
|
||||
# "type": "io"
|
||||
# }
|
||||
# ]
|
||||
# },
|
||||
# {
|
||||
# "bus": 0,
|
||||
# "qdev_id": "",
|
||||
# "slot": 2,
|
||||
# "class_info": {
|
||||
# "class": 768,
|
||||
# "desc": "VGA controller"
|
||||
# },
|
||||
# "id": {
|
||||
# "device": 4115,
|
||||
# "vendor": 184
|
||||
# },
|
||||
# "function": 0,
|
||||
# "regions": [
|
||||
# {
|
||||
# "prefetch": true,
|
||||
# "mem_type_64": false,
|
||||
# "bar": 0,
|
||||
# "size": 33554432,
|
||||
# "address": 4026531840,
|
||||
# "type": "memory"
|
||||
# },
|
||||
# {
|
||||
# "prefetch": false,
|
||||
# "mem_type_64": false,
|
||||
# "bar": 1,
|
||||
# "size": 4096,
|
||||
# "address": 4060086272,
|
||||
# "type": "memory"
|
||||
# },
|
||||
# {
|
||||
# "prefetch": false,
|
||||
# "mem_type_64": false,
|
||||
# "bar": 6,
|
||||
# "size": 65536,
|
||||
# "address": -1,
|
||||
# "type": "memory"
|
||||
# }
|
||||
# ]
|
||||
# },
|
||||
# {
|
||||
# "bus": 0,
|
||||
# "qdev_id": "",
|
||||
# "irq": 11,
|
||||
# "slot": 4,
|
||||
# "class_info": {
|
||||
# "class": 1280,
|
||||
# "desc": "RAM controller"
|
||||
# },
|
||||
# "id": {
|
||||
# "device": 6900,
|
||||
# "vendor": 4098
|
||||
# },
|
||||
# "function": 0,
|
||||
# "regions": [
|
||||
# {
|
||||
# "bar": 0,
|
||||
# "size": 32,
|
||||
# "address": 49280,
|
||||
# "type": "io"
|
||||
# }
|
||||
# ]
|
||||
# }
|
||||
# ]
|
||||
# }
|
||||
# ]
|
||||
# }
|
||||
#
|
||||
# Note: This example has been shortened as the real response is too long.
|
||||
#
|
||||
##
|
||||
{ 'command': 'query-pci', 'returns': ['PciInfo'] }
|
||||
|
||||
##
|
||||
# @stop:
|
||||
#
|
||||
|
@ -786,32 +361,6 @@
|
|||
##
|
||||
{ 'command': 'inject-nmi' }
|
||||
|
||||
##
|
||||
# @balloon:
|
||||
#
|
||||
# Request the balloon driver to change its balloon size.
|
||||
#
|
||||
# @value: the target size of the balloon in bytes
|
||||
#
|
||||
# Returns: - Nothing on success
|
||||
# - If the balloon driver is enabled but not functional because the KVM
|
||||
# kernel module cannot support it, KvmMissingCap
|
||||
# - If no balloon device is present, DeviceNotActive
|
||||
#
|
||||
# Notes: This command just issues a request to the guest. When it returns,
|
||||
# the balloon size may not have changed. A guest can change the balloon
|
||||
# size independent of this command.
|
||||
#
|
||||
# Since: 0.14.0
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# -> { "execute": "balloon", "arguments": { "value": 536870912 } }
|
||||
# <- { "return": {} }
|
||||
#
|
||||
##
|
||||
{ 'command': 'balloon', 'data': {'value': 'int'} }
|
||||
|
||||
##
|
||||
# @human-monitor-command:
|
||||
#
|
||||
|
@ -971,39 +520,6 @@
|
|||
##
|
||||
{ 'command': 'closefd', 'data': {'fdname': 'str'} }
|
||||
|
||||
##
|
||||
# @MemoryInfo:
|
||||
#
|
||||
# Actual memory information in bytes.
|
||||
#
|
||||
# @base-memory: size of "base" memory specified with command line
|
||||
# option -m.
|
||||
#
|
||||
# @plugged-memory: size of memory that can be hot-unplugged. This field
|
||||
# is omitted if target doesn't support memory hotplug
|
||||
# (i.e. CONFIG_MEM_DEVICE not defined at build time).
|
||||
#
|
||||
# Since: 2.11.0
|
||||
##
|
||||
{ 'struct': 'MemoryInfo',
|
||||
'data' : { 'base-memory': 'size', '*plugged-memory': 'size' } }
|
||||
|
||||
##
|
||||
# @query-memory-size-summary:
|
||||
#
|
||||
# Return the amount of initially allocated and present hotpluggable (if
|
||||
# enabled) memory in bytes.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# -> { "execute": "query-memory-size-summary" }
|
||||
# <- { "return": { "base-memory": 4294967296, "plugged-memory": 0 } }
|
||||
#
|
||||
# Since: 2.11.0
|
||||
##
|
||||
{ 'command': 'query-memory-size-summary', 'returns': 'MemoryInfo' }
|
||||
|
||||
|
||||
##
|
||||
# @AddfdInfo:
|
||||
#
|
||||
|
@ -1148,64 +664,6 @@
|
|||
##
|
||||
{ 'command': 'query-fdsets', 'returns': ['FdsetInfo'] }
|
||||
|
||||
##
|
||||
# @AcpiTableOptions:
|
||||
#
|
||||
# Specify an ACPI table on the command line to load.
|
||||
#
|
||||
# At most one of @file and @data can be specified. The list of files specified
|
||||
# by any one of them is loaded and concatenated in order. If both are omitted,
|
||||
# @data is implied.
|
||||
#
|
||||
# Other fields / optargs can be used to override fields of the generic ACPI
|
||||
# table header; refer to the ACPI specification 5.0, section 5.2.6 System
|
||||
# Description Table Header. If a header field is not overridden, then the
|
||||
# corresponding value from the concatenated blob is used (in case of @file), or
|
||||
# it is filled in with a hard-coded value (in case of @data).
|
||||
#
|
||||
# String fields are copied into the matching ACPI member from lowest address
|
||||
# upwards, and silently truncated / NUL-padded to length.
|
||||
#
|
||||
# @sig: table signature / identifier (4 bytes)
|
||||
#
|
||||
# @rev: table revision number (dependent on signature, 1 byte)
|
||||
#
|
||||
# @oem_id: OEM identifier (6 bytes)
|
||||
#
|
||||
# @oem_table_id: OEM table identifier (8 bytes)
|
||||
#
|
||||
# @oem_rev: OEM-supplied revision number (4 bytes)
|
||||
#
|
||||
# @asl_compiler_id: identifier of the utility that created the table
|
||||
# (4 bytes)
|
||||
#
|
||||
# @asl_compiler_rev: revision number of the utility that created the
|
||||
# table (4 bytes)
|
||||
#
|
||||
# @file: colon (:) separated list of pathnames to load and
|
||||
# concatenate as table data. The resultant binary blob is expected to
|
||||
# have an ACPI table header. At least one file is required. This field
|
||||
# excludes @data.
|
||||
#
|
||||
# @data: colon (:) separated list of pathnames to load and
|
||||
# concatenate as table data. The resultant binary blob must not have an
|
||||
# ACPI table header. At least one file is required. This field excludes
|
||||
# @file.
|
||||
#
|
||||
# Since: 1.5
|
||||
##
|
||||
{ 'struct': 'AcpiTableOptions',
|
||||
'data': {
|
||||
'*sig': 'str',
|
||||
'*rev': 'uint8',
|
||||
'*oem_id': 'str',
|
||||
'*oem_table_id': 'str',
|
||||
'*oem_rev': 'uint32',
|
||||
'*asl_compiler_id': 'str',
|
||||
'*asl_compiler_rev': 'uint32',
|
||||
'*file': 'str',
|
||||
'*data': 'str' }}
|
||||
|
||||
##
|
||||
# @CommandLineParameterType:
|
||||
#
|
||||
|
@ -1299,263 +757,6 @@
|
|||
'returns': ['CommandLineOptionInfo'],
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @PCDIMMDeviceInfo:
|
||||
#
|
||||
# PCDIMMDevice state information
|
||||
#
|
||||
# @id: device's ID
|
||||
#
|
||||
# @addr: physical address, where device is mapped
|
||||
#
|
||||
# @size: size of memory that the device provides
|
||||
#
|
||||
# @slot: slot number at which device is plugged in
|
||||
#
|
||||
# @node: NUMA node number where device is plugged in
|
||||
#
|
||||
# @memdev: memory backend linked with device
|
||||
#
|
||||
# @hotplugged: true if device was hotplugged
|
||||
#
|
||||
# @hotpluggable: true if device if could be added/removed while machine is running
|
||||
#
|
||||
# Since: 2.1
|
||||
##
|
||||
{ 'struct': 'PCDIMMDeviceInfo',
|
||||
'data': { '*id': 'str',
|
||||
'addr': 'int',
|
||||
'size': 'int',
|
||||
'slot': 'int',
|
||||
'node': 'int',
|
||||
'memdev': 'str',
|
||||
'hotplugged': 'bool',
|
||||
'hotpluggable': 'bool'
|
||||
}
|
||||
}
|
||||
|
||||
##
|
||||
# @VirtioPMEMDeviceInfo:
|
||||
#
|
||||
# VirtioPMEM state information
|
||||
#
|
||||
# @id: device's ID
|
||||
#
|
||||
# @memaddr: physical address in memory, where device is mapped
|
||||
#
|
||||
# @size: size of memory that the device provides
|
||||
#
|
||||
# @memdev: memory backend linked with device
|
||||
#
|
||||
# Since: 4.1
|
||||
##
|
||||
{ 'struct': 'VirtioPMEMDeviceInfo',
|
||||
'data': { '*id': 'str',
|
||||
'memaddr': 'size',
|
||||
'size': 'size',
|
||||
'memdev': 'str'
|
||||
}
|
||||
}
|
||||
|
||||
##
|
||||
# @VirtioMEMDeviceInfo:
|
||||
#
|
||||
# VirtioMEMDevice state information
|
||||
#
|
||||
# @id: device's ID
|
||||
#
|
||||
# @memaddr: physical address in memory, where device is mapped
|
||||
#
|
||||
# @requested-size: the user requested size of the device
|
||||
#
|
||||
# @size: the (current) size of memory that the device provides
|
||||
#
|
||||
# @max-size: the maximum size of memory that the device can provide
|
||||
#
|
||||
# @block-size: the block size of memory that the device provides
|
||||
#
|
||||
# @node: NUMA node number where device is assigned to
|
||||
#
|
||||
# @memdev: memory backend linked with the region
|
||||
#
|
||||
# Since: 5.1
|
||||
##
|
||||
{ 'struct': 'VirtioMEMDeviceInfo',
|
||||
'data': { '*id': 'str',
|
||||
'memaddr': 'size',
|
||||
'requested-size': 'size',
|
||||
'size': 'size',
|
||||
'max-size': 'size',
|
||||
'block-size': 'size',
|
||||
'node': 'int',
|
||||
'memdev': 'str'
|
||||
}
|
||||
}
|
||||
|
||||
##
|
||||
# @MemoryDeviceInfo:
|
||||
#
|
||||
# Union containing information about a memory device
|
||||
#
|
||||
# nvdimm is included since 2.12. virtio-pmem is included since 4.1.
|
||||
# virtio-mem is included since 5.1.
|
||||
#
|
||||
# Since: 2.1
|
||||
##
|
||||
{ 'union': 'MemoryDeviceInfo',
|
||||
'data': { 'dimm': 'PCDIMMDeviceInfo',
|
||||
'nvdimm': 'PCDIMMDeviceInfo',
|
||||
'virtio-pmem': 'VirtioPMEMDeviceInfo',
|
||||
'virtio-mem': 'VirtioMEMDeviceInfo'
|
||||
}
|
||||
}
|
||||
|
||||
##
|
||||
# @query-memory-devices:
|
||||
#
|
||||
# Lists available memory devices and their state
|
||||
#
|
||||
# Since: 2.1
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# -> { "execute": "query-memory-devices" }
|
||||
# <- { "return": [ { "data":
|
||||
# { "addr": 5368709120,
|
||||
# "hotpluggable": true,
|
||||
# "hotplugged": true,
|
||||
# "id": "d1",
|
||||
# "memdev": "/objects/memX",
|
||||
# "node": 0,
|
||||
# "size": 1073741824,
|
||||
# "slot": 0},
|
||||
# "type": "dimm"
|
||||
# } ] }
|
||||
#
|
||||
##
|
||||
{ 'command': 'query-memory-devices', 'returns': ['MemoryDeviceInfo'] }
|
||||
|
||||
##
|
||||
# @MEMORY_DEVICE_SIZE_CHANGE:
|
||||
#
|
||||
# Emitted when the size of a memory device changes. Only emitted for memory
|
||||
# devices that can actually change the size (e.g., virtio-mem due to guest
|
||||
# action).
|
||||
#
|
||||
# @id: device's ID
|
||||
# @size: the new size of memory that the device provides
|
||||
#
|
||||
# Note: this event is rate-limited.
|
||||
#
|
||||
# Since: 5.1
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# <- { "event": "MEMORY_DEVICE_SIZE_CHANGE",
|
||||
# "data": { "id": "vm0", "size": 1073741824},
|
||||
# "timestamp": { "seconds": 1588168529, "microseconds": 201316 } }
|
||||
#
|
||||
##
|
||||
{ 'event': 'MEMORY_DEVICE_SIZE_CHANGE',
|
||||
'data': { '*id': 'str', 'size': 'size' } }
|
||||
|
||||
|
||||
##
|
||||
# @MEM_UNPLUG_ERROR:
|
||||
#
|
||||
# Emitted when memory hot unplug error occurs.
|
||||
#
|
||||
# @device: device name
|
||||
#
|
||||
# @msg: Informative message
|
||||
#
|
||||
# Since: 2.4
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# <- { "event": "MEM_UNPLUG_ERROR"
|
||||
# "data": { "device": "dimm1",
|
||||
# "msg": "acpi: device unplug for unsupported device"
|
||||
# },
|
||||
# "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
|
||||
#
|
||||
##
|
||||
{ 'event': 'MEM_UNPLUG_ERROR',
|
||||
'data': { 'device': 'str', 'msg': 'str' } }
|
||||
|
||||
##
|
||||
# @ACPISlotType:
|
||||
#
|
||||
# @DIMM: memory slot
|
||||
# @CPU: logical CPU slot (since 2.7)
|
||||
##
|
||||
{ 'enum': 'ACPISlotType', 'data': [ 'DIMM', 'CPU' ] }
|
||||
|
||||
##
|
||||
# @ACPIOSTInfo:
|
||||
#
|
||||
# OSPM Status Indication for a device
|
||||
# For description of possible values of @source and @status fields
|
||||
# see "_OST (OSPM Status Indication)" chapter of ACPI5.0 spec.
|
||||
#
|
||||
# @device: device ID associated with slot
|
||||
#
|
||||
# @slot: slot ID, unique per slot of a given @slot-type
|
||||
#
|
||||
# @slot-type: type of the slot
|
||||
#
|
||||
# @source: an integer containing the source event
|
||||
#
|
||||
# @status: an integer containing the status code
|
||||
#
|
||||
# Since: 2.1
|
||||
##
|
||||
{ 'struct': 'ACPIOSTInfo',
|
||||
'data' : { '*device': 'str',
|
||||
'slot': 'str',
|
||||
'slot-type': 'ACPISlotType',
|
||||
'source': 'int',
|
||||
'status': 'int' } }
|
||||
|
||||
##
|
||||
# @query-acpi-ospm-status:
|
||||
#
|
||||
# Return a list of ACPIOSTInfo for devices that support status
|
||||
# reporting via ACPI _OST method.
|
||||
#
|
||||
# Since: 2.1
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# -> { "execute": "query-acpi-ospm-status" }
|
||||
# <- { "return": [ { "device": "d1", "slot": "0", "slot-type": "DIMM", "source": 1, "status": 0},
|
||||
# { "slot": "1", "slot-type": "DIMM", "source": 0, "status": 0},
|
||||
# { "slot": "2", "slot-type": "DIMM", "source": 0, "status": 0},
|
||||
# { "slot": "3", "slot-type": "DIMM", "source": 0, "status": 0}
|
||||
# ]}
|
||||
#
|
||||
##
|
||||
{ 'command': 'query-acpi-ospm-status', 'returns': ['ACPIOSTInfo'] }
|
||||
|
||||
##
|
||||
# @ACPI_DEVICE_OST:
|
||||
#
|
||||
# Emitted when guest executes ACPI _OST method.
|
||||
#
|
||||
# @info: OSPM Status Indication
|
||||
#
|
||||
# Since: 2.1
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# <- { "event": "ACPI_DEVICE_OST",
|
||||
# "data": { "device": "d1", "slot": "0",
|
||||
# "slot-type": "DIMM", "source": 1, "status": 0 } }
|
||||
#
|
||||
##
|
||||
{ 'event': 'ACPI_DEVICE_OST',
|
||||
'data': { 'info': 'ACPIOSTInfo' } }
|
||||
|
||||
##
|
||||
# @ReplayMode:
|
||||
#
|
||||
|
@ -1594,24 +795,3 @@
|
|||
#
|
||||
##
|
||||
{ 'command': 'xen-load-devices-state', 'data': {'filename': 'str'} }
|
||||
|
||||
##
|
||||
# @GuidInfo:
|
||||
#
|
||||
# GUID information.
|
||||
#
|
||||
# @guid: the globally unique identifier
|
||||
#
|
||||
# Since: 2.9
|
||||
##
|
||||
{ 'struct': 'GuidInfo', 'data': {'guid': 'str'} }
|
||||
|
||||
##
|
||||
# @query-vm-generation-id:
|
||||
#
|
||||
# Show Virtual Machine Generation ID
|
||||
#
|
||||
# Since: 2.9
|
||||
##
|
||||
{ 'command': 'query-vm-generation-id', 'returns': 'GuidInfo' }
|
||||
|
||||
|
|
316
qapi/pci.json
Normal file
316
qapi/pci.json
Normal file
|
@ -0,0 +1,316 @@
|
|||
# -*- Mode: Python -*-
|
||||
# vim: filetype=python
|
||||
#
|
||||
# This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
# See the COPYING file in the top-level directory.
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
##
|
||||
# = PCI
|
||||
##
|
||||
|
||||
##
|
||||
# @PciMemoryRange:
|
||||
#
|
||||
# A PCI device memory region
|
||||
#
|
||||
# @base: the starting address (guest physical)
|
||||
#
|
||||
# @limit: the ending address (guest physical)
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'struct': 'PciMemoryRange', 'data': {'base': 'int', 'limit': 'int'} }
|
||||
|
||||
##
|
||||
# @PciMemoryRegion:
|
||||
#
|
||||
# Information about a PCI device I/O region.
|
||||
#
|
||||
# @bar: the index of the Base Address Register for this region
|
||||
#
|
||||
# @type: - 'io' if the region is a PIO region
|
||||
# - 'memory' if the region is a MMIO region
|
||||
#
|
||||
# @size: memory size
|
||||
#
|
||||
# @prefetch: if @type is 'memory', true if the memory is prefetchable
|
||||
#
|
||||
# @mem_type_64: if @type is 'memory', true if the BAR is 64-bit
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'struct': 'PciMemoryRegion',
|
||||
'data': {'bar': 'int', 'type': 'str', 'address': 'int', 'size': 'int',
|
||||
'*prefetch': 'bool', '*mem_type_64': 'bool' } }
|
||||
|
||||
##
|
||||
# @PciBusInfo:
|
||||
#
|
||||
# Information about a bus of a PCI Bridge device
|
||||
#
|
||||
# @number: primary bus interface number. This should be the number of the
|
||||
# bus the device resides on.
|
||||
#
|
||||
# @secondary: secondary bus interface number. This is the number of the
|
||||
# main bus for the bridge
|
||||
#
|
||||
# @subordinate: This is the highest number bus that resides below the
|
||||
# bridge.
|
||||
#
|
||||
# @io_range: The PIO range for all devices on this bridge
|
||||
#
|
||||
# @memory_range: The MMIO range for all devices on this bridge
|
||||
#
|
||||
# @prefetchable_range: The range of prefetchable MMIO for all devices on
|
||||
# this bridge
|
||||
#
|
||||
# Since: 2.4
|
||||
##
|
||||
{ 'struct': 'PciBusInfo',
|
||||
'data': {'number': 'int', 'secondary': 'int', 'subordinate': 'int',
|
||||
'io_range': 'PciMemoryRange',
|
||||
'memory_range': 'PciMemoryRange',
|
||||
'prefetchable_range': 'PciMemoryRange' } }
|
||||
|
||||
##
|
||||
# @PciBridgeInfo:
|
||||
#
|
||||
# Information about a PCI Bridge device
|
||||
#
|
||||
# @bus: information about the bus the device resides on
|
||||
#
|
||||
# @devices: a list of @PciDeviceInfo for each device on this bridge
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'struct': 'PciBridgeInfo',
|
||||
'data': {'bus': 'PciBusInfo', '*devices': ['PciDeviceInfo']} }
|
||||
|
||||
##
|
||||
# @PciDeviceClass:
|
||||
#
|
||||
# Information about the Class of a PCI device
|
||||
#
|
||||
# @desc: a string description of the device's class
|
||||
#
|
||||
# @class: the class code of the device
|
||||
#
|
||||
# Since: 2.4
|
||||
##
|
||||
{ 'struct': 'PciDeviceClass',
|
||||
'data': {'*desc': 'str', 'class': 'int'} }
|
||||
|
||||
##
|
||||
# @PciDeviceId:
|
||||
#
|
||||
# Information about the Id of a PCI device
|
||||
#
|
||||
# @device: the PCI device id
|
||||
#
|
||||
# @vendor: the PCI vendor id
|
||||
#
|
||||
# @subsystem: the PCI subsystem id (since 3.1)
|
||||
#
|
||||
# @subsystem-vendor: the PCI subsystem vendor id (since 3.1)
|
||||
#
|
||||
# Since: 2.4
|
||||
##
|
||||
{ 'struct': 'PciDeviceId',
|
||||
'data': {'device': 'int', 'vendor': 'int', '*subsystem': 'int',
|
||||
'*subsystem-vendor': 'int'} }
|
||||
|
||||
##
|
||||
# @PciDeviceInfo:
|
||||
#
|
||||
# Information about a PCI device
|
||||
#
|
||||
# @bus: the bus number of the device
|
||||
#
|
||||
# @slot: the slot the device is located in
|
||||
#
|
||||
# @function: the function of the slot used by the device
|
||||
#
|
||||
# @class_info: the class of the device
|
||||
#
|
||||
# @id: the PCI device id
|
||||
#
|
||||
# @irq: if an IRQ is assigned to the device, the IRQ number
|
||||
#
|
||||
# @irq_pin: the IRQ pin, zero means no IRQ (since 5.1)
|
||||
#
|
||||
# @qdev_id: the device name of the PCI device
|
||||
#
|
||||
# @pci_bridge: if the device is a PCI bridge, the bridge information
|
||||
#
|
||||
# @regions: a list of the PCI I/O regions associated with the device
|
||||
#
|
||||
# Notes: the contents of @class_info.desc are not stable and should only be
|
||||
# treated as informational.
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'struct': 'PciDeviceInfo',
|
||||
'data': {'bus': 'int', 'slot': 'int', 'function': 'int',
|
||||
'class_info': 'PciDeviceClass', 'id': 'PciDeviceId',
|
||||
'*irq': 'int', 'irq_pin': 'int', 'qdev_id': 'str',
|
||||
'*pci_bridge': 'PciBridgeInfo', 'regions': ['PciMemoryRegion'] }}
|
||||
|
||||
##
|
||||
# @PciInfo:
|
||||
#
|
||||
# Information about a PCI bus
|
||||
#
|
||||
# @bus: the bus index
|
||||
#
|
||||
# @devices: a list of devices on this bus
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'struct': 'PciInfo', 'data': {'bus': 'int', 'devices': ['PciDeviceInfo']} }
|
||||
|
||||
##
|
||||
# @query-pci:
|
||||
#
|
||||
# Return information about the PCI bus topology of the guest.
|
||||
#
|
||||
# Returns: a list of @PciInfo for each PCI bus. Each bus is
|
||||
# represented by a json-object, which has a key with a json-array of
|
||||
# all PCI devices attached to it. Each device is represented by a
|
||||
# json-object.
|
||||
#
|
||||
# Since: 0.14.0
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# -> { "execute": "query-pci" }
|
||||
# <- { "return": [
|
||||
# {
|
||||
# "bus": 0,
|
||||
# "devices": [
|
||||
# {
|
||||
# "bus": 0,
|
||||
# "qdev_id": "",
|
||||
# "slot": 0,
|
||||
# "class_info": {
|
||||
# "class": 1536,
|
||||
# "desc": "Host bridge"
|
||||
# },
|
||||
# "id": {
|
||||
# "device": 32902,
|
||||
# "vendor": 4663
|
||||
# },
|
||||
# "function": 0,
|
||||
# "regions": [
|
||||
# ]
|
||||
# },
|
||||
# {
|
||||
# "bus": 0,
|
||||
# "qdev_id": "",
|
||||
# "slot": 1,
|
||||
# "class_info": {
|
||||
# "class": 1537,
|
||||
# "desc": "ISA bridge"
|
||||
# },
|
||||
# "id": {
|
||||
# "device": 32902,
|
||||
# "vendor": 28672
|
||||
# },
|
||||
# "function": 0,
|
||||
# "regions": [
|
||||
# ]
|
||||
# },
|
||||
# {
|
||||
# "bus": 0,
|
||||
# "qdev_id": "",
|
||||
# "slot": 1,
|
||||
# "class_info": {
|
||||
# "class": 257,
|
||||
# "desc": "IDE controller"
|
||||
# },
|
||||
# "id": {
|
||||
# "device": 32902,
|
||||
# "vendor": 28688
|
||||
# },
|
||||
# "function": 1,
|
||||
# "regions": [
|
||||
# {
|
||||
# "bar": 4,
|
||||
# "size": 16,
|
||||
# "address": 49152,
|
||||
# "type": "io"
|
||||
# }
|
||||
# ]
|
||||
# },
|
||||
# {
|
||||
# "bus": 0,
|
||||
# "qdev_id": "",
|
||||
# "slot": 2,
|
||||
# "class_info": {
|
||||
# "class": 768,
|
||||
# "desc": "VGA controller"
|
||||
# },
|
||||
# "id": {
|
||||
# "device": 4115,
|
||||
# "vendor": 184
|
||||
# },
|
||||
# "function": 0,
|
||||
# "regions": [
|
||||
# {
|
||||
# "prefetch": true,
|
||||
# "mem_type_64": false,
|
||||
# "bar": 0,
|
||||
# "size": 33554432,
|
||||
# "address": 4026531840,
|
||||
# "type": "memory"
|
||||
# },
|
||||
# {
|
||||
# "prefetch": false,
|
||||
# "mem_type_64": false,
|
||||
# "bar": 1,
|
||||
# "size": 4096,
|
||||
# "address": 4060086272,
|
||||
# "type": "memory"
|
||||
# },
|
||||
# {
|
||||
# "prefetch": false,
|
||||
# "mem_type_64": false,
|
||||
# "bar": 6,
|
||||
# "size": 65536,
|
||||
# "address": -1,
|
||||
# "type": "memory"
|
||||
# }
|
||||
# ]
|
||||
# },
|
||||
# {
|
||||
# "bus": 0,
|
||||
# "qdev_id": "",
|
||||
# "irq": 11,
|
||||
# "slot": 4,
|
||||
# "class_info": {
|
||||
# "class": 1280,
|
||||
# "desc": "RAM controller"
|
||||
# },
|
||||
# "id": {
|
||||
# "device": 6900,
|
||||
# "vendor": 4098
|
||||
# },
|
||||
# "function": 0,
|
||||
# "regions": [
|
||||
# {
|
||||
# "bar": 0,
|
||||
# "size": 32,
|
||||
# "address": 49280,
|
||||
# "type": "io"
|
||||
# }
|
||||
# ]
|
||||
# }
|
||||
# ]
|
||||
# }
|
||||
# ]
|
||||
# }
|
||||
#
|
||||
# Note: This example has been shortened as the real response is too long.
|
||||
#
|
||||
##
|
||||
{ 'command': 'query-pci', 'returns': ['PciInfo'] }
|
|
@ -21,8 +21,10 @@
|
|||
#
|
||||
# Example:
|
||||
#
|
||||
# | -> data issued by the Client
|
||||
# | <- Server data response
|
||||
# ::
|
||||
#
|
||||
# -> data issued by the Client
|
||||
# <- Server data response
|
||||
#
|
||||
# Please, refer to the QMP specification (docs/interop/qmp-spec.txt) for
|
||||
# detailed information on the Server command and response formats.
|
||||
|
@ -85,3 +87,5 @@
|
|||
{ 'include': 'misc.json' }
|
||||
{ 'include': 'misc-target.json' }
|
||||
{ 'include': 'audio.json' }
|
||||
{ 'include': 'acpi.json' }
|
||||
{ 'include': 'pci.json' }
|
||||
|
|
|
@ -16,7 +16,7 @@ qga_qapi_outputs = [
|
|||
]
|
||||
|
||||
qga_qapi_files = custom_target('QGA QAPI files',
|
||||
output: qga_qapi_outputs + ['qga-qapi-doc.texi'],
|
||||
output: qga_qapi_outputs,
|
||||
input: 'qapi-schema.json',
|
||||
command: [ qapi_gen, '-o', 'qga', '-p', 'qga-', '@INPUT0@' ],
|
||||
depend_files: qapi_gen_depends)
|
||||
|
@ -27,7 +27,6 @@ foreach output: qga_qapi_outputs
|
|||
qga_ss.add(qga_qapi_files[i])
|
||||
i = i + 1
|
||||
endforeach
|
||||
qga_qapi_doc_texi = qga_qapi_files[i]
|
||||
|
||||
qga_ss.add(files(
|
||||
'commands.c',
|
||||
|
|
|
@ -2,14 +2,16 @@
|
|||
# vim: filetype=python
|
||||
|
||||
##
|
||||
#
|
||||
# General note concerning the use of guest agent interfaces:
|
||||
# = General note concerning the use of guest agent interfaces
|
||||
#
|
||||
# "unsupported" is a higher-level error than the errors that individual
|
||||
# commands might document. The caller should always be prepared to receive
|
||||
# QERR_UNSUPPORTED, even if the given command doesn't specify it, or doesn't
|
||||
# document any failure mode at all.
|
||||
#
|
||||
##
|
||||
|
||||
##
|
||||
# = QEMU guest agent protocol commands and structs
|
||||
##
|
||||
|
||||
{ 'pragma': { 'doc-required': true } }
|
||||
|
|
|
@ -1659,7 +1659,7 @@ sub process {
|
|||
# tabs are only allowed in assembly source code, and in
|
||||
# some scripts we imported from other projects.
|
||||
next if ($realfile =~ /\.(s|S)$/);
|
||||
next if ($realfile =~ /(checkpatch|get_maintainer|texi2pod)\.pl$/);
|
||||
next if ($realfile =~ /(checkpatch|get_maintainer)\.pl$/);
|
||||
|
||||
if ($rawline =~ /^\+.*\t/) {
|
||||
my $herevet = "$here\n" . cat_vet($rawline) . "\n";
|
||||
|
|
|
@ -110,7 +110,6 @@ ENV PACKAGES \
|
|||
systemd-devel \
|
||||
systemtap-sdt-devel \
|
||||
tar \
|
||||
texinfo \
|
||||
usbredir-devel \
|
||||
virglrenderer-devel \
|
||||
vte291-devel \
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
# Documentation
|
||||
docs/*
|
||||
*.rst
|
||||
*.texi
|
||||
|
||||
# build system
|
||||
configure
|
||||
|
|
|
@ -10,7 +10,6 @@ import re
|
|||
import sys
|
||||
|
||||
from qapi.commands import gen_commands
|
||||
from qapi.doc import gen_doc
|
||||
from qapi.events import gen_events
|
||||
from qapi.introspect import gen_introspect
|
||||
from qapi.schema import QAPIError, QAPISchema
|
||||
|
@ -51,7 +50,6 @@ def main(argv):
|
|||
gen_commands(schema, args.output_dir, args.prefix)
|
||||
gen_events(schema, args.output_dir, args.prefix)
|
||||
gen_introspect(schema, args.output_dir, args.prefix, args.unmask)
|
||||
gen_doc(schema, args.output_dir, args.prefix)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -1,301 +0,0 @@
|
|||
# QAPI texi generator
|
||||
#
|
||||
# This work is licensed under the terms of the GNU LGPL, version 2+.
|
||||
# See the COPYING file in the top-level directory.
|
||||
"""This script produces the documentation of a qapi schema in texinfo format"""
|
||||
|
||||
import re
|
||||
from qapi.gen import QAPIGenDoc, QAPISchemaVisitor
|
||||
|
||||
|
||||
MSG_FMT = """
|
||||
@deftypefn {type} {{}} {name}
|
||||
|
||||
{body}{members}{features}{sections}
|
||||
@end deftypefn
|
||||
|
||||
""".format
|
||||
|
||||
TYPE_FMT = """
|
||||
@deftp {{{type}}} {name}
|
||||
|
||||
{body}{members}{features}{sections}
|
||||
@end deftp
|
||||
|
||||
""".format
|
||||
|
||||
EXAMPLE_FMT = """@example
|
||||
{code}
|
||||
@end example
|
||||
""".format
|
||||
|
||||
|
||||
def subst_strong(doc):
|
||||
"""Replaces *foo* by @strong{foo}"""
|
||||
return re.sub(r'\*([^*\n]+)\*', r'@strong{\1}', doc)
|
||||
|
||||
|
||||
def subst_emph(doc):
|
||||
"""Replaces _foo_ by @emph{foo}"""
|
||||
return re.sub(r'\b_([^_\n]+)_\b', r'@emph{\1}', doc)
|
||||
|
||||
|
||||
def subst_vars(doc):
|
||||
"""Replaces @var by @code{var}"""
|
||||
return re.sub(r'@([\w-]+)', r'@code{\1}', doc)
|
||||
|
||||
|
||||
def subst_braces(doc):
|
||||
"""Replaces {} with @{ @}"""
|
||||
return doc.replace('{', '@{').replace('}', '@}')
|
||||
|
||||
|
||||
def texi_example(doc):
|
||||
"""Format @example"""
|
||||
# TODO: Neglects to escape @ characters.
|
||||
# We should probably escape them in subst_braces(), and rename the
|
||||
# function to subst_special() or subs_texi_special(). If we do that, we
|
||||
# need to delay it until after subst_vars() in texi_format().
|
||||
doc = subst_braces(doc).strip('\n')
|
||||
return EXAMPLE_FMT(code=doc)
|
||||
|
||||
|
||||
def texi_format(doc):
|
||||
"""
|
||||
Format documentation
|
||||
|
||||
Lines starting with:
|
||||
- |: generates an @example
|
||||
- =: generates @section
|
||||
- ==: generates @subsection
|
||||
- 1. or 1): generates an @enumerate @item
|
||||
- */-: generates an @itemize list
|
||||
"""
|
||||
ret = ''
|
||||
doc = subst_braces(doc)
|
||||
doc = subst_vars(doc)
|
||||
doc = subst_emph(doc)
|
||||
doc = subst_strong(doc)
|
||||
inlist = ''
|
||||
lastempty = False
|
||||
for line in doc.split('\n'):
|
||||
empty = line == ''
|
||||
|
||||
# FIXME: Doing this in a single if / elif chain is
|
||||
# problematic. For instance, a line without markup terminates
|
||||
# a list if it follows a blank line (reaches the final elif),
|
||||
# but a line with some *other* markup, such as a = title
|
||||
# doesn't.
|
||||
#
|
||||
# Make sure to update section "Documentation markup" in
|
||||
# docs/devel/qapi-code-gen.txt when fixing this.
|
||||
if line.startswith('| '):
|
||||
line = EXAMPLE_FMT(code=line[2:])
|
||||
elif line.startswith('= '):
|
||||
line = '@section ' + line[2:]
|
||||
elif line.startswith('== '):
|
||||
line = '@subsection ' + line[3:]
|
||||
elif re.match(r'^([0-9]*\.) ', line):
|
||||
if not inlist:
|
||||
ret += '@enumerate\n'
|
||||
inlist = 'enumerate'
|
||||
ret += '@item\n'
|
||||
line = line[line.find(' ')+1:]
|
||||
elif re.match(r'^[*-] ', line):
|
||||
if not inlist:
|
||||
ret += '@itemize %s\n' % {'*': '@bullet',
|
||||
'-': '@minus'}[line[0]]
|
||||
inlist = 'itemize'
|
||||
ret += '@item\n'
|
||||
line = line[2:]
|
||||
elif lastempty and inlist:
|
||||
ret += '@end %s\n\n' % inlist
|
||||
inlist = ''
|
||||
|
||||
lastempty = empty
|
||||
ret += line + '\n'
|
||||
|
||||
if inlist:
|
||||
ret += '@end %s\n\n' % inlist
|
||||
return ret
|
||||
|
||||
|
||||
def texi_body(doc):
|
||||
"""Format the main documentation body"""
|
||||
return texi_format(doc.body.text)
|
||||
|
||||
|
||||
def texi_if(ifcond, prefix='\n', suffix='\n'):
|
||||
"""Format the #if condition"""
|
||||
if not ifcond:
|
||||
return ''
|
||||
return '%s@b{If:} @code{%s}%s' % (prefix, ', '.join(ifcond), suffix)
|
||||
|
||||
|
||||
def texi_enum_value(value, desc, suffix):
|
||||
"""Format a table of members item for an enumeration value"""
|
||||
return '@item @code{%s}\n%s%s' % (
|
||||
value.name, desc, texi_if(value.ifcond, prefix='@*'))
|
||||
|
||||
|
||||
def texi_member(member, desc, suffix):
|
||||
"""Format a table of members item for an object type member"""
|
||||
typ = member.type.doc_type()
|
||||
membertype = ': ' + typ if typ else ''
|
||||
return '@item @code{%s%s}%s%s\n%s%s' % (
|
||||
member.name, membertype,
|
||||
' (optional)' if member.optional else '',
|
||||
suffix, desc, texi_if(member.ifcond, prefix='@*'))
|
||||
|
||||
|
||||
def texi_members(doc, what, base=None, variants=None,
|
||||
member_func=texi_member):
|
||||
"""Format the table of members"""
|
||||
items = ''
|
||||
for section in doc.args.values():
|
||||
# TODO Drop fallbacks when undocumented members are outlawed
|
||||
if section.text:
|
||||
desc = texi_format(section.text)
|
||||
elif (variants and variants.tag_member == section.member
|
||||
and not section.member.type.doc_type()):
|
||||
values = section.member.type.member_names()
|
||||
members_text = ', '.join(['@t{"%s"}' % v for v in values])
|
||||
desc = 'One of ' + members_text + '\n'
|
||||
else:
|
||||
desc = 'Not documented\n'
|
||||
items += member_func(section.member, desc, suffix='')
|
||||
if base:
|
||||
items += '@item The members of @code{%s}\n' % base.doc_type()
|
||||
if variants:
|
||||
for v in variants.variants:
|
||||
when = ' when @code{%s} is @t{"%s"}%s' % (
|
||||
variants.tag_member.name, v.name, texi_if(v.ifcond, " (", ")"))
|
||||
if v.type.is_implicit():
|
||||
assert not v.type.base and not v.type.variants
|
||||
for m in v.type.local_members:
|
||||
items += member_func(m, desc='', suffix=when)
|
||||
else:
|
||||
items += '@item The members of @code{%s}%s\n' % (
|
||||
v.type.doc_type(), when)
|
||||
if not items:
|
||||
return ''
|
||||
return '\n@b{%s:}\n@table @asis\n%s@end table\n' % (what, items)
|
||||
|
||||
|
||||
def texi_arguments(doc, boxed_arg_type):
|
||||
if boxed_arg_type:
|
||||
assert not doc.args
|
||||
return ('\n@b{Arguments:} the members of @code{%s}\n'
|
||||
% boxed_arg_type.name)
|
||||
return texi_members(doc, 'Arguments')
|
||||
|
||||
|
||||
def texi_features(doc):
|
||||
"""Format the table of features"""
|
||||
items = ''
|
||||
for section in doc.features.values():
|
||||
desc = texi_format(section.text)
|
||||
items += '@item @code{%s}\n%s' % (section.name, desc)
|
||||
if not items:
|
||||
return ''
|
||||
return '\n@b{Features:}\n@table @asis\n%s@end table\n' % (items)
|
||||
|
||||
|
||||
def texi_sections(doc, ifcond):
|
||||
"""Format additional sections following arguments"""
|
||||
body = ''
|
||||
for section in doc.sections:
|
||||
if section.name:
|
||||
# prefer @b over @strong, so txt doesn't translate it to *Foo:*
|
||||
body += '\n@b{%s:}\n' % section.name
|
||||
if section.name and section.name.startswith('Example'):
|
||||
body += texi_example(section.text)
|
||||
else:
|
||||
body += texi_format(section.text)
|
||||
body += texi_if(ifcond, suffix='')
|
||||
return body
|
||||
|
||||
|
||||
def texi_type(typ, doc, ifcond, members):
|
||||
return TYPE_FMT(type=typ,
|
||||
name=doc.symbol,
|
||||
body=texi_body(doc),
|
||||
members=members,
|
||||
features=texi_features(doc),
|
||||
sections=texi_sections(doc, ifcond))
|
||||
|
||||
|
||||
def texi_msg(typ, doc, ifcond, members):
|
||||
return MSG_FMT(type=typ,
|
||||
name=doc.symbol,
|
||||
body=texi_body(doc),
|
||||
members=members,
|
||||
features=texi_features(doc),
|
||||
sections=texi_sections(doc, ifcond))
|
||||
|
||||
|
||||
class QAPISchemaGenDocVisitor(QAPISchemaVisitor):
|
||||
def __init__(self, prefix):
|
||||
self._prefix = prefix
|
||||
self._gen = QAPIGenDoc(self._prefix + 'qapi-doc.texi')
|
||||
self.cur_doc = None
|
||||
|
||||
def write(self, output_dir):
|
||||
self._gen.write(output_dir)
|
||||
|
||||
def visit_enum_type(self, name, info, ifcond, features, members, prefix):
|
||||
doc = self.cur_doc
|
||||
self._gen.add(texi_type('Enum', doc, ifcond,
|
||||
texi_members(doc, 'Values',
|
||||
member_func=texi_enum_value)))
|
||||
|
||||
def visit_object_type(self, name, info, ifcond, features,
|
||||
base, members, variants):
|
||||
doc = self.cur_doc
|
||||
if base and base.is_implicit():
|
||||
base = None
|
||||
self._gen.add(texi_type('Object', doc, ifcond,
|
||||
texi_members(doc, 'Members', base, variants)))
|
||||
|
||||
def visit_alternate_type(self, name, info, ifcond, features, variants):
|
||||
doc = self.cur_doc
|
||||
self._gen.add(texi_type('Alternate', doc, ifcond,
|
||||
texi_members(doc, 'Members')))
|
||||
|
||||
def visit_command(self, name, info, ifcond, features,
|
||||
arg_type, ret_type, gen, success_response, boxed,
|
||||
allow_oob, allow_preconfig):
|
||||
doc = self.cur_doc
|
||||
self._gen.add(texi_msg('Command', doc, ifcond,
|
||||
texi_arguments(doc,
|
||||
arg_type if boxed else None)))
|
||||
|
||||
def visit_event(self, name, info, ifcond, features, arg_type, boxed):
|
||||
doc = self.cur_doc
|
||||
self._gen.add(texi_msg('Event', doc, ifcond,
|
||||
texi_arguments(doc,
|
||||
arg_type if boxed else None)))
|
||||
|
||||
def symbol(self, doc, entity):
|
||||
if self._gen._body:
|
||||
self._gen.add('\n')
|
||||
self.cur_doc = doc
|
||||
entity.visit(self)
|
||||
self.cur_doc = None
|
||||
|
||||
def freeform(self, doc):
|
||||
assert not doc.args
|
||||
if self._gen._body:
|
||||
self._gen.add('\n')
|
||||
self._gen.add(texi_body(doc) + texi_sections(doc, None))
|
||||
|
||||
|
||||
def gen_doc(schema, output_dir, prefix):
|
||||
vis = QAPISchemaGenDocVisitor(prefix)
|
||||
vis.visit_begin(schema)
|
||||
for doc in schema.docs:
|
||||
if doc.symbol:
|
||||
vis.symbol(doc, schema.lookup_entity(doc.symbol))
|
||||
else:
|
||||
vis.freeform(doc)
|
||||
vis.write(output_dir)
|
|
@ -178,13 +178,6 @@ def ifcontext(ifcond, *args):
|
|||
arg.end_if()
|
||||
|
||||
|
||||
class QAPIGenDoc(QAPIGen):
|
||||
|
||||
def _top(self):
|
||||
return (super()._top()
|
||||
+ '@c AUTOMATICALLY GENERATED, DO NOT MODIFY\n\n')
|
||||
|
||||
|
||||
class QAPISchemaMonolithicCVisitor(QAPISchemaVisitor):
|
||||
|
||||
def __init__(self, prefix, what, blurb, pydoc):
|
||||
|
|
|
@ -319,17 +319,32 @@ class QAPIDoc:
|
|||
"""
|
||||
|
||||
class Section:
|
||||
def __init__(self, name=None):
|
||||
def __init__(self, parser, name=None, indent=0):
|
||||
# parser, for error messages about indentation
|
||||
self._parser = parser
|
||||
# optional section name (argument/member or section name)
|
||||
self.name = name
|
||||
self.text = ''
|
||||
# the expected indent level of the text of this section
|
||||
self._indent = indent
|
||||
|
||||
def append(self, line):
|
||||
# Strip leading spaces corresponding to the expected indent level
|
||||
# Blank lines are always OK.
|
||||
if line:
|
||||
indent = re.match(r'\s*', line).end()
|
||||
if indent < self._indent:
|
||||
raise QAPIParseError(
|
||||
self._parser,
|
||||
"unexpected de-indent (expected at least %d spaces)" %
|
||||
self._indent)
|
||||
line = line[self._indent:]
|
||||
|
||||
self.text += line.rstrip() + '\n'
|
||||
|
||||
class ArgSection(Section):
|
||||
def __init__(self, name):
|
||||
super().__init__(name)
|
||||
def __init__(self, parser, name, indent=0):
|
||||
super().__init__(parser, name, indent)
|
||||
self.member = None
|
||||
|
||||
def connect(self, member):
|
||||
|
@ -343,7 +358,7 @@ class QAPIDoc:
|
|||
self._parser = parser
|
||||
self.info = info
|
||||
self.symbol = None
|
||||
self.body = QAPIDoc.Section()
|
||||
self.body = QAPIDoc.Section(parser)
|
||||
# dict mapping parameter name to ArgSection
|
||||
self.args = OrderedDict()
|
||||
self.features = OrderedDict()
|
||||
|
@ -427,10 +442,10 @@ class QAPIDoc:
|
|||
self._append_line = self._append_various_line
|
||||
self._append_various_line(line)
|
||||
else:
|
||||
self._append_freeform(line.strip())
|
||||
self._append_freeform(line)
|
||||
else:
|
||||
# This is a free-form documentation block
|
||||
self._append_freeform(line.strip())
|
||||
self._append_freeform(line)
|
||||
|
||||
def _append_args_line(self, line):
|
||||
"""
|
||||
|
@ -447,8 +462,21 @@ class QAPIDoc:
|
|||
name = line.split(' ', 1)[0]
|
||||
|
||||
if name.startswith('@') and name.endswith(':'):
|
||||
line = line[len(name)+1:]
|
||||
self._start_args_section(name[1:-1])
|
||||
# If line is "@arg: first line of description", find
|
||||
# the index of 'f', which is the indent we expect for any
|
||||
# following lines. We then remove the leading "@arg:"
|
||||
# from line and replace it with spaces so that 'f' has the
|
||||
# same index as it did in the original line and can be
|
||||
# handled the same way we will handle following lines.
|
||||
indent = re.match(r'@\S*:\s*', line).end()
|
||||
line = line[indent:]
|
||||
if not line:
|
||||
# Line was just the "@arg:" header; following lines
|
||||
# are not indented
|
||||
indent = 0
|
||||
else:
|
||||
line = ' ' * indent + line
|
||||
self._start_args_section(name[1:-1], indent)
|
||||
elif self._is_section_tag(name):
|
||||
self._append_line = self._append_various_line
|
||||
self._append_various_line(line)
|
||||
|
@ -463,14 +491,27 @@ class QAPIDoc:
|
|||
self._append_various_line(line)
|
||||
return
|
||||
|
||||
self._append_freeform(line.strip())
|
||||
self._append_freeform(line)
|
||||
|
||||
def _append_features_line(self, line):
|
||||
name = line.split(' ', 1)[0]
|
||||
|
||||
if name.startswith('@') and name.endswith(':'):
|
||||
line = line[len(name)+1:]
|
||||
self._start_features_section(name[1:-1])
|
||||
# If line is "@arg: first line of description", find
|
||||
# the index of 'f', which is the indent we expect for any
|
||||
# following lines. We then remove the leading "@arg:"
|
||||
# from line and replace it with spaces so that 'f' has the
|
||||
# same index as it did in the original line and can be
|
||||
# handled the same way we will handle following lines.
|
||||
indent = re.match(r'@\S*:\s*', line).end()
|
||||
line = line[indent:]
|
||||
if not line:
|
||||
# Line was just the "@arg:" header; following lines
|
||||
# are not indented
|
||||
indent = 0
|
||||
else:
|
||||
line = ' ' * indent + line
|
||||
self._start_features_section(name[1:-1], indent)
|
||||
elif self._is_section_tag(name):
|
||||
self._append_line = self._append_various_line
|
||||
self._append_various_line(line)
|
||||
|
@ -482,7 +523,7 @@ class QAPIDoc:
|
|||
self._append_various_line(line)
|
||||
return
|
||||
|
||||
self._append_freeform(line.strip())
|
||||
self._append_freeform(line)
|
||||
|
||||
def _append_various_line(self, line):
|
||||
"""
|
||||
|
@ -502,16 +543,25 @@ class QAPIDoc:
|
|||
"'%s' can't follow '%s' section"
|
||||
% (name, self.sections[0].name))
|
||||
if self._is_section_tag(name):
|
||||
line = line[len(name)+1:]
|
||||
self._start_section(name[:-1])
|
||||
|
||||
if (not self._section.name or
|
||||
not self._section.name.startswith('Example')):
|
||||
line = line.strip()
|
||||
# If line is "Section: first line of description", find
|
||||
# the index of 'f', which is the indent we expect for any
|
||||
# following lines. We then remove the leading "Section:"
|
||||
# from line and replace it with spaces so that 'f' has the
|
||||
# same index as it did in the original line and can be
|
||||
# handled the same way we will handle following lines.
|
||||
indent = re.match(r'\S*:\s*', line).end()
|
||||
line = line[indent:]
|
||||
if not line:
|
||||
# Line was just the "Section:" header; following lines
|
||||
# are not indented
|
||||
indent = 0
|
||||
else:
|
||||
line = ' ' * indent + line
|
||||
self._start_section(name[:-1], indent)
|
||||
|
||||
self._append_freeform(line)
|
||||
|
||||
def _start_symbol_section(self, symbols_dict, name):
|
||||
def _start_symbol_section(self, symbols_dict, name, indent):
|
||||
# FIXME invalid names other than the empty string aren't flagged
|
||||
if not name:
|
||||
raise QAPIParseError(self._parser, "invalid parameter name")
|
||||
|
@ -520,21 +570,21 @@ class QAPIDoc:
|
|||
"'%s' parameter name duplicated" % name)
|
||||
assert not self.sections
|
||||
self._end_section()
|
||||
self._section = QAPIDoc.ArgSection(name)
|
||||
self._section = QAPIDoc.ArgSection(self._parser, name, indent)
|
||||
symbols_dict[name] = self._section
|
||||
|
||||
def _start_args_section(self, name):
|
||||
self._start_symbol_section(self.args, name)
|
||||
def _start_args_section(self, name, indent):
|
||||
self._start_symbol_section(self.args, name, indent)
|
||||
|
||||
def _start_features_section(self, name):
|
||||
self._start_symbol_section(self.features, name)
|
||||
def _start_features_section(self, name, indent):
|
||||
self._start_symbol_section(self.features, name, indent)
|
||||
|
||||
def _start_section(self, name=None):
|
||||
def _start_section(self, name=None, indent=0):
|
||||
if name in ('Returns', 'Since') and self.has_section(name):
|
||||
raise QAPIParseError(self._parser,
|
||||
"duplicated '%s' section" % name)
|
||||
self._end_section()
|
||||
self._section = QAPIDoc.Section(name)
|
||||
self._section = QAPIDoc.Section(self._parser, name, indent)
|
||||
self.sections.append(self._section)
|
||||
|
||||
def _end_section(self):
|
||||
|
@ -557,7 +607,8 @@ class QAPIDoc:
|
|||
def connect_member(self, member):
|
||||
if member.name not in self.args:
|
||||
# Undocumented TODO outlaw
|
||||
self.args[member.name] = QAPIDoc.ArgSection(member.name)
|
||||
self.args[member.name] = QAPIDoc.ArgSection(self._parser,
|
||||
member.name)
|
||||
self.args[member.name].connect(member)
|
||||
|
||||
def connect_feature(self, feature):
|
||||
|
|
|
@ -1,536 +0,0 @@
|
|||
#! /usr/bin/env perl
|
||||
|
||||
# Copyright (C) 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GCC.
|
||||
|
||||
# GCC is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# GCC is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GCC; see the file COPYING. If not,
|
||||
# see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# This does trivial (and I mean _trivial_) conversion of Texinfo
|
||||
# markup to Perl POD format. It's intended to be used to extract
|
||||
# something suitable for a manpage from a Texinfo document.
|
||||
|
||||
use warnings;
|
||||
|
||||
$output = 0;
|
||||
$skipping = 0;
|
||||
%sects = ();
|
||||
$section = "";
|
||||
@icstack = ();
|
||||
@endwstack = ();
|
||||
@skstack = ();
|
||||
@instack = ();
|
||||
$shift = "";
|
||||
%defs = ();
|
||||
$fnno = 1;
|
||||
$inf = "";
|
||||
$ibase = "";
|
||||
@ipath = ();
|
||||
$encoding = undef;
|
||||
@args = ();
|
||||
|
||||
while ($_ = shift) {
|
||||
if (/^-D(.*)$/) {
|
||||
if ($1 ne "") {
|
||||
$flag = $1;
|
||||
} else {
|
||||
$flag = shift;
|
||||
}
|
||||
$value = "";
|
||||
($flag, $value) = ($flag =~ /^([^=]+)(?:=(.+))?/);
|
||||
die "no flag specified for -D\n"
|
||||
unless $flag ne "";
|
||||
die "flags may only contain letters, digits, hyphens, dashes and underscores\n"
|
||||
unless $flag =~ /^[a-zA-Z0-9_-]+$/;
|
||||
$defs{$flag} = $value;
|
||||
} elsif (/^-I(.*)$/) {
|
||||
if ($1 ne "") {
|
||||
$flag = $1;
|
||||
} else {
|
||||
$flag = shift;
|
||||
}
|
||||
push (@ipath, $flag);
|
||||
} elsif (/^-/) {
|
||||
usage();
|
||||
} else {
|
||||
$in = $_, next unless defined $in;
|
||||
$out = $_, next unless defined $out;
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
if (defined $in) {
|
||||
$inf = gensym();
|
||||
open($inf, "<$in") or die "opening \"$in\": $!\n";
|
||||
$ibase = $1 if $in =~ m|^(.+)/[^/]+$|;
|
||||
} else {
|
||||
$inf = \*STDIN;
|
||||
}
|
||||
|
||||
if (defined $out) {
|
||||
open(STDOUT, ">$out") or die "opening \"$out\": $!\n";
|
||||
}
|
||||
|
||||
while(defined $inf) {
|
||||
while(<$inf>) {
|
||||
# Certain commands are discarded without further processing.
|
||||
/^\@(?:
|
||||
[a-z]+index # @*index: useful only in complete manual
|
||||
|need # @need: useful only in printed manual
|
||||
|(?:end\s+)?group # @group .. @end group: ditto
|
||||
|page # @page: ditto
|
||||
|node # @node: useful only in .info file
|
||||
|(?:end\s+)?ifnottex # @ifnottex .. @end ifnottex: use contents
|
||||
)\b/x and next;
|
||||
|
||||
chomp;
|
||||
|
||||
# Look for filename and title markers.
|
||||
/^\@setfilename\s+([^.]+)/ and $fn = $1, next;
|
||||
/^\@settitle\s+([^.]+)/ and $tl = postprocess($1), next;
|
||||
|
||||
# Look for document encoding
|
||||
/^\@documentencoding\s+([^.]+)/ and do {
|
||||
$encoding = $1 unless defined $encoding;
|
||||
next;
|
||||
};
|
||||
|
||||
# Identify a man title but keep only the one we are interested in.
|
||||
/^\@c\s+man\s+title\s+([A-Za-z0-9-]+)\s+(.+)/ and do {
|
||||
if (exists $defs{$1}) {
|
||||
$fn = $1;
|
||||
$tl = postprocess($2);
|
||||
}
|
||||
next;
|
||||
};
|
||||
|
||||
# Look for blocks surrounded by @c man begin SECTION ... @c man end.
|
||||
# This really oughta be @ifman ... @end ifman and the like, but such
|
||||
# would require rev'ing all other Texinfo translators.
|
||||
/^\@c\s+man\s+begin\s+([A-Z]+)\s+([A-Za-z0-9-]+)/ and do {
|
||||
$output = 1 if exists $defs{$2};
|
||||
$sect = $1;
|
||||
next;
|
||||
};
|
||||
/^\@c\s+man\s+begin\s+([A-Z]+)/ and $sect = $1, $output = 1, next;
|
||||
/^\@c\s+man\s+end/ and do {
|
||||
$sects{$sect} = "" unless exists $sects{$sect};
|
||||
$sects{$sect} .= postprocess($section);
|
||||
$section = "";
|
||||
$output = 0;
|
||||
next;
|
||||
};
|
||||
|
||||
# handle variables
|
||||
/^\@set\s+([a-zA-Z0-9_-]+)\s*(.*)$/ and do {
|
||||
$defs{$1} = $2;
|
||||
next;
|
||||
};
|
||||
/^\@clear\s+([a-zA-Z0-9_-]+)/ and do {
|
||||
delete $defs{$1};
|
||||
next;
|
||||
};
|
||||
|
||||
# Single line command handlers.
|
||||
|
||||
/^\@include\s+(.+)$/ and do {
|
||||
push @instack, $inf;
|
||||
$inf = gensym();
|
||||
$file = postprocess($1);
|
||||
|
||||
# Try cwd and $ibase, then explicit -I paths.
|
||||
$done = 0;
|
||||
foreach $path ("", $ibase, @ipath) {
|
||||
$mypath = $file;
|
||||
$mypath = $path . "/" . $mypath if ($path ne "");
|
||||
open($inf, "<" . $mypath) and ($done = 1, last);
|
||||
}
|
||||
die "cannot find $file" if !$done;
|
||||
next;
|
||||
};
|
||||
|
||||
next unless $output;
|
||||
|
||||
# Discard comments. (Can't do it above, because then we'd never see
|
||||
# @c man lines.)
|
||||
/^\@c\b/ and next;
|
||||
|
||||
# End-block handler goes up here because it needs to operate even
|
||||
# if we are skipping.
|
||||
/^\@end\s+([a-z]+)/ and do {
|
||||
# Ignore @end foo, where foo is not an operation which may
|
||||
# cause us to skip, if we are presently skipping.
|
||||
my $ended = $1;
|
||||
next if $skipping && $ended !~ /^(?:ifset|ifclear|ignore|menu|iftex|copying)$/;
|
||||
|
||||
die "\@end $ended without \@$ended at line $.\n" unless defined $endw;
|
||||
die "\@$endw ended by \@end $ended at line $.\n" unless $ended eq $endw;
|
||||
|
||||
$endw = pop @endwstack;
|
||||
|
||||
if ($ended =~ /^(?:ifset|ifclear|ignore|menu|iftex)$/) {
|
||||
$skipping = pop @skstack;
|
||||
next;
|
||||
} elsif ($ended =~ /^(?:example|smallexample|display
|
||||
|quotation|deftp|deftypefn)$/x) {
|
||||
$shift = "";
|
||||
$_ = ""; # need a paragraph break
|
||||
} elsif ($ended =~ /^(?:itemize|enumerate|[fv]?table)$/) {
|
||||
$_ = "\n=back\n";
|
||||
$ic = pop @icstack;
|
||||
} elsif ($ended eq "multitable") {
|
||||
$_ = "\n=back\n";
|
||||
} else {
|
||||
die "unknown command \@end $ended at line $.\n";
|
||||
}
|
||||
};
|
||||
|
||||
# We must handle commands which can cause skipping even while we
|
||||
# are skipping, otherwise we will not process nested conditionals
|
||||
# correctly.
|
||||
/^\@ifset\s+([a-zA-Z0-9_-]+)/ and do {
|
||||
push @endwstack, $endw;
|
||||
push @skstack, $skipping;
|
||||
$endw = "ifset";
|
||||
$skipping = 1 unless exists $defs{$1};
|
||||
next;
|
||||
};
|
||||
|
||||
/^\@ifclear\s+([a-zA-Z0-9_-]+)/ and do {
|
||||
push @endwstack, $endw;
|
||||
push @skstack, $skipping;
|
||||
$endw = "ifclear";
|
||||
$skipping = 1 if exists $defs{$1};
|
||||
next;
|
||||
};
|
||||
|
||||
/^\@(ignore|menu|iftex|copying)\b/ and do {
|
||||
push @endwstack, $endw;
|
||||
push @skstack, $skipping;
|
||||
$endw = $1;
|
||||
$skipping = 1;
|
||||
next;
|
||||
};
|
||||
|
||||
next if $skipping;
|
||||
|
||||
# Character entities. First the ones that can be replaced by raw text
|
||||
# or discarded outright:
|
||||
s/\@copyright\{\}/(c)/g;
|
||||
s/\@dots\{\}/.../g;
|
||||
s/\@enddots\{\}/..../g;
|
||||
s/\@([.!? ])/$1/g;
|
||||
s/\@[:-]//g;
|
||||
s/\@bullet(?:\{\})?/*/g;
|
||||
s/\@TeX\{\}/TeX/g;
|
||||
s/\@pounds\{\}/\#/g;
|
||||
s/\@minus(?:\{\})?/-/g;
|
||||
s/\\,/,/g;
|
||||
|
||||
# Now the ones that have to be replaced by special escapes
|
||||
# (which will be turned back into text by unmunge())
|
||||
s/&/&/g;
|
||||
s/\@\{/{/g;
|
||||
s/\@\}/}/g;
|
||||
s/\@\@/&at;/g;
|
||||
|
||||
# Inside a verbatim block, handle @var specially.
|
||||
if ($shift ne "") {
|
||||
s/\@var\{([^\}]*)\}/<$1>/g;
|
||||
}
|
||||
|
||||
# POD doesn't interpret E<> inside a verbatim block.
|
||||
if ($shift eq "") {
|
||||
s/</</g;
|
||||
s/>/>/g;
|
||||
} else {
|
||||
s/</</g;
|
||||
s/>/>/g;
|
||||
}
|
||||
|
||||
/^\@(?:section|unnumbered|unnumberedsec|center)\s+(.+)$/
|
||||
and $_ = "\n=head2 $1\n";
|
||||
/^\@subsection\s+(.+)$/
|
||||
and $_ = "\n=head3 $1\n";
|
||||
/^\@subsubsection\s+(.+)$/
|
||||
and $_ = "\n=head4 $1\n";
|
||||
|
||||
# Block command handlers:
|
||||
/^\@itemize(?:\s+(\@[a-z]+|\*|-))?/ and do {
|
||||
push @endwstack, $endw;
|
||||
push @icstack, $ic;
|
||||
if (defined $1) {
|
||||
$ic = $1;
|
||||
} else {
|
||||
$ic = '*';
|
||||
}
|
||||
$_ = "\n=over 4\n";
|
||||
$endw = "itemize";
|
||||
};
|
||||
|
||||
/^\@enumerate(?:\s+([a-zA-Z0-9]+))?/ and do {
|
||||
push @endwstack, $endw;
|
||||
push @icstack, $ic;
|
||||
if (defined $1) {
|
||||
$ic = $1 . ".";
|
||||
} else {
|
||||
$ic = "1.";
|
||||
}
|
||||
$_ = "\n=over 4\n";
|
||||
$endw = "enumerate";
|
||||
};
|
||||
|
||||
/^\@multitable\s.*/ and do {
|
||||
push @endwstack, $endw;
|
||||
$endw = "multitable";
|
||||
$_ = "\n=over 4\n";
|
||||
};
|
||||
|
||||
/^\@([fv]?table)\s+(\@[a-z]+)/ and do {
|
||||
push @endwstack, $endw;
|
||||
push @icstack, $ic;
|
||||
$endw = $1;
|
||||
$ic = $2;
|
||||
$ic =~ s/\@(?:samp|strong|key|gcctabopt|option|env)/B/;
|
||||
$ic =~ s/\@(?:code|kbd)/C/;
|
||||
$ic =~ s/\@(?:dfn|var|emph|cite|i)/I/;
|
||||
$ic =~ s/\@(?:file)/F/;
|
||||
$ic =~ s/\@(?:asis)//;
|
||||
$_ = "\n=over 4\n";
|
||||
};
|
||||
|
||||
/^\@((?:small)?example|display)/ and do {
|
||||
push @endwstack, $endw;
|
||||
$endw = $1;
|
||||
$shift = "\t";
|
||||
$_ = ""; # need a paragraph break
|
||||
};
|
||||
|
||||
/^\@item\s+(.*\S)\s*$/ and $endw eq "multitable" and do {
|
||||
@columns = ();
|
||||
for $column (split (/\s*\@tab\s*/, $1)) {
|
||||
# @strong{...} is used a @headitem work-alike
|
||||
$column =~ s/^\@strong\{(.*)\}$/$1/;
|
||||
push @columns, $column;
|
||||
}
|
||||
$_ = "\n=item ".join (" : ", @columns)."\n";
|
||||
};
|
||||
|
||||
/^\@(quotation)\s*(.+)?$/ and do {
|
||||
push @endwstack, $endw;
|
||||
$endw = $1;
|
||||
$_ = "\n$2:"
|
||||
};
|
||||
|
||||
/^{(.*)}$|^(.*)$/ and $#args > 0 and do {
|
||||
$kind = $args[0];
|
||||
$arguments = $1 // "";
|
||||
if ($endw eq "deftypefn") {
|
||||
$ret = $args[1];
|
||||
$fname = "B<$args[2]>";
|
||||
$_ = $ret ? "$ret " : "";
|
||||
$_ .= "$fname $arguments ($kind)";
|
||||
} else {
|
||||
$_ = "B<$args[1]> ($kind)\n\n$arguments";
|
||||
}
|
||||
@args = ();
|
||||
};
|
||||
|
||||
/^\@(deftp)\s*(.+)?$/ and do {
|
||||
push @endwstack, $endw;
|
||||
$endw = $1;
|
||||
$arg = $2;
|
||||
$arg =~ s/{([^}]*)}/$1/g;
|
||||
$arg =~ s/\@$//;
|
||||
@args = split (/ /, $arg);
|
||||
$_ = "";
|
||||
};
|
||||
|
||||
/^\@(deftypefn)\s*(.+)?$/ and do {
|
||||
push @endwstack, $endw;
|
||||
$endw = $1;
|
||||
$arg = $2;
|
||||
$arg =~ s/{([^}]*)}/$1/g;
|
||||
$arg =~ s/\@$//;
|
||||
@args = split (/ /, $arg);
|
||||
$_ = "";
|
||||
};
|
||||
|
||||
/^\@itemx?\s*(.+)?$/ and do {
|
||||
if (defined $1) {
|
||||
if ($ic eq "") {
|
||||
$_ = "\n=item $1\n";
|
||||
} else {
|
||||
# Entity escapes prevent munging by the <> processing below.
|
||||
$_ = "\n=item $ic\<$1\>\n";
|
||||
}
|
||||
} else {
|
||||
$_ = "\n=item $ic\n";
|
||||
$ic =~ y/A-Ya-y/B-Zb-z/;
|
||||
$ic =~ s/(\d+)/$1 + 1/eg;
|
||||
}
|
||||
};
|
||||
|
||||
$section .= $shift.$_."\n";
|
||||
}
|
||||
# End of current file.
|
||||
close($inf);
|
||||
$inf = pop @instack;
|
||||
}
|
||||
|
||||
die "No filename or title\n" unless defined $fn && defined $tl;
|
||||
|
||||
print "=encoding $encoding\n\n" if defined $encoding;
|
||||
|
||||
$sects{NAME} = "$fn \- $tl\n";
|
||||
$sects{FOOTNOTES} .= "=back\n" if exists $sects{FOOTNOTES};
|
||||
|
||||
for $sect (qw(NAME SYNOPSIS DESCRIPTION OPTIONS ENVIRONMENT FILES
|
||||
BUGS NOTES FOOTNOTES EXAMPLES SEEALSO AUTHOR COPYRIGHT)) {
|
||||
if(exists $sects{$sect}) {
|
||||
$head = $sect;
|
||||
$head =~ s/SEEALSO/SEE ALSO/;
|
||||
print "=head1 $head\n\n";
|
||||
print scalar unmunge ($sects{$sect});
|
||||
print "\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub usage
|
||||
{
|
||||
die "usage: $0 [-D toggle...] [infile [outfile]]\n";
|
||||
}
|
||||
|
||||
sub postprocess
|
||||
{
|
||||
local $_ = $_[0];
|
||||
|
||||
# @value{foo} is replaced by whatever 'foo' is defined as.
|
||||
while (m/(\@value\{([a-zA-Z0-9_-]+)\})/g) {
|
||||
if (! exists $defs{$2}) {
|
||||
print STDERR "Option $2 not defined\n";
|
||||
s/\Q$1\E//;
|
||||
} else {
|
||||
$value = $defs{$2};
|
||||
s/\Q$1\E/$value/;
|
||||
}
|
||||
}
|
||||
|
||||
# Formatting commands.
|
||||
# Temporary escape for @r.
|
||||
s/\@r\{([^\}]*)\}/R<$1>/g;
|
||||
s/\@(?:dfn|var|emph|cite|i)\{([^\}]*)\}/I<$1>/g;
|
||||
s/\@(?:code|kbd)\{([^\}]*)\}/C<$1>/g;
|
||||
s/\@(?:gccoptlist|samp|strong|key|option|env|command|b)\{([^\}]*)\}/B<$1>/g;
|
||||
s/\@sc\{([^\}]*)\}/\U$1/g;
|
||||
s/\@file\{([^\}]*)\}/F<$1>/g;
|
||||
s/\@w\{([^\}]*)\}/S<$1>/g;
|
||||
s/\@t\{([^\}]*)\}/$1/g;
|
||||
s/\@(?:dmn|math)\{([^\}]*)\}/$1/g;
|
||||
|
||||
# keep references of the form @ref{...}, print them bold
|
||||
s/\@(?:ref)\{([^\}]*)\}/B<$1>/g;
|
||||
|
||||
# Change double single quotes to double quotes.
|
||||
s/''/"/g;
|
||||
s/``/"/g;
|
||||
|
||||
# Cross references are thrown away, as are @noindent and @refill.
|
||||
# (@noindent is impossible in .pod, and @refill is unnecessary.)
|
||||
# @* is also impossible in .pod; we discard it and any newline that
|
||||
# follows it. Similarly, our macro @gol must be discarded.
|
||||
|
||||
s/\(?\@xref\{(?:[^\}]*)\}(?:[^.<]|(?:<[^<>]*>))*\.\)?//g;
|
||||
s/\s+\(\@pxref\{(?:[^\}]*)\}\)//g;
|
||||
s/;\s+\@pxref\{(?:[^\}]*)\}//g;
|
||||
s/\@noindent\s*//g;
|
||||
s/\@refill//g;
|
||||
s/\@gol//g;
|
||||
s/\@\*\s*\n?//g;
|
||||
|
||||
# Anchors are thrown away
|
||||
s/\@anchor\{(?:[^\}]*)\}//g;
|
||||
|
||||
# @uref can take one, two, or three arguments, with different
|
||||
# semantics each time. @url and @email are just like @uref with
|
||||
# one argument, for our purposes.
|
||||
s/\@(?:uref|url|email)\{([^\},]*)\}/<B<$1>>/g;
|
||||
s/\@uref\{([^\},]*),([^\},]*)\}/$2 (C<$1>)/g;
|
||||
s/\@uref\{([^\},]*),([^\},]*),([^\},]*)\}/$3/g;
|
||||
|
||||
# Un-escape <> at this point.
|
||||
s/</</g;
|
||||
s/>/>/g;
|
||||
|
||||
# Now un-nest all B<>, I<>, R<>. Theoretically we could have
|
||||
# indefinitely deep nesting; in practice, one level suffices.
|
||||
1 while s/([BIR])<([^<>]*)([BIR])<([^<>]*)>/$1<$2>$3<$4>$1</g;
|
||||
|
||||
# Replace R<...> with bare ...; eliminate empty markup, B<>;
|
||||
# shift white space at the ends of [BI]<...> expressions outside
|
||||
# the expression.
|
||||
s/R<([^<>]*)>/$1/g;
|
||||
s/[BI]<>//g;
|
||||
s/([BI])<(\s+)([^>]+)>/$2$1<$3>/g;
|
||||
s/([BI])<([^>]+?)(\s+)>/$1<$2>$3/g;
|
||||
|
||||
# Extract footnotes. This has to be done after all other
|
||||
# processing because otherwise the regexp will choke on formatting
|
||||
# inside @footnote.
|
||||
while (/\@footnote/g) {
|
||||
s/\@footnote\{([^\}]+)\}/[$fnno]/;
|
||||
add_footnote($1, $fnno);
|
||||
$fnno++;
|
||||
}
|
||||
|
||||
return $_;
|
||||
}
|
||||
|
||||
sub unmunge
|
||||
{
|
||||
# Replace escaped symbols with their equivalents.
|
||||
local $_ = $_[0];
|
||||
|
||||
s/</E<lt>/g;
|
||||
s/>/E<gt>/g;
|
||||
s/{/\{/g;
|
||||
s/}/\}/g;
|
||||
s/&at;/\@/g;
|
||||
s/&/&/g;
|
||||
return $_;
|
||||
}
|
||||
|
||||
sub add_footnote
|
||||
{
|
||||
unless (exists $sects{FOOTNOTES}) {
|
||||
$sects{FOOTNOTES} = "\n=over 4\n\n";
|
||||
}
|
||||
|
||||
$sects{FOOTNOTES} .= "=item $fnno.\n\n"; $fnno++;
|
||||
$sects{FOOTNOTES} .= $_[0];
|
||||
$sects{FOOTNOTES} .= "\n\n";
|
||||
}
|
||||
|
||||
# stolen from Symbol.pm
|
||||
{
|
||||
my $genseq = 0;
|
||||
sub gensym
|
||||
{
|
||||
my $name = "GEN" . $genseq++;
|
||||
my $ref = \*{$name};
|
||||
delete $::{$name};
|
||||
return $ref;
|
||||
}
|
||||
}
|
|
@ -29,7 +29,7 @@
|
|||
#include "sysemu/kvm.h"
|
||||
#include "sysemu/balloon.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qapi-commands-misc.h"
|
||||
#include "qapi/qapi-commands-machine.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "trace.h"
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
qsd_qapi_files = custom_target('QAPI files for qemu-storage-daemon',
|
||||
output: qapi_nonmodule_outputs + ['qapi-doc.texi'],
|
||||
output: qapi_nonmodule_outputs,
|
||||
input: [ files('qapi-schema.json') ],
|
||||
command: [ qapi_gen, '-o', 'storage-daemon/qapi', '@INPUT@' ],
|
||||
depend_files: [ qapi_inputs, qapi_gen_depends ])
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "qapi/qapi-commands-misc.h"
|
||||
#include "qapi/qapi-commands-machine.h"
|
||||
#include "qemu/uuid.h"
|
||||
|
||||
UuidInfo *qmp_query_uuid(Error **errp)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qapi-commands-misc.h"
|
||||
#include "qapi/qapi-commands-machine.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
|
||||
GuidInfo *qmp_query_vm_generation_id(Error **errp)
|
||||
|
|
|
@ -31,7 +31,6 @@ RUN apt update && \
|
|||
python3 \
|
||||
python3-setuptools \
|
||||
python3-sphinx \
|
||||
texinfo \
|
||||
$(apt-get -s build-dep qemu | egrep ^Inst | fgrep '[all]' | cut -d\ -f2)
|
||||
|
||||
ENV FEATURES docs
|
||||
|
|
|
@ -96,7 +96,6 @@ ENV PACKAGES \
|
|||
tar \
|
||||
tesseract \
|
||||
tesseract-langpack-eng \
|
||||
texinfo \
|
||||
usbredir-devel \
|
||||
virglrenderer-devel \
|
||||
vte291-devel \
|
||||
|
|
|
@ -63,7 +63,6 @@ ENV PACKAGES \
|
|||
python3-yaml \
|
||||
python3-sphinx \
|
||||
sparse \
|
||||
texinfo \
|
||||
xfslibs-dev
|
||||
RUN apt-get update && \
|
||||
DEBIAN_FRONTEND=noninteractive apt-get -y install $PACKAGES
|
||||
|
|
|
@ -49,7 +49,6 @@ ENV PACKAGES \
|
|||
python3-yaml \
|
||||
python3-sphinx \
|
||||
sparse \
|
||||
texinfo \
|
||||
xfslibs-dev
|
||||
RUN apt-get update && \
|
||||
DEBIAN_FRONTEND=noninteractive apt-get -y install $PACKAGES
|
||||
|
|
|
@ -57,7 +57,6 @@ ENV PACKAGES flex bison \
|
|||
sparse \
|
||||
tesseract-ocr \
|
||||
tesseract-ocr-eng \
|
||||
texinfo \
|
||||
xfslibs-dev\
|
||||
vim
|
||||
RUN apt-get update && \
|
||||
|
|
1
tests/qapi-schema/doc-bad-indent.err
Normal file
1
tests/qapi-schema/doc-bad-indent.err
Normal file
|
@ -0,0 +1 @@
|
|||
doc-bad-indent.json:6:1: unexpected de-indent (expected at least 4 spaces)
|
8
tests/qapi-schema/doc-bad-indent.json
Normal file
8
tests/qapi-schema/doc-bad-indent.json
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Multiline doc comments should have consistent indentation
|
||||
|
||||
##
|
||||
# @foo:
|
||||
# @a: line one
|
||||
# line two is wrongly indented
|
||||
##
|
||||
{ 'command': 'foo', 'data': { 'a': 'int' } }
|
0
tests/qapi-schema/doc-bad-indent.out
Normal file
0
tests/qapi-schema/doc-bad-indent.out
Normal file
|
@ -10,27 +10,27 @@
|
|||
#
|
||||
# == Subsection
|
||||
#
|
||||
# *strong* _with emphasis_
|
||||
# *with emphasis*
|
||||
# @var {in braces}
|
||||
#
|
||||
# * List item one
|
||||
# - Two, multiple
|
||||
# * Two, multiple
|
||||
# lines
|
||||
#
|
||||
# 3. Three
|
||||
# Still in list
|
||||
# * Three
|
||||
# Still in list
|
||||
#
|
||||
# Not in list
|
||||
#
|
||||
# Not in list
|
||||
# - Second list
|
||||
# Note: still in list
|
||||
# Note: still in list
|
||||
#
|
||||
# Note: not in list
|
||||
#
|
||||
# 1. Third list
|
||||
# is numbered
|
||||
#
|
||||
# - another item
|
||||
#
|
||||
# | example
|
||||
# | multiple lines
|
||||
# 2. another item
|
||||
#
|
||||
# Returns: the King
|
||||
# Since: the first age
|
||||
|
@ -68,7 +68,7 @@
|
|||
##
|
||||
# @Base:
|
||||
# @base1:
|
||||
# the first member
|
||||
# the first member
|
||||
##
|
||||
{ 'struct': 'Base', 'data': { 'base1': 'Enum' } }
|
||||
|
||||
|
@ -116,7 +116,7 @@
|
|||
##
|
||||
# @Alternate:
|
||||
# @i: an integer
|
||||
# @b is undocumented
|
||||
# @b is undocumented
|
||||
#
|
||||
# Features:
|
||||
# @alt-feat: a feature
|
||||
|
@ -134,7 +134,7 @@
|
|||
# @arg1: the first argument
|
||||
#
|
||||
# @arg2: the second
|
||||
# argument
|
||||
# argument
|
||||
#
|
||||
# Features:
|
||||
# @cmd-feat1: a feature
|
||||
|
@ -143,6 +143,7 @@
|
|||
# Returns: @Object
|
||||
# TODO: frobnicate
|
||||
# Notes:
|
||||
#
|
||||
# - Lorem ipsum dolor sit amet
|
||||
# - Ut enim ad minim veniam
|
||||
#
|
||||
|
|
|
@ -73,27 +73,27 @@ doc freeform
|
|||
body=
|
||||
== Subsection
|
||||
|
||||
*strong* _with emphasis_
|
||||
*with emphasis*
|
||||
@var {in braces}
|
||||
* List item one
|
||||
- Two, multiple
|
||||
lines
|
||||
|
||||
3. Three
|
||||
Still in list
|
||||
* List item one
|
||||
* Two, multiple
|
||||
lines
|
||||
|
||||
* Three
|
||||
Still in list
|
||||
|
||||
Not in list
|
||||
|
||||
- Second list
|
||||
Note: still in list
|
||||
Note: still in list
|
||||
|
||||
Note: not in list
|
||||
|
||||
1. Third list
|
||||
is numbered
|
||||
is numbered
|
||||
|
||||
- another item
|
||||
|
||||
| example
|
||||
| multiple lines
|
||||
2. another item
|
||||
|
||||
Returns: the King
|
||||
Since: the first age
|
||||
|
|
5
tests/qapi-schema/doc-good.rst
Normal file
5
tests/qapi-schema/doc-good.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
..
|
||||
Test Sphinx manual that pulls in the test schema file. We will generate
|
||||
a plain-text output file and compare it against a reference.
|
||||
|
||||
.. qapi-doc:: tests/qapi-schema/doc-good.json
|
|
@ -1,319 +0,0 @@
|
|||
@c AUTOMATICALLY GENERATED, DO NOT MODIFY
|
||||
|
||||
@section Section
|
||||
|
||||
@subsection Subsection
|
||||
|
||||
@strong{strong} @emph{with emphasis}
|
||||
@code{var} @{in braces@}
|
||||
@itemize @bullet
|
||||
@item
|
||||
List item one
|
||||
@item
|
||||
Two, multiple
|
||||
lines
|
||||
|
||||
@item
|
||||
Three
|
||||
Still in list
|
||||
|
||||
@end itemize
|
||||
|
||||
Not in list
|
||||
@itemize @minus
|
||||
@item
|
||||
Second list
|
||||
Note: still in list
|
||||
|
||||
@end itemize
|
||||
|
||||
Note: not in list
|
||||
@enumerate
|
||||
@item
|
||||
Third list
|
||||
is numbered
|
||||
|
||||
@item
|
||||
another item
|
||||
|
||||
@example
|
||||
example
|
||||
@end example
|
||||
|
||||
@example
|
||||
multiple lines
|
||||
@end example
|
||||
|
||||
|
||||
@end enumerate
|
||||
|
||||
Returns: the King
|
||||
Since: the first age
|
||||
Notes:
|
||||
|
||||
@enumerate
|
||||
@item
|
||||
Lorem ipsum dolor sit amet
|
||||
|
||||
@item
|
||||
Ut enim ad minim veniam
|
||||
|
||||
@end enumerate
|
||||
|
||||
Duis aute irure dolor
|
||||
|
||||
Example:
|
||||
|
||||
-> in
|
||||
<- out
|
||||
Examples:
|
||||
@itemize @minus
|
||||
@item
|
||||
@strong{verbatim}
|
||||
@item
|
||||
@{braces@}
|
||||
@end itemize
|
||||
|
||||
|
||||
|
||||
@deftp {Enum} Enum
|
||||
|
||||
|
||||
|
||||
@b{Values:}
|
||||
@table @asis
|
||||
@item @code{one}
|
||||
The @emph{one} @{and only@}
|
||||
@*@b{If:} @code{defined(IFONE)}
|
||||
@item @code{two}
|
||||
Not documented
|
||||
@end table
|
||||
|
||||
@b{Features:}
|
||||
@table @asis
|
||||
@item @code{enum-feat}
|
||||
Also @emph{one} @{and only@}
|
||||
@end table
|
||||
@code{two} is undocumented
|
||||
|
||||
@b{If:} @code{defined(IFCOND)}
|
||||
@end deftp
|
||||
|
||||
|
||||
|
||||
@deftp {Object} Base
|
||||
|
||||
|
||||
|
||||
@b{Members:}
|
||||
@table @asis
|
||||
@item @code{base1: Enum}
|
||||
the first member
|
||||
@end table
|
||||
|
||||
@end deftp
|
||||
|
||||
|
||||
|
||||
@deftp {Object} Variant1
|
||||
|
||||
A paragraph
|
||||
|
||||
Another paragraph (but no @code{var}: line)
|
||||
|
||||
@b{Members:}
|
||||
@table @asis
|
||||
@item @code{var1: string}
|
||||
Not documented
|
||||
@*@b{If:} @code{defined(IFSTR)}
|
||||
@end table
|
||||
|
||||
@b{Features:}
|
||||
@table @asis
|
||||
@item @code{variant1-feat}
|
||||
a feature
|
||||
@item @code{member-feat}
|
||||
a member feature
|
||||
@end table
|
||||
|
||||
@end deftp
|
||||
|
||||
|
||||
|
||||
@deftp {Object} Variant2
|
||||
|
||||
|
||||
|
||||
@end deftp
|
||||
|
||||
|
||||
|
||||
@deftp {Object} Object
|
||||
|
||||
|
||||
|
||||
@b{Members:}
|
||||
@table @asis
|
||||
@item The members of @code{Base}
|
||||
@item The members of @code{Variant1} when @code{base1} is @t{"one"}
|
||||
@item The members of @code{Variant2} when @code{base1} is @t{"two"} (@b{If:} @code{IFTWO})
|
||||
@end table
|
||||
|
||||
@b{Features:}
|
||||
@table @asis
|
||||
@item @code{union-feat1}
|
||||
a feature
|
||||
@end table
|
||||
|
||||
@end deftp
|
||||
|
||||
|
||||
|
||||
@deftp {Object} SugaredUnion
|
||||
|
||||
|
||||
|
||||
@b{Members:}
|
||||
@table @asis
|
||||
@item @code{type}
|
||||
One of @t{"one"}, @t{"two"}
|
||||
@item @code{data: Variant1} when @code{type} is @t{"one"}
|
||||
@item @code{data: Variant2} when @code{type} is @t{"two"} (@b{If:} @code{IFTWO})
|
||||
@end table
|
||||
|
||||
@b{Features:}
|
||||
@table @asis
|
||||
@item @code{union-feat2}
|
||||
a feature
|
||||
@end table
|
||||
|
||||
@end deftp
|
||||
|
||||
|
||||
|
||||
@deftp {Alternate} Alternate
|
||||
|
||||
|
||||
|
||||
@b{Members:}
|
||||
@table @asis
|
||||
@item @code{i: int}
|
||||
an integer
|
||||
@code{b} is undocumented
|
||||
@item @code{b: boolean}
|
||||
Not documented
|
||||
@end table
|
||||
|
||||
@b{Features:}
|
||||
@table @asis
|
||||
@item @code{alt-feat}
|
||||
a feature
|
||||
@end table
|
||||
|
||||
@end deftp
|
||||
|
||||
|
||||
@subsection Another subsection
|
||||
|
||||
|
||||
@deftypefn Command {} cmd
|
||||
|
||||
|
||||
|
||||
@b{Arguments:}
|
||||
@table @asis
|
||||
@item @code{arg1: int}
|
||||
the first argument
|
||||
@item @code{arg2: string} (optional)
|
||||
the second
|
||||
argument
|
||||
@item @code{arg3: boolean}
|
||||
Not documented
|
||||
@end table
|
||||
|
||||
@b{Features:}
|
||||
@table @asis
|
||||
@item @code{cmd-feat1}
|
||||
a feature
|
||||
@item @code{cmd-feat2}
|
||||
another feature
|
||||
@end table
|
||||
|
||||
@b{Note:}
|
||||
@code{arg3} is undocumented
|
||||
|
||||
@b{Returns:}
|
||||
@code{Object}
|
||||
|
||||
@b{TODO:}
|
||||
frobnicate
|
||||
|
||||
@b{Notes:}
|
||||
@itemize @minus
|
||||
@item
|
||||
Lorem ipsum dolor sit amet
|
||||
@item
|
||||
Ut enim ad minim veniam
|
||||
|
||||
@end itemize
|
||||
|
||||
Duis aute irure dolor
|
||||
|
||||
@b{Example:}
|
||||
@example
|
||||
-> in
|
||||
<- out
|
||||
@end example
|
||||
|
||||
@b{Examples:}
|
||||
@example
|
||||
- *verbatim*
|
||||
- @{braces@}
|
||||
@end example
|
||||
|
||||
@b{Since:}
|
||||
2.10
|
||||
|
||||
@end deftypefn
|
||||
|
||||
|
||||
|
||||
@deftypefn Command {} cmd-boxed
|
||||
|
||||
If you're bored enough to read this, go see a video of boxed cats
|
||||
|
||||
@b{Arguments:} the members of @code{Object}
|
||||
|
||||
@b{Features:}
|
||||
@table @asis
|
||||
@item @code{cmd-feat1}
|
||||
a feature
|
||||
@item @code{cmd-feat2}
|
||||
another feature
|
||||
@end table
|
||||
|
||||
@b{Example:}
|
||||
@example
|
||||
-> in
|
||||
|
||||
<- out
|
||||
@end example
|
||||
|
||||
@end deftypefn
|
||||
|
||||
|
||||
|
||||
@deftypefn Event {} EVT-BOXED
|
||||
|
||||
|
||||
|
||||
@b{Arguments:} the members of @code{Object}
|
||||
|
||||
@b{Features:}
|
||||
@table @asis
|
||||
@item @code{feat3}
|
||||
a feature
|
||||
@end table
|
||||
|
||||
@end deftypefn
|
||||
|
288
tests/qapi-schema/doc-good.txt
Normal file
288
tests/qapi-schema/doc-good.txt
Normal file
|
@ -0,0 +1,288 @@
|
|||
Section
|
||||
*******
|
||||
|
||||
|
||||
Subsection
|
||||
==========
|
||||
|
||||
*with emphasis* "var" {in braces}
|
||||
|
||||
* List item one
|
||||
|
||||
* Two, multiple lines
|
||||
|
||||
* Three Still in list
|
||||
|
||||
Not in list
|
||||
|
||||
* Second list Note: still in list
|
||||
|
||||
Note: not in list
|
||||
|
||||
1. Third list is numbered
|
||||
|
||||
2. another item
|
||||
|
||||
Returns: the King Since: the first age Notes:
|
||||
|
||||
1. Lorem ipsum dolor sit amet
|
||||
|
||||
2. Ut enim ad minim veniam
|
||||
|
||||
Duis aute irure dolor
|
||||
|
||||
Example:
|
||||
|
||||
-> in <- out Examples: - *verbatim* - {braces}
|
||||
|
||||
|
||||
"Enum" (Enum)
|
||||
-------------
|
||||
|
||||
|
||||
Values
|
||||
~~~~~~
|
||||
|
||||
"one" (**If: **"defined(IFONE)")
|
||||
The _one_ {and only}
|
||||
|
||||
"two"
|
||||
Not documented
|
||||
|
||||
|
||||
Features
|
||||
~~~~~~~~
|
||||
|
||||
"enum-feat"
|
||||
Also _one_ {and only}
|
||||
|
||||
"two" is undocumented
|
||||
|
||||
|
||||
If
|
||||
~~
|
||||
|
||||
"defined(IFCOND)"
|
||||
|
||||
|
||||
"Base" (Object)
|
||||
---------------
|
||||
|
||||
|
||||
Members
|
||||
~~~~~~~
|
||||
|
||||
"base1": "Enum"
|
||||
the first member
|
||||
|
||||
|
||||
"Variant1" (Object)
|
||||
-------------------
|
||||
|
||||
A paragraph
|
||||
|
||||
Another paragraph (but no "var": line)
|
||||
|
||||
|
||||
Members
|
||||
~~~~~~~
|
||||
|
||||
"var1": "string" (**If: **"defined(IFSTR)")
|
||||
Not documented
|
||||
|
||||
|
||||
Features
|
||||
~~~~~~~~
|
||||
|
||||
"variant1-feat"
|
||||
a feature
|
||||
|
||||
"member-feat"
|
||||
a member feature
|
||||
|
||||
|
||||
"Variant2" (Object)
|
||||
-------------------
|
||||
|
||||
|
||||
"Object" (Object)
|
||||
-----------------
|
||||
|
||||
|
||||
Members
|
||||
~~~~~~~
|
||||
|
||||
The members of "Base"
|
||||
The members of "Variant1" when "base1" is ""one""
|
||||
The members of "Variant2" when "base1" is ""two"" (**If: **"IFTWO")
|
||||
|
||||
Features
|
||||
~~~~~~~~
|
||||
|
||||
"union-feat1"
|
||||
a feature
|
||||
|
||||
|
||||
"SugaredUnion" (Object)
|
||||
-----------------------
|
||||
|
||||
|
||||
Members
|
||||
~~~~~~~
|
||||
|
||||
"type"
|
||||
One of "one", "two"
|
||||
|
||||
"data": "Variant1" when "type" is ""one""
|
||||
"data": "Variant2" when "type" is ""two"" (**If: **"IFTWO")
|
||||
|
||||
Features
|
||||
~~~~~~~~
|
||||
|
||||
"union-feat2"
|
||||
a feature
|
||||
|
||||
|
||||
"Alternate" (Alternate)
|
||||
-----------------------
|
||||
|
||||
|
||||
Members
|
||||
~~~~~~~
|
||||
|
||||
"i": "int"
|
||||
an integer "b" is undocumented
|
||||
|
||||
"b": "boolean"
|
||||
Not documented
|
||||
|
||||
|
||||
Features
|
||||
~~~~~~~~
|
||||
|
||||
"alt-feat"
|
||||
a feature
|
||||
|
||||
|
||||
Another subsection
|
||||
==================
|
||||
|
||||
|
||||
"cmd" (Command)
|
||||
---------------
|
||||
|
||||
|
||||
Arguments
|
||||
~~~~~~~~~
|
||||
|
||||
"arg1": "int"
|
||||
the first argument
|
||||
|
||||
"arg2": "string" (optional)
|
||||
the second argument
|
||||
|
||||
"arg3": "boolean"
|
||||
Not documented
|
||||
|
||||
|
||||
Features
|
||||
~~~~~~~~
|
||||
|
||||
"cmd-feat1"
|
||||
a feature
|
||||
|
||||
"cmd-feat2"
|
||||
another feature
|
||||
|
||||
|
||||
Note
|
||||
~~~~
|
||||
|
||||
"arg3" is undocumented
|
||||
|
||||
|
||||
Returns
|
||||
~~~~~~~
|
||||
|
||||
"Object"
|
||||
|
||||
|
||||
TODO
|
||||
~~~~
|
||||
|
||||
frobnicate
|
||||
|
||||
|
||||
Notes
|
||||
~~~~~
|
||||
|
||||
* Lorem ipsum dolor sit amet
|
||||
|
||||
* Ut enim ad minim veniam
|
||||
|
||||
Duis aute irure dolor
|
||||
|
||||
|
||||
Example
|
||||
~~~~~~~
|
||||
|
||||
-> in
|
||||
<- out
|
||||
|
||||
|
||||
Examples
|
||||
~~~~~~~~
|
||||
|
||||
- *verbatim*
|
||||
- {braces}
|
||||
|
||||
|
||||
Since
|
||||
~~~~~
|
||||
|
||||
2.10
|
||||
|
||||
|
||||
"cmd-boxed" (Command)
|
||||
---------------------
|
||||
|
||||
If you're bored enough to read this, go see a video of boxed cats
|
||||
|
||||
|
||||
Arguments
|
||||
~~~~~~~~~
|
||||
|
||||
The members of "Object"
|
||||
|
||||
Features
|
||||
~~~~~~~~
|
||||
|
||||
"cmd-feat1"
|
||||
a feature
|
||||
|
||||
"cmd-feat2"
|
||||
another feature
|
||||
|
||||
|
||||
Example
|
||||
~~~~~~~
|
||||
|
||||
-> in
|
||||
|
||||
<- out
|
||||
|
||||
|
||||
"EVT-BOXED" (Event)
|
||||
-------------------
|
||||
|
||||
|
||||
Arguments
|
||||
~~~~~~~~~
|
||||
|
||||
The members of "Object"
|
||||
|
||||
Features
|
||||
~~~~~~~~
|
||||
|
||||
"feat3"
|
||||
a feature
|
|
@ -53,6 +53,7 @@ schemas = [
|
|||
'doc-bad-enum-member.json',
|
||||
'doc-bad-event-arg.json',
|
||||
'doc-bad-feature.json',
|
||||
'doc-bad-indent.json',
|
||||
'doc-bad-section.json',
|
||||
'doc-bad-symbol.json',
|
||||
'doc-bad-union-member.json',
|
||||
|
@ -205,8 +206,7 @@ test('QAPI schema regression tests', python, args: files('test-qapi.py', schemas
|
|||
diff = find_program('diff')
|
||||
|
||||
qapi_doc = custom_target('QAPI doc',
|
||||
output: ['doc-good-qapi-doc.texi',
|
||||
'doc-good-qapi-commands.c', 'doc-good-qapi-commands.h',
|
||||
output: ['doc-good-qapi-commands.c', 'doc-good-qapi-commands.h',
|
||||
'doc-good-qapi-emit-events.c', 'doc-good-qapi-emit-events.h',
|
||||
'doc-good-qapi-events.c', 'doc-good-qapi-events.h',
|
||||
'doc-good-qapi-init-commands.c', 'doc-good-qapi-init-commands.h',
|
||||
|
@ -218,8 +218,57 @@ qapi_doc = custom_target('QAPI doc',
|
|||
'-p', 'doc-good-', '@INPUT0@' ],
|
||||
depend_files: qapi_gen_depends)
|
||||
|
||||
# "full_path()" needed here to work around
|
||||
# https://github.com/mesonbuild/meson/issues/7585
|
||||
test('QAPI doc', diff, args: ['-b', '-u', files('doc-good.texi'), qapi_doc[0].full_path()],
|
||||
depends: qapi_doc,
|
||||
suite: ['qapi-schema', 'qapi-doc'])
|
||||
# Test the document-comment document generation code by running a test schema
|
||||
# file through Sphinx's plain-text builder and comparing the result against
|
||||
# a golden reference. This is in theory susceptible to failures if Sphinx
|
||||
# changes its output, but the text output has historically been very stable
|
||||
# (no changes between Sphinx 1.6 and 3.0), so it is a better bet than
|
||||
# texinfo or HTML generation, both of which have had changes. We might
|
||||
# need to add more sophisticated logic here in future for some sort of
|
||||
# fuzzy comparison if future Sphinx versions produce different text,
|
||||
# but for now the simple comparison suffices.
|
||||
qapi_doc_out = custom_target('QAPI rST doc',
|
||||
output: ['doc-good.txt'],
|
||||
input: files('doc-good.json', 'doc-good.rst'),
|
||||
build_by_default: build_docs,
|
||||
depend_files: sphinx_extn_depends,
|
||||
# We use -E to suppress Sphinx's caching, because
|
||||
# we want it to always really run the QAPI doc
|
||||
# generation code. It also means we don't
|
||||
# clutter up the build dir with the cache.
|
||||
command: [SPHINX_ARGS,
|
||||
'-b', 'text', '-E',
|
||||
'-c', meson.source_root() / 'docs',
|
||||
'-D', 'master_doc=doc-good',
|
||||
meson.current_source_dir(),
|
||||
meson.current_build_dir()])
|
||||
|
||||
# Fix possible inconsistency in line endings in generated output and
|
||||
# in the golden reference (which could otherwise cause test failures
|
||||
# on Windows hosts). Unfortunately diff --strip-trailing-cr
|
||||
# is GNU-diff only. The odd-looking perl is because we must avoid
|
||||
# using an explicit '\' character in the command arguments to
|
||||
# a custom_target(), as Meson will unhelpfully replace it with a '/'
|
||||
# (https://github.com/mesonbuild/meson/issues/1564)
|
||||
qapi_doc_out_nocr = custom_target('QAPI rST doc newline-sanitized',
|
||||
output: ['doc-good.txt.nocr'],
|
||||
input: qapi_doc_out[0],
|
||||
build_by_default: build_docs,
|
||||
command: ['perl', '-pe', '$x = chr 13; s/$x$//', '@INPUT@'],
|
||||
capture: true)
|
||||
|
||||
qapi_doc_ref_nocr = custom_target('QAPI rST doc reference newline-sanitized',
|
||||
output: ['doc-good.ref.nocr'],
|
||||
input: files('doc-good.txt'),
|
||||
build_by_default: build_docs,
|
||||
command: ['perl', '-pe', '$x = chr 13; s/$x$//', '@INPUT@'],
|
||||
capture: true)
|
||||
|
||||
if build_docs
|
||||
# "full_path()" needed here to work around
|
||||
# https://github.com/mesonbuild/meson/issues/7585
|
||||
test('QAPI rST doc', diff, args: ['-u', qapi_doc_ref_nocr[0].full_path(),
|
||||
qapi_doc_out_nocr[0].full_path()],
|
||||
depends: [qapi_doc_ref_nocr, qapi_doc_out_nocr],
|
||||
suite: ['qapi-schema', 'qapi-doc'])
|
||||
endif
|
||||
|
|
Loading…
Reference in a new issue