Files
mob/src/conf.cpp
T

1028 lines
20 KiB
C++
Raw Normal View History

2020-04-27 09:43:05 -04:00
#include "pch.h"
#include "conf.h"
#include "utility.h"
2020-05-03 03:32:40 -04:00
#include "context.h"
2020-05-05 07:41:09 -04:00
#include "process.h"
2020-05-17 21:23:43 -04:00
#include "tasks/task.h"
#include "tools/tools.h"
2020-04-27 09:43:05 -04:00
2020-05-02 03:12:34 -04:00
namespace mob
2020-04-27 09:43:05 -04:00
{
conf::task_map conf::map_;
int conf::output_log_level_ = 3;
int conf::file_log_level_ = 5;
2020-05-19 20:19:56 -04:00
bool conf::dry_ = false;
2020-05-17 14:56:47 -04:00
std::string master_ini_filename()
{
return "mob.ini";
}
2020-05-05 07:41:09 -04:00
2020-05-17 14:14:29 -04:00
2020-05-17 15:50:15 -04:00
std::string conf::get_global(const std::string& section, const std::string& key)
2020-05-05 07:41:09 -04:00
{
2020-05-17 15:50:15 -04:00
auto global = map_.find("");
MOB_ASSERT(global != map_.end());
2020-05-05 07:41:09 -04:00
2020-05-17 15:50:15 -04:00
auto sitor = global->second.find(section);
if (sitor == global->second.end())
2020-05-17 14:14:29 -04:00
{
gcx().bail_out(context::conf,
"conf section '{}' doesn't exist", section);
}
2020-05-05 07:41:09 -04:00
2020-05-17 14:14:29 -04:00
auto kitor = sitor->second.find(key);
if (kitor == sitor->second.end())
{
gcx().bail_out(context::conf,
"key '{}' not found in section '{}'", key, section);
}
2020-05-06 05:22:42 -04:00
2020-05-17 14:14:29 -04:00
return kitor->second;
2020-05-05 07:41:09 -04:00
}
2020-05-17 15:50:15 -04:00
void conf::set_global(
2020-05-17 14:14:29 -04:00
const std::string& section,
const std::string& key, const std::string& value)
{
2020-05-17 15:50:15 -04:00
auto global = map_.find("");
MOB_ASSERT(global != map_.end());
2020-05-17 14:14:29 -04:00
2020-05-17 15:50:15 -04:00
auto sitor = global->second.find(section);
if (sitor == global->second.end())
2020-05-17 14:14:29 -04:00
{
gcx().bail_out(context::conf,
"conf section '{}' doesn't exist", section);
}
auto kitor = sitor->second.find(key);
if (kitor == sitor->second.end())
{
gcx().bail_out(context::conf,
"key '{}' not found in section '{}'", key, section);
}
kitor->second = value;
}
2020-05-17 15:50:15 -04:00
void conf::add_global(
2020-05-17 14:14:29 -04:00
const std::string& section,
const std::string& key, const std::string& value)
2020-05-05 07:41:09 -04:00
{
2020-05-17 15:50:15 -04:00
map_[""][section][key] = value;
2020-05-05 07:41:09 -04:00
}
2020-05-17 15:50:15 -04:00
std::string conf::get_for_task(
const std::vector<std::string>& task_names,
const std::string& section, const std::string& key)
2020-05-06 05:22:42 -04:00
{
2020-05-17 15:50:15 -04:00
task_map::iterator task = map_.end();
for (auto&& tn : task_names)
{
task = map_.find(tn);
if (task != map_.end())
break;
}
2020-05-17 21:23:43 -04:00
if (task == map_.end())
{
for (auto&& tn : task_names)
{
if (is_super_task(tn))
{
task = map_.find("super");
break;
}
}
}
2020-05-17 15:50:15 -04:00
if (task == map_.end())
return get_global(section, key);
auto sitor = task->second.find(section);
if (sitor == task->second.end())
return get_global(section, key);
auto kitor = sitor->second.find(key);
if (kitor == sitor->second.end())
return get_global(section, key);
return kitor->second;
}
void conf::set_for_task(
const std::string& task_name, const std::string& section,
const std::string& key, const std::string& value)
{
2020-05-17 21:23:43 -04:00
// make sure the key exists, will throw if it doesn't
2020-05-17 15:50:15 -04:00
get_global(section, key);
map_[task_name][section][key] = value;
}
bool conf::prebuilt_by_name(const std::string& task)
{
2020-05-19 20:19:56 -04:00
const std::string s = get_global("prebuilt", task);
return (s == "true" || s == "yes" || s == "1");
2020-05-06 05:22:42 -04:00
}
2020-05-17 15:50:15 -04:00
fs::path conf::path_by_name(const std::string& name)
2020-05-05 07:41:09 -04:00
{
2020-05-17 15:50:15 -04:00
return get_global("paths", name);
2020-05-05 07:41:09 -04:00
}
2020-05-17 15:50:15 -04:00
std::string conf::version_by_name(const std::string& name)
2020-05-05 07:41:09 -04:00
{
2020-05-17 15:50:15 -04:00
return get_global("versions", name);
2020-05-05 07:41:09 -04:00
}
2020-05-17 15:50:15 -04:00
fs::path conf::tool_by_name(const std::string& name)
2020-05-05 07:41:09 -04:00
{
2020-05-17 15:50:15 -04:00
return get_global("tools", name);
2020-05-05 07:41:09 -04:00
}
2020-05-17 15:50:15 -04:00
std::string conf::global_by_name(const std::string& name)
{
2020-05-17 15:50:15 -04:00
return get_global("global", name);
}
2020-05-05 07:41:09 -04:00
2020-05-17 15:50:15 -04:00
bool conf::bool_global_by_name(const std::string& name)
2020-05-07 17:27:29 -04:00
{
2020-05-19 20:19:56 -04:00
const std::string s = global_by_name(name);
return (s == "true" || s == "yes" || s == "1");
2020-05-07 17:27:29 -04:00
}
2020-05-17 15:50:15 -04:00
std::string conf::option_by_name(
const std::vector<std::string>& task_names, const std::string& name)
2020-05-07 17:27:29 -04:00
{
2020-05-17 15:50:15 -04:00
return get_for_task(task_names, "options", name);
2020-05-07 17:27:29 -04:00
}
2020-05-17 16:22:04 -04:00
bool conf::bool_option_by_name(
const std::vector<std::string>& task_names, const std::string& name)
{
2020-05-19 20:19:56 -04:00
const std::string s = option_by_name(task_names, name);
return (s == "true" || s == "yes" || s == "1");
2020-05-17 16:22:04 -04:00
}
2020-05-17 15:50:15 -04:00
void conf::set_output_log_level(const std::string& s)
2020-05-07 17:27:29 -04:00
{
2020-05-17 15:50:15 -04:00
if (s.empty())
return;
try
{
const auto i = std::stoi(s);
if (i < 0 || i > 6)
gcx().bail_out(context::generic, "bad output log level {}", i);
output_log_level_ = i;
}
catch(std::exception&)
{
gcx().bail_out(context::generic, "bad output log level {}", s);
}
}
void conf::set_file_log_level(const std::string& s)
{
if (s.empty())
return;
try
{
const auto i = std::stoi(s);
if (i < 0 || i > 6)
gcx().bail_out(context::generic, "bad file log level {}", i);
file_log_level_ = i;
}
catch(std::exception&)
{
gcx().bail_out(context::generic, "bad file log level {}", s);
}
}
2020-05-19 20:19:56 -04:00
void conf::set_dry(const std::string& s)
{
dry_ = (s == "true" || s == "yes" || s == "1");
}
2020-05-17 15:50:15 -04:00
std::vector<std::string> conf::format_options()
{
std::size_t longest_task = 0;
std::size_t longest_section = 0;
std::size_t longest_key = 0;
for (auto&& [t, ss] : map_)
{
longest_task = std::max(longest_task, t.size());
for (auto&& [s, kv] : ss)
{
longest_section = std::max(longest_section, s.size());
for (auto&& [k, v] : kv)
longest_key = std::max(longest_key, k.size());
}
}
std::vector<std::string> lines;
lines.push_back(
pad_right("task", longest_task) + " " +
pad_right("section", longest_section) + " " +
pad_right("key",longest_key) + " " +
"value");
lines.push_back(
pad_right("-", longest_task, '-') + " " +
pad_right("-", longest_section, '-') + " " +
pad_right("-",longest_key, '-') + " " +
"-----");
2020-05-17 15:50:15 -04:00
for (auto&& [t, ss] : map_)
{
for (auto&& [s, kv] : ss)
{
for (auto&& [k, v] : kv)
{
lines.push_back(
pad_right(t, longest_task) + " " +
pad_right(s, longest_section) + " " +
pad_right(k, longest_key) + " = " + v);
}
}
}
return lines;
2020-05-07 17:27:29 -04:00
}
2020-05-17 14:14:29 -04:00
struct parsed_option
2020-05-07 17:27:29 -04:00
{
2020-05-17 16:22:04 -04:00
std::string task, section, key, value;
2020-05-17 14:14:29 -04:00
};
2020-05-05 07:41:09 -04:00
2020-05-17 14:14:29 -04:00
parsed_option parse_option(const std::string& s)
{
2020-05-17 16:22:04 -04:00
// 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,
2020-05-17 16:22:04 -04:00
"bad option {}, must be [task:]section/key=value", s);
}
2020-05-19 16:21:52 -04:00
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());
2020-05-17 16:22:04 -04:00
return {task, section, key, value};
}
2020-05-05 07:41:09 -04:00
bool try_parts(fs::path& check, const std::vector<std::string>& parts)
{
2020-05-06 07:43:15 -04:00
for (std::size_t i=0; i<parts.size(); ++i)
2020-05-05 07:41:09 -04:00
{
fs::path p = check;
for (std::size_t j=i; j<parts.size(); ++j)
p /= parts[j];
2020-05-11 07:44:37 -04:00
gcx().trace(context::conf, "trying parts {}", p);
2020-05-06 07:43:15 -04:00
2020-05-05 07:41:09 -04:00
if (fs::exists(p))
{
check = p;
return true;
}
}
return false;
}
fs::path mob_exe_path()
2020-04-27 18:45:09 -04:00
{
// double the buffer size 10 times
const int max_tries = 10;
2020-04-27 18:45:09 -04:00
DWORD buffer_size = MAX_PATH;
2020-04-27 18:45:09 -04:00
for (int tries=0; tries<max_tries; ++tries)
{
auto buffer = std::make_unique<wchar_t[]>(buffer_size + 1);
DWORD n = GetModuleFileNameW(0, buffer.get(), buffer_size);
2020-04-27 18:45:09 -04:00
if (n == 0) {
const auto e = GetLastError();
gcx().bail_out(context::conf,
"can't get module filename, {}", error_message(e));
}
else if (n >= buffer_size) {
// buffer is too small, try again
buffer_size *= 2;
} else {
// if GetModuleFileName() works, `n` does not include the null
// terminator
const std::wstring s(buffer.get(), n);
return fs::canonical(s);
}
}
gcx().bail_out(context::conf, "can't get module filename");
2020-05-04 01:13:11 -04:00
}
fs::path find_root()
{
gcx().trace(context::conf, "looking for root directory");
2020-05-04 01:13:11 -04:00
fs::path p = mob_exe_path().parent_path();
2020-04-27 18:45:09 -04:00
if (try_parts(p, {"..", "..", "..", "third-party"}))
{
p = fs::canonical(p.parent_path());
gcx().trace(context::conf, "found root directory at {}", p);
return p;
}
gcx().bail_out(context::conf, "root directory not found");
2020-04-27 18:45:09 -04:00
}
fs::path find_in_root(const fs::path& file)
{
static fs::path root = find_root();
fs::path p = root / file;
if (!fs::exists(p))
2020-05-11 07:44:37 -04:00
gcx().bail_out(context::conf, "{} not found", p);
2020-04-27 18:45:09 -04:00
2020-05-11 07:44:37 -04:00
gcx().trace(context::conf, "found {}", p);
2020-04-27 18:45:09 -04:00
return p;
}
2020-04-28 22:14:47 -04:00
fs::path find_third_party_directory()
{
static fs::path path = find_in_root("third-party");
return path;
}
fs::path find_in_path(const std::string& exe)
{
2020-05-12 12:00:02 -04:00
const std::wstring wexe = utf8_to_utf16(exe);
2020-05-12 12:00:02 -04:00
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 {};
}
2020-05-05 07:41:09 -04:00
bool find_qmake(fs::path& check)
{
// try Qt/Qt5.14.2/msvc*/bin/qmake.exe
if (try_parts(check, {
2020-05-05 07:41:09 -04:00
"Qt",
"Qt" + qt::version(),
"msvc" + qt::vs_version() + "_64",
2020-05-05 07:41:09 -04:00
"bin",
"qmake.exe"}))
{
return true;
}
// try Qt/5.14.2/msvc*/bin/qmake.exe
if (try_parts(check, {
2020-05-05 07:41:09 -04:00
"Qt",
qt::version(),
"msvc" + qt::vs_version() + "_64",
2020-05-05 07:41:09 -04:00
"bin",
"qmake.exe"}))
{
return true;
}
return false;
}
2020-05-05 07:41:09 -04:00
bool try_qt_location(fs::path& check)
{
2020-05-05 07:41:09 -04:00
if (!find_qmake(check))
return false;
check = fs::absolute(check.parent_path() / "..");
return true;
}
2020-05-05 07:41:09 -04:00
fs::path find_qt()
{
2020-05-17 15:50:15 -04:00
fs::path p = conf::path_by_name("qt_install");
2020-05-05 07:41:09 -04:00
if (!p.empty())
{
2020-05-05 07:41:09 -04:00
p = fs::absolute(p);
2020-05-05 07:41:09 -04:00
if (!try_qt_location(p))
2020-05-11 07:44:37 -04:00
gcx().bail_out(context::conf, "no qt install in {}", p);
2020-05-05 07:41:09 -04:00
return p;
}
2020-05-05 07:41:09 -04:00
std::vector<fs::path> locations =
{
paths::pf_x64(),
2020-05-07 19:36:37 -04:00
"C:\\",
"D:\\"
2020-05-05 07:41:09 -04:00
};
2020-05-05 07:41:09 -04:00
// look for qmake, which is in %qt%/version/msvc.../bin
fs::path qmake = find_in_path("qmake.exe");
if (!qmake.empty())
locations.insert(locations.begin(), qmake.parent_path() / "../../");
2020-05-05 07:41:09 -04:00
// look for qtcreator.exe, which is in %qt%/Tools/QtCreator/bin
fs::path qtcreator = find_in_path("qtcreator.exe");
if (!qtcreator.empty())
locations.insert(locations.begin(), qtcreator.parent_path() / "../../../");
2020-05-05 07:41:09 -04:00
for (fs::path loc : locations)
{
loc = fs::absolute(loc);
if (try_qt_location(loc))
return loc;
}
2020-05-05 07:41:09 -04:00
gcx().bail_out(context::conf, "can't find qt install");
}
2020-05-05 07:41:09 -04:00
void validate_qt()
{
fs::path p = qt::installation_path();
2020-05-05 07:41:09 -04:00
if (!try_qt_location(p))
2020-05-11 07:44:37 -04:00
gcx().bail_out(context::conf, "qt path {} doesn't exist", p);
2020-05-05 07:41:09 -04:00
2020-05-17 15:50:15 -04:00
conf::set_global("paths", "qt_install", path_to_utf8(p));
}
fs::path get_known_folder(const GUID& id)
{
wchar_t* buffer = nullptr;
const auto r = ::SHGetKnownFolderPath(id, 0, 0, &buffer);
if (r != S_OK)
return {};
fs::path p = buffer;
::CoTaskMemFree(buffer);
return p;
}
2020-04-27 09:43:05 -04:00
2020-05-05 07:41:09 -04:00
fs::path find_program_files_x86()
2020-04-27 09:43:05 -04:00
{
2020-05-05 07:41:09 -04:00
fs::path p = get_known_folder(FOLDERID_ProgramFilesX86);
if (p.empty())
2020-04-27 09:43:05 -04:00
{
2020-05-05 07:41:09 -04:00
const auto e = GetLastError();
2020-04-27 09:43:05 -04:00
2020-05-05 07:41:09 -04:00
p = fs::path(R"(C:\Program Files (x86))");
2020-05-03 07:24:07 -04:00
2020-05-05 07:41:09 -04:00
gcx().warning(context::conf,
2020-05-11 07:44:37 -04:00
"failed to get x86 program files folder, defaulting to {}, {}",
p, error_message(e));
2020-05-05 07:41:09 -04:00
}
else
{
2020-05-11 07:44:37 -04:00
gcx().trace(context::conf, "x86 program files is {}", p);
2020-05-05 07:41:09 -04:00
}
2020-05-03 07:24:07 -04:00
2020-05-05 07:41:09 -04:00
return p;
}
2020-04-27 09:43:05 -04:00
2020-05-05 07:41:09 -04:00
fs::path find_program_files_x64()
{
fs::path p = get_known_folder(FOLDERID_ProgramFilesX64);
if (p.empty())
{
const auto e = GetLastError();
p = fs::path(R"(C:\Program Files)");
gcx().warning(context::conf,
2020-05-11 07:44:37 -04:00
"failed to get x64 program files folder, defaulting to {}, {}",
p, error_message(e));
2020-05-05 07:41:09 -04:00
}
else
{
2020-05-11 07:44:37 -04:00
gcx().trace(context::conf, "x64 program files is {}", p);
2020-05-05 07:41:09 -04:00
}
return p;
}
fs::path find_temp_dir()
{
const std::size_t buffer_size = MAX_PATH + 2;
wchar_t buffer[buffer_size] = {};
if (GetTempPathW(static_cast<DWORD>(buffer_size), buffer) == 0)
{
const auto e = GetLastError();
2020-05-11 07:44:37 -04:00
gcx().bail_out(context::conf, "can't get temp path", error_message(e));
2020-05-05 07:41:09 -04:00
}
fs::path p(buffer);
2020-05-11 07:44:37 -04:00
gcx().trace(context::conf, "temp dir is {}", p);
2020-05-05 07:41:09 -04:00
return p;
}
fs::path find_vs()
{
2020-05-06 05:22:42 -04:00
if (conf::dry())
return vs::vswhere();
2020-05-06 05:22:42 -04:00
2020-05-05 07:41:09 -04:00
auto p = process()
.binary(vs::vswhere())
2020-05-05 07:41:09 -04:00
.arg("-prerelease")
.arg("-version", vs::version())
2020-05-05 07:41:09 -04:00
.arg("-property", "installationPath")
.stdout_flags(process::keep_in_string)
.stderr_flags(process::inherit);
p.run();
p.join();
if (p.exit_code() != 0)
gcx().bail_out(context::conf, "vswhere failed");
2020-05-11 07:44:37 -04:00
fs::path path = trim_copy(p.stdout_string());
2020-05-05 07:41:09 -04:00
if (!fs::exists(path))
{
gcx().bail_out(context::conf,
2020-05-11 07:44:37 -04:00
"the path given by vswhere doesn't exist: {}", path);
2020-05-05 07:41:09 -04:00
}
return path;
}
bool try_vcvars(fs::path& bat)
{
if (!fs::exists(bat))
return false;
2020-05-05 07:41:09 -04:00
bat = fs::canonical(fs::absolute(bat));
return true;
2020-05-05 07:41:09 -04:00
}
void find_vcvars()
{
2020-05-17 15:50:15 -04:00
fs::path bat = conf::tool_by_name("vcvars");
2020-05-06 05:22:42 -04:00
if (conf::dry())
{
2020-05-06 05:22:42 -04:00
if (bat.empty())
bat = "vcvars.bat";
return;
}
else
{
2020-05-17 14:14:29 -04:00
if (bat.empty())
{
bat = vs::installation_path()
/ "VC" / "Auxiliary" / "Build" / "vcvarsall.bat";
if (!try_vcvars(bat))
gcx().bail_out(context::conf, "vcvars not found at {}", bat);
}
else
{
if (!try_vcvars(bat))
gcx().bail_out(context::conf, "vcvars not found at {}", bat);
}
}
2020-05-17 15:50:15 -04:00
conf::set_global("tools", "vcvars", path_to_utf8(bat));
2020-05-11 07:44:37 -04:00
gcx().trace(context::conf, "using vcvars at {}", bat);
}
2020-05-05 07:41:09 -04:00
2020-05-17 14:14:29 -04:00
void ini_error(const fs::path& ini, std::size_t line, const std::string& what)
2020-05-05 07:41:09 -04:00
{
gcx().bail_out(context::conf,
2020-05-11 07:44:37 -04:00
"{}:{}: {}",
2020-05-17 14:14:29 -04:00
ini.filename(), (line + 1), what);
2020-05-05 07:41:09 -04:00
}
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;
if (line.empty() || line[0] == '#' || line[0] == ';')
continue;
lines.push_back(std::move(line));
}
if (in.bad())
2020-05-11 07:44:37 -04:00
gcx().bail_out(context::conf, "failed to read ini {}", ini);
2020-05-05 07:41:09 -04:00
return lines;
}
void parse_section(
2020-05-17 14:14:29 -04:00
const fs::path& ini, std::size_t& i,
2020-05-17 15:50:15 -04:00
const std::vector<std::string>& lines,
const std::string& task, const std::string& section, bool add)
2020-05-05 07:41:09 -04:00
{
++i;
for (;;)
{
if (i >= lines.size() || lines[i][0] == '[')
break;
const auto& line = lines[i];
const auto sep = line.find("=");
if (sep == std::string::npos)
2020-05-17 14:14:29 -04:00
ini_error(ini, i, "bad line '" + line + "'");
2020-05-05 07:41:09 -04:00
const std::string k = trim_copy(line.substr(0, sep));
const std::string v = trim_copy(line.substr(sep + 1));
if (k.empty())
2020-05-17 14:14:29 -04:00
ini_error(ini, i, "bad line '" + line + "'");
2020-05-05 07:41:09 -04:00
2020-05-17 15:50:15 -04:00
if (task.empty())
{
if (add)
conf::add_global(section, k, v);
else
conf::set_global(section, k, v);
}
2020-05-17 14:14:29 -04:00
else
2020-05-17 15:50:15 -04:00
{
2020-05-17 21:23:43 -04:00
if (!task_exists(task))
ini_error(ini, i, "task '" + task + "' doesn't exist");
2020-05-17 15:50:15 -04:00
conf::set_for_task(task, section, k, v);
}
2020-05-05 07:41:09 -04:00
++i;
}
}
2020-05-17 14:14:29 -04:00
void parse_ini(const fs::path& ini, bool add)
2020-05-05 07:41:09 -04:00
{
2020-05-17 14:14:29 -04:00
gcx().debug(context::conf, "using ini at {}", ini);
2020-05-05 07:41:09 -04:00
2020-05-17 14:14:29 -04:00
const auto lines = read_ini(ini);
2020-05-05 07:41:09 -04:00
std::size_t i = 0;
for (;;)
{
if (i >= lines.size())
break;
const auto& line = lines[i];
if (line.starts_with("[") && line.ends_with("]"))
{
2020-05-17 15:50:15 -04:00
const std::string s = line.substr(1, line.size() - 2);
std::string task, section;
2020-05-17 16:22:04 -04:00
const auto col = s.find(":");
2020-05-17 15:50:15 -04:00
2020-05-17 16:22:04 -04:00
if (col == std::string::npos)
2020-05-17 15:50:15 -04:00
{
section = s;
}
else
{
2020-05-17 16:22:04 -04:00
task = s.substr(0, col);
section = s.substr(col + 1);
2020-05-17 15:50:15 -04:00
}
parse_section(ini, i, lines, task, section, add);
}
2020-05-05 07:41:09 -04:00
else
{
2020-05-17 14:14:29 -04:00
ini_error(ini, i, "bad line '" + line + "'");
}
2020-05-05 07:41:09 -04:00
}
}
2020-05-16 13:09:16 -04:00
bool check_missing_options()
2020-05-05 07:41:09 -04:00
{
if (paths::prefix().empty())
{
2020-05-11 05:25:37 -04:00
u8cerr
2020-05-06 07:43:15 -04:00
<< "missing prefix; either specify it the [paths] section of "
<< "the ini or pass '-d path'\n";
2020-05-16 13:09:16 -04:00
return false;
}
2020-05-05 07:41:09 -04:00
2020-05-16 13:09:16 -04:00
return true;
2020-05-05 07:41:09 -04:00
}
template <class F>
void set_path_if_empty(const std::string& k, F&& f)
2020-04-27 09:43:05 -04:00
{
2020-05-17 15:50:15 -04:00
fs::path p = conf::get_global("paths", k);
2020-05-05 07:41:09 -04:00
2020-05-17 14:14:29 -04:00
if (p.empty())
2020-05-05 07:41:09 -04:00
{
2020-05-17 14:14:29 -04:00
if constexpr (std::is_same_v<fs::path, std::decay_t<decltype(f)>>)
p = f;
2020-05-05 07:41:09 -04:00
else
2020-05-17 14:14:29 -04:00
p = f();
2020-05-05 07:41:09 -04:00
}
2020-05-17 14:14:29 -04:00
p = fs::absolute(p);
2020-05-05 07:41:09 -04:00
2020-05-17 14:14:29 -04:00
if (!conf::dry())
2020-05-06 05:22:42 -04:00
{
2020-05-17 14:14:29 -04:00
if (!fs::exists(p))
gcx().bail_out(context::conf, "path {} not found", p);
p = fs::canonical(p);
2020-05-06 05:22:42 -04:00
}
2020-05-17 15:50:15 -04:00
conf::set_global("paths", k, path_to_utf8(p));
2020-05-05 07:41:09 -04:00
}
void make_canonical_path(
const std::string& key,
const fs::path& default_parent, const std::string& default_dir)
2020-05-05 07:41:09 -04:00
{
2020-05-17 15:50:15 -04:00
fs::path p = conf::path_by_name(key);
2020-05-17 14:14:29 -04:00
if (p.empty())
{
2020-05-17 14:14:29 -04:00
p = default_parent / default_dir;
}
else
{
2020-05-17 14:14:29 -04:00
if (p.is_relative())
p = default_parent / p;
}
2020-05-06 05:22:42 -04:00
if (!conf::dry())
2020-05-17 14:14:29 -04:00
p = fs::weakly_canonical(fs::absolute(p));
2020-05-17 15:50:15 -04:00
conf::set_global("paths", key, path_to_utf8(p));
}
2020-05-17 14:14:29 -04:00
void set_special_options()
{
2020-05-17 15:50:15 -04:00
conf::set_output_log_level(conf::get_global("global", "output_log_level"));
conf::set_file_log_level(conf::get_global("global", "file_log_level"));
2020-05-19 20:19:56 -04:00
conf::set_dry(conf::get_global("global", "dry"));
2020-05-17 14:14:29 -04:00
}
std::vector<fs::path> find_inis(
bool auto_detect, const std::vector<std::string>& from_cl, bool verbose)
2020-05-17 14:14:29 -04:00
{
2020-05-17 14:56:47 -04:00
std::vector<fs::path> v;
auto add_or_move_up = [&](fs::path p)
2020-05-17 14:56:47 -04:00
{
for (auto itor=v.begin(); itor!=v.end(); ++itor)
{
if (fs::equivalent(p, *itor))
{
v.erase(itor);
v.push_back(p);
return;
2020-05-17 14:56:47 -04:00
}
}
v.push_back(p);
};
// auto detect from exe directory and cwd
if (auto_detect)
{
if (verbose)
u8cout << "root is " << path_to_utf8(find_root()) << "\n";
const auto master = find_in_root(master_ini_filename());
if (verbose)
u8cout << "found master " << master_ini_filename() << "\n";
v.push_back(master);
const auto in_cwd = fs::current_path() / master_ini_filename();
if (fs::exists(in_cwd) && !fs::equivalent(in_cwd, master))
{
if (verbose)
u8cout << "also found in cwd " << path_to_utf8(in_cwd) << "\n";
v.push_back(fs::canonical(in_cwd));
}
}
// MOBINI environment variable
if (auto e=this_env::get_opt("MOBINI"))
{
if (verbose)
u8cout << "found env MOBINI: " << *e << "\n";
for (auto&& i : split(*e, ";"))
{
if (verbose)
u8cout << "checking '" << i << "'\n";
auto p = fs::path(i);
if (!fs::exists(p))
{
u8cerr << "ini from env MOBINI " << i << " not found\n";
throw bailed();
}
p = fs::canonical(p);
if (verbose)
u8cout << "ini from env: " << path_to_utf8(p) << "\n";
add_or_move_up(p);
}
}
for (auto&& i : from_cl)
{
auto p = fs::path(i);
if (!fs::exists(p))
{
u8cerr << "ini " << i << " not found\n";
throw bailed();
}
p = fs::canonical(p);
if (verbose)
u8cout << "ini from command line: " << path_to_utf8(p) << "\n";
add_or_move_up(p);
2020-05-17 14:56:47 -04:00
}
return v;
}
void init_options(
const std::vector<fs::path>& inis, const std::vector<std::string>& opts)
2020-05-17 14:56:47 -04:00
{
MOB_ASSERT(!inis.empty());
bool add = true;
for (auto&& ini : inis)
{
parse_ini(ini, add);
add = false;
}
if (!opts.empty())
{
gcx().debug(context::conf, "overriding from command line:");
for (auto&& o : opts)
2020-05-17 14:14:29 -04:00
{
const auto po = parse_option(o);
2020-05-17 16:22:04 -04:00
if (po.task.empty())
2020-05-17 21:23:43 -04:00
{
2020-05-17 16:22:04 -04:00
conf::set_global(po.section, po.key, po.value);
2020-05-17 21:23:43 -04:00
}
2020-05-17 16:22:04 -04:00
else
2020-05-17 21:23:43 -04:00
{
if (!task_exists(po.task))
{
gcx().bail_out(context::generic,
"task '{}' doesn't exist (command line option)",
po.task);
}
2020-05-17 16:22:04 -04:00
conf::set_for_task(po.task, po.section, po.key, po.value);
2020-05-17 21:23:43 -04:00
}
2020-05-17 14:14:29 -04:00
}
}
2020-05-05 07:41:09 -04:00
2020-05-17 14:14:29 -04:00
set_special_options();
2020-05-07 17:27:29 -04:00
context::set_log_file(conf::log_file());
2020-05-05 07:41:09 -04:00
2020-05-17 18:29:42 -04:00
gcx().debug(context::conf,
"command line: {}", std::wstring(GetCommandLineW()));
2020-05-17 14:56:47 -04:00
gcx().debug(context::conf, "using inis in order:");
2020-05-17 18:29:42 -04:00
2020-05-17 14:56:47 -04:00
for (auto&& ini : inis)
gcx().debug(context::conf, " . {}", ini);
set_path_if_empty("third_party", find_third_party_directory);
this_env::prepend_to_path(paths::third_party() / "bin");
2020-05-05 07:41:09 -04:00
2020-05-07 11:08:33 -04:00
set_path_if_empty("pf_x86", find_program_files_x86);
set_path_if_empty("pf_x64", find_program_files_x64);
2020-05-07 19:36:37 -04:00
set_path_if_empty("vs", find_vs);
set_path_if_empty("qt_install", find_qt);
2020-05-07 11:08:33 -04:00
set_path_if_empty("temp_dir", find_temp_dir);
set_path_if_empty("patches", find_in_root("patches"));
set_path_if_empty("licenses", find_in_root("licenses"));
set_path_if_empty("qt_bin", qt::installation_path() / "bin");
2020-05-05 07:41:09 -04:00
find_vcvars();
2020-05-05 07:41:09 -04:00
validate_qt();
2020-05-16 13:09:16 -04:00
if (!paths::prefix().empty())
make_canonical_path("prefix", fs::current_path(), "");
2020-05-06 05:34:00 -04:00
make_canonical_path("cache", paths::prefix(), "downloads");
make_canonical_path("build", paths::prefix(), "build");
make_canonical_path("install", paths::prefix(), "install");
make_canonical_path("install_bin", paths::install(), "bin");
make_canonical_path("install_libs", paths::install(), "libs");
2020-05-16 17:55:39 -04:00
make_canonical_path("install_pdbs", paths::install(), "pdb");
2020-05-06 05:34:00 -04:00
make_canonical_path("install_dlls", paths::install_bin(), "dlls");
make_canonical_path("install_loot", paths::install_bin(), "loot");
make_canonical_path("install_plugins", paths::install_bin(), "plugins");
make_canonical_path("install_licenses", paths::install_bin(), "licenses");
2020-05-06 05:22:42 -04:00
2020-05-06 14:07:45 -04:00
make_canonical_path(
"install_pythoncore",
paths::install_bin(), "pythoncore");
2020-05-06 05:22:42 -04:00
make_canonical_path(
"install_stylesheets",
paths::install_bin(), "stylesheets");
2020-05-05 07:41:09 -04:00
}
2020-05-16 13:09:16 -04:00
bool verify_options()
{
return check_missing_options();
}
2020-05-17 14:14:29 -04:00
void log_options()
{
2020-05-17 15:50:15 -04:00
for (auto&& line : conf::format_options())
2020-05-17 14:14:29 -04:00
gcx().trace(context::conf, "{}", line);
}
void dump_available_options()
{
2020-05-17 15:50:15 -04:00
for (auto&& line : conf::format_options())
2020-05-17 14:14:29 -04:00
u8cout << line << "\n";
2020-05-05 07:41:09 -04:00
}
fs::path make_temp_file()
{
static fs::path dir = paths::temp_dir();
2020-04-27 09:43:05 -04:00
wchar_t name[MAX_PATH + 1] = {};
2020-05-03 07:24:07 -04:00
if (GetTempFileNameW(dir.native().c_str(), L"mob", 0, name) == 0)
2020-04-27 09:43:05 -04:00
{
const auto e = GetLastError();
2020-05-03 07:24:07 -04:00
2020-05-05 07:41:09 -04:00
gcx().bail_out(context::conf,
2020-05-11 07:44:37 -04:00
"can't create temp file in {}, {}", dir, error_message(e));
2020-04-27 09:43:05 -04:00
}
return dir / name;
}
} // namespace