55#include < stdexcept>
66#include < toml.hpp>
77#include < tsl/ordered_map.h>
8+ #include < tsl/ordered_set.h>
89
910namespace cmkr {
1011namespace parser {
@@ -49,8 +50,8 @@ static std::string format_key_error(const std::string &error, const toml::key &k
4950
5051class TomlChecker {
5152 const TomlBasicValue &m_v;
52- tsl::ordered_map <toml::key, bool > m_visited;
53- tsl::ordered_map <toml::key, bool > m_conditionVisited;
53+ tsl::ordered_set <toml::key> m_visited;
54+ tsl::ordered_set <toml::key> m_conditionVisited;
5455
5556 public:
5657 TomlChecker (const TomlBasicValue &v, const toml::key &ky) : m_v(toml::find(v, ky)) {}
@@ -77,7 +78,7 @@ class TomlChecker {
7778 // Handle visiting logic
7879 for (const auto &itr : destination) {
7980 if (!itr.first .empty ()) {
80- m_conditionVisited.emplace (itr.first , true );
81+ m_conditionVisited.emplace (itr.first );
8182 }
8283 }
8384 visit (ky);
@@ -108,7 +109,9 @@ class TomlChecker {
108109 return toml::find (m_v, ky);
109110 }
110111
111- void visit (const toml::key &ky) { m_visited.emplace (ky, true ); }
112+ void visit (const toml::key &ky) { m_visited.emplace (ky); }
113+
114+ bool visisted (const toml::key &ky) const { return m_visited.contains (ky); }
112115
113116 void check (const tsl::ordered_map<std::string, std::string> &conditions) const {
114117 for (const auto &itr : m_v.as_table ()) {
@@ -145,7 +148,7 @@ class TomlChecker {
145148class TomlCheckerRoot {
146149 const TomlBasicValue &m_root;
147150 std::deque<TomlChecker> m_checkers;
148- tsl::ordered_map <toml::key, bool > m_visisted;
151+ tsl::ordered_set <toml::key> m_visisted;
149152 bool m_checked = false ;
150153
151154 public:
@@ -154,7 +157,7 @@ class TomlCheckerRoot {
154157 TomlCheckerRoot (TomlCheckerRoot &&) = delete ;
155158
156159 bool contains (const toml::key &ky) {
157- m_visisted[ky] = true ;
160+ m_visisted. emplace (ky) ;
158161 return m_root.contains (ky);
159162 }
160163
@@ -353,19 +356,49 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
353356 }
354357 }
355358
356- // TODO: perform checking here
357359 if (checker.contains (" fetch-content" )) {
358360 const auto &fc = toml::find (toml, " fetch-content" ).as_table ();
359361 for (const auto &itr : fc) {
360362 Content content;
361363 content.name = itr.first ;
364+
365+ auto &c = checker.create (itr.second );
366+ c.optional (" condition" , content.condition );
367+ c.optional (" cmake-before" , content.cmake_before );
368+ c.optional (" cmake-after" , content.cmake_after );
369+ c.optional (" include-before" , content.include_before );
370+ c.optional (" include-after" , content.include_after );
371+
362372 for (const auto &argItr : itr.second .as_table ()) {
363- auto key = argItr.first ;
364- if (key == " condition" ) {
365- content.condition = argItr.second .as_string ();
366- continue ;
373+ std::string value;
374+ if (argItr.second .is_array ()) {
375+ for (const auto &list_val : argItr.second .as_array ()) {
376+ if (!value.empty ()) {
377+ value += ' ;' ;
378+ }
379+ value += list_val.as_string ();
380+ }
381+ } else if (argItr.second .is_boolean ()) {
382+ value = argItr.second .as_boolean () ? " ON" : " OFF" ;
383+ } else {
384+ value = argItr.second .as_string ();
367385 }
368386
387+ auto is_cmake_arg = [](const std::string &s) {
388+ for (auto c : s) {
389+ if (!(std::isdigit (c) || std::isupper (c) || c == ' _' )) {
390+ return false ;
391+ }
392+ }
393+ return true ;
394+ };
395+
396+ // https://cmake.org/cmake/help/latest/command/string.html#supported-hash-algorithms
397+ tsl::ordered_set<std::string> hash_algorithms = {
398+ " md5" , " sha1" , " sha224" , " sha256" , " sha384" , " sha512" , " sha3_224" , " sha3_256" , " sha3_384" , " sha3_512" ,
399+ };
400+
401+ auto key = argItr.first ;
369402 if (key == " git" ) {
370403 key = " GIT_REPOSITORY" ;
371404 } else if (key == " tag" ) {
@@ -378,18 +411,23 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
378411 key = " SVN_REVISION" ;
379412 } else if (key == " url" ) {
380413 key = " URL" ;
414+ } else if (hash_algorithms.contains (key)) {
415+ std::string algo;
416+ for (auto c : key) {
417+ algo.push_back (std::toupper (c));
418+ }
419+ key = " URL_HASH" ;
420+ value = algo + " =" + value;
381421 } else if (key == " hash" ) {
382422 key = " URL_HASH" ;
383- } else {
384- // don't change arg
423+ } else if (is_cmake_arg (key)) {
424+ // allow passthrough of ExternalProject options
425+ } else if (!c.visisted (key)) {
426+ throw std::runtime_error (format_key_error (" Unknown key '" + argItr.first + " '" , argItr.first , argItr.second ));
385427 }
386428
387- std::string value;
388- if (argItr.second .is_boolean ()) {
389- value = argItr.second .as_boolean () ? " ON" : " OFF" ;
390- } else {
391- value = argItr.second .as_string ();
392- }
429+ c.visit (argItr.first );
430+
393431 content.arguments .emplace (key, value);
394432 }
395433 contents.emplace_back (std::move (content));
0 commit comments