0.6.0
C++ to UML diagram generator based on Clang
Loading...
Searching...
No Matches
Public Member Functions | Static Public Member Functions | Public Attributes | Private Member Functions | Private Attributes | List of all members
clanguml::cli::cli_handler Class Reference

Command line options handler. More...

Detailed Description

Command line options handler.

This class is responsible for handling the command line options and executing required actions.

Definition at line 60 of file cli_handler.h.

#include <cli_handler.h>

Public Member Functions

 cli_handler (std::ostream &ostr=std::cout, std::shared_ptr< spdlog::logger > logger=spdlog::stdout_color_mt("clanguml-logger", spdlog::color_mode::automatic))
 
cli_flow_t handle_options (int argc, const char **argv)
 
cli_flow_t print_version ()
 
cli_flow_t print_diagrams_list ()
 
cli_flow_t print_diagram_templates ()
 
cli_flow_t print_diagram_template (const std::string &template_name)
 
cli_flow_t print_config ()
 
cli_flow_t create_config_file ()
 
cli_flow_t add_config_diagram (clanguml::common::model::diagram_t type, const std::string &config_file_path, const std::string &name)
 
cli_flow_t add_config_diagram_from_template (const std::string &config_file_path, const std::string &template_name)
 
cli_flow_t render_diagram_template (const std::string &template_name, YAML::Node &diagram_node)
 
cli_flow_t generate_diagram_from_template (const std::string &template_name)
 
bool ensure_output_directory_exists (const std::string &dir)
 
runtime_config get_runtime_config () const
 Combines runtime configuration parameters into a single structure.
 
void set_config_path (const std::string &path)
 Set the default config path.
 

Static Public Member Functions

static void create_json_progress_logger (spdlog::sink_ptr sink={})
 

Public Attributes

std::string config_path {".clang-uml"}
 
std::optional< std::string > compilation_database_dir {}
 
std::vector< std::string > diagram_names {}
 
std::optional< std::string > output_directory {}
 
std::string effective_output_directory {}
 
unsigned int thread_count {}
 
bool show_version {false}
 
int verbose {}
 
logging::logger_type_t logger_type {logging::logger_type_t::text}
 
bool progress {false}
 
bool list_diagrams {false}
 
bool quiet {false}
 
bool initialize {false}
 
bool allow_empty_diagrams {false}
 
std::optional< std::vector< std::string > > add_compile_flag
 
std::optional< std::vector< std::string > > remove_compile_flag
 
std::vector< std::pair< std::string, std::string > > user_data
 
std::optional< std::string > query_driver
 
std::optional< std::string > add_class_diagram
 
std::optional< std::string > add_sequence_diagram
 
std::optional< std::string > add_package_diagram
 
std::optional< std::string > add_include_diagram
 
std::optional< std::string > add_diagram_from_template
 
std::optional< std::string > generate_from_template
 
bool dump_config {false}
 
bool print_from {false}
 
bool print_to {false}
 
std::optional< bool > paths_relative_to_pwd {}
 
std::vector< std::string > template_variables {}
 
bool list_templates {false}
 
std::optional< bool > no_metadata {}
 
std::optional< std::string > show_template
 
std::vector< clanguml::common::generator_type_tgenerators
 
bool no_validate {false}
 
bool validate_only {false}
 
bool render_diagrams {false}
 
std::optional< std::string > plantuml_cmd
 
std::optional< std::string > mermaid_cmd
 
clanguml::config::config config
 

Private Member Functions

cli_flow_t parse (int argc, const char **argv)
 
cli_flow_t handle_pre_config_options ()
 
cli_flow_t load_config ()
 
cli_flow_t handle_post_config_options ()
 
cli_flow_t add_custom_user_data ()
 
void setup_logging ()
 

Private Attributes

std::ostream & ostr_
 
std::shared_ptr< spdlog::logger > logger_
 
CLI::App app {"Clang-based UML diagram generator for C++"}
 

Constructor & Destructor Documentation

◆ cli_handler()

clanguml::cli::cli_handler::cli_handler ( std::ostream &  ostr = std::cout,
std::shared_ptr< spdlog::logger >  logger = spdlog::stdout_color_mt(            "clanguml-logger", spdlog::color_mode::automatic) 
)

Definition at line 27 of file cli_handler.cc.

29 : ostr_{ostr}
30 , logger_{std::move(logger)}
31{
32}

Member Function Documentation

◆ add_config_diagram()

cli_flow_t clanguml::cli::cli_handler::add_config_diagram ( clanguml::common::model::diagram_t  type,
const std::string &  config_file_path,
const std::string &  name 
)

Add example diagram of given type to the config file.

Parameters
typeType of the sample diagram to add
config_file_pathPath to the config file
nameName of the new diagram
Returns
Command line handler state

Definition at line 653 of file cli_handler.cc.

656{
657 namespace fs = std::filesystem;
658
659 fs::path config_file{config_file_path};
660
661 if (!fs::exists(config_file)) {
662 std::cerr << "ERROR: " << config_file_path << " file doesn't exists\n";
663 return cli_flow_t::kError;
664 }
665
666 YAML::Node doc = YAML::LoadFile(config_file.string());
667
668 for (YAML::const_iterator it = doc["diagrams"].begin();
669 it != doc["diagrams"].end(); ++it) {
670 if (it->first.as<std::string>() == name) {
671 std::cerr << "ERROR: " << config_file_path
672 << " file already contains '" << name << "' diagram";
673 return cli_flow_t::kError;
674 }
675 }
676
678 doc["diagrams"][name]["type"] = "class";
679 doc["diagrams"][name]["glob"] = std::vector<std::string>{{"src/*.cpp"}};
680 doc["diagrams"][name]["using_namespace"] =
681 std::vector<std::string>{{"myproject"}};
682 doc["diagrams"][name]["include"]["namespaces"] =
683 std::vector<std::string>{{"myproject"}};
684 doc["diagrams"][name]["exclude"]["namespaces"] =
685 std::vector<std::string>{{"myproject::detail"}};
686 }
688 doc["diagrams"][name]["type"] = "sequence";
689 doc["diagrams"][name]["glob"] = std::vector<std::string>{{"src/*.cpp"}};
690 doc["diagrams"][name]["combine_free_functions_into_file_participants"] =
691 true;
692 doc["diagrams"][name]["inline_lambda_messages"] = false;
693 doc["diagrams"][name]["generate_message_comments"] = false;
694 doc["diagrams"][name]["fold_repeated_activities"] = false;
695 doc["diagrams"][name]["generate_condition_statements"] = false;
696 doc["diagrams"][name]["using_namespace"] =
697 std::vector<std::string>{{"myproject"}};
698 doc["diagrams"][name]["include"]["paths"] =
699 std::vector<std::string>{{"src"}};
700 doc["diagrams"][name]["exclude"]["namespaces"] =
701 std::vector<std::string>{{"myproject::detail"}};
702 doc["diagrams"][name]["start_from"] =
703 std::vector<std::map<std::string, std::string>>{
704 {{"function", "main(int,const char **)"}}};
705 }
707 doc["diagrams"][name]["type"] = "package";
708 doc["diagrams"][name]["glob"] = std::vector<std::string>{{"src/*.cpp"}};
709 doc["diagrams"][name]["using_namespace"] =
710 std::vector<std::string>{{"myproject"}};
711 doc["diagrams"][name]["include"]["namespaces"] =
712 std::vector<std::string>{{"myproject"}};
713 doc["diagrams"][name]["exclude"]["namespaces"] =
714 std::vector<std::string>{{"myproject::detail"}};
715 }
717 doc["diagrams"][name]["type"] = "include";
718 doc["diagrams"][name]["glob"] = std::vector<std::string>{{"src/*.cpp"}};
719 doc["diagrams"][name]["relative_to"] = ".";
720 doc["diagrams"][name]["include"]["paths"] =
721 std::vector<std::string>{{"src"}};
722 }
723
724 YAML::Emitter out;
725 out.SetIndent(2);
726
727 out << doc;
728 out << YAML::Newline;
729
730 std::ofstream ofs(config_file);
731 ofs << out.c_str();
732 ofs.close();
733
734 return cli_flow_t::kExit;
735}

◆ add_config_diagram_from_template()

cli_flow_t clanguml::cli::cli_handler::add_config_diagram_from_template ( const std::string &  config_file_path,
const std::string &  template_name 
)

Add diagram based on template

Parameters
config_file_pathPath to the configuration file
template_nameName of the diagram template
Returns
Command line handler state

Definition at line 781 of file cli_handler.cc.

783{
784 YAML::Node diagram_node;
785 const auto res = render_diagram_template(template_name, diagram_node);
786
787 if (res == cli_flow_t::kError)
788 return res;
789
790 namespace fs = std::filesystem;
791
792 fs::path config_file{config_file_path};
793
794 if (!fs::exists(config_file)) {
795 std::cerr << "ERROR: " << config_file_path << " file doesn't exists\n";
796 return cli_flow_t::kError;
797 }
798
799 YAML::Node doc = YAML::LoadFile(config_file.string());
800
801 const auto diagram_name = diagram_node.begin()->first.as<std::string>();
802 doc["diagrams"][diagram_name] = diagram_node.begin()->second;
803
804 YAML::Emitter out;
805 out.SetIndent(2);
806
807 out << doc;
808 out << YAML::Newline;
809
810 std::ofstream ofs(config_file);
811 ofs << out.c_str();
812 ofs.close();
813
814 return cli_flow_t::kExit;
815}

◆ add_custom_user_data()

cli_flow_t clanguml::cli::cli_handler::add_custom_user_data ( )
private

Handle custom Jinja context user data provider through --user-data

Returns
Command line handler state

Definition at line 855 of file cli_handler.cc.

856{
857 for (const auto &[key_path, value] : user_data) {
858 auto path = util::split(key_path, ".");
859 auto *user_data_it = &config.user_data();
860 for (const auto &key : path) {
861 if (!user_data_it->is_object() && !user_data_it->empty()) {
862 LOG_ERROR("Setting custom --user-data is only possible if "
863 "`user_data` in config file is empty or an object");
864 return cli_flow_t::kError;
865 }
866
867 user_data_it = &((*user_data_it)[key]);
868 }
869
870 *user_data_it = value;
871 }
872
874}

◆ create_config_file()

cli_flow_t clanguml::cli::cli_handler::create_config_file ( )

Generate sample configuration file and exit.

Returns
Command line handler state

Definition at line 603 of file cli_handler.cc.

604{
605 namespace fs = std::filesystem;
606
607 fs::path config_file{config_path};
608
609 if (fs::exists(config_file)) {
610 ostr_ << "ERROR: .clang-uml file already exists\n";
611 return cli_flow_t::kError;
612 }
613
614 YAML::Emitter out;
615 out.SetIndent(2);
616 out << YAML::BeginMap;
617 out << YAML::Comment("Change to directory where compile_commands.json is");
618 out << YAML::Key << "compilation_database_dir" << YAML::Value << ".";
619 out << YAML::Newline
620 << YAML::Comment("Change to directory where diagram should be written");
621 out << YAML::Key << "output_directory" << YAML::Value << "docs/diagrams";
622 out << YAML::Key << "diagrams" << YAML::Value;
623 out << YAML::BeginMap;
624 out << YAML::Key << "example_class_diagram" << YAML::Value;
625 out << YAML::BeginMap;
626 out << YAML::Key << "type" << YAML::Value << "class";
627 out << YAML::Key << "glob" << YAML::Value;
628 out << YAML::BeginSeq << "src/*.cpp" << YAML::EndSeq;
629 out << YAML::Key << "using_namespace" << YAML::Value;
630 out << YAML::BeginSeq << "myproject" << YAML::EndSeq;
631 out << YAML::Key << "include";
632 out << YAML::BeginMap;
633 out << YAML::Key << "namespaces";
634 out << YAML::BeginSeq << "myproject" << YAML::EndSeq;
635 out << YAML::EndMap;
636 out << YAML::Key << "exclude";
637 out << YAML::BeginMap;
638 out << YAML::Key << "namespaces";
639 out << YAML::BeginSeq << "myproject::detail" << YAML::EndSeq;
640 out << YAML::EndMap;
641 out << YAML::EndMap;
642 out << YAML::EndMap;
643 out << YAML::EndMap;
644 out << YAML::Newline;
645
646 std::ofstream ofs(config_file);
647 ofs << out.c_str();
648 ofs.close();
649
650 return cli_flow_t::kExit;
651}

◆ create_json_progress_logger()

void clanguml::cli::cli_handler::create_json_progress_logger ( spdlog::sink_ptr  sink = {})
static

Definition at line 67 of file cli_handler.cc.

68{
69 spdlog::drop("json-progress-logger");
70
71 auto json_progress_logger = spdlog::stdout_color_mt(
72 "json-progress-logger", spdlog::color_mode::automatic);
73
74 if (sink) {
75 json_progress_logger->sinks().clear();
76 json_progress_logger->sinks().emplace_back(std::move(sink));
77 }
78
79 json_progress_logger->set_level(spdlog::level::info);
80 json_progress_logger->set_pattern(
81 "{\"time\": \"%Y-%m-%dT%H:%M:%S.%f%z\", \"name\": "
82 "\"%n\", \"level\": \"%^%l%$\", "
83 "\"thread\": %t, \"progress\": %v}");
84}

◆ ensure_output_directory_exists()

bool clanguml::cli::cli_handler::ensure_output_directory_exists ( const std::string &  dir)

Check if diagram output directory exists, if not create it

Parameters
dirPath to the output directory
Returns
True if directory exists or has been created

Definition at line 499 of file cli_handler.cc.

500{
501 namespace fs = std::filesystem;
502 using std::cout;
503
504 fs::path output_dir{dir};
505
506 if (fs::exists(output_dir) && !fs::is_directory(output_dir)) {
507 cout << "ERROR: " << dir << " is not a directory...\n";
508 return false;
509 }
510
511 if (!fs::exists(output_dir)) {
512 return fs::create_directories(output_dir);
513 }
514
515 return true;
516}

◆ generate_diagram_from_template()

cli_flow_t clanguml::cli::cli_handler::generate_diagram_from_template ( const std::string &  template_name)

Generate diagram based on template

Parameters
template_nameName of the diagram template
Returns
Command line handler state

Definition at line 817 of file cli_handler.cc.

819{
820 YAML::Node diagram_node;
821 const auto res = render_diagram_template(template_name, diagram_node);
822
823 if (res == cli_flow_t::kError)
824 return res;
825
826 const auto diagram_name = diagram_node.begin()->first.as<std::string>();
827
828 auto diagram_config =
829 YAML::parse_diagram_config(diagram_node.begin()->second);
830 if (diagram_config) {
831 diagram_config->name = diagram_name;
832 config.diagrams[diagram_name] = std::move(diagram_config);
833 diagram_names.push_back(diagram_name);
834 }
835 else {
836 return cli_flow_t::kError;
837 }
838
840}

◆ get_runtime_config()

runtime_config clanguml::cli::cli_handler::get_runtime_config ( ) const

Combines runtime configuration parameters into a single structure.

Returns
Runtime config instance

Definition at line 454 of file cli_handler.cc.

455{
456 runtime_config cfg;
457 cfg.generators = generators;
458 cfg.verbose = verbose;
459 cfg.print_from = print_from;
460 cfg.print_to = print_to;
461 cfg.progress = progress;
462 cfg.thread_count = thread_count;
463 cfg.render_diagrams = render_diagrams;
464 cfg.output_directory = effective_output_directory;
465
466 return cfg;
467}

◆ handle_options()

cli_flow_t clanguml::cli::cli_handler::handle_options ( int  argc,
const char **  argv 
)

Main CLI handling method.

Parameters
argc
argv
Returns
Command line handler state

Definition at line 228 of file cli_handler.cc.

229{
230 auto res = parse(argc, argv);
231
232 if (res != cli_flow_t::kContinue)
233 return res;
234
236
238
239 if (res != cli_flow_t::kContinue)
240 return res;
241
242 res = load_config();
243
244 if (res != cli_flow_t::kContinue)
245 return res;
246
248
249 config.inherit();
250
251 if (progress && (logging::logger_type() == logging::logger_type_t::text)) {
252 spdlog::drop("clanguml-logger");
253
254 // Setup null logger for clean progress indicators
255 std::vector<spdlog::sink_ptr> sinks;
256 logger_ = std::make_shared<spdlog::logger>(
257 "clanguml-logger", begin(sinks), end(sinks));
258 spdlog::register_logger(logger_);
259 }
260
261 return res;
262}

◆ handle_post_config_options()

cli_flow_t clanguml::cli::cli_handler::handle_post_config_options ( )
private

Handle command line options before parsing the configuration file

Returns
Command line handler state

Definition at line 353 of file cli_handler.cc.

354{
355 if (dump_config) {
356 return print_config();
357 }
358
359 if (list_diagrams) {
360 return print_diagrams_list();
361 }
362
363 if (list_templates) {
365 }
366
367 if (show_template) {
369 }
370
374 }
375
378 }
379
380 LOG_INFO("Loaded clang-uml config from {}", config_path);
381
384 }
385
386 if (auto r = add_custom_user_data(); r != cli_flow_t::kContinue)
387 return r;
388
389 //
390 // Override selected config options from command line
391 //
395 .string());
396 }
397
399
400 // Override the output directory from the config
401 // with the value from the command line if any
404
405 if (output_directory) {
408 }
409
410 LOG_INFO("Loading compilation database from {} directory",
412
414 return cli_flow_t::kError;
415
416 //
417 // Append add_compile_flags and remove_compile_flags to the config
418 //
419 if (add_compile_flag) {
420 std::copy(add_compile_flag->begin(), add_compile_flag->end(),
421 std::back_inserter(config.add_compile_flags.value));
423 }
424
426 std::copy(remove_compile_flag->begin(), remove_compile_flag->end(),
427 std::back_inserter(config.remove_compile_flags.value));
428 config.remove_compile_flags.has_value = true;
429 }
430
431 if (plantuml_cmd) {
432 if (!config.puml)
433 config.puml.set({});
434
435 config.puml().cmd = plantuml_cmd.value();
436 }
437
438 if (mermaid_cmd) {
439 if (!config.mermaid)
440 config.mermaid.set({});
441
442 config.mermaid().cmd = mermaid_cmd.value();
443 }
444
445#if !defined(_WIN32)
446 if (query_driver) {
448 }
449#endif
450
452}

◆ handle_pre_config_options()

cli_flow_t clanguml::cli::cli_handler::handle_pre_config_options ( )
private

Handle command line options before parsing the configuration file

Returns
Command line handler state

Definition at line 264 of file cli_handler.cc.

265{
266 if (show_version) {
267 return print_version();
268 }
269
270 if ((config_path == "-") &&
272 add_class_diagram.has_value() || add_sequence_diagram.has_value() ||
273 add_package_diagram.has_value() ||
274 add_include_diagram.has_value())) {
275
276 LOG_ERROR(
277 "ERROR: Cannot add a diagram config to configuration from stdin");
278
279 return cli_flow_t::kError;
280 }
281
282 if (print_from || print_to) {
283 if (diagram_names.size() != 1) {
284 LOG_ERROR("ERROR: '--print-from' and '--print-to' require "
285 "specifying one diagram name using '-n' option");
286
287 return cli_flow_t::kError;
288 }
289 }
290
291 if (initialize) {
292 return create_config_file();
293 }
294
295 if (config_path != "-") {
296 if (add_class_diagram) {
297 return add_config_diagram(
300 }
301
303 return add_config_diagram(
306 }
307
309 return add_config_diagram(
312 }
313
315 return add_config_diagram(
318 }
319 }
320
322}

◆ load_config()

cli_flow_t clanguml::cli::cli_handler::load_config ( )
private

Load configuration file from file or stdin

Returns
Command line handler state

Definition at line 324 of file cli_handler.cc.

325{
326 try {
329 if (validate_only) {
330 if (logger_type == logging::logger_type_t::text) {
331 ostr_ << "Configuration file " << config_path << " is valid.\n";
332 }
333 else {
334 inja::json j;
335 j["valid"] = true;
336 ostr_ << j.dump();
337 }
338 return cli_flow_t::kExit;
339 }
340
342 }
345 }
346 catch (std::runtime_error &e) {
347 LOG_ERROR(e.what());
348 }
349
350 return cli_flow_t::kError;
351}

◆ parse()

cli_flow_t clanguml::cli::cli_handler::parse ( int  argc,
const char **  argv 
)
private

This method parses the command line options using CLI11 library.

Parameters
argc
argv
Returns
Command line handler state

Definition at line 86 of file cli_handler.cc.

87{
88 static const std::map<std::string, clanguml::common::generator_type_t>
89 generator_type_names{
94
95 static const std::map<std::string, clanguml::logging::logger_type_t>
96 logger_type_names{{"text", clanguml::logging::logger_type_t::text},
97 {"json", clanguml::logging::logger_type_t::json}};
98
99 app.add_option("-c,--config", config_path,
100 "Location of configuration file, when '-' read from stdin");
101 app.add_option("-d,--compile-database", compilation_database_dir,
102 "Location of compilation database directory");
103 app.add_option(
104 "-n,--diagram-name", diagram_names, "Name of diagram to generate");
105 app.add_option("-g,--generator", generators,
106 "Name of the generator: plantuml, mermaid, json or graphml "
107 "(default: "
108 "plantuml)")
109 ->transform(CLI::CheckedTransformer(generator_type_names))
110 ->option_text("TEXT ...");
111 app.add_option("-o,--output-directory", output_directory,
112 "Override output directory specified in config file");
113 app.add_option("-t,--thread-count", thread_count,
114 "Thread pool size (0 = hardware concurrency)");
115 app.add_flag("-V,--version", show_version, "Print version and exit");
116 app.add_flag("-v,--verbose", verbose,
117 "Verbose logging ('-v' - debug, '-vv' - trace)");
118 app.add_option(
119 "--logger", logger_type, "Log format: text, json (default: text)")
120 ->transform(CLI::CheckedTransformer(logger_type_names))
121 ->option_text("TEXT ...");
122 app.add_flag(
123 "-p,--progress", progress, "Show progress bars for generated diagrams");
124 app.add_flag("-q,--quiet", quiet, "Minimal logging");
125 app.add_flag("-l,--list-diagrams", list_diagrams,
126 "Print list of diagram names defined in the config file");
127 app.add_flag("--init", initialize, "Initialize example config file");
128 app.add_option("--add-compile-flag", add_compile_flag,
129 "Add a compilation flag to each entry in the compilation database");
130 app.add_option("--remove-compile-flag", remove_compile_flag,
131 "Remove a compilation flag from each entry in the compilation "
132 "database");
133#if !defined(_WIN32)
134 app.add_option("--query-driver", query_driver,
135 "Query the specific compiler driver to extract system paths and add "
136 "them to compile commands (e.g. arm-none-eabi-g++)");
137#endif
138 app.add_flag("--allow-empty-diagrams", allow_empty_diagrams,
139 "Do not raise an error when generated diagram model is empty");
140 app.add_option("--add-class-diagram", add_class_diagram,
141 "Add example class diagram to config file");
142 app.add_option("--add-sequence-diagram", add_sequence_diagram,
143 "Add example sequence diagram to config file");
144 app.add_option("--add-package-diagram", add_package_diagram,
145 "Add example package diagram to config file");
146 app.add_option("--add-include-diagram", add_include_diagram,
147 "Add example include diagram to config");
148 app.add_option("--add-diagram-from-template", add_diagram_from_template,
149 "Add diagram config based on diagram template");
150 app.add_option("--generate-from-template", generate_from_template,
151 "Generate diagram from template without adding it to config");
152 app.add_option("--template-var", template_variables,
153 "Specify a value for a template variable");
154 app.add_flag("--list-templates", list_templates,
155 "List all available diagram templates");
156 app.add_option("--show-template", show_template,
157 "Show specific diagram template definition");
158 app.add_flag(
159 "--dump-config", dump_config, "Print effective config to stdout");
160 app.add_flag("--paths-relative-to-pwd", paths_relative_to_pwd,
161 "If true, all paths in configuration files are relative to the $PWD "
162 "instead of actual location of `.clang-uml` file.");
163 app.add_flag("--no-metadata", no_metadata,
164 "Skip metadata (e.g. clang-uml version) from diagrams");
165 app.add_flag("--print-from,--print-start-from", print_from,
166 "Print all possible 'from' values for a given diagram");
167 app.add_flag("--print-to", print_to,
168 "Print all possible 'to' values for a given diagram");
169 app.add_flag("--no-validate", no_validate,
170 "Do not perform configuration file schema validation");
171 app.add_flag("--validate-only", validate_only,
172 "Perform configuration file schema validation and exit");
173 app.add_flag("-r,--render_diagrams", render_diagrams,
174 "Automatically render generated diagrams using appropriate command");
175 app.add_option("--plantuml-cmd", plantuml_cmd,
176 "Command template to render PlantUML diagram, `{}` will be replaced "
177 "with diagram name.");
178 app.add_option("--mermaid-cmd", mermaid_cmd,
179 "Command template to render MermaidJS diagram, `{}` will be replaced "
180 "with diagram name.");
181 app.add_option(
182 "--user-data",
183 [this](CLI::results_t vals) {
184 for (const auto &val : vals) {
185 auto res = util::split_at_first("=", val);
186
187 if (!res) {
188 throw CLI::ValidationError(
189 fmt::format("Invalid option '--user-data {}'", val),
190 "User data must be of the form '--user-data "
191 "key=value'");
192 }
193
194 user_data.emplace_back(std::move(*res));
195 }
196
197 return true;
198 },
199 "Add custom data properties to Jinja context available in the "
200 "diagrams")
201 ->take_all()
202 ->expected(1, -1);
203
204 try {
205 app.parse(argc, argv);
206 }
207 catch (const CLI::CallForHelp &e) {
208 exit(app.exit(e)); // NOLINT(concurrency-mt-unsafe)
209 }
210 catch (const CLI::Success &e) {
211 return cli_flow_t::kExit;
212 }
213 catch (const CLI::ParseError &e) {
214 exit(app.exit(e)); // NOLINT(concurrency-mt-unsafe)
215 }
216
218 verbose = 0;
219 else
220 verbose++;
221
222 if (progress && (logger_type == logging::logger_type_t::text))
223 verbose = 0;
224
226}

◆ print_config()

cli_flow_t clanguml::cli::cli_handler::print_config ( )

Print effective config after loading and setting default values.

Returns
Command line handler state

Definition at line 842 of file cli_handler.cc.

843{
844 YAML::Emitter out;
845 out.SetIndent(2);
846
847 out << config;
848 out << YAML::Newline;
849
850 ostr_ << out.c_str();
851
852 return cli_flow_t::kExit;
853}

◆ print_diagram_template()

cli_flow_t clanguml::cli::cli_handler::print_diagram_template ( const std::string &  template_name)

Print definition of a specific diagram template.

Parameters
template_nameName of the diagram template
Returns
Command line handler state

Definition at line 585 of file cli_handler.cc.

586{
588 config.diagram_templates().count(template_name) == 0) {
589 ostr_ << "No such diagram template: " << template_name << "\n";
590 return cli_flow_t::kError;
591 }
592
593 for (const auto &[name, diagram_template] : config.diagram_templates()) {
594 if (template_name == name) {
595 ostr_ << diagram_template.jinja_template << "\n";
596 return cli_flow_t::kExit;
597 }
598 }
599
600 return cli_flow_t::kError;
601}

◆ print_diagram_templates()

cli_flow_t clanguml::cli::cli_handler::print_diagram_templates ( )

Print list of available diagram templates, including their names and types.

Returns
Command line handler state

Definition at line 545 of file cli_handler.cc.

546{
547 using std::cout;
548
550 if (logger_type == logging::logger_type_t::text) {
551 ostr_ << "No diagram templates are defined in the config file\n";
552 }
553 else {
554 ostr_ << "[]";
555 }
556 return cli_flow_t::kExit;
557 }
558 if (logger_type == logging::logger_type_t::text) {
559 ostr_ << "The following diagram templates are available:\n";
560 for (const auto &[name, diagram_template] :
561 config.diagram_templates()) {
562 ostr_ << " - " << name << " [" << to_string(diagram_template.type)
563 << "]";
564 if (!diagram_template.description.empty())
565 ostr_ << ": " << diagram_template.description;
566 ostr_ << '\n';
567 }
568 }
569 else {
570 inja::json j = inja::json::array();
571 for (const auto &[name, diagram_template] :
572 config.diagram_templates()) {
573 inja::json dt;
574 dt["name"] = name;
575 dt["type"] = to_string(diagram_template.type);
576 dt["description"] = diagram_template.description;
577 j.emplace_back(std::move(dt));
578 }
579 ostr_ << j.dump();
580 }
581
582 return cli_flow_t::kExit;
583}

◆ print_diagrams_list()

cli_flow_t clanguml::cli::cli_handler::print_diagrams_list ( )

Print list of diagrams available in the configuration file

Returns
Command line handler state

Definition at line 518 of file cli_handler.cc.

519{
520 using std::cout;
521
522 if (logger_type == logging::logger_type_t::text) {
523 ostr_ << "The following diagrams are defined in the config file:\n";
524 for (const auto &[name, diagram] : config.diagrams) {
525 ostr_ << " - " << name << " [" << to_string(diagram->type())
526 << "]";
527 ostr_ << '\n';
528 }
529 }
530 else {
531 inja::json j = inja::json::array();
532 for (const auto &[name, diagram] : config.diagrams) {
533 inja::json d;
534 d["name"] = name;
535 d["type"] = to_string(diagram->type());
536 j.emplace_back(std::move(d));
537 }
538
539 ostr_ << j.dump();
540 }
541
542 return cli_flow_t::kExit;
543}

◆ print_version()

cli_flow_t clanguml::cli::cli_handler::print_version ( )

Print the program version and basic information

Returns
Command line handler state

Definition at line 474 of file cli_handler.cc.

475{
476 if (logger_type == clanguml::logging::logger_type_t::text) {
477 ostr_ << "clang-uml " << clanguml::version::version() << '\n';
478 ostr_ << "Copyright (C) 2021-2025 Bartek Kryza <bkryza@gmail.com>"
479 << '\n';
480 ostr_ << util::get_os_name() << '\n';
481 ostr_ << "Built against LLVM/Clang libraries version: "
482 << LLVM_VERSION_STRING << '\n';
483 ostr_ << "Using LLVM/Clang libraries version: "
484 << clang::getClangFullVersion() << '\n';
485 }
486 else {
487 nlohmann::json j;
488 j["version"] = clanguml::version::version();
489 j["copyright"] =
490 "Copyright (C) 2021-2025 Bartek Kryza <bkryza@gmail.com>";
491 j["llvm"]["built_with"] = LLVM_VERSION_STRING;
492 j["llvm"]["using"] = clang::getClangFullVersion();
493 ostr_ << j;
494 }
495
496 return cli_flow_t::kExit;
497}

◆ render_diagram_template()

cli_flow_t clanguml::cli::cli_handler::render_diagram_template ( const std::string &  template_name,
YAML::Node &  diagram_node 
)

Render diagram template

Parameters
template_nameTemplate name
diagram_nodeReference to YAML output node
Returns
Command line handler state

Definition at line 737 of file cli_handler.cc.

739{
741 !(config.diagram_templates().find(template_name) !=
742 config.diagram_templates().end())) {
743 std::cerr << "ERROR: No such diagram template: " << template_name
744 << "\n";
745 return cli_flow_t::kError;
746 }
747
748 // First, try to render the template using inja and create a YAML node
749 // from it
750 inja::json ctx;
751 for (const auto &tv : template_variables) {
752 const auto var = util::split(tv, "=");
753 if (var.size() != 2) {
754 std::cerr << "ERROR: Invalid template variable " << tv << "\n";
755 return cli_flow_t::kError;
756 }
757
758 ctx[var.at(0)] = var.at(1);
759 }
760
761 auto diagram_template_str =
762 config.diagram_templates().at(template_name).jinja_template;
763 try {
764 auto diagram_str = inja::render(diagram_template_str, ctx);
765 diagram_node = YAML::Load(diagram_str);
766 }
767 catch (inja::InjaError &e) {
768 std::cerr << "ERROR: Failed to generate diagram template '"
769 << template_name << "': " << e.what() << "\n";
770 return cli_flow_t::kError;
771 }
772 catch (YAML::Exception &e) {
773 std::cerr << "ERROR: Rendering diagram template '" << template_name
774 << "' resulted in invalid YAML: " << e.what() << "\n";
775 return cli_flow_t::kError;
776 }
777
779}

◆ set_config_path()

void clanguml::cli::cli_handler::set_config_path ( const std::string &  path)

Set the default config path.

Parameters
path

Definition at line 469 of file cli_handler.cc.

470{
471 config_path = path;
472}

◆ setup_logging()

void clanguml::cli::cli_handler::setup_logging ( )
private

Setup spdlog library depending on provided command line options

Definition at line 34 of file cli_handler.cc.

35{
36 spdlog::drop("clanguml-logger");
37
38 spdlog::register_logger(logger_);
39
40 if (logger_type == logging::logger_type_t::text) {
41 clanguml::logging::logger_type(logging::logger_type_t::text);
42 logger_->set_pattern("%^[%l]%$ [tid %t] %v");
43 }
44 else {
45 clanguml::logging::logger_type(logging::logger_type_t::json);
46 logger_->set_pattern("{\"time\": \"%Y-%m-%dT%H:%M:%S.%f%z\", \"name\": "
47 "\"%n\", \"level\": \"%^%l%$\", "
48 "\"thread\": %t, %v}");
49 if (progress) {
51 }
52 }
53
54 if (verbose == 0) { // --quiet
55 logger_->set_level(spdlog::level::err);
56 }
57 else if (verbose == 1) { // [default]
58 logger_->set_level(spdlog::level::info);
59 }
60 else if (verbose == 2) { // -v
61 logger_->set_level(spdlog::level::debug);
62 }
63 else { // -vv
64 logger_->set_level(spdlog::level::trace);
65 }
66}

Member Data Documentation

◆ add_class_diagram

std::optional<std::string> clanguml::cli::cli_handler::add_class_diagram

Definition at line 204 of file cli_handler.h.

◆ add_compile_flag

std::optional<std::vector<std::string> > clanguml::cli::cli_handler::add_compile_flag

Definition at line 198 of file cli_handler.h.

◆ add_diagram_from_template

std::optional<std::string> clanguml::cli::cli_handler::add_diagram_from_template

Definition at line 208 of file cli_handler.h.

◆ add_include_diagram

std::optional<std::string> clanguml::cli::cli_handler::add_include_diagram

Definition at line 207 of file cli_handler.h.

◆ add_package_diagram

std::optional<std::string> clanguml::cli::cli_handler::add_package_diagram

Definition at line 206 of file cli_handler.h.

◆ add_sequence_diagram

std::optional<std::string> clanguml::cli::cli_handler::add_sequence_diagram

Definition at line 205 of file cli_handler.h.

◆ allow_empty_diagrams

bool clanguml::cli::cli_handler::allow_empty_diagrams {false}

Definition at line 197 of file cli_handler.h.

◆ app

CLI::App clanguml::cli::cli_handler::app {"Clang-based UML diagram generator for C++"}
private

Definition at line 273 of file cli_handler.h.

◆ compilation_database_dir

std::optional<std::string> clanguml::cli::cli_handler::compilation_database_dir {}

Definition at line 185 of file cli_handler.h.

◆ config

clanguml::config::config clanguml::cli::cli_handler::config

Definition at line 226 of file cli_handler.h.

◆ config_path

std::string clanguml::cli::cli_handler::config_path {".clang-uml"}

Definition at line 184 of file cli_handler.h.

◆ diagram_names

std::vector<std::string> clanguml::cli::cli_handler::diagram_names {}

Definition at line 186 of file cli_handler.h.

◆ dump_config

bool clanguml::cli::cli_handler::dump_config {false}

Definition at line 210 of file cli_handler.h.

◆ effective_output_directory

std::string clanguml::cli::cli_handler::effective_output_directory {}

Definition at line 188 of file cli_handler.h.

◆ generate_from_template

std::optional<std::string> clanguml::cli::cli_handler::generate_from_template

Definition at line 209 of file cli_handler.h.

◆ generators

std::vector<clanguml::common::generator_type_t> clanguml::cli::cli_handler::generators
Initial value:

Definition at line 218 of file cli_handler.h.

◆ initialize

bool clanguml::cli::cli_handler::initialize {false}

Definition at line 196 of file cli_handler.h.

◆ list_diagrams

bool clanguml::cli::cli_handler::list_diagrams {false}

Definition at line 194 of file cli_handler.h.

◆ list_templates

bool clanguml::cli::cli_handler::list_templates {false}

Definition at line 215 of file cli_handler.h.

◆ logger_

std::shared_ptr<spdlog::logger> clanguml::cli::cli_handler::logger_
private

Definition at line 272 of file cli_handler.h.

◆ logger_type

logging::logger_type_t clanguml::cli::cli_handler::logger_type {logging::logger_type_t::text}

Definition at line 192 of file cli_handler.h.

◆ mermaid_cmd

std::optional<std::string> clanguml::cli::cli_handler::mermaid_cmd

Definition at line 224 of file cli_handler.h.

◆ no_metadata

std::optional<bool> clanguml::cli::cli_handler::no_metadata {}

Definition at line 216 of file cli_handler.h.

◆ no_validate

bool clanguml::cli::cli_handler::no_validate {false}

Definition at line 220 of file cli_handler.h.

◆ ostr_

std::ostream& clanguml::cli::cli_handler::ostr_
private

Definition at line 271 of file cli_handler.h.

◆ output_directory

std::optional<std::string> clanguml::cli::cli_handler::output_directory {}

Definition at line 187 of file cli_handler.h.

◆ paths_relative_to_pwd

std::optional<bool> clanguml::cli::cli_handler::paths_relative_to_pwd {}

Definition at line 213 of file cli_handler.h.

◆ plantuml_cmd

std::optional<std::string> clanguml::cli::cli_handler::plantuml_cmd

Definition at line 223 of file cli_handler.h.

◆ print_from

bool clanguml::cli::cli_handler::print_from {false}

Definition at line 211 of file cli_handler.h.

◆ print_to

bool clanguml::cli::cli_handler::print_to {false}

Definition at line 212 of file cli_handler.h.

◆ progress

bool clanguml::cli::cli_handler::progress {false}

Definition at line 193 of file cli_handler.h.

◆ query_driver

std::optional<std::string> clanguml::cli::cli_handler::query_driver

Definition at line 202 of file cli_handler.h.

◆ quiet

bool clanguml::cli::cli_handler::quiet {false}

Definition at line 195 of file cli_handler.h.

◆ remove_compile_flag

std::optional<std::vector<std::string> > clanguml::cli::cli_handler::remove_compile_flag

Definition at line 199 of file cli_handler.h.

◆ render_diagrams

bool clanguml::cli::cli_handler::render_diagrams {false}

Definition at line 222 of file cli_handler.h.

◆ show_template

std::optional<std::string> clanguml::cli::cli_handler::show_template

Definition at line 217 of file cli_handler.h.

◆ show_version

bool clanguml::cli::cli_handler::show_version {false}

Definition at line 190 of file cli_handler.h.

◆ template_variables

std::vector<std::string> clanguml::cli::cli_handler::template_variables {}

Definition at line 214 of file cli_handler.h.

◆ thread_count

unsigned int clanguml::cli::cli_handler::thread_count {}

Definition at line 189 of file cli_handler.h.

◆ user_data

std::vector<std::pair<std::string, std::string> > clanguml::cli::cli_handler::user_data

Definition at line 200 of file cli_handler.h.

◆ validate_only

bool clanguml::cli::cli_handler::validate_only {false}

Definition at line 221 of file cli_handler.h.

◆ verbose

int clanguml::cli::cli_handler::verbose {}

Definition at line 191 of file cli_handler.h.


The documentation for this class was generated from the following files: