Implement CLI options for adding diagrams to config from templates
This commit is contained in:
@@ -553,12 +553,20 @@ template <> struct convert<diagram_template> {
|
||||
if (node.Type() == NodeType::Scalar) {
|
||||
// Check that the template provided as string is at least valid YAML
|
||||
const auto yaml_node = Load(node.as<std::string>());
|
||||
const auto diagram_type = yaml_node["type"].as<std::string>();
|
||||
const auto template_root_it = yaml_node.begin();
|
||||
const auto diagram_name_template =
|
||||
template_root_it->first.as<std::string>();
|
||||
const auto diagram_type =
|
||||
template_root_it->second["type"].as<std::string>();
|
||||
rhs.type = clanguml::common::model::from_string(diagram_type);
|
||||
rhs.jinja_template = Dump(yaml_node);
|
||||
}
|
||||
else {
|
||||
const auto diagram_type = node["type"].as<std::string>();
|
||||
const auto template_root_it = node.begin();
|
||||
const auto diagram_name_template =
|
||||
template_root_it->first.as<std::string>();
|
||||
const auto diagram_type =
|
||||
template_root_it->second["type"].as<std::string>();
|
||||
rhs.type = clanguml::common::model::from_string(diagram_type);
|
||||
rhs.jinja_template = Dump(node);
|
||||
}
|
||||
|
||||
119
src/main.cc
119
src/main.cc
@@ -62,6 +62,14 @@ void print_version();
|
||||
*/
|
||||
void print_diagrams_list(const clanguml::config::config &cfg);
|
||||
|
||||
/**
|
||||
* Print list of available diagram templates, including their names
|
||||
* and types.
|
||||
*
|
||||
* @param cfg
|
||||
*/
|
||||
void print_diagram_templates(const clanguml::config::config &cfg);
|
||||
|
||||
/**
|
||||
* Print effective config after loading and setting default values.
|
||||
*
|
||||
@@ -87,6 +95,18 @@ int create_config_file();
|
||||
int add_config_diagram(clanguml::common::model::diagram_t type,
|
||||
const std::string &config_file_path, const std::string &name);
|
||||
|
||||
/**
|
||||
* Add diagram based on template
|
||||
* @param config_file_path
|
||||
* @param cfg
|
||||
* @param template_name
|
||||
* @param template_variables
|
||||
* @return
|
||||
*/
|
||||
int add_config_diagram_from_template(const std::string &config_file_path,
|
||||
const config::config &cfg, const std::string &template_name,
|
||||
const std::vector<std::string> &template_variables);
|
||||
|
||||
/**
|
||||
* Check if diagram output directory exists, if not create it
|
||||
*
|
||||
@@ -172,8 +192,11 @@ int main(int argc, const char *argv[])
|
||||
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;
|
||||
bool dump_config{false};
|
||||
std::optional<bool> paths_relative_to_pwd{};
|
||||
std::vector<std::string> template_variables{};
|
||||
bool list_templates{false};
|
||||
|
||||
app.add_option("-c,--config", config_path,
|
||||
"Location of configuration file, when '-' read from stdin");
|
||||
@@ -200,6 +223,12 @@ int main(int argc, const char *argv[])
|
||||
"Add package diagram config");
|
||||
app.add_option("--add-include-diagram", add_include_diagram,
|
||||
"Add include diagram config");
|
||||
app.add_option("--add-diagram-from-template", add_diagram_from_template,
|
||||
"Add diagram config based on diagram template");
|
||||
app.add_option("--template-variable", template_variables,
|
||||
"Specify a value for a template variable");
|
||||
app.add_flag("--list-templates", list_templates,
|
||||
"List all available diagram templates");
|
||||
app.add_flag(
|
||||
"--dump-config", dump_config, "Print effective config to stdout");
|
||||
app.add_flag("--paths-relative-to-pwd", paths_relative_to_pwd,
|
||||
@@ -221,8 +250,8 @@ int main(int argc, const char *argv[])
|
||||
}
|
||||
|
||||
if ((config_path == "-") &&
|
||||
(initialize || add_class_diagram.has_value() ||
|
||||
add_sequence_diagram.has_value() ||
|
||||
(initialize || add_diagram_from_template ||
|
||||
add_class_diagram.has_value() || add_sequence_diagram.has_value() ||
|
||||
add_package_diagram.has_value() ||
|
||||
add_include_diagram.has_value())) {
|
||||
|
||||
@@ -276,6 +305,16 @@ int main(int argc, const char *argv[])
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (list_templates) {
|
||||
print_diagram_templates(config);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (config_path != "-" && add_diagram_from_template) {
|
||||
return add_config_diagram_from_template(config_path, config,
|
||||
add_diagram_from_template.value(), template_variables);
|
||||
}
|
||||
|
||||
LOG_INFO("Loaded clang-uml config from {}", config_path);
|
||||
|
||||
//
|
||||
@@ -539,6 +578,23 @@ void print_diagrams_list(const clanguml::config::config &cfg)
|
||||
}
|
||||
}
|
||||
|
||||
void print_diagram_templates(const clanguml::config::config &cfg)
|
||||
{
|
||||
using std::cout;
|
||||
|
||||
if (!cfg.diagram_templates) {
|
||||
cout << "No diagram templates are defined in the config file\n";
|
||||
return;
|
||||
}
|
||||
|
||||
cout << "The following diagram templates are available:\n";
|
||||
for (const auto &[name, diagram_template] : cfg.diagram_templates()) {
|
||||
cout << " - " << name << " [" << to_string(diagram_template.type)
|
||||
<< "]";
|
||||
cout << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
int create_config_file()
|
||||
{
|
||||
namespace fs = std::filesystem;
|
||||
@@ -669,6 +725,65 @@ int add_config_diagram(clanguml::common::model::diagram_t type,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int add_config_diagram_from_template(const std::string &config_file_path,
|
||||
const config::config &cfg, const std::string &template_name,
|
||||
const std::vector<std::string> &template_variables)
|
||||
{
|
||||
if (!cfg.diagram_templates ||
|
||||
!(cfg.diagram_templates().find(template_name) !=
|
||||
cfg.diagram_templates().end())) {
|
||||
std::cerr << "ERROR: No such diagram template: " << template_name
|
||||
<< "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
// First, try to render the template using inja and create a YAML node from
|
||||
// it
|
||||
inja::json ctx;
|
||||
for (const auto &tv : template_variables) {
|
||||
const auto var = util::split(tv, "=");
|
||||
if (var.size() != 2) {
|
||||
std::cerr << "ERROR: Invalid template variable " << tv << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
ctx[var.at(0)] = var.at(1);
|
||||
}
|
||||
|
||||
auto diagram_template_str =
|
||||
cfg.diagram_templates().at(template_name).jinja_template;
|
||||
|
||||
auto diagram_str = inja::render(diagram_template_str, ctx);
|
||||
|
||||
auto diagram_node = YAML::Load(diagram_str);
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
fs::path config_file{config_file_path};
|
||||
|
||||
if (!fs::exists(config_file)) {
|
||||
std::cerr << "ERROR: " << config_file_path << " file doesn't exists\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
YAML::Node doc = YAML::LoadFile(config_file.string());
|
||||
|
||||
const auto diagram_name = diagram_node.begin()->first.as<std::string>();
|
||||
doc["diagrams"][diagram_name] = diagram_node.begin()->second;
|
||||
|
||||
YAML::Emitter out;
|
||||
out.SetIndent(2);
|
||||
|
||||
out << doc;
|
||||
out << YAML::Newline;
|
||||
|
||||
std::ofstream ofs(config_file);
|
||||
ofs << out.c_str();
|
||||
ofs.close();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void print_config(const clanguml::config::config &cfg)
|
||||
{
|
||||
YAML::Emitter out;
|
||||
|
||||
@@ -270,7 +270,7 @@ TEST_CASE("Test config diagram_templates", "[unit-test]")
|
||||
REQUIRE(cfg.diagram_templates()["bases_hierarchy_tmpl"].type ==
|
||||
clanguml::common::model::diagram_t::kClass);
|
||||
REQUIRE(cfg.diagram_templates()["bases_hierarchy_tmpl"].jinja_template ==
|
||||
R"(name: "{{ class_name }}_parents_hierarchy"
|
||||
R"("{{ class_name }}_parents_hierarchy":
|
||||
type: class
|
||||
include:
|
||||
parents: "{{ class_name }}"
|
||||
@@ -286,7 +286,7 @@ plantuml:
|
||||
REQUIRE(cfg.diagram_templates()["children_hierarchy_tmpl"].type ==
|
||||
clanguml::common::model::diagram_t::kClass);
|
||||
REQUIRE(cfg.diagram_templates()["children_hierarchy_tmpl"].jinja_template ==
|
||||
R"(name: "{{ class_name }}_children_hierarchy"
|
||||
R"("{{ class_name }}_children_hierarchy":
|
||||
type: class
|
||||
include:
|
||||
subclasses: "{{ class_name }}"
|
||||
|
||||
@@ -3,7 +3,7 @@ output_directory: output
|
||||
|
||||
diagram_templates:
|
||||
bases_hierarchy_tmpl:
|
||||
name: '{{ class_name }}_parents_hierarchy'
|
||||
'{{ class_name }}_parents_hierarchy':
|
||||
type: class
|
||||
include:
|
||||
parents: '{{ class_name }}'
|
||||
@@ -16,7 +16,7 @@ diagram_templates:
|
||||
before:
|
||||
- left to right direction
|
||||
children_hierarchy_tmpl: |
|
||||
name: '{{ class_name }}_children_hierarchy'
|
||||
'{{ class_name }}_children_hierarchy':
|
||||
type: class
|
||||
include:
|
||||
subclasses: '{{ class_name }}'
|
||||
@@ -29,9 +29,9 @@ diagram_templates:
|
||||
before:
|
||||
- left to right direction
|
||||
main_sequence_tmpl: |
|
||||
name: main_sequence_diargam
|
||||
main_sequence_diagram:
|
||||
type: sequence
|
||||
glob: [ {{ }} ]
|
||||
glob: [ {{ glob }} ]
|
||||
start_from:
|
||||
- function: 'main(int,const char**)'
|
||||
diagrams:
|
||||
|
||||
Reference in New Issue
Block a user