ini parsing doesn't set options anymore, it returns a structure

moved a lot of stuff back to conf, didn't belong in ini
This commit is contained in:
isanae
2020-12-03 17:45:32 -05:00
parent aa8efaa515
commit ca1cd358bb
7 changed files with 279 additions and 196 deletions
-1
View File
@@ -11,7 +11,6 @@
namespace mob
{
BOOL WINAPI signal_handler(DWORD) noexcept
{
gcx().debug(context::generic, "caught sigint");
+85 -15
View File
@@ -228,6 +228,20 @@ std::vector<std::string> 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<fs::path>& inis, const std::vector<std::string>& 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;
+12 -24
View File
@@ -3,23 +3,6 @@
namespace mob
{
std::vector<fs::path> find_inis(
bool auto_detect, const std::vector<std::string>& from_cl,
bool verbose);
void init_options(
const std::vector<fs::path>& inis, const std::vector<std::string>& 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<fs::path>& inis, const std::vector<std::string>& 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 DefaultType>
class conf_section
{
+151 -152
View File
@@ -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 <class... Args>
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>(args)...));
}
std::vector<std::string> read_ini(const fs::path& ini)
ini_data::kv_map& ini_data::get_section(std::string_view name)
{
std::ifstream in(ini);
std::vector<std::string> 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<std::string>& 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<fs::path> find_inis(
@@ -260,7 +125,8 @@ std::vector<fs::path> 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<fs::path> find_inis(
return map(v, [&](auto&& p){ return p.second; });
}
std::vector<std::string> read_ini(const fs::path& ini)
{
std::ifstream in(ini);
std::vector<std::string> 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<std::string>& 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
+19 -4
View File
@@ -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<fs::path> find_inis(
bool auto_detect, const std::vector<std::string>& from_cl,
bool verbose);
struct ini_data
{
std::string task, section, key, value;
using alias_patterns = std::vector<std::string>;
using aliases_map = std::map<std::string, alias_patterns>;
using kv_map = std::map<std::string, std::string>;
using sections_vector = std::vector<std::pair<std::string, kv_map>>;
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
+11
View File
@@ -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
+1
View File
@@ -25,6 +25,7 @@ void run_all_tasks();
bool is_super_task(const std::string& name);
std::vector<task*> 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<task*> get_all_tasks();
std::vector<task*> get_top_level_tasks();