Refactored command line handling
This commit is contained in:
16
.clang-uml
16
.clang-uml
@@ -1,8 +1,8 @@
|
|||||||
compilation_database_dir: debug
|
compilation_database_dir: debug
|
||||||
output_directory: docs/diagrams
|
output_directory: docs/diagrams
|
||||||
generate_links:
|
generate_links:
|
||||||
link: 'https://github.com/bkryza/clang-uml/blob/{{ git.commit }}/{{ element.source.path }}#L{{ element.source.line }}'
|
link: https://github.com/bkryza/clang-uml/blob/{{ git.commit }}/{{ element.source.path }}#L{{ element.source.line }}
|
||||||
tooltip: '{% if existsIn(element, "comment") and existsIn(element.comment, "brief") %}{{ abbrv(trim(replace(element.comment.brief.0, "\n+", " ")), 256) }}{% else %}{{ element.name }}{% endif %}'
|
tooltip: "{% if existsIn(element, \"comment\") and existsIn(element.comment, \"brief\") %}{{ abbrv(trim(replace(element.comment.brief.0, \"\\n+\", \" \")), 256) }}{% else %}{{ element.name }}{% endif %}"
|
||||||
diagrams:
|
diagrams:
|
||||||
main_package:
|
main_package:
|
||||||
include!: uml/main_package_diagram.yml
|
include!: uml/main_package_diagram.yml
|
||||||
@@ -26,3 +26,15 @@ diagrams:
|
|||||||
include!: uml/package_model_class_diagram.yml
|
include!: uml/package_model_class_diagram.yml
|
||||||
include_graph:
|
include_graph:
|
||||||
include!: uml/include_diagram.yml
|
include!: uml/include_diagram.yml
|
||||||
|
include3_diagram_parents_hierarchy:
|
||||||
|
type: class
|
||||||
|
include:
|
||||||
|
parents: [clanguml::config::include_diagram]
|
||||||
|
namespaces: [clanguml]
|
||||||
|
relationships:
|
||||||
|
- inheritance
|
||||||
|
exclude:
|
||||||
|
access: [public, protected, private]
|
||||||
|
plantuml:
|
||||||
|
before:
|
||||||
|
- left to right direction
|
||||||
561
src/cli/cli_handler.cc
Normal file
561
src/cli/cli_handler.cc
Normal file
File diff suppressed because it is too large
Load Diff
153
src/cli/cli_handler.h
Normal file
153
src/cli/cli_handler.h
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
/**
|
||||||
|
* src/options/cli_options.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 "common/model/enums.h"
|
||||||
|
#include "config/config.h"
|
||||||
|
|
||||||
|
#include <cli11/CLI11.hpp>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
namespace clanguml::cli {
|
||||||
|
|
||||||
|
enum class cli_flow_t { kExit, kError, kContinue };
|
||||||
|
|
||||||
|
class cli_handler {
|
||||||
|
public:
|
||||||
|
cli_handler(std::ostream &ostr = std::cout,
|
||||||
|
std::shared_ptr<spdlog::logger> logger = spdlog::stdout_color_mt(
|
||||||
|
"clanguml-logger", spdlog::color_mode::automatic));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main CLI handling method.
|
||||||
|
*
|
||||||
|
* @param argc
|
||||||
|
* @param argv
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
cli_flow_t handle_options(int argc, const char *argv[]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print the program version and basic information
|
||||||
|
*/
|
||||||
|
cli_flow_t print_version();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print list of diagrams available in the configuration file
|
||||||
|
*/
|
||||||
|
cli_flow_t print_diagrams_list();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print list of available diagram templates, including their names
|
||||||
|
* and types.
|
||||||
|
*/
|
||||||
|
cli_flow_t print_diagram_templates();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print definition of a specific diagram template.
|
||||||
|
*
|
||||||
|
* @param template_name
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
cli_flow_t print_diagram_template(const std::string &template_name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print effective config after loading and setting default values.
|
||||||
|
*/
|
||||||
|
cli_flow_t print_config();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate sample configuration file and exit.
|
||||||
|
*
|
||||||
|
* @return 0 on success or error code
|
||||||
|
*/
|
||||||
|
cli_flow_t create_config_file();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add example diagram of given type to the config file.
|
||||||
|
*
|
||||||
|
* @param type Type of the sample diagram to add
|
||||||
|
* @param config_file_path Path to the config file
|
||||||
|
* @param name Name of the new diagram
|
||||||
|
* @return 0 on success or error code
|
||||||
|
*/
|
||||||
|
cli_flow_t 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 template_name
|
||||||
|
* @param template_variables
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
cli_flow_t add_config_diagram_from_template(
|
||||||
|
const std::string &config_file_path, const std::string &template_name,
|
||||||
|
const std::vector<std::string> &template_variables);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if diagram output directory exists, if not create it
|
||||||
|
*
|
||||||
|
* @param dir Path to the output directory
|
||||||
|
* @return True if directory exists or has been created
|
||||||
|
*/
|
||||||
|
bool ensure_output_directory_exists(const std::string &dir);
|
||||||
|
|
||||||
|
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{};
|
||||||
|
bool list_diagrams{false};
|
||||||
|
bool quiet{false};
|
||||||
|
bool initialize{false};
|
||||||
|
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;
|
||||||
|
bool dump_config{false};
|
||||||
|
std::optional<bool> paths_relative_to_pwd{};
|
||||||
|
std::vector<std::string> template_variables{};
|
||||||
|
bool list_templates{false};
|
||||||
|
std::optional<std::string> show_template;
|
||||||
|
|
||||||
|
clanguml::config::config config;
|
||||||
|
|
||||||
|
private:
|
||||||
|
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();
|
||||||
|
|
||||||
|
void setup_logging();
|
||||||
|
|
||||||
|
std::ostream &ostr_;
|
||||||
|
std::shared_ptr<spdlog::logger> logger_;
|
||||||
|
CLI::App app{"Clang-based UML diagram generator for C++"};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace clanguml::options
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "diagram_templates.h"
|
||||||
#include "glob/glob.hpp"
|
#include "glob/glob.hpp"
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ struct plantuml {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct diagram_template {
|
struct diagram_template {
|
||||||
|
std::string description;
|
||||||
common::model::diagram_t type;
|
common::model::diagram_t type;
|
||||||
std::string jinja_template;
|
std::string jinja_template;
|
||||||
};
|
};
|
||||||
@@ -227,6 +228,8 @@ struct config : public inheritable_diagram_options {
|
|||||||
"diagram_templates"};
|
"diagram_templates"};
|
||||||
|
|
||||||
std::map<std::string, std::shared_ptr<diagram>> diagrams;
|
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,
|
config load(const std::string &config_file,
|
||||||
std::optional<bool> paths_relative_to_pwd = {});
|
std::optional<bool> paths_relative_to_pwd = {});
|
||||||
|
|
||||||
|
config load_plain(const std::string &config_file);
|
||||||
} // namespace config
|
} // namespace config
|
||||||
|
|
||||||
namespace common::model {
|
namespace common::model {
|
||||||
|
|||||||
93
src/config/diagram_templates.cc
Normal file
93
src/config/diagram_templates.cc
Normal 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
|
||||||
28
src/config/diagram_templates.h
Normal file
28
src/config/diagram_templates.h
Normal 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
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "diagram_templates.h"
|
||||||
|
|
||||||
namespace YAML {
|
namespace YAML {
|
||||||
using clanguml::common::model::access_t;
|
using clanguml::common::model::access_t;
|
||||||
@@ -112,9 +113,24 @@ void get_option<std::map<std::string, clanguml::config::diagram_template>>(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
option.set(
|
if (node[option.name].IsMap() && node[option.name]["include!"]) {
|
||||||
node[option.name]
|
auto parent_path = node["__parent_path"].as<std::string>();
|
||||||
.as<std::map<std::string, clanguml::config::diagram_template>>());
|
|
||||||
|
// 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)
|
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> {
|
template <> struct convert<diagram_template> {
|
||||||
static bool decode(const Node &node, diagram_template &rhs)
|
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) {
|
rhs.type = clanguml::common::model::from_string(
|
||||||
// Check that the template provided as string is at least valid YAML
|
node["type"].as<std::string>());
|
||||||
const auto yaml_node = Load(node.as<std::string>());
|
rhs.jinja_template = node["template"].as<std::string>();
|
||||||
const auto template_root_it = yaml_node.begin();
|
rhs.description = node["description"].as<std::string>();
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -611,10 +611,11 @@ template <> struct convert<config> {
|
|||||||
auto include_path = std::filesystem::path{parent_path};
|
auto include_path = std::filesystem::path{parent_path};
|
||||||
include_path /= d.second["include!"].as<std::string>();
|
include_path /= d.second["include!"].as<std::string>();
|
||||||
|
|
||||||
YAML::Node node = YAML::LoadFile(include_path.string());
|
YAML::Node included_node =
|
||||||
node.force_insert("__parent_path", parent_path);
|
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 {
|
else {
|
||||||
d.second.force_insert("__parent_path", parent_path);
|
d.second.force_insert("__parent_path", parent_path);
|
||||||
@@ -638,6 +639,20 @@ template <> struct convert<config> {
|
|||||||
|
|
||||||
namespace clanguml::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 {
|
namespace {
|
||||||
void resolve_option_path(YAML::Node &doc, const std::string &option)
|
void resolve_option_path(YAML::Node &doc, const std::string &option)
|
||||||
{
|
{
|
||||||
@@ -729,6 +744,30 @@ config load(
|
|||||||
doc["git"] = git_config;
|
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>();
|
auto d = doc.as<config>();
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|||||||
506
src/main.cc
506
src/main.cc
File diff suppressed because it is too large
Load Diff
@@ -25,27 +25,6 @@ namespace clanguml::util {
|
|||||||
|
|
||||||
static const auto WHITESPACE = " \n\r\t\f\v";
|
static const auto WHITESPACE = " \n\r\t\f\v";
|
||||||
|
|
||||||
void setup_logging(int verbose)
|
|
||||||
{
|
|
||||||
auto console =
|
|
||||||
spdlog::stdout_color_mt("console", spdlog::color_mode::automatic);
|
|
||||||
|
|
||||||
console->set_pattern("[%^%l%^] [tid %t] %v");
|
|
||||||
|
|
||||||
if (verbose == 0) {
|
|
||||||
console->set_level(spdlog::level::err);
|
|
||||||
}
|
|
||||||
else if (verbose == 1) {
|
|
||||||
console->set_level(spdlog::level::info);
|
|
||||||
}
|
|
||||||
else if (verbose == 2) {
|
|
||||||
console->set_level(spdlog::level::debug);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
console->set_level(spdlog::level::trace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string get_process_output(const std::string &command)
|
std::string get_process_output(const std::string &command)
|
||||||
{
|
{
|
||||||
constexpr size_t kBufferSize{1024};
|
constexpr size_t kBufferSize{1024};
|
||||||
|
|||||||
@@ -28,29 +28,29 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#define LOG_ERROR(fmt__, ...) \
|
#define LOG_ERROR(fmt__, ...) \
|
||||||
spdlog::get("console")->error( \
|
spdlog::get("clanguml-logger") \
|
||||||
fmt::runtime(std::string("[{}:{}] ") + fmt__), FILENAME_, __LINE__, \
|
->error(fmt::runtime(std::string("[{}:{}] ") + fmt__), FILENAME_, \
|
||||||
##__VA_ARGS__)
|
__LINE__, ##__VA_ARGS__)
|
||||||
|
|
||||||
#define LOG_WARN(fmt__, ...) \
|
#define LOG_WARN(fmt__, ...) \
|
||||||
spdlog::get("console")->warn( \
|
spdlog::get("clanguml-logger") \
|
||||||
fmt::runtime(std::string("[{}:{}] ") + fmt__), FILENAME_, __LINE__, \
|
->warn(fmt::runtime(std::string("[{}:{}] ") + fmt__), FILENAME_, \
|
||||||
##__VA_ARGS__)
|
__LINE__, ##__VA_ARGS__)
|
||||||
|
|
||||||
#define LOG_INFO(fmt__, ...) \
|
#define LOG_INFO(fmt__, ...) \
|
||||||
spdlog::get("console")->info( \
|
spdlog::get("clanguml-logger") \
|
||||||
fmt::runtime(std::string("[{}:{}] ") + fmt__), FILENAME_, __LINE__, \
|
->info(fmt::runtime(std::string("[{}:{}] ") + fmt__), FILENAME_, \
|
||||||
##__VA_ARGS__)
|
__LINE__, ##__VA_ARGS__)
|
||||||
|
|
||||||
#define LOG_DBG(fmt__, ...) \
|
#define LOG_DBG(fmt__, ...) \
|
||||||
spdlog::get("console")->debug( \
|
spdlog::get("clanguml-logger") \
|
||||||
fmt::runtime(std::string("[{}:{}] ") + fmt__), FILENAME_, __LINE__, \
|
->debug(fmt::runtime(std::string("[{}:{}] ") + fmt__), FILENAME_, \
|
||||||
##__VA_ARGS__)
|
__LINE__, ##__VA_ARGS__)
|
||||||
|
|
||||||
#define LOG_TRACE(fmt__, ...) \
|
#define LOG_TRACE(fmt__, ...) \
|
||||||
spdlog::get("console")->trace( \
|
spdlog::get("clanguml-logger") \
|
||||||
fmt::runtime(std::string("[{}:{}] ") + fmt__), FILENAME_, __LINE__, \
|
->trace(fmt::runtime(std::string("[{}:{}] ") + fmt__), FILENAME_, \
|
||||||
##__VA_ARGS__)
|
__LINE__, ##__VA_ARGS__)
|
||||||
|
|
||||||
namespace clanguml::util {
|
namespace clanguml::util {
|
||||||
|
|
||||||
@@ -61,13 +61,6 @@ std::string trim(const std::string &s);
|
|||||||
#define FILENAME_ \
|
#define FILENAME_ \
|
||||||
(strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
|
(strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Setup spdlog logger.
|
|
||||||
*
|
|
||||||
* @param verbose Whether the logging should be verbose or not.
|
|
||||||
*/
|
|
||||||
void setup_logging(int verbose);
|
|
||||||
|
|
||||||
std::string get_process_output(const std::string &command);
|
std::string get_process_output(const std::string &command);
|
||||||
|
|
||||||
std::string get_env(const std::string &name);
|
std::string get_env(const std::string &name);
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ set(TEST_CASES
|
|||||||
test_cases
|
test_cases
|
||||||
test_decorator_parser
|
test_decorator_parser
|
||||||
test_config
|
test_config
|
||||||
|
test_cli_handler
|
||||||
test_filters
|
test_filters
|
||||||
test_thread_pool_executor)
|
test_thread_pool_executor)
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "test_cases.h"
|
#include "test_cases.h"
|
||||||
|
|
||||||
|
#include "cli/cli_handler.h"
|
||||||
#include "common/generators/plantuml/generator.h"
|
#include "common/generators/plantuml/generator.h"
|
||||||
|
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
@@ -345,7 +347,17 @@ int main(int argc, char *argv[])
|
|||||||
if (returnCode != 0)
|
if (returnCode != 0)
|
||||||
return returnCode;
|
return returnCode;
|
||||||
|
|
||||||
clanguml::util::setup_logging(debug_log ? 3 : 1);
|
clanguml::cli::cli_handler clih;
|
||||||
|
|
||||||
|
std::vector<const char *> argvv = {
|
||||||
|
"clang-uml", "--config", "./test_config_data/simple.yml"};
|
||||||
|
|
||||||
|
if (debug_log)
|
||||||
|
argvv.push_back("-vvv");
|
||||||
|
else
|
||||||
|
argvv.push_back("-q");
|
||||||
|
|
||||||
|
clih.handle_options(argvv.size(), argvv.data());
|
||||||
|
|
||||||
return session.run();
|
return session.run();
|
||||||
}
|
}
|
||||||
|
|||||||
74
tests/test_cli_handler.cc
Normal file
74
tests/test_cli_handler.cc
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
/**
|
||||||
|
* tests/test_cli_handler.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.
|
||||||
|
*/
|
||||||
|
#define CATCH_CONFIG_MAIN
|
||||||
|
|
||||||
|
#include "cli/cli_handler.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
|
#include "catch.h"
|
||||||
|
|
||||||
|
#include <spdlog/sinks/ostream_sink.h>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
|
std::shared_ptr<spdlog::logger> make_sstream_logger(std::ostream &ostr)
|
||||||
|
{
|
||||||
|
auto oss_sink = std::make_shared<spdlog::sinks::ostream_sink_mt>(ostr);
|
||||||
|
return std::make_shared<spdlog::logger>(
|
||||||
|
"clanguml-logger", std::move(oss_sink));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test cli handler print_version", "[unit-test]")
|
||||||
|
{
|
||||||
|
using clanguml::cli::cli_flow_t;
|
||||||
|
using clanguml::cli::cli_handler;
|
||||||
|
|
||||||
|
std::vector<const char *> argv = {"clang-uml", "--version"};
|
||||||
|
|
||||||
|
std::ostringstream ostr;
|
||||||
|
cli_handler cli{ostr, make_sstream_logger(ostr)};
|
||||||
|
|
||||||
|
auto res = cli.handle_options(argv.size(), argv.data());
|
||||||
|
|
||||||
|
REQUIRE(res == cli_flow_t::kExit);
|
||||||
|
|
||||||
|
auto output = ostr.str();
|
||||||
|
|
||||||
|
REQUIRE(output.find(fmt::format(
|
||||||
|
"clang-uml {}", clanguml::version::CLANG_UML_VERSION)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test cli handler print_config", "[unit-test]")
|
||||||
|
{
|
||||||
|
using clanguml::cli::cli_flow_t;
|
||||||
|
using clanguml::cli::cli_handler;
|
||||||
|
|
||||||
|
std::vector<const char *> argv = {"clang-uml", "--config",
|
||||||
|
"./test_config_data/simple.yml", "--dump-config"};
|
||||||
|
|
||||||
|
std::ostringstream ostr;
|
||||||
|
cli_handler cli{ostr, make_sstream_logger(ostr)};
|
||||||
|
|
||||||
|
auto res = cli.handle_options(argv.size(), argv.data());
|
||||||
|
|
||||||
|
REQUIRE(res == cli_flow_t::kExit);
|
||||||
|
|
||||||
|
auto output = ostr.str();
|
||||||
|
YAML::Node doc = YAML::Load(output);
|
||||||
|
|
||||||
|
REQUIRE(doc["diagrams"]["class_main"]);
|
||||||
|
}
|
||||||
@@ -265,39 +265,55 @@ TEST_CASE("Test config diagram_templates", "[unit-test]")
|
|||||||
auto cfg =
|
auto cfg =
|
||||||
clanguml::config::load("./test_config_data/diagram_templates.yml");
|
clanguml::config::load("./test_config_data/diagram_templates.yml");
|
||||||
|
|
||||||
REQUIRE(cfg.diagram_templates().size() == 3);
|
REQUIRE(cfg.diagram_templates().size() == 4);
|
||||||
|
|
||||||
REQUIRE(cfg.diagram_templates()["bases_hierarchy_tmpl"].type ==
|
REQUIRE(cfg.diagram_templates()["parents_hierarchy_tmpl"].type ==
|
||||||
clanguml::common::model::diagram_t::kClass);
|
clanguml::common::model::diagram_t::kClass);
|
||||||
REQUIRE(cfg.diagram_templates()["bases_hierarchy_tmpl"].jinja_template ==
|
REQUIRE(cfg.diagram_templates()["parents_hierarchy_tmpl"].jinja_template ==
|
||||||
R"("{{ class_name }}_parents_hierarchy":
|
"{{ diagram_name }}:"
|
||||||
|
R"(
|
||||||
type: class
|
type: class
|
||||||
|
{% if exists("glob") %}
|
||||||
|
glob: [{{ glob }}]
|
||||||
|
{% endif %}
|
||||||
|
{% if exists("using_namespace") %}
|
||||||
|
using_namespace: {{ using_namespace }}
|
||||||
|
{% endif %}
|
||||||
include:
|
include:
|
||||||
parents: "{{ class_name }}"
|
parents: [{{ class_name }}]
|
||||||
namespaces: "{{ namespace_name }}"
|
namespaces: [{{ namespace_names }}]
|
||||||
relationships:
|
relationships:
|
||||||
- inheritance
|
- inheritance
|
||||||
exclude:
|
exclude:
|
||||||
access: [public, protected, private]
|
access: [public, protected, private]
|
||||||
plantuml:
|
plantuml:
|
||||||
before:
|
before:
|
||||||
- left to right direction)");
|
- left to right direction
|
||||||
|
)");
|
||||||
|
|
||||||
REQUIRE(cfg.diagram_templates()["children_hierarchy_tmpl"].type ==
|
REQUIRE(cfg.diagram_templates()["children_hierarchy_tmpl"].type ==
|
||||||
clanguml::common::model::diagram_t::kClass);
|
clanguml::common::model::diagram_t::kClass);
|
||||||
REQUIRE(cfg.diagram_templates()["children_hierarchy_tmpl"].jinja_template ==
|
REQUIRE(cfg.diagram_templates()["subclass_hierarchy_tmpl"].jinja_template ==
|
||||||
R"("{{ class_name }}_children_hierarchy":
|
"{{ diagram_name }}:"
|
||||||
|
R"(
|
||||||
type: class
|
type: class
|
||||||
|
{% if exists("glob") %}
|
||||||
|
glob: [{{ glob }}]
|
||||||
|
{% endif %}
|
||||||
|
{% if exists("using_namespace") %}
|
||||||
|
using_namespace: {{ using_namespace }}
|
||||||
|
{% endif %}
|
||||||
include:
|
include:
|
||||||
subclasses: "{{ class_name }}"
|
parents: [{{ class_name }}]
|
||||||
namespaces: "{{ namespace_name }}"
|
namespaces: [{{ namespace_name }}]
|
||||||
relationships:
|
relationships:
|
||||||
- inheritance
|
- inheritance
|
||||||
exclude:
|
exclude:
|
||||||
access: [public, protected, private]
|
access: [public, protected, private]
|
||||||
plantuml:
|
plantuml:
|
||||||
before:
|
before:
|
||||||
- left to right direction)");
|
- left to right direction
|
||||||
|
)");
|
||||||
|
|
||||||
REQUIRE(cfg.diagram_templates()["main_sequence_tmpl"].type ==
|
REQUIRE(cfg.diagram_templates()["main_sequence_tmpl"].type ==
|
||||||
clanguml::common::model::diagram_t::kSequence);
|
clanguml::common::model::diagram_t::kSequence);
|
||||||
|
|||||||
@@ -2,33 +2,10 @@ compilation_database_dir: debug
|
|||||||
output_directory: output
|
output_directory: output
|
||||||
|
|
||||||
diagram_templates:
|
diagram_templates:
|
||||||
bases_hierarchy_tmpl:
|
main_sequence_tmpl:
|
||||||
'{{ class_name }}_parents_hierarchy':
|
description: Sequence diagram of the main() function
|
||||||
type: class
|
type: sequence
|
||||||
include:
|
template: |
|
||||||
parents: '{{ class_name }}'
|
|
||||||
namespaces: '{{ namespace_name }}'
|
|
||||||
relationships:
|
|
||||||
- inheritance
|
|
||||||
exclude:
|
|
||||||
access: [public, protected, private]
|
|
||||||
plantuml:
|
|
||||||
before:
|
|
||||||
- left to right direction
|
|
||||||
children_hierarchy_tmpl: |
|
|
||||||
'{{ class_name }}_children_hierarchy':
|
|
||||||
type: class
|
|
||||||
include:
|
|
||||||
subclasses: '{{ class_name }}'
|
|
||||||
namespaces: '{{ namespace_name }}'
|
|
||||||
relationships:
|
|
||||||
- inheritance
|
|
||||||
exclude:
|
|
||||||
access: [public, protected, private]
|
|
||||||
plantuml:
|
|
||||||
before:
|
|
||||||
- left to right direction
|
|
||||||
main_sequence_tmpl: |
|
|
||||||
main_sequence_diagram:
|
main_sequence_diagram:
|
||||||
type: sequence
|
type: sequence
|
||||||
glob: [ {{ glob }} ]
|
glob: [ {{ glob }} ]
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
compilation_database_dir: debug
|
compilation_database_dir: debug
|
||||||
output_directory: output
|
output_directory: output
|
||||||
|
|
||||||
diagrams:
|
diagrams:
|
||||||
class_main:
|
class_main:
|
||||||
type: class
|
type: class
|
||||||
|
|||||||
Reference in New Issue
Block a user