import collections
import sys
+import os
import shlex
import subprocess
import io
-import pprint
from lxml import etree
PARSER = etree.XMLParser(no_network=True,
class NoCommand(Exception):
pass
-def find_command(lines):
- acc = []
- for num, line in enumerate(lines):
- # skip empty leading line
- if num == 0 and not line:
- continue
- cont = line.endswith('\\')
- if cont:
- line = line[:-1].rstrip()
- acc.append(line if not acc else line.lstrip())
- if not cont:
- break
- joined = ' '.join(acc)
- if not joined.startswith('$ '):
- raise NoCommand
- return joined[2:], lines[:num+1] + [''], lines[-1]
-
BORING_INTERFACES = [
'org.freedesktop.DBus.Peer',
'org.freedesktop.DBus.Introspectable',
access = ACCESS_MAP.get(access, access)
print(f'''{prefix}{access} {type} {name} = {value_ellipsis(type)};''', file=file)
-def print_interface(iface, *, prefix, file, print_boring, declarations):
+def print_interface(iface, *, prefix, file, print_boring, only_interface, declarations):
name = iface.get('name')
- is_boring = name in BORING_INTERFACES
+ is_boring = (name in BORING_INTERFACES or
+ only_interface is not None and name != only_interface)
+
if is_boring and print_boring:
print(f'''{prefix}interface {name} {{ ... }};''', file=file)
+
elif not is_boring and not print_boring:
print(f'''{prefix}interface {name} {{''', file=file)
prefix2 = prefix + ' '
return missing
-def xml_to_text(destination, xml):
+def xml_to_text(destination, xml, *, only_interface=None):
file = io.StringIO()
declarations = collections.defaultdict(list)
+ interfaces = []
print(f'''node {destination} {{''', file=file)
for iface in xml.findall('./interface'):
print_interface(iface, prefix=' ', file=file,
print_boring=print_boring,
+ only_interface=only_interface,
declarations=declarations)
+ name = iface.get('name')
+ if not name in BORING_INTERFACES:
+ interfaces.append(name)
print(f'''}};''', file=file)
- return file.getvalue(), declarations
+ return file.getvalue(), declarations, interfaces
def subst_output(document, programlisting):
- try:
- cmd, prefix_lines, footer = find_command(programlisting.text.splitlines())
- except NoCommand:
+ executable = programlisting.get('executable', None)
+ if executable is None:
+ # Not our thing
return
+ executable = programlisting.get('executable')
+ node = programlisting.get('node')
+ interface = programlisting.get('interface')
- argv = shlex.split(cmd)
- argv += ['--xml']
+ argv = [f'{build_dir}/{executable}', f'--bus-introspect={interface}']
print(f'COMMAND: {shlex.join(argv)}')
- object_idx = argv.index('--object-path')
- object_path = argv[object_idx + 1]
-
try:
out = subprocess.check_output(argv, text=True)
- except subprocess.CalledProcessError:
- print('command failed, ignoring', file=sys.stderr)
+ except FileNotFoundError:
+ print(f'{executable} not found, ignoring', file=sys.stderr)
return
xml = etree.fromstring(out, parser=PARSER)
- new_text, declarations = xml_to_text(object_path, xml)
-
- programlisting.text = '\n'.join(prefix_lines) + '\n' + new_text + footer
+ new_text, declarations, interfaces = xml_to_text(node, xml, only_interface=interface)
+ programlisting.text = '\n' + new_text + ' '
if declarations:
missing = check_documented(document, declarations)
# delete old comments
for child in parent:
+ if (child.tag == etree.Comment
+ and 'Autogenerated' in child.text):
+ parent.remove(child)
if (child.tag == etree.Comment
and 'not documented' in child.text):
parent.remove(child)
+ if (child.tag == "variablelist"
+ and child.attrib.get("generated",False) == "True"):
+ parent.remove(child)
+
+ # insert pointer for systemd-directives generation
+ the_tail = programlisting.tail #tail is erased by addnext, so save it here.
+ prev_element = etree.Comment("Autogenerated cross-references for systemd.directives, do not edit")
+ programlisting.addnext(prev_element)
+ programlisting.tail = the_tail
+
+ for interface in interfaces:
+ variablelist = etree.Element("variablelist")
+ variablelist.attrib['class'] = 'dbus-interface'
+ variablelist.attrib['generated'] = 'True'
+ variablelist.attrib['extra-ref'] = interface
+
+ prev_element.addnext(variablelist)
+ prev_element.tail = the_tail
+ prev_element = variablelist
+
+ for decl_type,decl_list in declarations.items():
+ for declaration in decl_list:
+ variablelist = etree.Element("variablelist")
+ variablelist.attrib['class'] = 'dbus-'+decl_type
+ variablelist.attrib['generated'] = 'True'
+ if decl_type == 'method' :
+ variablelist.attrib['extra-ref'] = declaration + '()'
+ else:
+ variablelist.attrib['extra-ref'] = declaration
+
+ prev_element.addnext(variablelist)
+ prev_element.tail = the_tail
+ prev_element = variablelist
+
+ last_element = etree.Comment("End of Autogenerated section")
+ prev_element.addnext(last_element)
+ prev_element.tail = the_tail
+ last_element.tail = the_tail
# insert comments for undocumented items
for item in reversed(missing):
subst_output(xml, pl)
out_text = etree.tostring(xml, encoding='unicode')
- # massage format to avoid some lxml whitespace handling idiosyncracies
+ # massage format to avoid some lxml whitespace handling idiosyncrasies
# https://bugs.launchpad.net/lxml/+bug/526799
out_text = (src[:src.find('<refentryinfo')] +
out_text[out_text.find('<refentryinfo'):] +
if __name__ == '__main__':
pages = sys.argv[1:]
+ if pages[0].startswith('--build-dir='):
+ build_dir = pages[0].partition('=')[2]
+ pages = pages[1:]
+ else:
+ build_dir = 'build'
+
+ if not os.path.exists(f'{build_dir}/systemd'):
+ exit(f"{build_dir}/systemd doesn't exist. Use --build-dir=.")
+
for page in pages:
process(page)