Skip to content

Commit 4a57265

Browse files
committed
To review
1 parent fefb698 commit 4a57265

File tree

10 files changed

+268
-76
lines changed

10 files changed

+268
-76
lines changed

mkdocs.yml

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,23 @@ theme:
2525
repo: fontawesome/brands/github
2626

2727
palette:
28-
- scheme: slate
28+
# Palette toggle for dark mode
29+
- media: "(prefers-color-scheme: dark)"
30+
scheme: slate
2931
primary: orange
3032
accent: orange
33+
toggle:
34+
icon: material/brightness-4
35+
name: Switch to light mode
36+
37+
# Palette toggle for light mode
38+
- media: "(prefers-color-scheme: light)"
39+
scheme: default
40+
primary: orange
41+
accent: orange
42+
toggle:
43+
icon: material/brightness-7
44+
name: Switch to dark mode
3145

3246
extra:
3347
social:
@@ -61,7 +75,7 @@ plugins:
6175
- search
6276
- open-in-new-tab
6377
- mkdoxy:
64-
enabled: !ENV [ENABLE_MKDOXY, True]
78+
enabled: !ENV [ ENABLE_MKDOXY, True ]
6579
projects:
6680
mkdoxyApi:
6781
src_dirs: mkdoxy
@@ -75,14 +89,19 @@ plugins:
7589
OPTIMIZE_OUTPUT_JAVA: True
7690
JAVADOC_AUTOBRIEF: True
7791
EXTRACT_ALL: True
92+
DOT_IMAGE_FORMAT: svg
93+
HAVE_DOT: YES
7894
animal:
7995
src_dirs: demo-projects/animal
8096
full_doc: True
8197
doxy_cfg:
8298
FILE_PATTERNS: "*.cpp *.h*"
8399
EXAMPLE_PATH: examples
84100
RECURSIVE: True
101+
DOT_IMAGE_FORMAT: svg
102+
HAVE_DOT: YES
85103
custom_api_folder: .mkdoxy
104+
86105
full_doc: True
87106
debug: False
88107
# ignore_errors: False

mkdoxy/doxy_config.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,20 @@
1616
("debug", c.Type(bool, default=False)),
1717
("ignore-errors", c.Type(bool, default=None, required=False)), # legacy option
1818
("ignore_errors", c.Type(bool, default=False)),
19+
20+
# Custom API folder for Doxygen and MD output
1921
("save-api", c.Type(str, default=None, required=False)), # legacy option
2022
("custom_api_folder", c.Type(str, default="")),
21-
("doxygen-bin-path", c.Type(str, default=None, required=False)), # legacy option
22-
("doxygen_bin_path", c.Type(str, default="doxygen", required=False)),
23+
24+
# Doxygen
25+
("doxygen-bin-path", c.Type(Path, default=None, required=False)), # legacy option
26+
("doxygen_bin_path", c.Type(Path, default=Path("doxygen"), required=False)),
27+
28+
# Diagrams
29+
("generate_diagrams", c.Type(bool, default=True, required=False)),
30+
# one of the following: svg, png, jpg, gif
31+
("generate_diagrams_format", c.Choice(("svg", "png", "jpg", "gif"), default="svg")),
32+
("generate_diagrams_type", c.Choice(("dot", "uml"), default="dot")),
2333
)
2434
config_scheme_legacy = {
2535
"full-doc": "full_doc",
@@ -93,7 +103,11 @@ class MkDoxyConfig(Config):
93103
debug = c.Type(bool, default=False) # debug mode
94104
ignore_errors = c.Type(bool, default=False) # ignore errors
95105
custom_api_folder = c.Optional(c.Type(str)) # custom API folder for Doxygen and MD output (default in temp folder)
96-
doxygen_bin_path = c.Type(str, default="doxygen") # path to Doxygen binary - default "doxygen"
106+
doxygen_bin_path = c.Type(Path, default=Path("doxygen")) # path to Doxygen binary (default "doxygen"
107+
108+
generate_diagrams = c.Type(bool, default=False) # generate diagrams
109+
generate_diagrams_format = c.Choice(("svg", "png", "jpg", "gif"), default="svg") # diagram format
110+
generate_diagrams_type = c.Choice(("dot", "uml"), default="dot") # diagram type
97111

98112

99113
def load_config_by_key(key: str, legacy_key: str, config: Config, legacy: list) -> any:
@@ -127,6 +141,10 @@ def process_configuration(config: Config) -> MkDoxyConfig:
127141
doxy_config.custom_api_folder = load_config_by_key("custom_api_folder", "save-api", config, legacy_options)
128142
doxy_config.doxygen_bin_path = load_config_by_key("doxygen_bin_path", "doxygen-bin-path", config, legacy_options)
129143

144+
doxy_config.generate_diagrams = config.get("generate_diagrams")
145+
doxy_config.generate_diagrams_format = config.get("generate_diagrams_format")
146+
doxy_config.generate_diagrams_type = config.get("generate_diagrams_type")
147+
130148
# Validate the global configuration
131149
validate_project_config(doxy_config, legacy_options)
132150

mkdoxy/doxygen_generator.py

Lines changed: 68 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
import shutil
55
from pathlib import Path
66
from subprocess import PIPE, Popen
7-
from typing import Optional
87

98
from mkdocs import exceptions
109

10+
from mkdoxy.doxy_config import MkDoxyConfig, MkDoxyConfigProject
11+
1112
log: logging.Logger = logging.getLogger("mkdocs")
1213

1314

@@ -17,12 +18,10 @@ class DoxygenGenerator:
1718
"""
1819

1920
def __init__(
20-
self,
21-
doxygen_bin_path: Path,
22-
doxygen_source_dirs: str,
23-
temp_doxy_folder: Path,
24-
doxy_config_file: Optional[Path] = None,
25-
doxy_config_dict: dict = None,
21+
self,
22+
doxy_config: MkDoxyConfig,
23+
project_config: MkDoxyConfigProject,
24+
temp_doxy_folder: Path,
2625
):
2726
"""! Constructor.
2827
Default Doxygen config options:
@@ -38,30 +37,24 @@ def __init__(
3837
- GENERATE_LATEX: NO
3938
4039
@details
41-
@param doxygen_bin_path: (str) Path to the Doxygen binary.
42-
@param doxygen_source_dirs: (str) Source files for Doxygen.
43-
@param temp_doxy_folder: (str) Temporary folder for Doxygen.
44-
@param doxy_config_file: (Path) Custom Doxygen config file.
45-
@param doxy_config_dict: (dict) New Doxygen config options that will be added to the default config (new options will overwrite default options)
46-
""" # noqa: E501
47-
48-
if doxy_config_dict is None:
40+
@param doxy_config: (MkDoxyConfig) Doxygen configuration.
41+
@param project_config: (MkDoxyConfigProject) Project configuration.
42+
@param temp_doxy_folder: (Path) Temporary Doxygen folder.
43+
"""
44+
self.doxy_config = doxy_config
45+
self.project_config = project_config
46+
self.temp_doxy_folder = temp_doxy_folder
47+
48+
if project_config.doxy_config_dict is None:
4949
doxy_config_dict = {}
50-
if not self.is_doxygen_valid_path(doxygen_bin_path):
50+
if not self.is_doxygen_valid_path(doxy_config.doxygen_bin_path):
5151
raise DoxygenBinPathNotValid(
52-
f"Invalid Doxygen binary path: {doxygen_bin_path}\n"
52+
f"Invalid Doxygen binary path: {doxy_config.doxygen_bin_path}\n"
5353
f"Make sure Doxygen is installed and the path is correct.\n"
5454
f"Look at https://mkdoxy.kubaandrysek.cz/usage/advanced/#configure-custom-doxygen-binary."
5555
)
5656

57-
self.doxygen_bin_path: Path = doxygen_bin_path
58-
self.doxygen_source_dirs: str = doxygen_source_dirs
59-
self.temp_doxy_folder: Path = temp_doxy_folder
60-
self.doxy_config_file: Optional[Path] = doxy_config_file
61-
self.hash_file_name: Path = Path("mkdoxy_hash.txt")
62-
self.doxy_cfg: dict = self.set_doxy_config(doxy_config_dict)
63-
64-
def set_doxy_config(self, doxyCfgNew: dict) -> dict:
57+
def set_doxy_config(self, doxy_cfg_new: dict) -> dict:
6558
"""! Set the Doxygen configuration.
6659
@details If a custom Doxygen config file is provided, it will be used. Otherwise, default options will be used.
6760
@details Order of application of parameters:
@@ -82,26 +75,26 @@ def set_doxy_config(self, doxyCfgNew: dict) -> dict:
8275
@details - SHOW_NAMESPACES: YES
8376
@details - GENERATE_HTML: NO
8477
@details - GENERATE_LATEX: NO
85-
@param doxyCfgNew: (dict) New Doxygen config options that will be
78+
@param doxy_cfg_new: (dict) New Doxygen config options that will be
8679
added to the default config (new options will overwrite default options)
8780
@return: (dict) Doxygen configuration.
8881
"""
8982
doxy_config = {}
9083

91-
if self.doxy_config_file is not None:
92-
if not self.doxy_config_file.is_file():
84+
if self.project_config.doxy_config_file is not None:
85+
if not self.project_config.doxy_config_file.is_file():
9386
raise DoxygenCustomConfigNotFound(
94-
f"Custom Doxygen config file not found: {self.doxy_config_file}\n"
87+
f"Custom Doxygen config file not found: {self.project_config.doxy_config_file}\n"
9588
f"Make sure the path is correct."
96-
f"Loaded path: '{self.doxy_config_file}'"
89+
f"Loaded path: '{self.project_config.doxy_config_file}'"
9790
)
9891

9992
try:
100-
with open(self.doxy_config_file, "r") as file:
93+
with open(self.project_config.doxy_config_file, "r") as file:
10194
doxy_config.update(self.str2dox_dict(file.read()))
10295
except FileNotFoundError as e:
10396
raise DoxygenCustomConfigNotFound(
104-
f"Custom Doxygen config file not found: {self.doxy_config_file}\n"
97+
f"Custom Doxygen config file not found: {self.project_config.doxy_config_file}\n"
10598
f"Make sure the path is correct."
10699
f"Look at https://mkdoxy.kubaandrysek.cz/usage/advanced/#configure-custom-doxygen-configuration-file."
107100
) from e
@@ -116,11 +109,34 @@ def set_doxy_config(self, doxyCfgNew: dict) -> dict:
116109
"GENERATE_LATEX": "NO",
117110
}
118111

119-
doxy_config.update(doxyCfgNew)
120-
doxy_config["INPUT"] = self.doxygen_source_dirs
112+
doxy_config.update(doxy_cfg_new)
113+
114+
if self.doxy_config.generate_diagrams:
115+
self.diagram_update_config(doxy_config)
116+
117+
# rewrite INPUT and OUTPUT_DIRECTORY with the provided values from mkdocs.yml
118+
doxy_config["INPUT"] = self.project_config.src_dirs
121119
doxy_config["OUTPUT_DIRECTORY"] = str(self.temp_doxy_folder)
122120
return doxy_config
123121

122+
def diagram_update_config(self, doxy_config):
123+
log.debug(" -> Setting up Doxygen for diagrams")
124+
doxy_config["HAVE_DOT"] = "YES"
125+
doxy_config["DOT_IMAGE_FORMATS"] = self.doxy_config.generate_diagrams_format
126+
doxy_config["UML_LOOK"] = "YES" if self.doxy_config.generate_diagrams_type == "uml" else "NO"
127+
doxy_config["DOT_CLEANUP"] = "NO"
128+
doxy_config["GENERATE_LEGEND"] = "NO"
129+
doxy_config["GENERATE_HTML"] = "YES"
130+
doxy_config["SEARCHENGINE"] = "NO"
131+
132+
# have to be tested
133+
# doxy_config["CLASS_DIAGRAMS"] = "YES"
134+
# doxy_config["COLLABORATION_GRAPH"] = "YES"
135+
# doxy_config["INCLUDE_GRAPH"] = "YES"
136+
# doxy_config["GRAPHICAL_HIERARCHY"] = "YES"
137+
# doxy_config["CALL_GRAPH"] = "YES"
138+
# doxy_config["CALLER_GRAPH"] = "YES"
139+
124140
@staticmethod
125141
def is_doxygen_valid_path(doxygen_bin_path: Path) -> bool:
126142
"""! Check if the Doxygen binary path is valid.
@@ -178,17 +194,27 @@ def str2dox_dict(self, dox_str: str) -> dict:
178194
doxy_dict[key] = value
179195
except ValueError as e:
180196
raise DoxygenCustomConfigNotValid(
181-
f"Invalid custom Doxygen config file: {self.doxy_config_file}\n"
197+
f"Invalid custom Doxygen config file: {self.project_config.doxy_config_file}\n"
182198
f"Make sure the file is in standard Doxygen format."
183199
f"Look at https://mkdoxy.kubaandrysek.cz/usage/advanced/."
184200
) from e
185201
return doxy_dict
186202

187203
def hash_write(self, file_name: Path, hash_key: str):
204+
"""! Write the hash to the file.
205+
@details
206+
@param file_name: (Path) Path to the file where the hash will be saved.
207+
@param hash_key: (str) Hash.
208+
"""
188209
with open(file_name, "w") as hash_file:
189210
hash_file.write(hash_key)
190211

191212
def hash_read(self, file_name: Path) -> str:
213+
"""! Read the hash from the file.
214+
@details
215+
@param file_name: (Path) Path to the file with the hash.
216+
@return: (str) Hash.
217+
"""
192218
with open(file_name, "r") as hash_file:
193219
return str(hash_file.read())
194220

@@ -198,7 +224,7 @@ def has_changes(self) -> bool:
198224
@return: (bool) True if the source files have changed since the last run.
199225
"""
200226
sha1 = hashlib.sha1()
201-
sources = self.doxygen_source_dirs.split(" ")
227+
sources = self.project_config.src_dirs.split(" ")
202228
# Code from https://stackoverflow.com/a/22058673/15411117
203229
BUF_SIZE = 65536 # let's read stuff in 64kb chunks!
204230
for source in sources:
@@ -212,7 +238,8 @@ def has_changes(self) -> bool:
212238
sha1.update(data)
213239

214240
hash_new = sha1.hexdigest()
215-
hash_file_path = Path.joinpath(self.temp_doxy_folder, self.hash_file_name)
241+
hash_file_name: Path = Path("mkdoxy_hash.txt")
242+
hash_file_path = Path.joinpath(self.temp_doxy_folder, hash_file_name)
216243
if hash_file_path.is_file():
217244
hash_old = self.hash_read(hash_file_path)
218245
if hash_new == hash_old:
@@ -226,16 +253,16 @@ def run(self) -> None:
226253
@details
227254
"""
228255
doxy_builder = Popen(
229-
[self.doxygen_bin_path, "-"],
256+
[self.doxy_config.doxygen_bin_path, "-"],
230257
stdout=PIPE,
231258
stdin=PIPE,
232259
stderr=PIPE,
233260
)
234-
doxy_str = self.dox_dict2str(self.doxy_cfg).encode("utf-8")
235-
stdout_data, stderr_data = doxy_builder.communicate(doxy_str)
261+
doxy_str = self.dox_dict2str(self.set_doxy_config(self.project_config.doxy_config_dict))
262+
stdout_data, stderr_data = doxy_builder.communicate(input=doxy_str.encode("utf-8"))
236263
if doxy_builder.returncode != 0:
237264
log.error(f"Error running Doxygen: {stderr_data.decode('utf-8')}")
238-
raise Exception("Error running Doxygen")
265+
raise exceptions.PluginError(f"Error running Doxygen: {stderr_data.decode('utf-8')}")
239266

240267
def get_output_xml_folder(self) -> Path:
241268
"""! Get the path to the XML output folder.

0 commit comments

Comments
 (0)