25 inja::json &context,
const std::string &prefix)
27 if (!context.contains(
"element"))
30 if (!context[
"element"].contains(
"source"))
33 auto &source = context[
"element"][
"source"];
35 if (source.at(
"path").empty())
38 auto path = std::filesystem::path{source.at(
"path")};
39 auto prefix_path = std::filesystem::path(prefix);
41 source[
"path"] = relative(path, prefix_path);
47 const std::vector<std::string> &diagram_names,
49 const std::vector<std::string> &compilation_database_files,
50 std::map<std::string, std::vector<std::string>> &translation_units_map)
52 for (
const auto &[name, diagram] : config.
diagrams) {
55 if (!diagram_names.empty() && !
util::contains(diagram_names, name))
58 translation_units_map[name] =
59 diagram->glob_translation_units(compilation_database_files);
61 LOG_DBG(
"Found {} translation units for diagram {}",
62 translation_units_map.at(name).size(), name);
67 std::shared_ptr<config::diagram> diagram_config)
70 switch (generator_type) {
72 cmd = diagram_config->
puml().cmd;
75 cmd = diagram_config->
mermaid().cmd;
82 throw std::runtime_error(
83 fmt::format(
"No render command template provided for {} diagrams",
88 LOG_INFO(
"Rendering diagram {} using {}", diagram_config->
name,
96template <
typename DiagramConfig,
typename GeneratorTag,
typename DiagramModel>
98 const std::string &name, std::shared_ptr<clanguml::config::diagram> diagram,
99 const DiagramModel &model)
101 using diagram_generator =
104 std::stringstream buffer;
105 buffer << diagram_generator(
106 dynamic_cast<DiagramConfig &
>(*diagram), *model);
110 auto path = std::filesystem::path{od} /
111 fmt::format(
"{}.{}", name, GeneratorTag::extension);
113 ofs.open(path, std::ofstream::out | std::ofstream::trunc);
118 LOG_INFO(
"Written {} diagram to {}", name, path.string());
121template <
typename DiagramConfig>
123 std::shared_ptr<clanguml::config::diagram> diagram,
125 const std::vector<std::string> &translation_units,
128 using diagram_config = DiagramConfig;
133 diagram_config, diagram_visitor>(db, diagram->name,
134 dynamic_cast<diagram_config &
>(*diagram), translation_units,
135 runtime_config.
verbose, std::move(progress));
137 if constexpr (std::is_same_v<DiagramConfig, config::sequence_diagram>) {
139 auto from_values = model->list_from_values();
141 for (
const auto &from : from_values) {
142 std::cout << from <<
'\n';
148 auto to_values = model->list_to_values();
150 for (
const auto &to : to_values) {
151 std::cout <<
"|" << to <<
"|" <<
'\n';
158 for (
const auto generator_type : runtime_config.
generators) {
185 std::shared_ptr<clanguml::config::diagram> diagram,
187 const std::vector<std::string> &translation_units,
198 if (diagram->type() == diagram_t::kClass) {
199 detail::generate_diagram_impl<class_diagram>(name, diagram, db,
200 translation_units, runtime_config, std::move(progress));
202 else if (diagram->type() == diagram_t::kSequence) {
203 detail::generate_diagram_impl<sequence_diagram>(name, diagram, db,
204 translation_units, runtime_config, std::move(progress));
206 else if (diagram->type() == diagram_t::kPackage) {
207 detail::generate_diagram_impl<package_diagram>(name, diagram, db,
208 translation_units, runtime_config, std::move(progress));
210 else if (diagram->type() == diagram_t::kInclude) {
211 detail::generate_diagram_impl<include_diagram>(name, diagram, db,
212 translation_units, runtime_config, std::move(progress));
219 const std::map<std::string, std::vector<std::string>>
220 &translation_units_map)
223 std::vector<std::future<void>> futs;
225 std::unique_ptr<progress_indicator> indicator;
228 std::cout << termcolor::white
229 <<
"Processing translation units and generating diagrams:\n";
230 indicator = std::make_unique<progress_indicator>();
233 for (
const auto &[name, diagram] : config.
diagrams) {
236 if (!diagram_names.empty() && !
util::contains(diagram_names, name))
239 const auto &valid_translation_units = translation_units_map.at(name);
241 LOG_DBG(
"Found {} valid translation units for diagram {}",
242 valid_translation_units.size(), name);
244 const auto matching_commands_count =
245 db->count_matching_commands(valid_translation_units);
247 if (matching_commands_count == 0) {
249 indicator->add_progress_bar(
251 indicator->fail(name);
255 "Diagram {} generation failed: no translation units "
256 "found. Please make sure that your 'glob' patterns match "
257 "at least 1 file in 'compile_commands.json'.",
263 LOG_DBG(
"Found {} matching translation unit commands for diagram {}",
264 matching_commands_count, name);
266 auto generator = [&name = name, &diagram = diagram, &indicator,
267 db = std::ref(*db), matching_commands_count,
268 translation_units = valid_translation_units,
269 runtime_config]()
mutable {
272 indicator->add_progress_bar(name, matching_commands_count,
276 runtime_config, [&indicator, &name]() {
278 indicator->increment(name);
282 indicator->complete(name);
284 catch (
const std::exception &e) {
286 indicator->fail(name);
289 "ERROR: Failed to generate diagram {}: {}", name, e.what());
293 futs.emplace_back(generator_executor.add(std::move(
generator)));
296 for (
auto &fut : futs) {
302 std::cout << termcolor::white <<
"Done\n";
303 std::cout << termcolor::reset;
309 switch (diagram_type) {
311 return indicators::Color::yellow;
313 return indicators::Color::blue;
315 return indicators::Color::cyan;
317 return indicators::Color::magenta;
319 return indicators::Color::unspecified;