Skip to content

Commit

Permalink
feat: Generate config descriptions (#1842)
Browse files Browse the repository at this point in the history
Fixes #1460
  • Loading branch information
PeterChen13579 authored Feb 10, 2025
1 parent f5e6c95 commit cd6289b
Show file tree
Hide file tree
Showing 14 changed files with 454 additions and 62 deletions.
22 changes: 18 additions & 4 deletions src/app/CliArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include "migration/MigrationApplication.hpp"
#include "util/build/Build.hpp"
#include "util/newconfig/ConfigDescription.hpp"

#include <boost/program_options/options_description.hpp>
#include <boost/program_options/parsers.hpp>
Expand All @@ -29,6 +30,7 @@
#include <boost/program_options/variables_map.hpp>

#include <cstdlib>
#include <filesystem>
#include <iostream>
#include <string>
#include <utility>
Expand All @@ -42,12 +44,13 @@ CliArgs::parse(int argc, char const* argv[])
// clang-format off
po::options_description description("Options");
description.add_options()
("help,h", "print help message and exit")
("version,v", "print version and exit")
("conf,c", po::value<std::string>()->default_value(kDEFAULT_CONFIG_PATH), "configuration file")
("help,h", "Print help message and exit")
("version,v", "Print version and exit")
("conf,c", po::value<std::string>()->default_value(kDEFAULT_CONFIG_PATH), "Configuration file")
("ng-web-server,w", "Use ng-web-server")
("migrate", po::value<std::string>(), "start migration helper")
("migrate", po::value<std::string>(), "Start migration helper")
("verify", "Checks the validity of config values")
("config-description,d", po::value<std::string>(), "Generate config description markdown file")
;
// clang-format on
po::positional_options_description positional;
Expand All @@ -67,6 +70,17 @@ CliArgs::parse(int argc, char const* argv[])
return Action{Action::Exit{EXIT_SUCCESS}};
}

if (parsed.count("config-description") != 0u) {
std::filesystem::path filePath = parsed["config-description"].as<std::string>();

auto const res = util::config::ClioConfigDescription::generateConfigDescriptionToFile(filePath);
if (res.has_value())
return Action{Action::Exit{EXIT_SUCCESS}};

std::cerr << res.error().error << std::endl;
return Action{Action::Exit{EXIT_FAILURE}};
}

auto configPath = parsed["conf"].as<std::string>();

if (parsed.count("migrate") != 0u) {
Expand Down
1 change: 1 addition & 0 deletions src/util/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ target_sources(
newconfig/ConfigDefinition.cpp
newconfig/ConfigFileJson.cpp
newconfig/ObjectView.cpp
newconfig/Types.cpp
newconfig/ValueView.cpp
)

Expand Down
15 changes: 15 additions & 0 deletions src/util/newconfig/Array.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

#include <cstddef>
#include <optional>
#include <ostream>
#include <string_view>
#include <vector>

Expand Down Expand Up @@ -103,4 +104,18 @@ class Array {
std::vector<ConfigValue> elements_;
};

/**
* @brief Custom output stream for Array
*
* @param stream The output stream
* @param arr The Array
* @return The same ostream we were given
*/
inline std::ostream&
operator<<(std::ostream& stream, Array arr)
{
stream << arr.getArrayPattern();
return stream;
}

} // namespace util::config
78 changes: 78 additions & 0 deletions src/util/newconfig/ConfigConstraints.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <cstdint>
#include <limits>
#include <optional>
#include <ostream>
#include <string>
#include <string_view>
#include <variant>
Expand Down Expand Up @@ -149,6 +150,28 @@ class Constraint {
*/
virtual std::optional<Error>
checkValueImpl(Value const& val) const = 0;

/**
* @brief Prints to the output stream for this specific constraint.
*
* @param stream The output stream
*/
virtual void
print(std::ostream& stream) const = 0;

/**
* @brief Custom output stream for constraint
*
* @param stream The output stream
* @param cons The constraint
* @return The same ostream we were given
*/
friend std::ostream&
operator<<(std::ostream& stream, Constraint const& cons)
{
cons.print(stream);
return stream;
}
};

/**
Expand Down Expand Up @@ -177,6 +200,17 @@ class PortConstraint final : public Constraint {
[[nodiscard]] std::optional<Error>
checkValueImpl(Value const& port) const override;

/**
* @brief Prints to the output stream for this specific constraint.
*
* @param stream The output stream
*/
void
print(std::ostream& stream) const override
{
stream << fmt::format("The minimum value is `{}`. The maximum value is `{}", kPORT_MIN, kPORT_MAX);
}

static constexpr uint32_t kPORT_MIN = 1;
static constexpr uint32_t kPORT_MAX = 65535;
};
Expand Down Expand Up @@ -206,6 +240,17 @@ class ValidIPConstraint final : public Constraint {
*/
[[nodiscard]] std::optional<Error>
checkValueImpl(Value const& ip) const override;

/**
* @brief Prints to the output stream for this specific constraint.
*
* @param stream The output stream
*/
void
print(std::ostream& stream) const override
{
stream << "The value must be a valid IP address";
}
};

/**
Expand Down Expand Up @@ -260,6 +305,17 @@ class OneOf final : public Constraint {
return Error{makeErrorMsg(key_, val, arr_)};
}

/**
* @brief Prints to the output stream for this specific constraint.
*
* @param stream The output stream
*/
void
print(std::ostream& stream) const override
{
stream << fmt::format("The value must be one of the following: `{}`", fmt::join(arr_, ", "));
}

std::string_view key_;
std::array<char const*, ArrSize> arr_;
};
Expand Down Expand Up @@ -312,6 +368,17 @@ class NumberValueConstraint final : public Constraint {
return Error{fmt::format("Number must be between {} and {}", min_, max_)};
}

/**
* @brief Prints to the output stream for this specific constraint.
*
* @param stream The output stream
*/
void
print(std::ostream& stream) const override
{
stream << fmt::format("The minimum value is `{}`. The maximum value is `{}`", min_, max_);
}

NumType min_;
NumType max_;
};
Expand Down Expand Up @@ -341,6 +408,17 @@ class PositiveDouble final : public Constraint {
*/
[[nodiscard]] std::optional<Error>
checkValueImpl(Value const& num) const override;

/**
* @brief Prints to the output stream for this specific constraint.
*
* @param stream The output stream
*/
void
print(std::ostream& stream) const override
{
stream << fmt::format("The value must be a positive double number");
}
};

static constinit PortConstraint gValidatePort{};
Expand Down
1 change: 1 addition & 0 deletions src/util/newconfig/ConfigDefinition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ ClioConfigDefinition::getObject(std::string_view prefix, std::optional<std::size
auto const hasPrefix = mapKey.starts_with(prefixWithDot);
if (idx.has_value() && hasPrefix && std::holds_alternative<Array>(mapVal)) {
ASSERT(std::get<Array>(mapVal).size() > idx.value(), "Index provided is out of scope");

// we want to support getObject("array") and getObject("array.[]"), so we check if "[]" exists
if (!prefix.contains("[]"))
return ObjectView{prefixWithDot + "[]", idx.value(), *this};
Expand Down
27 changes: 0 additions & 27 deletions src/util/newconfig/ConfigDefinition.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,17 @@
#include "util/Assert.hpp"
#include "util/newconfig/Array.hpp"
#include "util/newconfig/ConfigConstraints.hpp"
#include "util/newconfig/ConfigDescription.hpp"
#include "util/newconfig/ConfigFileInterface.hpp"
#include "util/newconfig/ConfigValue.hpp"
#include "util/newconfig/Error.hpp"
#include "util/newconfig/ObjectView.hpp"
#include "util/newconfig/Types.hpp"
#include "util/newconfig/ValueView.hpp"

#include <boost/json/value.hpp>
#include <boost/json/value_to.hpp>
#include <fmt/core.h>

#include <algorithm>
#include <cassert>
#include <chrono>
#include <cstddef>
#include <cstdint>
#include <expected>
#include <initializer_list>
#include <optional>
#include <string>
Expand Down Expand Up @@ -84,26 +77,6 @@ class ClioConfigDefinition {
[[nodiscard]] std::optional<std::vector<Error>>
parse(ConfigFileInterface const& config);

/**
* @brief Validates the configuration file
*
* Should only check for valid values, without populating
*
* @param config The configuration file interface
* @return An optional vector of Error objects stating all the failures if validation fails
*/
[[nodiscard]] std::optional<std::vector<Error>>
validate(ConfigFileInterface const& config) const;

/**
* @brief Generate markdown file of all the clio config descriptions
*
* @param configDescription The configuration description object
* @return An optional Error if generating markdown fails
*/
[[nodiscard]] std::expected<std::string, Error>
getMarkdown(ClioConfigDescription const& configDescription) const;

/**
* @brief Returns the ObjectView specified with the prefix
*
Expand Down
Loading

0 comments on commit cd6289b

Please sign in to comment.