mirror of
https://github.com/ModOrganizer2/mob.git
synced 2026-07-27 14:07:05 -07:00
Merge pull request #43 from isanae/release
Installer and translations tasks
This commit is contained in:
@@ -19,10 +19,11 @@ mo_branch = master
|
||||
no_pull = false
|
||||
ignore_ts = false
|
||||
revert_ts = false
|
||||
|
||||
git_url_prefix = https://github.com/
|
||||
git_shallow = true
|
||||
git_username =
|
||||
git_email =
|
||||
git_shallow = true
|
||||
git_username =
|
||||
git_email =
|
||||
|
||||
set_origin_remote = false
|
||||
remote_org =
|
||||
@@ -36,6 +37,12 @@ git_shallow = false
|
||||
[usvfs:task]
|
||||
git_shallow = false
|
||||
|
||||
[translations:task]
|
||||
enabled = false
|
||||
|
||||
[installer:task]
|
||||
enabled = false
|
||||
|
||||
[tools]
|
||||
sevenz = 7z.exe
|
||||
jom = jom.exe
|
||||
@@ -50,15 +57,19 @@ vswhere = vswhere.exe
|
||||
nasm = nasm.exe
|
||||
tx = tx.py37-x64.exe
|
||||
lrelease = lrelease.exe
|
||||
iscc = ISCC.exe
|
||||
vcvars =
|
||||
|
||||
[transifex]
|
||||
enabled = true
|
||||
key =
|
||||
team = mod-organizer-2-team
|
||||
project = mod-organizer-2
|
||||
url = https://www.transifex.com
|
||||
minimum = 60
|
||||
enabled = true
|
||||
key =
|
||||
team = mod-organizer-2-team
|
||||
project = mod-organizer-2
|
||||
url = https://www.transifex.com
|
||||
minimum = 60
|
||||
force = false
|
||||
configure = true
|
||||
pull = true
|
||||
|
||||
[prebuilt]
|
||||
boost = true
|
||||
@@ -103,25 +114,27 @@ ss_paper_mono_6788 = 2.1
|
||||
ss_dark_mode_1809_6788 = 2.0
|
||||
|
||||
[paths]
|
||||
third_party =
|
||||
prefix =
|
||||
cache =
|
||||
patches =
|
||||
licenses =
|
||||
build =
|
||||
install =
|
||||
install_bin =
|
||||
install_libs =
|
||||
install_pdbs =
|
||||
install_dlls =
|
||||
install_loot =
|
||||
install_plugins =
|
||||
install_stylesheets =
|
||||
install_licenses =
|
||||
install_pythoncore =
|
||||
vs =
|
||||
qt_install =
|
||||
qt_bin =
|
||||
pf_x86 =
|
||||
pf_x64 =
|
||||
temp_dir =
|
||||
third_party =
|
||||
prefix =
|
||||
cache =
|
||||
patches =
|
||||
licenses =
|
||||
build =
|
||||
install =
|
||||
install_bin =
|
||||
install_installer =
|
||||
install_libs =
|
||||
install_pdbs =
|
||||
install_dlls =
|
||||
install_loot =
|
||||
install_plugins =
|
||||
install_stylesheets =
|
||||
install_licenses =
|
||||
install_pythoncore =
|
||||
install_translations =
|
||||
vs =
|
||||
qt_install =
|
||||
qt_bin =
|
||||
pf_x86 =
|
||||
pf_x64 =
|
||||
temp_dir =
|
||||
|
||||
+65
-124
@@ -326,7 +326,7 @@ int help_command::do_run()
|
||||
"be loaded, but the one in the current directory will override the\n"
|
||||
"the other. Additional INIs can be specified with --ini, those will\n"
|
||||
"be loaded after the two mentioned above. Use --no-default-inis to\n"
|
||||
"only disable auto detection and only use --ini.");
|
||||
"disable auto detection and only use --ini.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1357,21 +1357,29 @@ clipp::group tx_command::do_group()
|
||||
|
||||
"get" %
|
||||
(clipp::command("get").set(mode_, modes::get),
|
||||
(clipp::option("-m", "--minimum")
|
||||
& clipp::value("PERCENT") >> min_)
|
||||
% "minimum translation threshold to download [0-100]",
|
||||
|
||||
(clipp::option("-k", "--key")
|
||||
& clipp::value("APIKEY") >> key_)
|
||||
% "API key",
|
||||
|
||||
(clipp::option("-f", "--force").set(force_)
|
||||
% "don't check timestamps, re-download all translation files"),
|
||||
(clipp::option("-t", "--team")
|
||||
& clipp::value("TEAM") >> team_)
|
||||
% "team name",
|
||||
|
||||
(clipp::option("-p", "--project")
|
||||
& clipp::value("PROJECT") >> project_)
|
||||
% "project name",
|
||||
|
||||
(clipp::option("-u", "--url")
|
||||
& clipp::value("URL") >> url_)
|
||||
% "project URL",
|
||||
|
||||
(clipp::option("-m", "--minimum")
|
||||
& clipp::value("PERCENT").set(min_))
|
||||
% "minimum translation threshold to download [0-100]",
|
||||
|
||||
(clipp::option("-f", "--force").call([&]{ force_ = true; }))
|
||||
% "don't check timestamps, re-download all translation files",
|
||||
|
||||
(clipp::value("path") >> path_)
|
||||
% "path that will contain the .tx directory"
|
||||
)
|
||||
@@ -1390,6 +1398,29 @@ clipp::group tx_command::do_group()
|
||||
);
|
||||
}
|
||||
|
||||
void tx_command::convert_cl_to_conf()
|
||||
{
|
||||
command::convert_cl_to_conf();
|
||||
|
||||
if (!key_.empty())
|
||||
common.options.push_back("transifex/key=" + key_);
|
||||
|
||||
if (!team_.empty())
|
||||
common.options.push_back("transifex/team=" + team_);
|
||||
|
||||
if (!project_.empty())
|
||||
common.options.push_back("transifex/project=" + project_);
|
||||
|
||||
if (!url_.empty())
|
||||
common.options.push_back("transifex/url=" + url_);
|
||||
|
||||
if (min_ >= 0)
|
||||
common.options.push_back("transifex/minimum=" + std::to_string(min_));
|
||||
|
||||
if (force_)
|
||||
common.options.push_back("transifex/force=" + std::to_string(*force_));
|
||||
}
|
||||
|
||||
int tx_command::do_run()
|
||||
{
|
||||
switch (mode_)
|
||||
@@ -1414,8 +1445,7 @@ int tx_command::do_run()
|
||||
std::string tx_command::do_doc()
|
||||
{
|
||||
return
|
||||
"Values for --key, --minimum and --url will be taken from the INI\n"
|
||||
"file if not specified.\n"
|
||||
"Some values will be taken from the INI file if not specified.\n"
|
||||
"\n"
|
||||
"Commands:\n"
|
||||
"get\n"
|
||||
@@ -1430,40 +1460,20 @@ std::string tx_command::do_doc()
|
||||
|
||||
void tx_command::do_get()
|
||||
{
|
||||
if (min_ < 0)
|
||||
{
|
||||
const auto s = conf::get_global("transifex", "minimum");
|
||||
const url u =
|
||||
conf::get_global("transifex", "url") + "/" +
|
||||
conf::get_global("transifex", "team") + "/" +
|
||||
conf::get_global("transifex", "project");
|
||||
|
||||
try
|
||||
{
|
||||
min_ = std::stoi(s);
|
||||
}
|
||||
catch(std::exception&)
|
||||
{
|
||||
gcx().bail_out(context::generic,
|
||||
"bad transifex minimum percentage '{}'", s);
|
||||
}
|
||||
}
|
||||
const std::string key = conf::get_global("transifex", "key");
|
||||
|
||||
if (key_.empty())
|
||||
key_ = conf::get_global("transifex", "key");
|
||||
|
||||
if (url_.empty())
|
||||
{
|
||||
url_ =
|
||||
conf::get_global("transifex", "url") + "/" +
|
||||
conf::get_global("transifex", "team") + "/" +
|
||||
conf::get_global("transifex", "project");
|
||||
}
|
||||
|
||||
if (key_.empty() && !this_env::get_opt("TX_TOKEN"))
|
||||
if (key.empty() && !this_env::get_opt("TX_TOKEN"))
|
||||
{
|
||||
u8cout <<
|
||||
"(no key was in the INI, --key wasn't given and TX_TOKEN env\n"
|
||||
"variable doesn't exist, this will probably fail)\n\n";
|
||||
}
|
||||
|
||||
|
||||
context cxcopy = gcx();
|
||||
|
||||
u8cout << "initializing\n";
|
||||
@@ -1475,17 +1485,17 @@ void tx_command::do_get()
|
||||
transifex(transifex::config)
|
||||
.stdout_level(context::level::info)
|
||||
.root(path_)
|
||||
.api_key(key_)
|
||||
.url(url_)
|
||||
.api_key(key)
|
||||
.url(u)
|
||||
.run(cxcopy);
|
||||
|
||||
u8cout << "pulling\n";
|
||||
transifex(transifex::pull)
|
||||
.stdout_level(context::level::info)
|
||||
.root(path_)
|
||||
.api_key(key_)
|
||||
.minimum(min_)
|
||||
.force(force_)
|
||||
.api_key(key)
|
||||
.minimum(conf::get_global_int("transifex", "minimum"))
|
||||
.force(conf::get_global_bool("transifex", "force"))
|
||||
.run(cxcopy);
|
||||
}
|
||||
|
||||
@@ -1495,97 +1505,28 @@ void tx_command::do_build()
|
||||
if (fs::exists(root / ".tx") && fs::exists(root / "translations"))
|
||||
root = root / "translations";
|
||||
|
||||
translations::projects ps(root);
|
||||
|
||||
fs::path dest = dest_;
|
||||
op::create_directories(gcx(), dest, op::unsafe);
|
||||
|
||||
std::set<fs::path> warned;
|
||||
for (auto&& w : ps.warnings())
|
||||
u8cerr << w << "\n";
|
||||
|
||||
for (auto e : fs::directory_iterator(root))
|
||||
thread_pool tp;
|
||||
|
||||
for (auto& p : ps.get())
|
||||
{
|
||||
if (!e.is_directory())
|
||||
continue;
|
||||
|
||||
const auto dir = path_to_utf8(e.path().filename());
|
||||
const auto dir_cs = split(dir, ".");
|
||||
if (dir_cs.size() != 2)
|
||||
for (auto& lg : p.langs)
|
||||
{
|
||||
u8cerr << "bad directory name '" << dir << "'; skipping\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto project = trim_copy(dir_cs[1]);
|
||||
if (project.empty())
|
||||
{
|
||||
u8cerr << "bad directory name '" << dir << "'; skipping\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
u8cout << project << "\n";
|
||||
|
||||
const bool is_gamebryo_plugin = [&]
|
||||
{
|
||||
auto tasks = find_tasks(project);
|
||||
if (tasks.empty())
|
||||
tp.add([&, cxcopy=gcx()]() mutable
|
||||
{
|
||||
u8cerr
|
||||
<< "directory '" << dir << "' was parsed as project "
|
||||
<< "'" << project << "', but there's no task with this "
|
||||
<< "name\n";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const task& t = *tasks[0];
|
||||
|
||||
if (!t.is_super())
|
||||
return false;
|
||||
|
||||
const auto& mo_task = static_cast<const modorganizer&>(t);
|
||||
return mo_task.is_gamebryo_plugin();
|
||||
}();
|
||||
|
||||
|
||||
const fs::path gamebryo_dir =
|
||||
conf::get_global("transifex", "project") + "." +
|
||||
"game_gamebryo";
|
||||
|
||||
|
||||
for (auto f : fs::directory_iterator(e.path()))
|
||||
{
|
||||
if (!f.is_regular_file())
|
||||
continue;
|
||||
|
||||
lrelease lr;
|
||||
lr
|
||||
.project(project)
|
||||
.add_source(f.path())
|
||||
.out(dest_);
|
||||
|
||||
if (is_gamebryo_plugin)
|
||||
{
|
||||
const auto gb_f = root / gamebryo_dir / f.path().filename();
|
||||
|
||||
if (fs::exists(gb_f))
|
||||
{
|
||||
lr.add_source(gb_f);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!warned.contains(gb_f))
|
||||
{
|
||||
u8cerr
|
||||
<< "this is a gamebryo plugin but there is no "
|
||||
<< "'" << path_to_utf8(gb_f) << "'; "
|
||||
<< "the .qm file will be missing some "
|
||||
<< "translations (will only warn once)\n";
|
||||
|
||||
warned.insert(gb_f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context cxcopy = gcx();
|
||||
lr.run(cxcopy);
|
||||
lrelease()
|
||||
.project(p.name)
|
||||
.sources(lg.ts_files)
|
||||
.out(dest)
|
||||
.run(cxcopy);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -287,6 +287,7 @@ public:
|
||||
|
||||
protected:
|
||||
clipp::group do_group() override;
|
||||
void convert_cl_to_conf() override;
|
||||
int do_run() override;
|
||||
std::string do_doc() override;
|
||||
|
||||
@@ -299,10 +300,9 @@ private:
|
||||
};
|
||||
|
||||
modes mode_ = modes::none;
|
||||
std::string key_, team_, project_, url_;
|
||||
int min_ = -1;
|
||||
std::string key_;
|
||||
std::string url_;
|
||||
bool force_ = false;
|
||||
std::optional<bool> force_;
|
||||
std::string path_;
|
||||
std::string dest_;
|
||||
|
||||
|
||||
+97
-20
@@ -19,6 +19,11 @@ std::string master_ini_filename()
|
||||
return "mob.ini";
|
||||
}
|
||||
|
||||
bool bool_from_string(const std::string& s)
|
||||
{
|
||||
return (s == "true" || s == "yes" || s == "1");
|
||||
}
|
||||
|
||||
|
||||
std::string conf::get_global(const std::string& section, const std::string& key)
|
||||
{
|
||||
@@ -66,6 +71,26 @@ void conf::set_global(
|
||||
kitor->second = value;
|
||||
}
|
||||
|
||||
int conf::get_global_int(const std::string& section, const std::string& key)
|
||||
{
|
||||
const auto s = conf::get_global(section, key);
|
||||
|
||||
try
|
||||
{
|
||||
return std::stoi(s);
|
||||
}
|
||||
catch(std::exception&)
|
||||
{
|
||||
gcx().bail_out(context::conf, "bad int for {}/{}", section, key);
|
||||
}
|
||||
}
|
||||
|
||||
bool conf::get_global_bool(const std::string& section, const std::string& key)
|
||||
{
|
||||
const auto s = conf::get_global(section, key);
|
||||
return bool_from_string(s);
|
||||
}
|
||||
|
||||
void conf::add_global(
|
||||
const std::string& section,
|
||||
const std::string& key, const std::string& value)
|
||||
@@ -141,7 +166,7 @@ void conf::set_for_task(
|
||||
bool conf::prebuilt_by_name(const std::string& task)
|
||||
{
|
||||
const std::string s = get_global("prebuilt", task);
|
||||
return (s == "true" || s == "yes" || s == "1");
|
||||
return bool_from_string(s);
|
||||
}
|
||||
|
||||
fs::path conf::path_by_name(const std::string& name)
|
||||
@@ -167,7 +192,7 @@ std::string conf::global_by_name(const std::string& name)
|
||||
bool conf::bool_global_by_name(const std::string& name)
|
||||
{
|
||||
const std::string s = global_by_name(name);
|
||||
return (s == "true" || s == "yes" || s == "1");
|
||||
return bool_from_string(s);
|
||||
}
|
||||
|
||||
std::string conf::task_option_by_name(
|
||||
@@ -180,7 +205,7 @@ bool conf::bool_task_option_by_name(
|
||||
const std::vector<std::string>& task_names, const std::string& name)
|
||||
{
|
||||
const std::string s = task_option_by_name(task_names, name);
|
||||
return (s == "true" || s == "yes" || s == "1");
|
||||
return bool_from_string(s);
|
||||
}
|
||||
|
||||
void conf::set_output_log_level(const std::string& s)
|
||||
@@ -224,7 +249,7 @@ void conf::set_file_log_level(const std::string& s)
|
||||
|
||||
void conf::set_dry(const std::string& s)
|
||||
{
|
||||
dry_ = (s == "true" || s == "yes" || s == "1");
|
||||
dry_ = bool_from_string(s);
|
||||
}
|
||||
|
||||
|
||||
@@ -662,7 +687,7 @@ void ini_error(const fs::path& ini, std::size_t line, const std::string& what)
|
||||
{
|
||||
gcx().bail_out(context::conf,
|
||||
"{}:{}: {}",
|
||||
ini.filename(), (line + 1), what);
|
||||
path_to_utf8(ini), (line + 1), what);
|
||||
}
|
||||
|
||||
std::vector<std::string> read_ini(const fs::path& ini)
|
||||
@@ -680,9 +705,6 @@ std::vector<std::string> read_ini(const fs::path& ini)
|
||||
if (!in)
|
||||
break;
|
||||
|
||||
if (line.empty() || line[0] == '#' || line[0] == ';')
|
||||
continue;
|
||||
|
||||
lines.push_back(std::move(line));
|
||||
}
|
||||
|
||||
@@ -706,6 +728,12 @@ void parse_section(
|
||||
|
||||
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 + "'");
|
||||
@@ -758,6 +786,11 @@ void parse_ini(const fs::path& ini, bool add)
|
||||
break;
|
||||
|
||||
const auto& line = lines[i];
|
||||
if (line.empty() || line[0] == '#' || line[0] == ';')
|
||||
{
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.starts_with("[") && line.ends_with("]"))
|
||||
{
|
||||
@@ -963,6 +996,41 @@ std::vector<fs::path> find_inis(
|
||||
return map(v, [&](auto&& p){ return p.second; });
|
||||
}
|
||||
|
||||
fs::path find_iscc()
|
||||
{
|
||||
const auto tasks = find_tasks("installer");
|
||||
MOB_ASSERT(tasks.size() == 1);
|
||||
|
||||
if (!tasks[0]->enabled())
|
||||
return {};
|
||||
|
||||
const auto iscc = conf::tool_by_name("iscc");
|
||||
if (iscc.is_absolute())
|
||||
{
|
||||
if (!fs::exists(iscc))
|
||||
{
|
||||
gcx().bail_out(context::conf,
|
||||
"{} doesn't exist (from ini, absolute path)", iscc);
|
||||
}
|
||||
|
||||
return iscc;
|
||||
}
|
||||
|
||||
for (int v : {5, 6, 7, 8})
|
||||
{
|
||||
const fs::path inno = ::fmt::format("inno setup {}", v);
|
||||
|
||||
for (fs::path pf : {paths::pf_x86(), paths::pf_x64()})
|
||||
{
|
||||
fs::path p = pf / inno / iscc;
|
||||
if (fs::exists(p))
|
||||
return fs::canonical(fs::absolute(p));
|
||||
}
|
||||
}
|
||||
|
||||
gcx().bail_out(context::conf, "can't find {} anywhere", iscc);
|
||||
}
|
||||
|
||||
void init_options(
|
||||
const std::vector<fs::path>& inis, const std::vector<std::string>& opts)
|
||||
{
|
||||
@@ -1037,19 +1105,22 @@ void init_options(
|
||||
find_vcvars();
|
||||
validate_qt();
|
||||
|
||||
if (!paths::prefix().empty())
|
||||
make_canonical_path("prefix", fs::current_path(), "");
|
||||
this_env::append_to_path(conf::path_by_name("qt_bin"));
|
||||
|
||||
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");
|
||||
make_canonical_path("install_pdbs", paths::install(), "pdb");
|
||||
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");
|
||||
if (!paths::prefix().empty())
|
||||
make_canonical_path("prefix", fs::current_path(), "");
|
||||
|
||||
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_installer", paths::install(), "installer");
|
||||
make_canonical_path("install_bin", paths::install(), "bin");
|
||||
make_canonical_path("install_libs", paths::install(), "libs");
|
||||
make_canonical_path("install_pdbs", paths::install(), "pdb");
|
||||
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");
|
||||
|
||||
make_canonical_path(
|
||||
"install_pythoncore",
|
||||
@@ -1058,6 +1129,12 @@ void init_options(
|
||||
make_canonical_path(
|
||||
"install_stylesheets",
|
||||
paths::install_bin(), "stylesheets");
|
||||
|
||||
make_canonical_path(
|
||||
"install_translations",
|
||||
paths::install_bin(), "translations");
|
||||
|
||||
conf::set_global("tools", "iscc", path_to_utf8(find_iscc()));
|
||||
}
|
||||
|
||||
bool verify_options()
|
||||
|
||||
@@ -9,6 +9,13 @@ public:
|
||||
static std::string get_global(
|
||||
const std::string& section, const std::string& key);
|
||||
|
||||
static int get_global_int(
|
||||
const std::string& section, const std::string& key);
|
||||
|
||||
static bool get_global_bool(
|
||||
const std::string& section, const std::string& key);
|
||||
|
||||
|
||||
static void set_global(
|
||||
const std::string& section,
|
||||
const std::string& key, const std::string& value);
|
||||
@@ -98,6 +105,7 @@ struct paths
|
||||
VALUE(build);
|
||||
|
||||
VALUE(install);
|
||||
VALUE(install_installer);
|
||||
VALUE(install_bin);
|
||||
VALUE(install_libs);
|
||||
VALUE(install_pdbs);
|
||||
@@ -108,6 +116,7 @@ struct paths
|
||||
VALUE(install_stylesheets);
|
||||
VALUE(install_licenses);
|
||||
VALUE(install_pythoncore);
|
||||
VALUE(install_translations);
|
||||
|
||||
VALUE(pf_x86);
|
||||
VALUE(pf_x64);
|
||||
|
||||
@@ -449,6 +449,12 @@ void this_env::prepend_to_path(const fs::path& p)
|
||||
set("PATH", path_to_utf8(p) + ";", env::prepend);
|
||||
}
|
||||
|
||||
void this_env::append_to_path(const fs::path& p)
|
||||
{
|
||||
gcx().trace(context::generic, "appending to PATH: {}", p);
|
||||
set("PATH", ";" + path_to_utf8(p), env::append);
|
||||
}
|
||||
|
||||
std::string this_env::get(const std::string& name)
|
||||
{
|
||||
auto v = get_impl(name);
|
||||
|
||||
@@ -70,6 +70,7 @@ struct this_env
|
||||
env::flags f=env::replace);
|
||||
|
||||
static void prepend_to_path(const fs::path& p);
|
||||
static void append_to_path(const fs::path& p);
|
||||
|
||||
static env get();
|
||||
|
||||
|
||||
+7
-1
@@ -136,6 +136,9 @@ void add_tasks()
|
||||
.add_task<mo>({"modorganizer-bsapacker", "bsa_packer"})
|
||||
.add_task<mo>("modorganizer-preview_bsa");
|
||||
|
||||
// the gamebryo flag must be set for all game plugins that inherit from
|
||||
// the gamebryo classes; this will merge the .ts file from gamebryo with
|
||||
// the one from the specific plugin
|
||||
add_task<parallel_tasks>(true)
|
||||
.add_task<mo>("modorganizer-game_oblivion", mo::gamebryo)
|
||||
.add_task<mo>("modorganizer-game_fallout3", mo::gamebryo)
|
||||
@@ -163,7 +166,8 @@ void add_tasks()
|
||||
.add_task<mo>("modorganizer-installer_fomod_csharp")
|
||||
.add_task<mo>("modorganizer-installer_ncc")
|
||||
.add_task<mo>("modorganizer-bsa_extractor")
|
||||
.add_task<mo>("modorganizer-plugin_python");
|
||||
.add_task<mo>("modorganizer-plugin_python")
|
||||
.add_task<translations>();
|
||||
|
||||
add_task<parallel_tasks>(true)
|
||||
.add_task<mo>({"modorganizer-tool_configurator", "pycfg"})
|
||||
@@ -175,6 +179,8 @@ void add_tasks()
|
||||
.add_task<mo>({"modorganizer-form43_checker", "form43checker"})
|
||||
.add_task<mo>({"modorganizer-preview_dds", "ddspreview"})
|
||||
.add_task<mo>({"modorganizer", "organizer"});
|
||||
|
||||
add_task<installer>();
|
||||
}
|
||||
|
||||
|
||||
|
||||
+35
-1
@@ -84,12 +84,46 @@ void delete_file(const context& cx, const fs::path& p, flags f)
|
||||
}
|
||||
|
||||
if (fs::exists(p) && !fs::is_regular_file(p))
|
||||
cx.bail_out(context::fs, "can't delete {}, not a file", p);
|
||||
{
|
||||
if (f & optional)
|
||||
cx.warning(context::fs, "can't delete {}, not a file", p);
|
||||
else
|
||||
cx.bail_out(context::fs, "can't delete {}, not a file", p);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!conf::dry())
|
||||
do_delete_file(cx, p);
|
||||
}
|
||||
|
||||
void delete_file_glob(const context& cx, const fs::path& glob, flags f)
|
||||
{
|
||||
cx.trace(context::fs, "deleting glob {}", glob);
|
||||
|
||||
const auto parent = glob.parent_path();
|
||||
const auto wildcard = glob.filename().native();
|
||||
|
||||
if (!fs::exists(parent))
|
||||
return;
|
||||
|
||||
for (auto&& e : fs::directory_iterator(parent))
|
||||
{
|
||||
const auto p = e.path();
|
||||
const auto name = p.filename().native();
|
||||
|
||||
if (!PathMatchSpecW(name.c_str(), wildcard.c_str()))
|
||||
{
|
||||
cx.trace(context::fs,
|
||||
"{} did not match {}; skipping", name, wildcard);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
delete_file(cx, p, f);
|
||||
}
|
||||
}
|
||||
|
||||
void remove_readonly(const context& cx, const fs::path& first)
|
||||
{
|
||||
cx.trace(context::fs, "removing read-only from {}", first);
|
||||
|
||||
@@ -30,6 +30,9 @@ void delete_directory(
|
||||
void delete_file(
|
||||
const context& cx, const fs::path& p, flags f=noflags);
|
||||
|
||||
void delete_file_glob(
|
||||
const context& cx, const fs::path& glob, flags f=noflags);
|
||||
|
||||
void remove_readonly(
|
||||
const context& cx, const fs::path& first);
|
||||
|
||||
|
||||
@@ -706,6 +706,8 @@ void process::on_completed()
|
||||
code_ = 0xffff;
|
||||
}
|
||||
|
||||
read_pipes(false);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
read_pipes(true);
|
||||
|
||||
+9
-6
@@ -137,14 +137,17 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
if (line.empty() && finished)
|
||||
if (line.empty())
|
||||
{
|
||||
line = {
|
||||
reinterpret_cast<const CharT*>(bytes.data() + byte_offset),
|
||||
size - byte_offset
|
||||
};
|
||||
if (finished)
|
||||
{
|
||||
line = {
|
||||
reinterpret_cast<const CharT*>(bytes.data() + byte_offset),
|
||||
size - byte_offset
|
||||
};
|
||||
|
||||
byte_offset = bytes.size();
|
||||
byte_offset = bytes.size();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
#include "pch.h"
|
||||
#include "tasks.h"
|
||||
|
||||
namespace mob
|
||||
{
|
||||
|
||||
installer::installer()
|
||||
: basic_task("installer", "modorganizer-Installer")
|
||||
{
|
||||
}
|
||||
|
||||
bool installer::prebuilt()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string installer::version()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
fs::path installer::source_path()
|
||||
{
|
||||
return modorganizer::super_path() / "installer";
|
||||
}
|
||||
|
||||
void installer::do_clean(clean c)
|
||||
{
|
||||
instrument<times::clean>([&]
|
||||
{
|
||||
if (is_set(c, clean::reclone))
|
||||
git::delete_directory(cx(), source_path());
|
||||
|
||||
if (is_set(c, clean::rebuild))
|
||||
op::delete_directory(cx(), paths::install_installer());
|
||||
});
|
||||
}
|
||||
|
||||
void installer::do_fetch()
|
||||
{
|
||||
const std::string repo = "modorganizer-Installer";
|
||||
|
||||
instrument<times::fetch>([&]
|
||||
{
|
||||
run_tool(task_conf().make_git()
|
||||
.url(task_conf().make_git_url(task_conf().mo_org(), repo))
|
||||
.branch(task_conf().mo_branch())
|
||||
.root(source_path()));
|
||||
});
|
||||
}
|
||||
|
||||
void installer::do_build_and_install()
|
||||
{
|
||||
instrument<times::build>([&]
|
||||
{
|
||||
run_tool<iscc>(source_path() / "dist" / "MO2-Installer.iss");
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
+73
-15
@@ -72,7 +72,6 @@ public:
|
||||
|
||||
static std::string version();
|
||||
static bool prebuilt();
|
||||
|
||||
static fs::path source_path();
|
||||
|
||||
protected:
|
||||
@@ -88,7 +87,6 @@ public:
|
||||
|
||||
static std::string version();
|
||||
static bool prebuilt();
|
||||
|
||||
static fs::path source_path();
|
||||
|
||||
protected:
|
||||
@@ -107,7 +105,6 @@ public:
|
||||
|
||||
static std::string version();
|
||||
static bool prebuilt();
|
||||
|
||||
static fs::path source_path();
|
||||
|
||||
protected:
|
||||
@@ -126,7 +123,6 @@ public:
|
||||
|
||||
static std::string version();
|
||||
static bool prebuilt();
|
||||
|
||||
static fs::path source_path();
|
||||
|
||||
protected:
|
||||
@@ -152,7 +148,6 @@ public:
|
||||
|
||||
static std::string version();
|
||||
static bool prebuilt();
|
||||
|
||||
static fs::path source_path();
|
||||
|
||||
protected:
|
||||
@@ -166,6 +161,22 @@ private:
|
||||
};
|
||||
|
||||
|
||||
class installer : public basic_task<installer>
|
||||
{
|
||||
public:
|
||||
installer();
|
||||
|
||||
static bool prebuilt();
|
||||
static std::string version();
|
||||
static fs::path source_path();
|
||||
|
||||
protected:
|
||||
void do_clean(clean c) override;
|
||||
void do_fetch() override;
|
||||
void do_build_and_install() override;
|
||||
};
|
||||
|
||||
|
||||
class licenses : public basic_task<licenses>
|
||||
{
|
||||
public:
|
||||
@@ -173,7 +184,6 @@ public:
|
||||
|
||||
static std::string version();
|
||||
static bool prebuilt();
|
||||
|
||||
static fs::path source_path();
|
||||
|
||||
protected:
|
||||
@@ -188,7 +198,6 @@ public:
|
||||
|
||||
static std::string version();
|
||||
static bool prebuilt();
|
||||
|
||||
static fs::path source_path();
|
||||
|
||||
protected:
|
||||
@@ -228,7 +237,6 @@ public:
|
||||
static std::string version();
|
||||
static std::string hash();
|
||||
static bool prebuilt();
|
||||
|
||||
static fs::path source_path();
|
||||
|
||||
protected:
|
||||
@@ -249,7 +257,6 @@ public:
|
||||
|
||||
static std::string version();
|
||||
static bool prebuilt();
|
||||
|
||||
static fs::path source_path();
|
||||
|
||||
protected:
|
||||
@@ -323,7 +330,6 @@ public:
|
||||
|
||||
static std::string version();
|
||||
static bool prebuilt();
|
||||
|
||||
static fs::path source_path();
|
||||
|
||||
protected:
|
||||
@@ -343,7 +349,6 @@ public:
|
||||
|
||||
static std::string version();
|
||||
static bool prebuilt();
|
||||
|
||||
static fs::path source_path();
|
||||
|
||||
protected:
|
||||
@@ -515,7 +520,6 @@ public:
|
||||
|
||||
static std::string version();
|
||||
static bool prebuilt();
|
||||
|
||||
static fs::path source_path();
|
||||
|
||||
protected:
|
||||
@@ -539,7 +543,6 @@ public:
|
||||
|
||||
static std::string version();
|
||||
static bool prebuilt();
|
||||
|
||||
static fs::path source_path();
|
||||
|
||||
protected:
|
||||
@@ -587,6 +590,63 @@ private:
|
||||
};
|
||||
|
||||
|
||||
class translations : public basic_task<translations>
|
||||
{
|
||||
public:
|
||||
class projects
|
||||
{
|
||||
public:
|
||||
struct lang
|
||||
{
|
||||
std::string name;
|
||||
std::vector<fs::path> ts_files;
|
||||
|
||||
lang(std::string n);
|
||||
};
|
||||
|
||||
struct project
|
||||
{
|
||||
std::string name;
|
||||
std::vector<lang> langs;
|
||||
|
||||
project(std::string n);
|
||||
};
|
||||
|
||||
|
||||
projects(fs::path root);
|
||||
|
||||
const std::vector<project>& get() const;
|
||||
const std::vector<std::string>& warnings() const;
|
||||
|
||||
private:
|
||||
const fs::path root_;
|
||||
std::vector<project> projects_;
|
||||
std::vector<std::string> warnings_;
|
||||
std::set<fs::path> warned_;
|
||||
|
||||
void create();
|
||||
bool is_gamebryo_plugin(
|
||||
const std::string& dir, const std::string& project);
|
||||
void handle_project_dir(const fs::path& dir);
|
||||
|
||||
lang handle_ts_file(
|
||||
bool gamebryo, const std::string& project_name, const fs::path& f);
|
||||
};
|
||||
|
||||
|
||||
translations();
|
||||
|
||||
static bool prebuilt();
|
||||
static std::string version();
|
||||
static fs::path source_path();
|
||||
|
||||
protected:
|
||||
void do_clean(clean c) override;
|
||||
void do_fetch() override;
|
||||
void do_build_and_install() override;
|
||||
};
|
||||
|
||||
|
||||
class usvfs : public basic_task<usvfs>
|
||||
{
|
||||
public:
|
||||
@@ -594,7 +654,6 @@ public:
|
||||
|
||||
static std::string version();
|
||||
static bool prebuilt();
|
||||
|
||||
static fs::path source_path();
|
||||
|
||||
protected:
|
||||
@@ -627,7 +686,6 @@ public:
|
||||
|
||||
static std::string version();
|
||||
static bool prebuilt();
|
||||
|
||||
static fs::path source_path();
|
||||
|
||||
protected:
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
#include "pch.h"
|
||||
#include "tasks.h"
|
||||
|
||||
namespace mob
|
||||
{
|
||||
|
||||
translations::projects::lang::lang(std::string n)
|
||||
: name(std::move(n))
|
||||
{
|
||||
}
|
||||
|
||||
translations::projects::project::project(std::string n)
|
||||
: name(std::move(n))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
translations::projects::projects(fs::path root)
|
||||
: root_(std::move(root))
|
||||
{
|
||||
create();
|
||||
}
|
||||
|
||||
const std::vector<translations::projects::project>&
|
||||
translations::projects::get() const
|
||||
{
|
||||
return projects_;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& translations::projects::warnings() const
|
||||
{
|
||||
return warnings_;
|
||||
}
|
||||
|
||||
void translations::projects::create()
|
||||
{
|
||||
for (auto e : fs::directory_iterator(root_))
|
||||
{
|
||||
if (!e.is_directory())
|
||||
continue;
|
||||
|
||||
handle_project_dir(e.path());
|
||||
}
|
||||
}
|
||||
|
||||
bool translations::projects::is_gamebryo_plugin(
|
||||
const std::string& dir, const std::string& project)
|
||||
{
|
||||
auto tasks = find_tasks(project);
|
||||
if (tasks.empty())
|
||||
{
|
||||
warnings_.push_back(::fmt::format(
|
||||
"directory '{}' was parsed as project '{}', but there's "
|
||||
"no task with this name", dir, project));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const task& t = *tasks[0];
|
||||
|
||||
if (!t.is_super())
|
||||
return false;
|
||||
|
||||
const auto& mo_task = static_cast<const modorganizer&>(t);
|
||||
return mo_task.is_gamebryo_plugin();
|
||||
}
|
||||
|
||||
void translations::projects::handle_project_dir(const fs::path& dir)
|
||||
{
|
||||
const auto dir_name = path_to_utf8(dir.filename());
|
||||
const auto dir_cs = split(dir_name, ".");
|
||||
|
||||
if (dir_cs.size() != 2)
|
||||
{
|
||||
warnings_.push_back(::fmt::format(
|
||||
"bad directory name '{}'; skipping", dir_name));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const auto project_name = trim_copy(dir_cs[1]);
|
||||
if (project_name.empty())
|
||||
{
|
||||
warnings_.push_back(::fmt::format(
|
||||
"bad directory name '{}', skipping", dir_name));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
project p(project_name);
|
||||
|
||||
const bool gamebryo = is_gamebryo_plugin(dir_name, project_name);
|
||||
|
||||
for (auto f : fs::directory_iterator(dir))
|
||||
{
|
||||
if (!f.is_regular_file())
|
||||
continue;
|
||||
|
||||
p.langs.push_back(handle_ts_file(gamebryo, project_name, f.path()));
|
||||
}
|
||||
|
||||
projects_.push_back(p);
|
||||
}
|
||||
|
||||
translations::projects::lang translations::projects::handle_ts_file(
|
||||
bool gamebryo, const std::string& project_name, const fs::path& f)
|
||||
{
|
||||
lang lg(path_to_utf8(f.stem()));
|
||||
|
||||
lg.ts_files.push_back(f);
|
||||
|
||||
if (gamebryo)
|
||||
{
|
||||
const fs::path gamebryo_dir =
|
||||
conf::get_global("transifex", "project") + "." +
|
||||
"game_gamebryo";
|
||||
|
||||
const auto gb_f = root_ / gamebryo_dir / f.filename();
|
||||
|
||||
if (fs::exists(gb_f))
|
||||
{
|
||||
lg.ts_files.push_back(gb_f);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!warned_.contains(gb_f))
|
||||
{
|
||||
warned_.insert(gb_f);
|
||||
|
||||
warnings_.push_back(::fmt::format(
|
||||
"{} is a gamebryo plugin but there is no '{}'; the "
|
||||
".qm file will be missing some translations (will "
|
||||
"only warn once)",
|
||||
project_name, path_to_utf8(gb_f)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return lg;
|
||||
}
|
||||
|
||||
|
||||
translations::translations()
|
||||
: basic_task("translations")
|
||||
{
|
||||
}
|
||||
|
||||
bool translations::prebuilt()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string translations::version()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
fs::path translations::source_path()
|
||||
{
|
||||
return paths::build() / "transifex-translations";
|
||||
}
|
||||
|
||||
void translations::do_clean(clean c)
|
||||
{
|
||||
instrument<times::clean>([&]
|
||||
{
|
||||
if (is_set(c, clean::redownload))
|
||||
op::delete_directory(cx(), source_path(), op::optional);
|
||||
|
||||
if (is_set(c, clean::rebuild))
|
||||
{
|
||||
op::delete_file_glob(
|
||||
cx(), paths::install_translations() / "*.qm", op::optional);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void translations::do_fetch()
|
||||
{
|
||||
instrument<times::fetch>([&]
|
||||
{
|
||||
const url u =
|
||||
conf::get_global("transifex", "url") + "/" +
|
||||
conf::get_global("transifex", "team") + "/" +
|
||||
conf::get_global("transifex", "project");
|
||||
|
||||
const std::string key = conf::get_global("transifex", "key");
|
||||
|
||||
if (key.empty() && !this_env::get_opt("TX_TOKEN"))
|
||||
{
|
||||
cx().warning(context::generic,
|
||||
"no key was in the INI and the TX_TOKEN env variable doesn't "
|
||||
"exist, this will probably fail");
|
||||
}
|
||||
|
||||
cx().debug(context::generic, "init tx");
|
||||
run_tool(transifex(transifex::init)
|
||||
.root(source_path()));
|
||||
|
||||
if (conf::get_global_bool("transifex", "configure"))
|
||||
{
|
||||
cx().debug(context::generic, "configuring");
|
||||
run_tool(transifex(transifex::config)
|
||||
.root(source_path())
|
||||
.api_key(key)
|
||||
.url(u));
|
||||
}
|
||||
else
|
||||
{
|
||||
cx().trace(context::generic, "skipping configuring");
|
||||
}
|
||||
|
||||
if (conf::get_global_bool("transifex", "pull"))
|
||||
{
|
||||
cx().debug(context::generic, "pulling");
|
||||
run_tool(transifex(transifex::pull)
|
||||
.root(source_path())
|
||||
.api_key(key)
|
||||
.minimum(conf::get_global_int("transifex", "minimum"))
|
||||
.force(conf::get_global_bool("transifex", "force")));
|
||||
}
|
||||
else
|
||||
{
|
||||
cx().trace(context::generic, "skipping pulling");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void translations::do_build_and_install()
|
||||
{
|
||||
instrument<times::build>([&]
|
||||
{
|
||||
const auto root = source_path() / "translations";
|
||||
const auto dest = paths::install_translations();
|
||||
const projects ps(root);
|
||||
|
||||
op::create_directories(cx(), dest);
|
||||
|
||||
for (auto&& w : ps.warnings())
|
||||
cx().warning(context::generic, "{}", w);
|
||||
|
||||
thread_pool tp;
|
||||
|
||||
for (auto& p : ps.get())
|
||||
{
|
||||
for (auto& lg : p.langs)
|
||||
{
|
||||
tp.add([&]
|
||||
{
|
||||
threaded_run(lg.name + "." + p.name, [&]
|
||||
{
|
||||
run_tool(lrelease()
|
||||
.project(p.name)
|
||||
.sources(lg.ts_files)
|
||||
.out(dest));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
+36
-1
@@ -392,7 +392,7 @@ lrelease::lrelease()
|
||||
|
||||
fs::path lrelease::binary()
|
||||
{
|
||||
return conf::path_by_name("qt_bin") / conf::tool_by_name("lrelease");
|
||||
return conf::tool_by_name("lrelease");
|
||||
}
|
||||
|
||||
lrelease& lrelease::project(const std::string& name)
|
||||
@@ -407,6 +407,12 @@ lrelease& lrelease::add_source(const fs::path& ts_file)
|
||||
return *this;
|
||||
}
|
||||
|
||||
lrelease& lrelease::sources(const std::vector<fs::path>& v)
|
||||
{
|
||||
sources_ = v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
lrelease& lrelease::out(const fs::path& dir)
|
||||
{
|
||||
out_ = dir;
|
||||
@@ -453,4 +459,33 @@ void lrelease::do_run()
|
||||
execute_and_join();
|
||||
}
|
||||
|
||||
|
||||
iscc::iscc(fs::path iss)
|
||||
: basic_process_runner("iscc"), iss_(std::move(iss))
|
||||
{
|
||||
}
|
||||
|
||||
fs::path iscc::binary()
|
||||
{
|
||||
return conf::tool_by_name("iscc");
|
||||
}
|
||||
|
||||
iscc& iscc::iss(const fs::path& p)
|
||||
{
|
||||
iss_ = p;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void iscc::do_run()
|
||||
{
|
||||
if (iss_.empty())
|
||||
cx().bail_out(context::generic, "iscc missing iss file");
|
||||
|
||||
process_
|
||||
.binary(binary())
|
||||
.arg(iss_);
|
||||
|
||||
execute_and_join();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -608,6 +608,7 @@ public:
|
||||
|
||||
lrelease& project(const std::string& name);
|
||||
lrelease& add_source(const fs::path& ts_file);
|
||||
lrelease& sources(const std::vector<fs::path>& v);
|
||||
lrelease& out(const fs::path& dir);
|
||||
|
||||
fs::path qm_file() const;
|
||||
@@ -621,4 +622,21 @@ private:
|
||||
fs::path out_;
|
||||
};
|
||||
|
||||
|
||||
class iscc : public basic_process_runner
|
||||
{
|
||||
public:
|
||||
static fs::path binary();
|
||||
|
||||
iscc(fs::path iss = {});
|
||||
|
||||
iscc& iss(const fs::path& p);
|
||||
|
||||
protected:
|
||||
void do_run() override;
|
||||
|
||||
private:
|
||||
fs::path iss_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -918,4 +918,63 @@ std::string path_to_utf8(fs::path p)
|
||||
return utf16_to_utf8(p.native());
|
||||
}
|
||||
|
||||
|
||||
|
||||
thread_pool::thread_pool(std::size_t count)
|
||||
: count_(std::max<std::size_t>(1, count))
|
||||
{
|
||||
for (std::size_t i=0; i<count_; ++i)
|
||||
threads_.emplace_back(std::make_unique<thread_info>());
|
||||
}
|
||||
|
||||
thread_pool::~thread_pool()
|
||||
{
|
||||
join();
|
||||
}
|
||||
|
||||
void thread_pool::join()
|
||||
{
|
||||
for (auto&& t : threads_)
|
||||
{
|
||||
if (t->thread.joinable())
|
||||
t->thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
void thread_pool::add(fun thread_fun)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (try_add(thread_fun))
|
||||
break;
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
}
|
||||
|
||||
bool thread_pool::try_add(fun thread_fun)
|
||||
{
|
||||
for (auto& t : threads_)
|
||||
{
|
||||
if (!t->running)
|
||||
{
|
||||
if (t->thread.joinable())
|
||||
t->thread.join();
|
||||
|
||||
t->running = true;
|
||||
t->thread_fun = thread_fun;
|
||||
|
||||
t->thread = std::thread([&]
|
||||
{
|
||||
t->thread_fun();
|
||||
t->running = false;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -588,4 +588,35 @@ auto map(const std::vector<T>& v, F&& f)
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
class thread_pool
|
||||
{
|
||||
public:
|
||||
typedef std::function<void ()> fun;
|
||||
|
||||
thread_pool(std::size_t count=std::thread::hardware_concurrency());
|
||||
~thread_pool();
|
||||
|
||||
// non-copyable
|
||||
thread_pool(const thread_pool&) = delete;
|
||||
thread_pool& operator=(const thread_pool&) = delete;
|
||||
|
||||
void add(fun f);
|
||||
void join();
|
||||
|
||||
private:
|
||||
struct thread_info
|
||||
{
|
||||
std::atomic<bool> running = false;
|
||||
fun thread_fun;
|
||||
std::thread thread;
|
||||
};
|
||||
|
||||
|
||||
const std::size_t count_;
|
||||
std::vector<std::unique_ptr<thread_info>> threads_;
|
||||
|
||||
bool try_add(fun thread_fun);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -76,6 +76,7 @@
|
||||
<ClCompile Include="..\src\tasks\explorerpp.cpp" />
|
||||
<ClCompile Include="..\src\tasks\fmt.cpp" />
|
||||
<ClCompile Include="..\src\tasks\gtest.cpp" />
|
||||
<ClCompile Include="..\src\tasks\installer.cpp" />
|
||||
<ClCompile Include="..\src\tasks\libbsarch.cpp" />
|
||||
<ClCompile Include="..\src\tasks\libffi.cpp" />
|
||||
<ClCompile Include="..\src\tasks\libloot.cpp" />
|
||||
@@ -92,6 +93,7 @@
|
||||
<ClCompile Include="..\src\tasks\spdlog.cpp" />
|
||||
<ClCompile Include="..\src\tasks\stylesheets.cpp" />
|
||||
<ClCompile Include="..\src\tasks\task.cpp" />
|
||||
<ClCompile Include="..\src\tasks\translations.cpp" />
|
||||
<ClCompile Include="..\src\tasks\usvfs.cpp" />
|
||||
<ClCompile Include="..\src\tasks\zlib.cpp" />
|
||||
<ClCompile Include="..\src\tools\cmake.cpp" />
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user