diff --git a/conf/modules/boards/index.rst b/conf/modules/boards/index.rst new file mode 100644 index 0000000000..0a225c3e47 --- /dev/null +++ b/conf/modules/boards/index.rst @@ -0,0 +1,10 @@ + +Boards +====== + +.. toctree:: + :maxdepth: 1 + :glob: + + ./* + diff --git a/conf/modules/firmwares/index.rst b/conf/modules/firmwares/index.rst new file mode 100644 index 0000000000..21b13adbea --- /dev/null +++ b/conf/modules/firmwares/index.rst @@ -0,0 +1,9 @@ + +Firmwares +========= + +.. toctree:: + :maxdepth: 1 + :glob: + + ./* diff --git a/conf/modules/index.rst b/conf/modules/index.rst new file mode 100644 index 0000000000..7381b50e4a --- /dev/null +++ b/conf/modules/index.rst @@ -0,0 +1,12 @@ + +Modules +======= + +.. toctree:: + :maxdepth: 1 + :glob: + + boards/index + firmwares/index.rst + targets/index.rst + ./* diff --git a/conf/modules/targets/index.rst b/conf/modules/targets/index.rst new file mode 100644 index 0000000000..4c37563ceb --- /dev/null +++ b/conf/modules/targets/index.rst @@ -0,0 +1,9 @@ + +Targets +======= + +.. toctree:: + :maxdepth: 1 + :glob: + + ./* diff --git a/conf/modules/time_countdown.xml b/conf/modules/time_countdown.xml index 4d1f756f30..98617b8fe4 100644 --- a/conf/modules/time_countdown.xml +++ b/conf/modules/time_countdown.xml @@ -1,4 +1,3 @@ - diff --git a/doc/sphinx/source/conf.py b/doc/sphinx/source/conf.py index 5ee07a2fc1..a722165b3c 100644 --- a/doc/sphinx/source/conf.py +++ b/doc/sphinx/source/conf.py @@ -17,7 +17,9 @@ # documentation root, use os.path.abspath to make it absolute, like shown here. # # import os -# import sys +import sys +sys.path.insert(0, "../../sw/tools/modules_doc") + # sys.path.insert(0, os.path.abspath('.')) # -- General configuration ------------------------------------------------ @@ -35,6 +37,7 @@ extensions = [ 'sphinx.ext.todo', 'sphinx.ext.viewcode', 'sphinx.ext.githubpages', + 'modules_parser', ] # Add any paths that contain templates here, relative to this directory. diff --git a/doc/sphinx/source/index.rst b/doc/sphinx/source/index.rst index 68f0060c5e..b44d10e37b 100644 --- a/doc/sphinx/source/index.rst +++ b/doc/sphinx/source/index.rst @@ -33,6 +33,7 @@ Contents: developer_guide/index_developer tutorials/index_tutorials support/index_support + modules/index.rst -------------- diff --git a/doc/sphinx/source/modules b/doc/sphinx/source/modules new file mode 120000 index 0000000000..8c0fd1fcff --- /dev/null +++ b/doc/sphinx/source/modules @@ -0,0 +1 @@ +../../../conf/modules/ \ No newline at end of file diff --git a/sw/tools/modules_doc/modules_parser.py b/sw/tools/modules_doc/modules_parser.py new file mode 100644 index 0000000000..ce4e7e2243 --- /dev/null +++ b/sw/tools/modules_doc/modules_parser.py @@ -0,0 +1,157 @@ +from sphinx.application import Sphinx +from sphinx.parsers import Parser +from typing import Dict, Any, List +from sphinx import addnodes, errors +from sphinx.parsers import RSTParser +from docutils import nodes +from lxml import etree as ET +from dataclasses import dataclass + + +class Define: + def __init__(self, xml: ET._Element): + self.name = xml.attrib["name"] + self.value = xml.get("value", "") + self.description = xml.get("description", "") + + +class Section: + def __init__(self, xml: ET._Element): + self.name = xml.attrib["name"] + self.prefix = xml.attrib.get("prefix") + self.defines = [Define(x) for x in xml.findall("define")] + + +class ModuleParser: + def __init__(self, inputstring): + root = ET.fromstring(inputstring) + self.name = root.attrib["name"] # name required + # self.dir = root.attrib["dir"] # dir optional!!! + edoc = root.find("doc") # doc required + self.description = edoc.find("description").text # description required + self.configures = [Define(xml) for xml in edoc.findall("configure")] + self.defines = [Define(xml) for xml in edoc.findall("define")] + self.sections = [Section(xml) for xml in edoc.findall("section")] + self.depends = [] + self.conflicts = [] + self.provides = [] + edep = root.find("dep") # type: ET._Element + if edep is not None: + edepends = edep.find("depends") # type: ET._Element + if edepends is not None: + self.depends = edepends.text.split(",") + eprovides = edep.find("provides") + if eprovides is not None: + self.provides = eprovides.text.split(",") + econflicts = edep.find("conflicts") + if econflicts is not None: + self.conflicts = econflicts.text.split(",") + + +class ModuleDoc(Parser): + + supported = ("pprz_module", "xml") + + def make_table_row(self, *args, colwidth=[]): + row = nodes.row() + for i, arg in enumerate(args): + if len(colwidth) > i: + entry = nodes.entry(morecols=colwidth[i]-1) + else: + entry = nodes.entry() + entry += nodes.paragraph(text=arg) + row += entry + return row + + def define_to_table(self, defines, title, section_row=None): + t = nodes.table() + t += nodes.title(text=title) + tgroup = nodes.tgroup(cols=3) + for _ in range(3): + colspec = nodes.colspec(colwidth=1) + tgroup.append(colspec) + rows = [] + + header_row = self.make_table_row("Name", "Value", "Description") + nt = nodes.thead() + if section_row is not None: + nt += section_row + nt += header_row + tgroup += nt + + for define in defines: + row = self.make_table_row(define.name, define.value, define.description) + rows.append(row) + tbody = nodes.tbody() + tbody.extend(rows) + tgroup += tbody + t += tgroup + return t + + def make_section(self, title): + section = nodes.section() + section += nodes.title(text=title) + section["ids"].append(title) + return section + + def make_list(self, args): + dl = nodes.bullet_list() + for arg in args: + item = nodes.list_item() + txt = nodes.Text(arg) + item += txt + dl += item + return dl + + def parse(self, inputstring: str, document: addnodes.document): + self.setup_parse(inputstring, document) + try: + m = ModuleParser(inputstring) + except: + # print(document.source, document.current_source) + print(document.reporter.warning("test")) + # print(document.transformer) + self.finish_parse() + return + pass + + root = self.make_section(m.name) + + # description + root.append(nodes.paragraph(text=m.description)) + + if len(m.configures) > 0: + root += self.define_to_table(m.configures, "Configures") + if len(m.defines) > 0: + header_row = self.make_table_row("Defines", colwidth=[3]) + root += self.define_to_table(m.defines, "Defines") + if len(m.sections) > 0: + for s in m.sections: + header_row = self.make_table_row("{}".format(s.prefix), colwidth=[3]) + root += self.define_to_table(s.defines, "Section {}".format(s.name), header_row) + if len(m.depends) > 0: + ds = self.make_section("Depends") + ds.append(self.make_list(m.depends)) + root.append(ds) + if len(m.provides) > 0: + ds = self.make_section("Provides") + ds.append(self.make_list(m.provides)) + + root.append(ds) + if len(m.conflicts) > 0: + ds = self.make_section("Conflicts") + ds.append(self.make_list(m.conflicts)) + root.append(ds) + + if len(m.sections) > 0: + ds = self.make_section("Sections") + + root.append(ds) + + document.append(root) + self.finish_parse() + + +def setup(app: "Sphinx") -> Dict[str, Any]: + app.add_source_suffix(".xml", "pprz_module") + app.add_source_parser(ModuleDoc)