4
4
import shutil
5
5
from pathlib import Path
6
6
from subprocess import PIPE , Popen
7
- from typing import Optional
8
7
9
8
from mkdocs import exceptions
10
9
10
+ from mkdoxy .doxy_config import MkDoxyConfig , MkDoxyConfigProject
11
+
11
12
log : logging .Logger = logging .getLogger ("mkdocs" )
12
13
13
14
@@ -17,12 +18,10 @@ class DoxygenGenerator:
17
18
"""
18
19
19
20
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 ,
26
25
):
27
26
"""! Constructor.
28
27
Default Doxygen config options:
@@ -38,30 +37,24 @@ def __init__(
38
37
- GENERATE_LATEX: NO
39
38
40
39
@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 :
49
49
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 ):
51
51
raise DoxygenBinPathNotValid (
52
- f"Invalid Doxygen binary path: { doxygen_bin_path } \n "
52
+ f"Invalid Doxygen binary path: { doxy_config . doxygen_bin_path } \n "
53
53
f"Make sure Doxygen is installed and the path is correct.\n "
54
54
f"Look at https://mkdoxy.kubaandrysek.cz/usage/advanced/#configure-custom-doxygen-binary."
55
55
)
56
56
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 :
65
58
"""! Set the Doxygen configuration.
66
59
@details If a custom Doxygen config file is provided, it will be used. Otherwise, default options will be used.
67
60
@details Order of application of parameters:
@@ -82,26 +75,26 @@ def set_doxy_config(self, doxyCfgNew: dict) -> dict:
82
75
@details - SHOW_NAMESPACES: YES
83
76
@details - GENERATE_HTML: NO
84
77
@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
86
79
added to the default config (new options will overwrite default options)
87
80
@return: (dict) Doxygen configuration.
88
81
"""
89
82
doxy_config = {}
90
83
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 ():
93
86
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 "
95
88
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 } '"
97
90
)
98
91
99
92
try :
100
- with open (self .doxy_config_file , "r" ) as file :
93
+ with open (self .project_config . doxy_config_file , "r" ) as file :
101
94
doxy_config .update (self .str2dox_dict (file .read ()))
102
95
except FileNotFoundError as e :
103
96
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 "
105
98
f"Make sure the path is correct."
106
99
f"Look at https://mkdoxy.kubaandrysek.cz/usage/advanced/#configure-custom-doxygen-configuration-file."
107
100
) from e
@@ -116,11 +109,34 @@ def set_doxy_config(self, doxyCfgNew: dict) -> dict:
116
109
"GENERATE_LATEX" : "NO" ,
117
110
}
118
111
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
121
119
doxy_config ["OUTPUT_DIRECTORY" ] = str (self .temp_doxy_folder )
122
120
return doxy_config
123
121
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
+
124
140
@staticmethod
125
141
def is_doxygen_valid_path (doxygen_bin_path : Path ) -> bool :
126
142
"""! Check if the Doxygen binary path is valid.
@@ -178,17 +194,27 @@ def str2dox_dict(self, dox_str: str) -> dict:
178
194
doxy_dict [key ] = value
179
195
except ValueError as e :
180
196
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 "
182
198
f"Make sure the file is in standard Doxygen format."
183
199
f"Look at https://mkdoxy.kubaandrysek.cz/usage/advanced/."
184
200
) from e
185
201
return doxy_dict
186
202
187
203
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
+ """
188
209
with open (file_name , "w" ) as hash_file :
189
210
hash_file .write (hash_key )
190
211
191
212
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
+ """
192
218
with open (file_name , "r" ) as hash_file :
193
219
return str (hash_file .read ())
194
220
@@ -198,7 +224,7 @@ def has_changes(self) -> bool:
198
224
@return: (bool) True if the source files have changed since the last run.
199
225
"""
200
226
sha1 = hashlib .sha1 ()
201
- sources = self .doxygen_source_dirs .split (" " )
227
+ sources = self .project_config . src_dirs .split (" " )
202
228
# Code from https://stackoverflow.com/a/22058673/15411117
203
229
BUF_SIZE = 65536 # let's read stuff in 64kb chunks!
204
230
for source in sources :
@@ -212,7 +238,8 @@ def has_changes(self) -> bool:
212
238
sha1 .update (data )
213
239
214
240
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 )
216
243
if hash_file_path .is_file ():
217
244
hash_old = self .hash_read (hash_file_path )
218
245
if hash_new == hash_old :
@@ -226,16 +253,16 @@ def run(self) -> None:
226
253
@details
227
254
"""
228
255
doxy_builder = Popen (
229
- [self .doxygen_bin_path , "-" ],
256
+ [self .doxy_config . doxygen_bin_path , "-" ],
230
257
stdout = PIPE ,
231
258
stdin = PIPE ,
232
259
stderr = PIPE ,
233
260
)
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" ) )
236
263
if doxy_builder .returncode != 0 :
237
264
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' ) } " )
239
266
240
267
def get_output_xml_folder (self ) -> Path :
241
268
"""! Get the path to the XML output folder.
0 commit comments