mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
doc: generate man-pages also for pipewire modules
Use pandoc + some processing to convert Doxygen html output to man pages. Requires pandoc & python for building. Generates manpages: libpipewire-modules.7, libpipewire-module-*.7
This commit is contained in:
parent
62f69581bf
commit
21854f24a5
7 changed files with 265 additions and 0 deletions
|
|
@ -166,3 +166,33 @@ html_target = custom_target('pipewire-docs',
|
||||||
command: [ doxygen, doxyfile ],
|
command: [ doxygen, doxyfile ],
|
||||||
install: true,
|
install: true,
|
||||||
install_dir: docdir)
|
install_dir: docdir)
|
||||||
|
|
||||||
|
|
||||||
|
if generate_module_manpages
|
||||||
|
module_man_rst_py = meson.project_source_root() / 'doc' / 'module-man-rst.py'
|
||||||
|
module_man_defines = []
|
||||||
|
foreach m : manpage_conf.keys()
|
||||||
|
if m != 'LIBPIPEWIRE_MODULES'
|
||||||
|
module_man_defines += ['-D', m, manpage_conf.get(m)]
|
||||||
|
endif
|
||||||
|
endforeach
|
||||||
|
|
||||||
|
foreach m : module_sources
|
||||||
|
name = m.split('.c').get(0)
|
||||||
|
file = 'libpipewire-' + name + '.7'
|
||||||
|
|
||||||
|
rst = custom_target(file + '.rst',
|
||||||
|
command : [python, module_man_rst_py, pandoc, name, '@INPUT@' ] + module_man_defines,
|
||||||
|
input : [ html_target ],
|
||||||
|
depend_files : [ module_man_rst_py ],
|
||||||
|
output : file + '.rst',
|
||||||
|
capture : true
|
||||||
|
)
|
||||||
|
custom_target(file,
|
||||||
|
output : file,
|
||||||
|
input : rst,
|
||||||
|
command : [rst2man, '@INPUT@', '@OUTPUT@'],
|
||||||
|
install : true,
|
||||||
|
install_dir : get_option('mandir') / 'man7')
|
||||||
|
endforeach
|
||||||
|
endif
|
||||||
|
|
|
||||||
159
doc/module-man-rst.py
Normal file
159
doc/module-man-rst.py
Normal file
|
|
@ -0,0 +1,159 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
"""
|
||||||
|
Convert Doxygen HTML documentation for a PipeWire module to RST.
|
||||||
|
"""
|
||||||
|
import argparse
|
||||||
|
import html, html.parser
|
||||||
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
from subprocess import check_output
|
||||||
|
|
||||||
|
TEMPLATE = """
|
||||||
|
{name}
|
||||||
|
{name_underline}
|
||||||
|
|
||||||
|
{subtitle_underline}
|
||||||
|
{subtitle}
|
||||||
|
{subtitle_underline}
|
||||||
|
|
||||||
|
:Manual section: 7
|
||||||
|
:Manual group: PipeWire
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
-----------
|
||||||
|
|
||||||
|
{content}
|
||||||
|
|
||||||
|
AUTHORS
|
||||||
|
-------
|
||||||
|
|
||||||
|
The PipeWire Developers <{PACKAGE_BUGREPORT}>;
|
||||||
|
PipeWire is available from {PACKAGE_URL}
|
||||||
|
|
||||||
|
SEE ALSO
|
||||||
|
--------
|
||||||
|
|
||||||
|
``pipewire(1)``,
|
||||||
|
``pipewire.conf(5)``,
|
||||||
|
``libpipewire-modules(7)``
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
p = argparse.ArgumentParser(description=__doc__.strip())
|
||||||
|
p.add_argument(
|
||||||
|
"-D",
|
||||||
|
"--define",
|
||||||
|
nargs=2,
|
||||||
|
action="append",
|
||||||
|
dest="define",
|
||||||
|
default=[],
|
||||||
|
)
|
||||||
|
p.add_argument("pandoc")
|
||||||
|
p.add_argument("module")
|
||||||
|
p.add_argument("htmldir", type=Path)
|
||||||
|
args = p.parse_args()
|
||||||
|
|
||||||
|
page = args.module.lower().replace("-", "_")
|
||||||
|
src = args.htmldir / f"page_{page}.html"
|
||||||
|
|
||||||
|
# Pick content block only
|
||||||
|
parser = DoxyParser()
|
||||||
|
with open(src, "r") as f:
|
||||||
|
parser.feed(f.read())
|
||||||
|
data = "".join(parser.content)
|
||||||
|
|
||||||
|
# Produce output
|
||||||
|
content = check_output(
|
||||||
|
[args.pandoc, "-f", "html", "-t", "rst"], input=data, encoding="utf-8"
|
||||||
|
)
|
||||||
|
|
||||||
|
if not content.strip():
|
||||||
|
content = "Undocumented."
|
||||||
|
|
||||||
|
name = f"libpipewire-{args.module}"
|
||||||
|
subtitle = "PipeWire module"
|
||||||
|
|
||||||
|
env = dict(
|
||||||
|
content=content,
|
||||||
|
name=name,
|
||||||
|
name_underline="#" * len(name),
|
||||||
|
subtitle=subtitle,
|
||||||
|
subtitle_underline="-" * len(subtitle),
|
||||||
|
)
|
||||||
|
|
||||||
|
for k, v in args.define:
|
||||||
|
env[k] = v
|
||||||
|
|
||||||
|
print(TEMPLATE.format(**env))
|
||||||
|
|
||||||
|
|
||||||
|
def replace_pw_key(key):
|
||||||
|
key = key.lower().replace("_", ".")
|
||||||
|
if key in ("protocol", "access", "client.access") or key.startswith("sec."):
|
||||||
|
return f"pipewire.{key}"
|
||||||
|
return key
|
||||||
|
|
||||||
|
|
||||||
|
class DoxyParser(html.parser.HTMLParser):
|
||||||
|
"""
|
||||||
|
Capture div.textblock, and:
|
||||||
|
- Convert div.fragment to pre
|
||||||
|
- Convert a[@href="page_module_XXX.html"] to <tt>libpipewire-module-xxx(7)</tt>
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.content = []
|
||||||
|
self.stack = []
|
||||||
|
|
||||||
|
def feed(self, data):
|
||||||
|
try:
|
||||||
|
super().feed(data)
|
||||||
|
except EOFError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def handle_starttag(self, tag, attrs):
|
||||||
|
attrs = dict(attrs)
|
||||||
|
|
||||||
|
if self.stack:
|
||||||
|
if self.stack[-1] is None:
|
||||||
|
self.stack.append(None)
|
||||||
|
return
|
||||||
|
|
||||||
|
if tag == "div" and attrs.get("class") == "fragment":
|
||||||
|
tag = "pre"
|
||||||
|
attrs = dict()
|
||||||
|
elif tag == "a" and attrs.get("href").startswith("page_module_"):
|
||||||
|
module = attrs["href"].replace("page_module_", "libpipewire-module-")
|
||||||
|
module = module.replace(".html", "").replace("_", "-")
|
||||||
|
self.content.append(f"<tt>{module}(7)</tt>")
|
||||||
|
self.stack.append(None)
|
||||||
|
return
|
||||||
|
|
||||||
|
attrstr = " ".join(f'{k}="{html.escape(v)}"' for k, v in attrs.items())
|
||||||
|
self.content.append(f"<{tag} {attrstr}>")
|
||||||
|
self.stack.append(tag)
|
||||||
|
elif tag == "div" and attrs.get("class") == "textblock":
|
||||||
|
self.stack.append(tag)
|
||||||
|
|
||||||
|
def handle_endtag(self, tag):
|
||||||
|
if len(self.stack) == 1:
|
||||||
|
raise EOFError()
|
||||||
|
elif self.stack:
|
||||||
|
otag = self.stack.pop()
|
||||||
|
if otag is not None:
|
||||||
|
self.content.append(f"</{otag}>")
|
||||||
|
|
||||||
|
def handle_data(self, data):
|
||||||
|
if self.stack and self.stack[-1] is not None:
|
||||||
|
if self.stack[-1] == "a":
|
||||||
|
m = re.match(r"^(PW|SPA)_KEY_([A-Z_]+)$", data)
|
||||||
|
if m:
|
||||||
|
data = replace_pw_key(m.group(2))
|
||||||
|
|
||||||
|
self.content.append(html.escape(data))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
56
man/libpipewire-modules.7.rst.in
Normal file
56
man/libpipewire-modules.7.rst.in
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
libpipewire-modules
|
||||||
|
###################
|
||||||
|
|
||||||
|
----------------
|
||||||
|
PipeWire modules
|
||||||
|
----------------
|
||||||
|
|
||||||
|
:Manual section: 7
|
||||||
|
:Manual group: PipeWire
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
===========
|
||||||
|
|
||||||
|
A PipeWire module is effectively a PipeWire client running inside
|
||||||
|
``pipewire(1)`` which can host multiple modules. Usually modules are
|
||||||
|
loaded when they are listed in the configuration files. For example
|
||||||
|
the default configuration file loads several modules:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
context.modules = [
|
||||||
|
...
|
||||||
|
# The native communication protocol.
|
||||||
|
{ name = libpipewire-module-protocol-native }
|
||||||
|
|
||||||
|
# The profile module. Allows application to access profiler
|
||||||
|
# and performance data. It provides an interface that is used
|
||||||
|
# by pw-top and pw-profiler.
|
||||||
|
{ name = libpipewire-module-profiler }
|
||||||
|
|
||||||
|
# Allows applications to create metadata objects. It creates
|
||||||
|
# a factory for Metadata objects.
|
||||||
|
{ name = libpipewire-module-metadata }
|
||||||
|
|
||||||
|
# Creates a factory for making devices that run in the
|
||||||
|
# context of the PipeWire server.
|
||||||
|
{ name = libpipewire-module-spa-device-factory }
|
||||||
|
...
|
||||||
|
]
|
||||||
|
|
||||||
|
KNOWN MODULES
|
||||||
|
=============
|
||||||
|
|
||||||
|
- @LIBPIPEWIRE_MODULES@
|
||||||
|
|
||||||
|
AUTHORS
|
||||||
|
=======
|
||||||
|
|
||||||
|
The PipeWire Developers <@PACKAGE_BUGREPORT@>; PipeWire is available from @PACKAGE_URL@
|
||||||
|
|
||||||
|
SEE ALSO
|
||||||
|
========
|
||||||
|
|
||||||
|
``pipewire(1)``,
|
||||||
|
``pipewire.conf(5)``,
|
||||||
|
|
||||||
|
|
@ -6,6 +6,14 @@ manpage_conf.set('PACKAGE_BUGREPORT', 'https://gitlab.freedesktop.org/pipewire/p
|
||||||
manpage_conf.set('PIPEWIRE_CONFIG_DIR', pipewire_configdir)
|
manpage_conf.set('PIPEWIRE_CONFIG_DIR', pipewire_configdir)
|
||||||
manpage_conf.set('PIPEWIRE_CONFDATADIR', pipewire_confdatadir)
|
manpage_conf.set('PIPEWIRE_CONFDATADIR', pipewire_confdatadir)
|
||||||
|
|
||||||
|
module_manpage_list = []
|
||||||
|
foreach m : module_sources
|
||||||
|
name = m.split('.c').get(0)
|
||||||
|
module_manpage_list += ['``libpipewire-' + name + '(7)``']
|
||||||
|
endforeach
|
||||||
|
|
||||||
|
manpage_conf.set('LIBPIPEWIRE_MODULES', '\n- '.join(module_manpage_list))
|
||||||
|
|
||||||
manpages = [
|
manpages = [
|
||||||
'pipewire.1.rst.in',
|
'pipewire.1.rst.in',
|
||||||
'pipewire-pulse.1.rst.in',
|
'pipewire-pulse.1.rst.in',
|
||||||
|
|
@ -22,6 +30,7 @@ manpages = [
|
||||||
'pw-mon.1.rst.in',
|
'pw-mon.1.rst.in',
|
||||||
'pw-profiler.1.rst.in',
|
'pw-profiler.1.rst.in',
|
||||||
'pw-top.1.rst.in',
|
'pw-top.1.rst.in',
|
||||||
|
'libpipewire-modules.7.rst.in',
|
||||||
]
|
]
|
||||||
|
|
||||||
if get_option('pipewire-jack').allowed()
|
if get_option('pipewire-jack').allowed()
|
||||||
|
|
|
||||||
|
|
@ -52,3 +52,4 @@ SEE ALSO
|
||||||
``pw-mon(1)``,
|
``pw-mon(1)``,
|
||||||
``pw-cat(1)``,
|
``pw-cat(1)``,
|
||||||
``pw-cli(1)``,
|
``pw-cli(1)``,
|
||||||
|
``libpipewire-modules(7)``,
|
||||||
|
|
|
||||||
|
|
@ -110,3 +110,4 @@ SEE ALSO
|
||||||
|
|
||||||
``pipewire(1)``,
|
``pipewire(1)``,
|
||||||
``pw-mon(1)``,
|
``pw-mon(1)``,
|
||||||
|
``libpipewire-modules(7)``,
|
||||||
|
|
|
||||||
|
|
@ -501,6 +501,15 @@ subdir('man')
|
||||||
|
|
||||||
doxygen = find_program('doxygen', required : get_option('docs'))
|
doxygen = find_program('doxygen', required : get_option('docs'))
|
||||||
if doxygen.found()
|
if doxygen.found()
|
||||||
|
generate_module_manpages = get_option('docs').enabled() and get_option('man').enabled()
|
||||||
|
if generate_manpages
|
||||||
|
pymod = import('python')
|
||||||
|
python = pymod.find_installation('python3', required: generate_module_manpages)
|
||||||
|
pandoc = find_program('pandoc', required: generate_module_manpages)
|
||||||
|
generate_module_manpages = python.found() and pandoc.found()
|
||||||
|
endif
|
||||||
|
summary({'Module manpage generation': generate_module_manpages}, bool_yn: true)
|
||||||
|
|
||||||
subdir('doc')
|
subdir('doc')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue