Improved fetch-content support

Closes #38
This commit is contained in:
Duncan Ogilvie
2022-02-12 04:05:51 +01:00
parent 06a4c04df6
commit 85370968f8
3 changed files with 72 additions and 28 deletions
+57 -19
View File
@@ -5,6 +5,7 @@
#include <stdexcept>
#include <toml.hpp>
#include <tsl/ordered_map.h>
#include <tsl/ordered_set.h>
namespace cmkr {
namespace parser {
@@ -49,8 +50,8 @@ static std::string format_key_error(const std::string &error, const toml::key &k
class TomlChecker {
const TomlBasicValue &m_v;
tsl::ordered_map<toml::key, bool> m_visited;
tsl::ordered_map<toml::key, bool> m_conditionVisited;
tsl::ordered_set<toml::key> m_visited;
tsl::ordered_set<toml::key> m_conditionVisited;
public:
TomlChecker(const TomlBasicValue &v, const toml::key &ky) : m_v(toml::find(v, ky)) {}
@@ -77,7 +78,7 @@ class TomlChecker {
// Handle visiting logic
for (const auto &itr : destination) {
if (!itr.first.empty()) {
m_conditionVisited.emplace(itr.first, true);
m_conditionVisited.emplace(itr.first);
}
}
visit(ky);
@@ -108,7 +109,9 @@ class TomlChecker {
return toml::find(m_v, ky);
}
void visit(const toml::key &ky) { m_visited.emplace(ky, true); }
void visit(const toml::key &ky) { m_visited.emplace(ky); }
bool visisted(const toml::key &ky) const { return m_visited.contains(ky); }
void check(const tsl::ordered_map<std::string, std::string> &conditions) const {
for (const auto &itr : m_v.as_table()) {
@@ -145,7 +148,7 @@ class TomlChecker {
class TomlCheckerRoot {
const TomlBasicValue &m_root;
std::deque<TomlChecker> m_checkers;
tsl::ordered_map<toml::key, bool> m_visisted;
tsl::ordered_set<toml::key> m_visisted;
bool m_checked = false;
public:
@@ -154,7 +157,7 @@ class TomlCheckerRoot {
TomlCheckerRoot(TomlCheckerRoot &&) = delete;
bool contains(const toml::key &ky) {
m_visisted[ky] = true;
m_visisted.emplace(ky);
return m_root.contains(ky);
}
@@ -353,19 +356,49 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
}
}
// TODO: perform checking here
if (checker.contains("fetch-content")) {
const auto &fc = toml::find(toml, "fetch-content").as_table();
for (const auto &itr : fc) {
Content content;
content.name = itr.first;
auto &c = checker.create(itr.second);
c.optional("condition", content.condition);
c.optional("cmake-before", content.cmake_before);
c.optional("cmake-after", content.cmake_after);
c.optional("include-before", content.include_before);
c.optional("include-after", content.include_after);
for (const auto &argItr : itr.second.as_table()) {
auto key = argItr.first;
if (key == "condition") {
content.condition = argItr.second.as_string();
continue;
std::string value;
if (argItr.second.is_array()) {
for (const auto &list_val : argItr.second.as_array()) {
if (!value.empty()) {
value += ';';
}
value += list_val.as_string();
}
} else if (argItr.second.is_boolean()) {
value = argItr.second.as_boolean() ? "ON" : "OFF";
} else {
value = argItr.second.as_string();
}
auto is_cmake_arg = [](const std::string &s) {
for (auto c : s) {
if (!(std::isdigit(c) || std::isupper(c) || c == '_')) {
return false;
}
}
return true;
};
// https://cmake.org/cmake/help/latest/command/string.html#supported-hash-algorithms
tsl::ordered_set<std::string> hash_algorithms = {
"md5", "sha1", "sha224", "sha256", "sha384", "sha512", "sha3_224", "sha3_256", "sha3_384", "sha3_512",
};
auto key = argItr.first;
if (key == "git") {
key = "GIT_REPOSITORY";
} else if (key == "tag") {
@@ -378,18 +411,23 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
key = "SVN_REVISION";
} else if (key == "url") {
key = "URL";
} else if (hash_algorithms.contains(key)) {
std::string algo;
for (auto c : key) {
algo.push_back(std::toupper(c));
}
key = "URL_HASH";
value = algo + "=" + value;
} else if (key == "hash") {
key = "URL_HASH";
} else {
// don't change arg
} else if (is_cmake_arg(key)) {
// allow passthrough of ExternalProject options
} else if (!c.visisted(key)) {
throw std::runtime_error(format_key_error("Unknown key '" + argItr.first + "'", argItr.first, argItr.second));
}
std::string value;
if (argItr.second.is_boolean()) {
value = argItr.second.as_boolean() ? "ON" : "OFF";
} else {
value = argItr.second.as_string();
}
c.visit(argItr.first);
content.arguments.emplace(key, value);
}
contents.emplace_back(std::move(content));