Path:
strictdoc/core/actions/export_action.py
Lines:
322
Non-empty lines:
289
Non-empty lines covered with requirements:
289 / 289 (100.0%)
Functions:
6
Functions covered by requirements:
6 / 6 (100.0%)
- "2.2. Identical SDoc content by import/export roundtrip" (REQUIREMENT)
- "6.1.1. Export to static HTML website" (REQUIREMENT)
1
import os
2
import sys
3
from pathlib import Path
4
from typing import Optional
5
6
from strictdoc.backend.excel.export.excel_generator import ExcelGenerator
7
from strictdoc.backend.markdown.writer import SDMarkdownWriter
8
from strictdoc.backend.reqif.reqif_export import ReqIFExport
9
from strictdoc.backend.sdoc.errors.document_tree_error import DocumentTreeError
10
from strictdoc.backend.sdoc.models.document import SDocDocument
11
from strictdoc.backend.sdoc.writer import SDWriter
12
from strictdoc.core.project_config import ProjectConfig
13
from strictdoc.core.traceability_index import TraceabilityIndex
14
from strictdoc.core.traceability_index_builder import TraceabilityIndexBuilder
15
from strictdoc.export.doxygen.doxygen_generator import DoxygenGenerator
16
from strictdoc.export.html.document_type import DocumentType
17
from strictdoc.export.html.html_generator import HTMLGenerator
18
from strictdoc.export.html.html_templates import HTMLTemplates
19
from strictdoc.export.json.json_generator import JSONGenerator
20
from strictdoc.export.rst.document_rst_generator import DocumentRSTGenerator
21
from strictdoc.export.spdx.spdx_generator import SPDXGenerator
22
from strictdoc.features.diff_and_changelog.change_generator import (
23
ChangeGenerator,
24
)25
from strictdoc.features.html2pdf.html2pdf_generator import HTML2PDFGenerator
26
from strictdoc.helpers.parallelizer import NullParallelizer, Parallelizer
27
from strictdoc.helpers.timing import timing_decorator
28
29
30
class ExportAction:
31
def __init__(
32
self,
33
project_config: ProjectConfig,
34
parallelizer: Parallelizer,
35
):36
assert parallelizer
37
self.project_config: ProjectConfig = project_config
38
self.parallelizer = parallelizer
39
self.traceability_index: TraceabilityIndex = self.build_index()
40
41
@timing_decorator("Parse SDoc project tree")
42
def build_index(self) -> TraceabilityIndex:
43
try:
44
traceability_index: TraceabilityIndex = (
45
TraceabilityIndexBuilder.create(
46
project_config=self.project_config,
47
parallelizer=self.parallelizer,
48
)49
)50
except DocumentTreeError as exc:
51
print(exc.to_print_message()) # noqa: T201
52
sys.exit(1)
53
self.traceability_index = traceability_index
54
return traceability_index
55
56
@timing_decorator("Export SDoc")
57
def export(self) -> None:
58
assert self.traceability_index is not None, (
59
"The index must be built at this point."60
)61
assert self.project_config.export_formats is not None, (
62
"The export_formats must not be None."63
)64
65
if (
66
"html" in self.project_config.export_formats
67
or "html2pdf" in self.project_config.export_formats
68
):69
is_small_project = self.traceability_index.is_small_project()
70
71
html_templates = HTMLTemplates.create(
72
project_config=self.project_config,
73
enable_caching=not is_small_project,
74
strictdoc_last_update=self.traceability_index.strictdoc_last_update,
75
)76
77
# The bundle document is generated only when the option is provided.78
traceability_index_copy: Optional[TraceabilityIndex] = None
79
bundle_document: Optional[SDocDocument] = None
80
if self.project_config.generate_bundle_document:
81
traceability_index_copy, bundle_document = (
82
self.traceability_index.clone_to_bundle_document(
83
self.project_config
84
)85
)86
87
if "html" in self.project_config.export_formats:
88
html_generator = HTMLGenerator(
89
self.project_config, html_templates
90
)91
html_generator.export_complete_tree(
92
traceability_index=self.traceability_index,
93
parallelizer=self.parallelizer,
94
)95
if self.project_config.generate_bundle_document:
96
assert bundle_document is not None, (
97
"bundle_document must not be None."98
)99
assert traceability_index_copy is not None, (
100
"traceability_index_copy must not be None."101
)102
html_generator.export_single_document(
103
document=bundle_document,
104
traceability_index=traceability_index_copy,
105
specific_documents=(DocumentType.DOCUMENT,),
106
)107
108
if "html" in self.project_config.export_formats:
109
if (
110
diff_git_revisions := self.project_config.diff_git_revisions
111
) is not None:
112
ChangeGenerator().generate_from_revisions(
113
diff_git_revisions,
114
project_config=self.project_config,
115
html_templates=html_templates,
116
)117
if (
118
diff_dir_revisions := self.project_config.diff_dir_revisions
119
) is not None:
120
ChangeGenerator().generate_from_paths(
121
diff_dir_revisions[0],
122
diff_dir_revisions[1],
123
project_config=self.project_config,
124
html_templates=html_templates,
125
)126
127
# @relation(SDOC-SRS-51, scope=range_start)128
if "html2pdf" in self.project_config.export_formats:
129
output_html2pdf_root = os.path.join(
130
self.project_config.output_dir, "html2pdf"
131
)132
Path(output_html2pdf_root).mkdir(parents=True, exist_ok=True)
133
HTML2PDFGenerator.export_tree(
134
self.project_config,
135
self.traceability_index,
136
html_templates,
137
output_html2pdf_root,
138
)139
140
if self.project_config.generate_bundle_document:
141
assert traceability_index_copy is not None, (
142
"traceability_index_copy must not be None."143
)144
HTML2PDFGenerator.export_tree(
145
self.project_config,
146
traceability_index_copy,
147
html_templates,
148
output_html2pdf_root,
149
flat_assets=True,
150
)151
# @relation(SDOC-SRS-51, scope=range_end)152
153
if "rst" in self.project_config.export_formats:
154
output_rst_root = os.path.join(
155
self.project_config.output_dir, "rst"
156
)157
Path(output_rst_root).mkdir(parents=True, exist_ok=True)
158
DocumentRSTGenerator.export_tree(
159
self.traceability_index, output_rst_root
160
)161
162
if "excel" in self.project_config.export_formats:
163
output_excel_root = f"{self.project_config.output_dir}/excel"
164
ExcelGenerator.export_tree(
165
self.traceability_index,
166
output_excel_root,
167
project_config=self.project_config,
168
)169
170
if "reqif-sdoc" in self.project_config.export_formats:
171
output_reqif_root = f"{self.project_config.output_dir}/reqif"
172
ReqIFExport.export(
173
project_config=self.project_config,
174
traceability_index=self.traceability_index,
175
output_reqif_root=output_reqif_root,
176
reqifz=False,
177
)178
179
if "reqifz-sdoc" in self.project_config.export_formats:
180
output_reqif_root = f"{self.project_config.output_dir}/reqif"
181
ReqIFExport.export(
182
project_config=self.project_config,
183
traceability_index=self.traceability_index,
184
output_reqif_root=output_reqif_root,
185
reqifz=True,
186
)187
188
if "sdoc" in self.project_config.export_formats:
189
self.export_sdoc()
190
191
if "markdown" in self.project_config.export_formats:
192
self.export_markdown()
193
194
if "doxygen" in self.project_config.export_formats:
195
output_doxygen_root = os.path.join(
196
self.project_config.output_dir, "doxygen"
197
)198
doxygen_generator = DoxygenGenerator(
199
project_config=self.project_config
200
)201
doxygen_generator.export(
202
traceability_index=self.traceability_index,
203
path_to_output_dir=output_doxygen_root,
204
)205
206
if "spdx" in self.project_config.export_formats:
207
output_dot_root = os.path.join(
208
self.project_config.output_dir, "spdx"
209
)210
Path(output_dot_root).mkdir(parents=True, exist_ok=True)
211
SPDXGenerator().export_tree(
212
self.project_config, self.traceability_index, output_dot_root
213
)214
215
if "json" in self.project_config.export_formats:
216
output_json_root = os.path.join(
217
self.project_config.output_dir, "json"
218
)219
Path(output_json_root).mkdir(parents=True, exist_ok=True)
220
JSONGenerator().export_tree(
221
self.traceability_index, self.project_config, output_json_root
222
)223
224
def export_sdoc(self) -> None:
225
assert self.project_config.input_paths
226
try:
227
traceability_index: TraceabilityIndex = (
228
TraceabilityIndexBuilder.create(
229
project_config=self.project_config,
230
parallelizer=NullParallelizer(),
231
)232
)233
except DocumentTreeError as exc:
234
print(exc.to_print_message()) # noqa: T201
235
sys.exit(1)
236
else:
237
assert traceability_index.document_tree
238
239
writer = SDWriter(
240
self.project_config, node_filter=traceability_index.node_filter
241
)242
243
output_base_dir = (
244
self.project_config.output_dir
245
if self.project_config.output_dir is not None
246
else os.path.join(os.getcwd(), "output")
247
)248
output_dir = os.path.join(output_base_dir, "sdoc")
249
for document in traceability_index.document_tree.document_list:
250
assert document.meta
251
assert document.meta.document_filename_base
252
assert document.meta.input_doc_dir_rel_path
253
output, fragments_dict = writer.write_with_fragments(
254
document,
255
)256
257
path_to_output_file_dir: str = os.path.join(
258
output_dir, document.meta.input_doc_dir_rel_path.relative_path
259
)260
Path(path_to_output_file_dir).mkdir(parents=True, exist_ok=True)
261
path_to_output_file = os.path.join(
262
path_to_output_file_dir, document.meta.document_filename_base
263
)264
path_to_output_file += ".sdoc"
265
with open(path_to_output_file, "w", encoding="utf8") as file:
266
file.write(output)
267
268
for fragment_path_, fragment_content_ in fragments_dict.items():
269
path_to_output_fragment = os.path.join(
270
path_to_output_file_dir, fragment_path_
271
)272
with open(
273
path_to_output_fragment, "w", encoding="utf8"
274
) as file_:
275
file_.write(fragment_content_)
276
277
def export_markdown(self) -> None:
278
assert self.project_config.input_paths
279
try:
280
traceability_index: TraceabilityIndex = (
281
TraceabilityIndexBuilder.create(
282
project_config=self.project_config,
283
parallelizer=NullParallelizer(),
284
)285
)286
except DocumentTreeError as exc:
287
print(exc.to_print_message()) # noqa: T201
288
sys.exit(1)
289
else:
290
assert traceability_index.document_tree
291
292
writer = SDMarkdownWriter()
293
294
output_base_dir = (
295
self.project_config.output_dir
296
if self.project_config.output_dir is not None
297
else os.path.join(os.getcwd(), "output")
298
)299
output_dir = os.path.join(output_base_dir, "markdown")
300
301
for document in traceability_index.document_tree.document_list:
302
assert document.meta
303
assert document.meta.document_filename_base
304
assert document.meta.input_doc_dir_rel_path
305
306
output = writer.write(document)
307
308
path_to_output_file_dir: str = os.path.join(
309
output_dir, document.meta.input_doc_dir_rel_path.relative_path
310
)311
Path(path_to_output_file_dir).mkdir(parents=True, exist_ok=True)
312
313
path_to_output_file = os.path.join(
314
path_to_output_file_dir,
315
document.meta.document_filename_base + ".md",
316
)317
with open(
318
path_to_output_file,
319
"w",
320
encoding="utf8",
321
) as file:
322
file.write(output)