From ca1cd358bbee925368cd81c545beb948e700695f Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Sat, 21 Nov 2020 02:56:19 -0500 Subject: [PATCH] ini parsing doesn't set options anymore, it returns a structure moved a lot of stuff back to conf, didn't belong in ini --- src/cmd/commands.cpp | 1 - src/core/conf.cpp | 100 +++++++++++--- src/core/conf.h | 36 ++--- src/core/ini.cpp | 303 +++++++++++++++++++++---------------------- src/core/ini.h | 23 +++- src/tasks/task.cpp | 11 ++ src/tasks/task.h | 1 + 7 files changed, 279 insertions(+), 196 deletions(-) diff --git a/src/cmd/commands.cpp b/src/cmd/commands.cpp index 594fa59..89607b4 100644 --- a/src/cmd/commands.cpp +++ b/src/cmd/commands.cpp @@ -11,7 +11,6 @@ namespace mob { - BOOL WINAPI signal_handler(DWORD) noexcept { gcx().debug(context::generic, "caught sigint"); diff --git a/src/core/conf.cpp b/src/core/conf.cpp index 8ef295e..8913b28 100644 --- a/src/core/conf.cpp +++ b/src/core/conf.cpp @@ -228,6 +228,20 @@ std::vector format_options() return lines; } + +fs::path find_in_path(std::string_view exe) +{ + const std::wstring wexe = utf8_to_utf16(exe); + + const std::size_t size = MAX_PATH; + wchar_t buffer[size + 1] = {}; + + if (SearchPathW(nullptr, wexe.c_str(), nullptr, size, buffer, nullptr)) + return buffer; + else + return {}; +} + fs::path find_iscc() { const auto tasks = find_tasks("installer"); @@ -436,20 +450,6 @@ fs::path find_third_party_directory() return path; } - -fs::path find_in_path(std::string_view exe) -{ - const std::wstring wexe = utf8_to_utf16(exe); - - const std::size_t size = MAX_PATH; - wchar_t buffer[size + 1] = {}; - - if (SearchPathW(nullptr, wexe.c_str(), nullptr, size, buffer, nullptr)) - return buffer; - else - return {}; -} - bool find_qmake(fs::path& check) { // try Qt/Qt5.14.2/msvc*/bin/qmake.exe @@ -691,6 +691,31 @@ void find_vcvars() } +struct parsed_option +{ + std::string task, section, key, value; +}; + +parsed_option parse_option(const std::string& s) +{ + // parses "task:section/key=value" where "task:" is optional + static std::regex re(R"((?:(.+)\:)?(.+)/(.*)=(.*))"); + std::smatch m; + + if (!std::regex_match(s, m, re)) + { + gcx().bail_out(context::conf, + "bad option {}, must be [task:]section/key=value", s); + } + + return { + trim_copy(m[1].str()), + trim_copy(m[2].str()), + trim_copy(m[3].str()), + trim_copy(m[4].str()) + }; +} + void init_options( const std::vector& inis, const std::vector& opts) { @@ -703,7 +728,52 @@ void init_options( { // Check if the prefix is set by this ini file: fs::path cprefix = add ? fs::path{} : conf().path().prefix(); - parse_ini(ini, add); + const auto data = parse_ini(ini); + + for (auto&& a : data.aliases) + add_alias(a.first, a.second); + + for (auto&& [section_string, kvs] : data.sections) + { + const auto col = section_string.find(":"); + std::string task, section; + + if (col == std::string::npos) + { + section = section_string; + } + else + { + task = section_string.substr(0, col); + section = section_string.substr(col + 1); + } + + for (auto&& [k, v] : kvs) + { + if (task.empty()) + { + if (add) + details::add_string(section, k, v); + else + details::set_string(section, k, v); + } + else + { + if (task == "_override") + { + details::set_string_for_task("_override", section, k, v); + } + else + { + const auto& tasks = find_tasks(task); + MOB_ASSERT(!tasks.empty()); + + for (auto& t : tasks) + details::set_string_for_task(t->name(), section, k, v); + } + } + } + } if (conf().path().prefix() != cprefix) ini_prefix = ini; diff --git a/src/core/conf.h b/src/core/conf.h index 0180d2c..91b8651 100644 --- a/src/core/conf.h +++ b/src/core/conf.h @@ -3,23 +3,6 @@ namespace mob { -std::vector find_inis( - bool auto_detect, const std::vector& from_cl, - bool verbose); - -void init_options( - const std::vector& inis, const std::vector& opts); - -bool verify_options(); -void log_options(); -void dump_available_options(); - -fs::path find_in_path(std::string_view exe); -fs::path find_root(bool verbose=false); -fs::path find_in_root(const fs::path& file); -fs::path make_temp_file(); - - namespace details { std::string get_string(std::string_view section, std::string_view key); @@ -29,16 +12,21 @@ namespace details void set_string( std::string_view section, std::string_view key, std::string_view value); - - void add_string( - std::string_view section, std::string_view key, std::string_view value); - - void set_string_for_task( - std::string_view task_name, std::string_view section, - std::string_view key, std::string_view value); } +void init_options( + const std::vector& inis, const std::vector& opts); + +bool verify_options(); +void log_options(); +void dump_available_options(); + +fs::path find_root(bool verbose=false); +fs::path find_in_root(const fs::path& file); +fs::path make_temp_file(); + + template class conf_section { diff --git a/src/core/ini.cpp b/src/core/ini.cpp index 488d20f..4a644ba 100644 --- a/src/core/ini.cpp +++ b/src/core/ini.cpp @@ -9,175 +9,40 @@ namespace mob { -std::string default_ini_filename() -{ - return "mob.ini"; -} - -parsed_option parse_option(const std::string& s) -{ - // task:section/key=value - // task: is optional - std::regex re(R"((?:(.+)\:)?(.+)/(.*)=(.*))"); - std::smatch m; - - if (!std::regex_match(s, m, re)) - { - gcx().bail_out(context::conf, - "bad option {}, must be [task:]section/key=value", s); - } - - std::string task = trim_copy(m[1].str()); - std::string section = trim_copy(m[2].str()); - std::string key = trim_copy(m[3].str()); - std::string value = trim_copy(m[4].str()); - - return {task, section, key, value}; -} - - - template void ini_error( - const fs::path& ini, std::size_t line, std::string_view f, Args&&... args) + const ini_data& ini, std::size_t line, std::string_view f, Args&&... args) { gcx().bail_out(context::conf, "{}:{}: {}", - path_to_utf8(ini), (line + 1), + path_to_utf8(ini.path), (line + 1), fmt::format(f, std::forward(args)...)); } -std::vector read_ini(const fs::path& ini) + +ini_data::kv_map& ini_data::get_section(std::string_view name) { - std::ifstream in(ini); - - std::vector lines; - - for (;;) + for (auto itor=sections.begin(); itor!=sections.end(); ++itor) { - std::string line; - std::getline(in, line); - trim(line); - - if (!in) - break; - - lines.push_back(std::move(line)); + if (itor->first == name) + return itor->second; } - if (in.bad()) - gcx().bail_out(context::conf, "failed to read ini {}", ini); - - return lines; + sections.push_back({std::string(name), kv_map()}); + return sections.back().second; } -void parse_section( - const fs::path& ini, std::size_t& i, - const std::vector& lines, - std::string_view task, std::string_view section, bool add) +void ini_data::set(std::string_view section, std::string key, std::string value) { - ++i; - - for (;;) - { - if (i >= lines.size() || lines[i][0] == '[') - break; - - const auto& line = lines[i]; - - if (line.empty() || line[0] == '#' || line[0] == ';') - { - ++i; - continue; - } - - const auto sep = line.find("="); - if (sep == std::string::npos) - ini_error(ini, i, "bad line '{}'", line); - - const std::string k = trim_copy(line.substr(0, sep)); - const std::string v = trim_copy(line.substr(sep + 1)); - - if (k.empty()) - ini_error(ini, i, "bad line '{}'", line); - - if (section == "aliases") - { - add_alias(k, split_quoted(v, " ")); - } - else if (task.empty()) - { - if (add) - details::add_string(section, k, v); - else - details::set_string(section, k, v); - } - else - { - if (task == "_override") - { - details::set_string_for_task("_override", section, k, v); - } - else - { - const auto& tasks = find_tasks(task); - - if (tasks.empty()) - ini_error(ini, i, "no task matching '{}' found", task); - - for (auto& t : tasks) - details::set_string_for_task(t->name(), section, k, v); - } - } - - ++i; - } + auto& s = get_section(section); + s.emplace(std::move(key), std::move(value)); } -void parse_ini(const fs::path& ini, bool add) + + +std::string default_ini_filename() { - gcx().debug(context::conf, "using ini at {}", ini); - - const auto lines = read_ini(ini); - std::size_t i = 0; - - for (;;) - { - if (i >= lines.size()) - break; - - const auto& line = lines[i]; - if (line.empty() || line[0] == '#' || line[0] == ';') - { - ++i; - continue; - } - - if (line.starts_with("[") && line.ends_with("]")) - { - const std::string s = line.substr(1, line.size() - 2); - - std::string task, section; - - const auto col = s.find(":"); - - if (col == std::string::npos) - { - section = s; - } - else - { - task = s.substr(0, col); - section = s.substr(col + 1); - } - - parse_section(ini, i, lines, task, section, add); - } - else - { - ini_error(ini, i, "bad line '{}'", line); - } - } + return "mob.ini"; } std::vector find_inis( @@ -260,7 +125,8 @@ std::vector find_inis( auto cwd = fs::current_path(); - while (!cwd.empty()) { + while (!cwd.empty()) + { const auto in_cwd = cwd / default_ini_filename(); if (fs::exists(in_cwd) && !fs::equivalent(in_cwd, master)) { @@ -315,4 +181,137 @@ std::vector find_inis( return map(v, [&](auto&& p){ return p.second; }); } +std::vector read_ini(const fs::path& ini) +{ + std::ifstream in(ini); + + std::vector lines; + + for (;;) + { + std::string line; + std::getline(in, line); + trim(line); + + if (!in) + break; + + lines.push_back(std::move(line)); + } + + if (in.bad()) + gcx().bail_out(context::conf, "failed to read ini {}", ini); + + return lines; +} + +void parse_line( + ini_data& ini, std::size_t i, const std::string& line, + const std::string& task, const std::string& section) +{ + const auto sep = line.find("="); + if (sep == std::string::npos) + ini_error(ini, i, "bad line '{}'", line); + + const std::string k = trim_copy(line.substr(0, sep)); + const std::string v = trim_copy(line.substr(sep + 1)); + + if (k.empty()) + ini_error(ini, i, "bad line '{}'", line); + + if (section == "aliases") + { + add_alias(k, split_quoted(v, " ")); + } + else if (task.empty()) + { + ini.set(section, k, v); + } + else + { + if (!valid_task_name(task)) + ini_error(ini, i, "no task matching '{}' found", task); + + ini.set(task + ":" + section, k, v); + } +} + +void parse_section( + ini_data& ini, std::size_t& i, const std::vector& lines, + const std::string& section_string) +{ + std::string task, section; + + const auto col = section_string.find(":"); + + if (col == std::string::npos) + { + section = section_string; + } + else + { + task = section_string.substr(0, col); + section = section_string.substr(col + 1); + } + + + ++i; + + for (;;) + { + if (i >= lines.size() || lines[i][0] == '[') + break; + + const auto& line = lines[i]; + + // empty or comment + if (line.empty() || line[0] == '#' || line[0] == ';') + { + ++i; + continue; + } + + parse_line(ini, i, line, task, section); + ++i; + } +} + +ini_data parse_ini(const fs::path& path) +{ + gcx().debug(context::conf, "using ini at {}", path); + + ini_data ini; + ini.path = path; + + const auto lines = read_ini(path); + std::size_t i = 0; + + for (;;) + { + if (i >= lines.size()) + break; + + const auto& line = lines[i]; + + // empty or comment + if (line.empty() || line[0] == '#' || line[0] == ';') + { + ++i; + continue; + } + + if (line.starts_with("[") && line.ends_with("]")) + { + const std::string name = line.substr(1, line.size() - 2); + parse_section(ini, i, lines, name); + } + else + { + ini_error(ini, i, "bad line '{}'", line); + } + } + + return ini; +} + } // namespace diff --git a/src/core/ini.h b/src/core/ini.h index 1680782..2130b60 100644 --- a/src/core/ini.h +++ b/src/core/ini.h @@ -4,13 +4,28 @@ namespace mob { std::string default_ini_filename(); -void parse_ini(const fs::path& ini, bool add); -struct parsed_option +std::vector find_inis( + bool auto_detect, const std::vector& from_cl, + bool verbose); + + +struct ini_data { - std::string task, section, key, value; + using alias_patterns = std::vector; + using aliases_map = std::map; + + using kv_map = std::map; + using sections_vector = std::vector>; + + fs::path path; + aliases_map aliases; + sections_vector sections; + + kv_map& get_section(std::string_view name); + void set(std::string_view section, std::string key, std::string value); }; -parsed_option parse_option(const std::string& s); +ini_data parse_ini(const fs::path& ini); } // namespace diff --git a/src/tasks/task.cpp b/src/tasks/task.cpp index 9c9bd7f..40ea135 100644 --- a/src/tasks/task.cpp +++ b/src/tasks/task.cpp @@ -141,6 +141,17 @@ task* find_one_task(std::string_view pattern, bool verbose) return tasks[0]; } +bool valid_task_name(std::string_view pattern) +{ + if (!find_tasks(pattern).empty()) + return true; + + if (pattern == "_override") + return true; + + return false; +} + void run_all_tasks() { try diff --git a/src/tasks/task.h b/src/tasks/task.h index 78ecd6a..1525734 100644 --- a/src/tasks/task.h +++ b/src/tasks/task.h @@ -25,6 +25,7 @@ void run_all_tasks(); bool is_super_task(const std::string& name); std::vector find_tasks(std::string_view pattern); task* find_one_task(std::string_view pattern, bool verbose=true); +bool valid_task_name(std::string_view pattern); std::vector get_all_tasks(); std::vector get_top_level_tasks();