qemu

Форк
0
/
dbusdoc.py 
166 строк · 5.2 Кб
1
# D-Bus XML documentation extension
2
#
3
# Copyright (C) 2021, Red Hat Inc.
4
#
5
# SPDX-License-Identifier: LGPL-2.1-or-later
6
#
7
# Author: Marc-André Lureau <marcandre.lureau@redhat.com>
8
"""dbus-doc is a Sphinx extension that provides documentation from D-Bus XML."""
9

10
import os
11
import re
12
from typing import (
13
    TYPE_CHECKING,
14
    Any,
15
    Callable,
16
    Dict,
17
    Iterator,
18
    List,
19
    Optional,
20
    Sequence,
21
    Set,
22
    Tuple,
23
    Type,
24
    TypeVar,
25
    Union,
26
)
27

28
import sphinx
29
from docutils import nodes
30
from docutils.nodes import Element, Node
31
from docutils.parsers.rst import Directive, directives
32
from docutils.parsers.rst.states import RSTState
33
from docutils.statemachine import StringList, ViewList
34
from sphinx.application import Sphinx
35
from sphinx.errors import ExtensionError
36
from sphinx.util import logging
37
from sphinx.util.docstrings import prepare_docstring
38
from sphinx.util.docutils import SphinxDirective, switch_source_input
39
from sphinx.util.nodes import nested_parse_with_titles
40

41
import dbusdomain
42
from dbusparser import parse_dbus_xml
43

44
logger = logging.getLogger(__name__)
45

46
__version__ = "1.0"
47

48

49
class DBusDoc:
50
    def __init__(self, sphinx_directive, dbusfile):
51
        self._cur_doc = None
52
        self._sphinx_directive = sphinx_directive
53
        self._dbusfile = dbusfile
54
        self._top_node = nodes.section()
55
        self.result = StringList()
56
        self.indent = ""
57

58
    def add_line(self, line: str, *lineno: int) -> None:
59
        """Append one line of generated reST to the output."""
60
        if line.strip():  # not a blank line
61
            self.result.append(self.indent + line, self._dbusfile, *lineno)
62
        else:
63
            self.result.append("", self._dbusfile, *lineno)
64

65
    def add_method(self, method):
66
        self.add_line(f".. dbus:method:: {method.name}")
67
        self.add_line("")
68
        self.indent += "   "
69
        for arg in method.in_args:
70
            self.add_line(f":arg {arg.signature} {arg.name}: {arg.doc_string}")
71
        for arg in method.out_args:
72
            self.add_line(f":ret {arg.signature} {arg.name}: {arg.doc_string}")
73
        self.add_line("")
74
        for line in prepare_docstring("\n" + method.doc_string):
75
            self.add_line(line)
76
        self.indent = self.indent[:-3]
77

78
    def add_signal(self, signal):
79
        self.add_line(f".. dbus:signal:: {signal.name}")
80
        self.add_line("")
81
        self.indent += "   "
82
        for arg in signal.args:
83
            self.add_line(f":arg {arg.signature} {arg.name}: {arg.doc_string}")
84
        self.add_line("")
85
        for line in prepare_docstring("\n" + signal.doc_string):
86
            self.add_line(line)
87
        self.indent = self.indent[:-3]
88

89
    def add_property(self, prop):
90
        self.add_line(f".. dbus:property:: {prop.name}")
91
        self.indent += "   "
92
        self.add_line(f":type: {prop.signature}")
93
        access = {"read": "readonly", "write": "writeonly", "readwrite": "readwrite"}[
94
            prop.access
95
        ]
96
        self.add_line(f":{access}:")
97
        if prop.emits_changed_signal:
98
            self.add_line(f":emits-changed: yes")
99
        self.add_line("")
100
        for line in prepare_docstring("\n" + prop.doc_string):
101
            self.add_line(line)
102
        self.indent = self.indent[:-3]
103

104
    def add_interface(self, iface):
105
        self.add_line(f".. dbus:interface:: {iface.name}")
106
        self.add_line("")
107
        self.indent += "   "
108
        for line in prepare_docstring("\n" + iface.doc_string):
109
            self.add_line(line)
110
        for method in iface.methods:
111
            self.add_method(method)
112
        for sig in iface.signals:
113
            self.add_signal(sig)
114
        for prop in iface.properties:
115
            self.add_property(prop)
116
        self.indent = self.indent[:-3]
117

118

119
def parse_generated_content(state: RSTState, content: StringList) -> List[Node]:
120
    """Parse a generated content by Documenter."""
121
    with switch_source_input(state, content):
122
        node = nodes.paragraph()
123
        node.document = state.document
124
        state.nested_parse(content, 0, node)
125

126
        return node.children
127

128

129
class DBusDocDirective(SphinxDirective):
130
    """Extract documentation from the specified D-Bus XML file"""
131

132
    has_content = True
133
    required_arguments = 1
134
    optional_arguments = 0
135
    final_argument_whitespace = True
136

137
    def run(self):
138
        reporter = self.state.document.reporter
139

140
        try:
141
            source, lineno = reporter.get_source_and_line(self.lineno)  # type: ignore
142
        except AttributeError:
143
            source, lineno = (None, None)
144

145
        logger.debug("[dbusdoc] %s:%s: input:\n%s", source, lineno, self.block_text)
146

147
        env = self.state.document.settings.env
148
        dbusfile = env.config.qapidoc_srctree + "/" + self.arguments[0]
149
        with open(dbusfile, "rb") as f:
150
            xml_data = f.read()
151
        xml = parse_dbus_xml(xml_data)
152
        doc = DBusDoc(self, dbusfile)
153
        for iface in xml:
154
            doc.add_interface(iface)
155

156
        result = parse_generated_content(self.state, doc.result)
157
        return result
158

159

160
def setup(app: Sphinx) -> Dict[str, Any]:
161
    """Register dbus-doc directive with Sphinx"""
162
    app.add_config_value("dbusdoc_srctree", None, "env")
163
    app.add_directive("dbus-doc", DBusDocDirective)
164
    dbusdomain.setup(app)
165

166
    return dict(version=__version__, parallel_read_safe=True, parallel_write_safe=True)
167

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.