File plugin.py¶
File List > mkdoxy > plugin.py
Go to the documentation of this file
"""@package mkdoxy.plugin
MkDoxy → MkDocs + Doxygen = easy documentation generator with code snippets
MkDoxy is a MkDocs plugin for generating documentation from Doxygen XML files.
"""
import logging
from pathlib import Path, PurePath
from mkdocs import exceptions
from mkdocs.config import Config, base, config_options
from mkdocs.plugins import BasePlugin
from mkdocs.structure import files, pages
from mkdoxy.cache import Cache
from mkdoxy.doxygen import Doxygen
from mkdoxy.doxyrun import DoxygenRun
from mkdoxy.generatorAuto import GeneratorAuto
from mkdoxy.generatorBase import GeneratorBase
from mkdoxy.generatorSnippets import GeneratorSnippets
from mkdoxy.xml_parser import XmlParser
log: logging.Logger = logging.getLogger("mkdocs")
pluginName: str = "MkDoxy"
class MkDoxy(BasePlugin):
"""! MkDocs plugin for generating documentation from Doxygen XML files."""
# Config options for the plugin
config_scheme = (
("projects", config_options.Type(dict, default={})),
("full-doc", config_options.Type(bool, default=True)),
("debug", config_options.Type(bool, default=False)),
("ignore-errors", config_options.Type(bool, default=False)),
("save-api", config_options.Type(str, default="")),
("enabled", config_options.Type(bool, default=True)),
(
"doxygen-bin-path",
config_options.Type(str, default="doxygen", required=False),
),
)
# Config options for each project
config_project = (
("src-dirs", config_options.Type(str)),
("full-doc", config_options.Type(bool, default=True)),
("debug", config_options.Type(bool, default=False)),
# ('ignore-errors', config_options.Type(bool, default=False)),
("api-path", config_options.Type(str, default=".")),
("doxy-cfg", config_options.Type(dict, default={}, required=False)),
("doxy-cfg-file", config_options.Type(str, default="", required=False)),
("template-dir", config_options.Type(str, default="", required=False)),
)
def is_enabled(self) -> bool:
"""! Checks if the plugin is enabled
@details
@return: (bool) True if the plugin is enabled.
"""
return self.config.get("enabled")
def on_files(self, files: files.Files, config: base.Config) -> files.Files:
"""! Called after files have been gathered by MkDocs.
@details
@param files: (Files) The files gathered by MkDocs.
@param config: (Config) The global configuration object.
@return: (Files) The files gathered by MkDocs.
"""
if not self.is_enabledis_enabled():
return files
def checkConfig(config_project, proData, strict: bool):
cfg = Config(config_project, "")
cfg.load_dict(proData)
errors, warnings = cfg.validate()
for config_name, warning in warnings:
log.warning(f" -> Config value: '{config_name}' in project '{project_name}'. Warning: {warning}")
for config_name, error in errors:
log.error(f" -> Config value: '{config_name}' in project '{project_name}'. Error: {error}")
if len(errors) > 0:
raise exceptions.Abort(f"Aborted with {len(errors)} Configuration Errors!")
elif strict and len(warnings) > 0:
raise exceptions.Abort(f"Aborted with {len(warnings)} Configuration Warnings in 'strict' mode!")
def tempDir(siteDir: str, tempDir: str, projectName: str) -> str:
tempDoxyDir = PurePath.joinpath(Path(siteDir), Path(tempDir), Path(projectName))
tempDoxyDir.mkdir(parents=True, exist_ok=True)
return str(tempDoxyDir)
self.doxygendoxygen = {}
self.generatorBasegeneratorBase = {}
self.projects_config: dict[str, dict[str, any]] = self.config["projects"]
self.debugdebug = self.config.get("debug", False)
# generate automatic documentation and append files in the list of files to be processed by mkdocs
self.defaultTemplateConfig: dict = {
"indent_level": 0,
}
log.info(f"Start plugin {pluginName}")
for project_name, project_data in self.projects_config.items():
log.info(f"-> Start project '{project_name}'")
# Check project config -> raise exceptions
checkConfig(self.config_projectconfig_project, project_data, config["strict"])
if self.config.get("save-api"):
tempDirApi = tempDir("", self.config.get("save-api"), project_name)
else:
tempDirApi = tempDir(config["site_dir"], "assets/.doxy/", project_name)
# Check src changes -> run Doxygen
doxygenRun = DoxygenRun(
self.config["doxygen-bin-path"],
project_data.get("src-dirs"),
tempDirApi,
project_data.get("doxy-cfg", {}),
project_data.get("doxy-cfg-file", ""),
)
if doxygenRun.checkAndRun():
log.info(" -> generating Doxygen files")
else:
log.info(" -> skip generating Doxygen files (nothing changes)")
# Parse XML to basic structure
cache = Cache()
parser = XmlParser(cache=cache, debug=self.debugdebug)
# Parse basic structure to recursive Nodes
self.doxygendoxygen[project_name] = Doxygen(doxygenRun.getOutputFolder(), parser=parser, cache=cache)
# Print parsed files
if self.debugdebug:
self.doxygendoxygen[project_name].printStructure()
# Prepare generator for future use (GeneratorAuto, SnippetGenerator)
self.generatorBasegeneratorBase[project_name] = GeneratorBase(
project_data.get("template-dir", ""),
ignore_errors=self.config["ignore-errors"],
debug=self.debugdebug,
)
if self.config["full-doc"] and project_data.get("full-doc", True):
generatorAuto = GeneratorAuto(
generatorBase=self.generatorBasegeneratorBase[project_name],
tempDoxyDir=tempDirApi,
siteDir=config["site_dir"],
apiPath=project_data.get("api-path", project_name),
doxygen=self.doxygendoxygen[project_name],
useDirectoryUrls=config["use_directory_urls"],
)
project_config = self.defaultTemplateConfig.copy()
project_config.update(project_data)
generatorAuto.fullDoc(project_config)
generatorAuto.summary(project_config)
for file in generatorAuto.fullDocFiles:
files.append(file)
return files
def on_page_markdown(
self,
markdown: str,
page: pages.Page,
config: base.Config,
files: files.Files,
) -> str:
"""! Generate snippets and append them to the markdown.
@details
@param markdown (str): The markdown.
@param page (Page): The MkDocs page.
@param config (Config): The MkDocs config.
@param files (Files): The MkDocs files.
@return: (str) The markdown.
"""
if not self.is_enabledis_enabled():
return markdown
# update default template config with page meta
page_config = self.defaultTemplateConfig.copy()
page_config.update(page.meta)
generatorSnippets = GeneratorSnippets(
markdown=markdown,
generatorBase=self.generatorBasegeneratorBase,
doxygen=self.doxygendoxygen,
projects=self.projects_config,
useDirectoryUrls=config["use_directory_urls"],
page=page,
config=page_config,
debug=self.debugdebug,
)
return generatorSnippets.generate()
# def on_serve(self, server):
# return server
#
# def on_files(self, files: files.Files, config):
# return files
# def on_nav(self, nav, config, files):
# return nav
#
# def on_env(self, env, config, files):
# return env
#
# def on_config(self, config):
# return config
#
# def on_pre_build(self, config: base.Config):
# return
# def on_post_build(self, config):
# return
#
# def on_pre_template(self, template, template_name, config):
# return template
#
# def on_template_context(self, context, template_name, config):
# return context
#
# def on_post_template(self, output_content, template_name, config):
# return output_content
#
# def on_pre_page(self, page: pages.Page, config, files: files.Files):
# return page
#
# def on_page_read_source(self, page: pages.Page, config):
# return
#
# def on_page_markdown(self, markdown, page, config, files):
# return markdown
#
# def on_page_content(self, html, page, config, files):
# return html
#
# def on_page_context(self, context, page, config, nav):
# return context
#
# def on_post_page(self, output_content, page, config):
# return output_content