Refactored command line handling

This commit is contained in:
Bartek Kryza
2023-03-11 18:59:53 +01:00
parent 41537c5401
commit f1c125bf32
17 changed files with 1066 additions and 609 deletions

View File

@@ -17,6 +17,7 @@
*/
#include "config.h"
#include "diagram_templates.h"
#include "glob/glob.hpp"
#include <filesystem>

View File

@@ -51,6 +51,7 @@ struct plantuml {
};
struct diagram_template {
std::string description;
common::model::diagram_t type;
std::string jinja_template;
};
@@ -227,6 +228,8 @@ struct config : public inheritable_diagram_options {
"diagram_templates"};
std::map<std::string, std::shared_ptr<diagram>> diagrams;
void initialize_diagram_templates();
};
//
@@ -287,6 +290,8 @@ YAML::Emitter &operator<<(YAML::Emitter &out, const option<T> &o)
config load(const std::string &config_file,
std::optional<bool> paths_relative_to_pwd = {});
config load_plain(const std::string &config_file);
} // namespace config
namespace common::model {

View File

@@ -0,0 +1,93 @@
/**
* src/config/diagram_templates.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "diagram_templates.h"
namespace clanguml {
namespace config {
const std::string &get_predefined_diagram_templates()
{
static const std::string predefined_diagram_templates =
R"(# Predefined diagram templates
parents_hierarchy_tmpl:
description: Generate class parents inheritance diagram
type: class
template: |
{{ diagram_name }}:
type: class
{% if exists("glob") %}
glob: [{{ glob }}]
{% endif %}
{% if exists("using_namespace") %}
using_namespace: {{ using_namespace }}
{% endif %}
include:
parents: [{{ class_name }}]
namespaces: [{{ namespace_names }}]
relationships:
- inheritance
exclude:
access: [public, protected, private]
plantuml:
before:
- left to right direction
subclass_hierarchy_tmpl:
description: Generate class children inheritance diagram
type: class
template: |
{{ diagram_name }}:
type: class
{% if exists("glob") %}
glob: [{{ glob }}]
{% endif %}
{% if exists("using_namespace") %}
using_namespace: {{ using_namespace }}
{% endif %}
include:
parents: [{{ class_name }}]
namespaces: [{{ namespace_name }}]
relationships:
- inheritance
exclude:
access: [public, protected, private]
plantuml:
before:
- left to right direction
class_context_tmpl:
description: Generate class context diagram
type: class
template: |
"{{ diagram_name }}":
type: class
{% if exists("glob") %}
glob: [{{ glob }}]
{% endif %}
{% if exists("using_namespace") %}
using_namespace: {{ using_namespace }}
{% endif %}
include:
context: [{{ class_name }}]
namespaces: [{{ namespace_name }}]
)";
return predefined_diagram_templates;
}
} // namespace config
} // namespace clanguml

View File

@@ -0,0 +1,28 @@
/**
* src/config/diagram_templates.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <string>
namespace clanguml {
namespace config {
const std::string &get_predefined_diagram_templates();
} // namespace config
} // namespace clanguml

View File

@@ -17,6 +17,7 @@
*/
#include "config.h"
#include "diagram_templates.h"
namespace YAML {
using clanguml::common::model::access_t;
@@ -112,9 +113,24 @@ void get_option<std::map<std::string, clanguml::config::diagram_template>>(
return;
}
option.set(
node[option.name]
.as<std::map<std::string, clanguml::config::diagram_template>>());
if (node[option.name].IsMap() && node[option.name]["include!"]) {
auto parent_path = node["__parent_path"].as<std::string>();
// Load templates from file
auto include_path = std::filesystem::path{parent_path};
include_path /= node[option.name]["include!"].as<std::string>();
YAML::Node included_node = YAML::LoadFile(include_path.string());
// diagram_config = parse_diagram_config(included_node);
option.set(
included_node.as<
std::map<std::string, clanguml::config::diagram_template>>());
}
else
option.set(node[option.name]
.as<std::map<std::string,
clanguml::config::diagram_template>>());
}
std::shared_ptr<clanguml::config::diagram> parse_diagram_config(const Node &d)
@@ -548,28 +564,12 @@ template <> struct convert<relationship_hint_t> {
template <> struct convert<diagram_template> {
static bool decode(const Node &node, diagram_template &rhs)
{
assert(node.Type() == NodeType::Map || node.Type() == NodeType::Scalar);
assert(node.Type() == NodeType::Map);
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 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 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);
}
rhs.type = clanguml::common::model::from_string(
node["type"].as<std::string>());
rhs.jinja_template = node["template"].as<std::string>();
rhs.description = node["description"].as<std::string>();
return true;
}
@@ -611,10 +611,11 @@ template <> struct convert<config> {
auto include_path = std::filesystem::path{parent_path};
include_path /= d.second["include!"].as<std::string>();
YAML::Node node = YAML::LoadFile(include_path.string());
node.force_insert("__parent_path", parent_path);
YAML::Node included_node =
YAML::LoadFile(include_path.string());
included_node.force_insert("__parent_path", parent_path);
diagram_config = parse_diagram_config(node);
diagram_config = parse_diagram_config(included_node);
}
else {
d.second.force_insert("__parent_path", parent_path);
@@ -638,6 +639,20 @@ template <> struct convert<config> {
namespace clanguml::config {
void config::initialize_diagram_templates()
{
const auto &predefined_templates_str = get_predefined_diagram_templates();
YAML::Node predefined_templates = YAML::Load(predefined_templates_str);
if (!diagram_templates) {
diagram_templates.set({});
}
diagram_templates().merge(
predefined_templates.as<std::map<std::string, diagram_template>>());
}
namespace {
void resolve_option_path(YAML::Node &doc, const std::string &option)
{
@@ -729,6 +744,30 @@ config load(
doc["git"] = git_config;
}
auto d = doc.as<config>();
d.initialize_diagram_templates();
return d;
}
catch (YAML::BadFile &e) {
throw std::runtime_error(fmt::format(
"Could not open config file {}: {}", config_file, e.what()));
}
catch (YAML::Exception &e) {
throw std::runtime_error(fmt::format(
"Cannot parse YAML file {}: {}", config_file, e.what()));
}
}
config load_plain(const std::string &config_file)
{
try {
YAML::Node doc;
std::filesystem::path config_file_path{};
doc = YAML::LoadFile(config_file);
auto d = doc.as<config>();
return d;
}