Author SHA1 Message Date
Mikaël Capelle 60eb00e04e Start working on extensions.
- Update translations task to put translations under extensions.
- Put translations in the right place.
- Remove INI bakery plugin.
- Use mo2- prefixed extensions for translations.
- Generate metadata for the translations extension.
2023-11-10 13:10:20 +01:00
90 changed files with 18578 additions and 20460 deletions
+26
View File
@@ -0,0 +1,26 @@
---
# We'll use defaults from the LLVM style, but with 4 columns indentation.
BasedOnStyle: LLVM
IndentWidth: 4
---
Language: Cpp
# Force pointers to the type for C++.
DerivePointerAlignment: false
PointerAlignment: Left
AlignConsecutiveAssignments: true
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: Empty
AlwaysBreakTemplateDeclarations: Yes
AccessModifierOffset: -4
AlignTrailingComments: true
SpacesBeforeTrailingComments: 2
NamespaceIndentation: All
MaxEmptyLinesToKeep: 1
BreakBeforeBraces: Stroustrup
ColumnLimit: 88
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"pch.h"$'
Priority: -1
SortPriority: -1
+7
View File
@@ -0,0 +1,7 @@
# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto
# Explicitly declare text files you want to always be normalized and converted
# to native line endings on checkout.
*.cpp text eol=crlf
*.h text eol=crlf
+5 -1
View File
@@ -21,6 +21,10 @@ host =
super = cmake_common modorganizer* githubpp super = cmake_common modorganizer* githubpp
plugins = check_fnis bsapacker bsa_extractor diagnose_basic installer_* plugin_python preview_base preview_bsa tool_* game_* plugins = check_fnis bsapacker bsa_extractor diagnose_basic installer_* plugin_python preview_base preview_bsa tool_* game_*
[translations]
mo2-translations = organizer
mo2-game-bethesda = game_creation game_enderal game_enderalse game_fallout3 game_fallout4 game_fallout4vr game_falloutNV game_gamebryo game_morrowind game_nehrim game_oblivion game_skyrim game_skyrimse game_skyrimvr game_ttw
[task] [task]
enabled = true enabled = true
mo_org = ModOrganizer2 mo_org = ModOrganizer2
@@ -144,10 +148,10 @@ install_pdbs =
install_dlls = install_dlls =
install_loot = install_loot =
install_plugins = install_plugins =
install_extensions =
install_stylesheets = install_stylesheets =
install_licenses = install_licenses =
install_pythoncore = install_pythoncore =
install_translations =
vs = vs =
qt_install = qt_install =
qt_bin = qt_bin =
+150 -155
View File
@@ -1,200 +1,195 @@
#include "pch.h" #include "pch.h"
#include "commands.h"
#include "../core/ini.h"
#include "../core/conf.h" #include "../core/conf.h"
#include "../core/context.h" #include "../core/context.h"
#include "../core/ini.h"
#include "../core/op.h" #include "../core/op.h"
#include "../tasks/task_manager.h" #include "../tasks/task_manager.h"
#include "commands.h"
namespace mob namespace mob {
{
build_command::build_command() build_command::build_command() : command(requires_options | handle_sigint) {}
: command(requires_options | handle_sigint)
{
}
command::meta_t build_command::meta() const command::meta_t build_command::meta() const
{ {
return return {"build", "builds tasks"};
{ }
"build",
"builds tasks"
};
}
clipp::group build_command::do_group() clipp::group build_command::do_group()
{ {
return return (clipp::command("build")).set(picked_),
(clipp::command("build")).set(picked_),
(clipp::option("-h", "--help") >> help_) (clipp::option("-h", "--help") >> help_) % ("shows this message"),
% ("shows this message"),
(clipp::option("-g", "--redownload") >> redownload_) (clipp::option("-g", "--redownload") >> redownload_) %
% "redownloads archives, see --reextract", "redownloads archives, see --reextract",
(clipp::option("-e", "--reextract") >> reextract_) (clipp::option("-e", "--reextract") >> reextract_) %
% "deletes source directories and re-extracts archives", "deletes source directories and re-extracts archives",
(clipp::option("-c", "--reconfigure") >> reconfigure_) (clipp::option("-c", "--reconfigure") >> reconfigure_) %
% "reconfigures the task by running cmake, configure scripts, " "reconfigures the task by running cmake, configure scripts, "
"etc.; some tasks might have to delete the whole source " "etc.; some tasks might have to delete the whole source "
"directory", "directory",
(clipp::option("-b", "--rebuild") >> rebuild_) (clipp::option("-b", "--rebuild") >> rebuild_) %
% "cleans and rebuilds projects; some tasks might have to " "cleans and rebuilds projects; some tasks might have to "
"delete the whole source directory", "delete the whole source directory",
(clipp::option("-n", "--new") >> new_) (clipp::option("-n", "--new") >> new_) %
% "deletes everything and starts from scratch", "deletes everything and starts from scratch",
( (clipp::option("--clean-task").call([&] {
clipp::option("--clean-task").call([&]{ clean_ = true; }) | clean_ = true;
clipp::option("--no-clean-task").call([&]{ clean_ = false; }) }) |
) % "sets whether tasks are cleaned", clipp::option("--no-clean-task").call([&] {
clean_ = false;
})) %
"sets whether tasks are cleaned",
( (clipp::option("--fetch-task").call([&] {
clipp::option("--fetch-task").call([&]{ fetch_ = true; }) | fetch_ = true;
clipp::option("--no-fetch-task").call([&]{ fetch_ = false; }) }) |
) % "sets whether tasks are fetched", clipp::option("--no-fetch-task").call([&] {
fetch_ = false;
})) %
"sets whether tasks are fetched",
( (clipp::option("--build-task").call([&] {
clipp::option("--build-task").call([&]{ build_ = true; }) | build_ = true;
clipp::option("--no-build-task").call([&]{ build_ = false; }) }) |
) % "sets whether tasks are built", clipp::option("--no-build-task").call([&] {
build_ = false;
})) %
"sets whether tasks are built",
( (clipp::option("--pull").call([&] {
clipp::option("--pull").call([&]{ nopull_ = false; }) | nopull_ = false;
clipp::option("--no-pull").call([&]{ nopull_ = true; }) }) |
) % "whether to pull repos that are already cloned; global override", clipp::option("--no-pull").call([&] {
nopull_ = true;
})) %
"whether to pull repos that are already cloned; global override",
( (clipp::option("--revert-ts").call([&] {
clipp::option("--revert-ts").call([&]{ revert_ts_ = true; }) | revert_ts_ = true;
clipp::option("--no-revert-ts").call([&]{ revert_ts_ = false; }) }) |
) % "whether to revert all the .ts files in a repo before pulling to " clipp::option("--no-revert-ts").call([&] {
"avoid merge errors; global override", revert_ts_ = false;
})) %
"whether to revert all the .ts files in a repo before pulling to "
"avoid merge errors; global override",
(clipp::option("--ignore-uncommitted-changes") >> ignore_uncommitted_) (clipp::option("--ignore-uncommitted-changes") >> ignore_uncommitted_) %
% "when --reextract is given, directories controlled by git will " "when --reextract is given, directories controlled by git will "
"be deleted even if they contain uncommitted changes", "be deleted even if they contain uncommitted changes",
(clipp::option("--keep-msbuild") >> keep_msbuild_) (clipp::option("--keep-msbuild") >> keep_msbuild_) %
% "don't terminate msbuild.exe instances after building", "don't terminate msbuild.exe instances after building",
(clipp::opt_values( (clipp::opt_values(clipp::match::prefix_not("-"), "task", tasks_)) %
clipp::match::prefix_not("-"), "task", tasks_)) "tasks to run; specify 'super' to only build modorganizer "
% "tasks to run; specify 'super' to only build modorganizer " "projects";
"projects"; }
}
void build_command::convert_cl_to_conf() void build_command::convert_cl_to_conf()
{ {
command::convert_cl_to_conf(); command::convert_cl_to_conf();
if (redownload_ || new_) if (redownload_ || new_)
common.options.push_back("global/redownload=true"); common.options.push_back("global/redownload=true");
if (reextract_ || new_) if (reextract_ || new_)
common.options.push_back("global/reextract=true"); common.options.push_back("global/reextract=true");
if (reconfigure_ || new_) if (reconfigure_ || new_)
common.options.push_back("global/reconfigure=true"); common.options.push_back("global/reconfigure=true");
if (rebuild_ || new_) if (rebuild_ || new_)
common.options.push_back("global/rebuild=true"); common.options.push_back("global/rebuild=true");
if (ignore_uncommitted_) if (ignore_uncommitted_)
common.options.push_back("global/ignore_uncommitted=true"); common.options.push_back("global/ignore_uncommitted=true");
if (clean_) if (clean_) {
{ if (*clean_)
if (*clean_) common.options.push_back("global/clean_task=true");
common.options.push_back("global/clean_task=true"); else
else common.options.push_back("global/clean_task=false");
common.options.push_back("global/clean_task=false"); }
}
if (fetch_) if (fetch_) {
{ if (*fetch_)
if (*fetch_) common.options.push_back("global/fetch_task=true");
common.options.push_back("global/fetch_task=true"); else
else common.options.push_back("global/fetch_task=false");
common.options.push_back("global/fetch_task=false"); }
}
if (build_) if (build_) {
{ if (*build_)
if (*build_) common.options.push_back("global/build_task=true");
common.options.push_back("global/build_task=true"); else
else common.options.push_back("global/build_task=false");
common.options.push_back("global/build_task=false"); }
}
if (nopull_) if (nopull_) {
{ if (*nopull_)
if (*nopull_) common.options.push_back("_override:task/no_pull=true");
common.options.push_back("_override:task/no_pull=true"); else
else common.options.push_back("_override:task/no_pull=false");
common.options.push_back("_override:task/no_pull=false"); }
}
if (revert_ts_) if (revert_ts_) {
{ if (*revert_ts_)
if (*revert_ts_) common.options.push_back("_override:task/revert_ts=true");
common.options.push_back("_override:task/revert_ts=true"); else
else common.options.push_back("_override:task/revert_ts=false");
common.options.push_back("_override:task/revert_ts=false"); }
}
if (!tasks_.empty()) if (!tasks_.empty())
set_task_enabled_flags(tasks_); set_task_enabled_flags(tasks_);
} }
int build_command::do_run() int build_command::do_run()
{ {
try try {
{ create_prefix_ini();
create_prefix_ini();
task_manager::instance().run_all(); task_manager::instance().run_all();
if (!keep_msbuild_) if (!keep_msbuild_)
terminate_msbuild(); terminate_msbuild();
mob::gcx().info(mob::context::generic, "mob done"); mob::gcx().info(mob::context::generic, "mob done");
return 0; return 0;
} }
catch(bailed&) catch (bailed&) {
{ gcx().error(context::generic, "bailing out");
gcx().error(context::generic, "bailing out"); return 1;
return 1; }
} }
}
void build_command::create_prefix_ini() void build_command::create_prefix_ini()
{ {
const auto prefix = conf().path().prefix(); const auto prefix = conf().path().prefix();
// creating prefix // creating prefix
if (!exists(prefix)) if (!exists(prefix))
op::create_directories(gcx(), prefix); op::create_directories(gcx(), prefix);
const auto ini = prefix / default_ini_filename(); const auto ini = prefix / default_ini_filename();
if (!exists(ini)) if (!exists(ini)) {
{ std::ofstream(ini) << "[paths]\n"
std::ofstream(ini) << "prefix = .\n";
<< "[paths]\n" }
<< "prefix = .\n"; }
}
}
void build_command::terminate_msbuild() void build_command::terminate_msbuild()
{ {
if (conf().global().dry()) if (conf().global().dry())
return; return;
system("taskkill /im msbuild.exe /f > NUL 2>&1"); system("taskkill /im msbuild.exe /f > NUL 2>&1");
} }
} // namespace } // namespace mob
+45 -63
View File
@@ -1,83 +1,65 @@
#include "pch.h" #include "pch.h"
#include "commands.h"
#include "../tasks/tasks.h" #include "../tasks/tasks.h"
#include "commands.h"
namespace mob namespace mob {
{
cmake_command::cmake_command() cmake_command::cmake_command() : command(requires_options) {}
: command(requires_options)
{
}
command::meta_t cmake_command::meta() const command::meta_t cmake_command::meta() const
{ {
return return {"cmake", "runs cmake in a directory"};
{ }
"cmake",
"runs cmake in a directory"
};
}
clipp::group cmake_command::do_group() clipp::group cmake_command::do_group()
{ {
return clipp::group( return clipp::group(
clipp::command("cmake").set(picked_), clipp::command("cmake").set(picked_),
(clipp::option("-h", "--help") >> help_) (clipp::option("-h", "--help") >> help_) % "shows this message",
% "shows this message",
(clipp::option("-G", "--generator") (clipp::option("-G", "--generator") & clipp::value("GEN") >> gen_) %
& clipp::value("GEN") >> gen_) ("sets the -G option for cmake [default: VS]"),
% ("sets the -G option for cmake [default: VS]"),
(clipp::option("-c", "--cmd") (clipp::option("-c", "--cmd") & clipp::value("CMD") >> cmd_) %
& clipp::value("CMD") >> cmd_) "overrides the cmake command line [default: \"..\"]",
% "overrides the cmake command line [default: \"..\"]",
( (clipp::option("--x64").set(x64_, true) |
clipp::option("--x64").set(x64_, true) | clipp::option("--x86").set(x64_, false)) %
clipp::option("--x86").set(x64_, false) "whether to use the x64 or x86 vcvars; if -G is not set, "
) "whether to pass \"-A Win32\" or \"-A x64\" for the default "
% "whether to use the x64 or x86 vcvars; if -G is not set, " "VS generator [default: x64]",
"whether to pass \"-A Win32\" or \"-A x64\" for the default "
"VS generator [default: x64]",
(clipp::option("--install-prefix") (clipp::option("--install-prefix") & clipp::value("PATH") >> prefix_) %
& clipp::value("PATH") >> prefix_) "sets CMAKE_INSTALL_PREFIX [default: empty]",
% "sets CMAKE_INSTALL_PREFIX [default: empty]",
(clipp::value("PATH") >> path_) (clipp::value("PATH") >> path_) % "path from which to run `cmake`");
% "path from which to run `cmake`" }
);
}
int cmake_command::do_run() int cmake_command::do_run()
{ {
auto t = tasks::modorganizer::create_cmake_tool( auto t = tasks::modorganizer::create_cmake_tool(fs::path(utf8_to_utf16(path_)));
fs::path(utf8_to_utf16(path_)));
t.generator(gen_); t.generator(gen_);
t.cmd(cmd_); t.cmd(cmd_);
t.prefix(prefix_); t.prefix(prefix_);
t.output(path_); t.output(path_);
if (!x64_) if (!x64_)
t.architecture(arch::x86); t.architecture(arch::x86);
// copy the global context, the tool will modify it // copy the global context, the tool will modify it
context cxcopy(gcx()); context cxcopy(gcx());
t.run(cxcopy); t.run(cxcopy);
return 0; return 0;
} }
std::string cmake_command::do_doc() std::string cmake_command::do_doc()
{ {
return return "Runs `cmake ..` in the given directory with the same command line\n"
"Runs `cmake ..` in the given directory with the same command line\n" "as the one used for modorganizer projects.";
"as the one used for modorganizer projects."; }
}
} // namespace } // namespace mob
+319 -372
View File
File diff suppressed because it is too large Load Diff
+423 -479
View File
File diff suppressed because it is too large Load Diff
+191 -229
View File
@@ -1,285 +1,247 @@
#include "pch.h" #include "pch.h"
#include "commands.h"
#include "../tasks/tasks.h" #include "../tasks/tasks.h"
#include "../tools/tools.h" #include "../tools/tools.h"
#include "commands.h"
namespace mob namespace mob {
{
git_command::git_command() git_command::git_command() : command(requires_options) {}
: command(requires_options)
{
}
command::meta_t git_command::meta() const command::meta_t git_command::meta() const
{ {
return return {"git", "manages the git repos"};
{ }
"git",
"manages the git repos"
};
}
clipp::group git_command::do_group() clipp::group git_command::do_group()
{ {
return clipp::group( return clipp::group(
clipp::command("git").set(picked_), clipp::command("git").set(picked_),
(clipp::option("-h", "--help") >> help_) (clipp::option("-h", "--help") >> help_) % ("shows this message"),
% ("shows this message"),
"set-remotes" % "set-remotes" %
(clipp::command("set-remotes").set(mode_, modes::set_remotes), (clipp::command("set-remotes").set(mode_, modes::set_remotes),
(clipp::required("-u", "--username") (clipp::required("-u", "--username") &
& clipp::value("USERNAME") >> username_) clipp::value("USERNAME") >> username_) %
% "git username", "git username",
(clipp::required("-e", "--email") (clipp::required("-e", "--email") &
& clipp::value("EMAIL") >> email_) clipp::value("EMAIL") >> email_) %
% "git email", "git email",
(clipp::option("-k", "--key") (clipp::option("-k", "--key") & clipp::value("PATH") >> key_) %
& clipp::value("PATH") >> key_) "path to putty key",
% "path to putty key",
(clipp::option("-s", "--no-push").set(nopush_) (clipp::option("-s", "--no-push").set(nopush_) %
% "disables pushing to 'upstream' by changing the push url " "disables pushing to 'upstream' by changing the push url "
"to 'nopushurl' to avoid accidental pushes"), "to 'nopushurl' to avoid accidental pushes"),
(clipp::option("-p", "--push-origin").set(push_default_) (clipp::option("-p", "--push-origin").set(push_default_) %
% "sets the new 'origin' remote as the default push target"), "sets the new 'origin' remote as the default push target"),
(clipp::opt_value("path") >> path_) (clipp::opt_value("path") >> path_) % "only use this repo")
% "only use this repo"
)
| |
"add-remote" % "add-remote" %
(clipp::command("add-remote").set(mode_, modes::add_remote), (clipp::command("add-remote").set(mode_, modes::add_remote),
(clipp::required("-n", "--name") (clipp::required("-n", "--name") &
& clipp::value("NAME") >> remote_) clipp::value("NAME") >> remote_) %
% "name of new remote", "name of new remote",
(clipp::required("-u", "--username") (clipp::required("-u", "--username") &
& clipp::value("USERNAME") >> username_) clipp::value("USERNAME") >> username_) %
% "git username", "git username",
(clipp::option("-k", "--key") (clipp::option("-k", "--key") & clipp::value("PATH") >> key_) %
& clipp::value("PATH") >> key_) "path to putty key",
% "path to putty key",
(clipp::option("-p", "--push-origin").set(push_default_) (clipp::option("-p", "--push-origin").set(push_default_) %
% "sets this new remote as the default push target"), "sets this new remote as the default push target"),
(clipp::opt_value("path") >> path_) (clipp::opt_value("path") >> path_) % "only use this repo")
% "only use this repo"
)
| |
"ignore-ts" % "ignore-ts" % (clipp::command("ignore-ts").set(mode_, modes::ignore_ts),
(clipp::command("ignore-ts").set(mode_, modes::ignore_ts), (clipp::command("on").set(tson_, true) |
( clipp::command("off").set(tson_, false)))
clipp::command("on").set(tson_, true) |
clipp::command("off").set(tson_, false)
)
)
| |
"branches" % "branches" % (clipp::command("branches").set(mode_, modes::branches),
(clipp::command("branches").set(mode_, modes::branches), clipp::option("-a", "--all").set(all_branches_) %
clipp::option("-a", "--all").set(all_branches_) "shows all branches, including those on master"));
% "shows all branches, including those on master" }
)
);
}
int git_command::do_run() int git_command::do_run()
{ {
switch (mode_) switch (mode_) {
{ case modes::set_remotes: {
case modes::set_remotes: do_set_remotes();
{ break;
do_set_remotes(); }
break;
}
case modes::add_remote: case modes::add_remote: {
{ do_add_remote();
do_add_remote(); break;
break; }
}
case modes::ignore_ts: case modes::ignore_ts: {
{ do_ignore_ts();
do_ignore_ts(); break;
break; }
}
case modes::branches: case modes::branches: {
{ do_branches();
do_branches(); break;
break; }
}
case modes::none: case modes::none:
default: default:
u8cerr << "bad git mode " << static_cast<int>(mode_) << "\n"; u8cerr << "bad git mode " << static_cast<int>(mode_) << "\n";
throw bailed(); throw bailed();
} }
return 0; return 0;
} }
std::string git_command::do_doc() std::string git_command::do_doc()
{ {
return return "All the commands will go through all modorganizer repos, plus usvfs\n"
"All the commands will go through all modorganizer repos, plus usvfs\n" "and NCC.\n"
"and NCC.\n" "\n"
"\n" "Commands:\n"
"Commands:\n" "set-remotes\n"
"set-remotes\n" " For each repo, this first sets the username and email. Then, it\n"
" For each repo, this first sets the username and email. Then, it\n" " will rename the remote 'origin' to 'upstream' and create a new\n"
" will rename the remote 'origin' to 'upstream' and create a new\n" " remote 'origin' with the given information. If the remote\n"
" remote 'origin' with the given information. If the remote\n" " 'upstream' already exists in a repo, nothing happens.\n"
" 'upstream' already exists in a repo, nothing happens.\n" "\n"
"\n" "add-remote\n"
"add-remote\n" " For each repo, adds a new remote with the given information. If a\n"
" For each repo, adds a new remote with the given information. If a\n" " remote with the same name already exists, nothing happens.\n"
" remote with the same name already exists, nothing happens.\n" "\n"
"\n" "ignore-ts\n"
"ignore-ts\n" " Toggles the --assume-changed status of all .ts files in all repos.\n"
" Toggles the --assume-changed status of all .ts files in all repos.\n" "\n"
"\n" "branches\n"
"branches\n" " Lists all git repos that are not on master. With -a, show all \n"
" Lists all git repos that are not on master. With -a, show all \n" " repos and their current branch.";
" repos and their current branch."; }
}
void git_command::do_set_remotes() void git_command::do_set_remotes()
{ {
if (path_.empty()) if (path_.empty()) {
{ const auto repos = get_repos();
const auto repos = get_repos();
for (auto&& r : repos) for (auto&& r : repos)
do_set_remotes(r); do_set_remotes(r);
} }
else else {
{ do_set_remotes(path_);
do_set_remotes(path_); }
} }
}
void git_command::do_set_remotes(const fs::path& r) void git_command::do_set_remotes(const fs::path& r)
{ {
u8cout << "setting up " << path_to_utf8(r.filename()) << "\n"; u8cout << "setting up " << path_to_utf8(r.filename()) << "\n";
git_wrap(r).set_credentials(username_, email_); git_wrap(r).set_credentials(username_, email_);
git_wrap(r).set_origin_and_upstream_remotes( git_wrap(r).set_origin_and_upstream_remotes(username_, key_, nopush_,
username_, key_, nopush_, push_default_); push_default_);
} }
void git_command::do_add_remote() void git_command::do_add_remote()
{ {
u8cout u8cout << "adding remote '" << remote_ << "' "
<< "adding remote '" << remote_ << "' " << "from '" << username_ << "' to repos\n";
<< "from '" << username_ << "' to repos\n";
if (path_.empty()) if (path_.empty()) {
{ const auto repos = get_repos();
const auto repos = get_repos();
for (auto&& r : repos) for (auto&& r : repos)
do_add_remote(r); do_add_remote(r);
} }
else else {
{ do_add_remote(path_);
do_add_remote(path_); }
} }
}
void git_command::do_add_remote(const fs::path& r) void git_command::do_add_remote(const fs::path& r)
{ {
u8cout << path_to_utf8(r.filename()) << "\n"; u8cout << path_to_utf8(r.filename()) << "\n";
git_wrap(r).add_remote(remote_, username_, key_, push_default_); git_wrap(r).add_remote(remote_, username_, key_, push_default_);
} }
void git_command::do_ignore_ts() void git_command::do_ignore_ts()
{ {
if (tson_) if (tson_)
u8cout << "ignoring .ts files\n"; u8cout << "ignoring .ts files\n";
else else
u8cout << "un-ignoring .ts files\n"; u8cout << "un-ignoring .ts files\n";
if (path_.empty()) if (path_.empty()) {
{ const auto repos = get_repos();
const auto repos = get_repos();
for (auto&& r : repos) for (auto&& r : repos)
do_ignore_ts(r); do_ignore_ts(r);
} }
else else {
{ do_ignore_ts(path_);
do_ignore_ts(path_); }
} }
}
void git_command::do_ignore_ts(const fs::path& r) void git_command::do_ignore_ts(const fs::path& r)
{ {
u8cout << path_to_utf8(r.filename()) << "\n"; u8cout << path_to_utf8(r.filename()) << "\n";
git_wrap(r).ignore_ts(tson_); git_wrap(r).ignore_ts(tson_);
} }
void git_command::do_branches() void git_command::do_branches()
{ {
std::vector<std::pair<std::string, std::string>> v; std::vector<std::pair<std::string, std::string>> v;
for (auto&& r : get_repos()) for (auto&& r : get_repos()) {
{ const auto b = git_wrap(r).current_branch();
const auto b = git_wrap(r).current_branch(); if (b == "master" && !all_branches_)
if (b == "master" && !all_branches_) continue;
continue;
if (b.empty()) if (b.empty())
v.push_back({r.filename().string(), "detached head"}); v.push_back({r.filename().string(), "detached head"});
else else
v.push_back({r.filename().string(), b}); v.push_back({r.filename().string(), b});
} }
u8cout << table(v, 0, 3) << "\n"; u8cout << table(v, 0, 3) << "\n";
} }
std::vector<fs::path> git_command::get_repos() const std::vector<fs::path> git_command::get_repos() const
{ {
std::vector<fs::path> v; std::vector<fs::path> v;
// usvfs // usvfs
if (fs::exists(tasks::usvfs::source_path())) if (fs::exists(tasks::usvfs::source_path()))
v.push_back(tasks::usvfs::source_path()); v.push_back(tasks::usvfs::source_path());
const auto super = tasks::modorganizer::super_path(); const auto super = tasks::modorganizer::super_path();
// all directories in super except for those starting with a dot // all directories in super except for those starting with a dot
if (fs::exists(super)) if (fs::exists(super)) {
{ for (auto e : fs::directory_iterator(super)) {
for (auto e : fs::directory_iterator(super)) if (!e.is_directory())
{ continue;
if (!e.is_directory())
continue;
const auto p = e.path(); const auto p = e.path();
if (path_to_utf8(p.filename()).starts_with(".")) if (path_to_utf8(p.filename()).starts_with("."))
continue; continue;
v.push_back(p); v.push_back(p);
} }
} }
return v; return v;
} }
} // namespace } // namespace mob
+62 -79
View File
@@ -1,100 +1,83 @@
#include "pch.h" #include "pch.h"
#include "commands.h"
#include "../tasks/task_manager.h"
#include "../tasks/task.h" #include "../tasks/task.h"
#include "../tasks/task_manager.h"
#include "../utility/io.h" #include "../utility/io.h"
#include "commands.h"
namespace mob namespace mob {
{
command::meta_t list_command::meta() const command::meta_t list_command::meta() const
{ {
return return {"list", "lists available tasks"};
{ }
"list",
"lists available tasks"
};
}
clipp::group list_command::do_group() clipp::group list_command::do_group()
{ {
return clipp::group( return clipp::group(
clipp::command("list").set(picked_), clipp::command("list").set(picked_),
(clipp::option("-h", "--help") >> help_) (clipp::option("-h", "--help") >> help_) % "shows this message",
% "shows this message",
(clipp::option("-a", "--all") >> all_) (clipp::option("-a", "--all") >> all_) %
% "shows all the tasks, including pseudo parallel tasks", "shows all the tasks, including pseudo parallel tasks",
(clipp::option("-i", "--aliases") >> aliases_) (clipp::option("-i", "--aliases") >> aliases_) % "shows only aliases",
% "shows only aliases",
(clipp::opt_values( (clipp::opt_values(clipp::match::prefix_not("-"), "task", tasks_)) %
clipp::match::prefix_not("-"), "task", tasks_)) "with -a; when given, acts like the tasks given to `build` and "
% "with -a; when given, acts like the tasks given to `build` and " "shows only the tasks that would run");
"shows only the tasks that would run" }
);
}
int list_command::do_run() int list_command::do_run()
{ {
auto& tm = task_manager::instance(); auto& tm = task_manager::instance();
if (aliases_) if (aliases_) {
{ load_options();
load_options(); dump_aliases();
dump_aliases(); }
} else {
else if (all_) {
{ if (!tasks_.empty())
if (all_) set_task_enabled_flags(tasks_);
{
if (!tasks_.empty())
set_task_enabled_flags(tasks_);
load_options(); load_options();
dump(tm.top_level(), 0); dump(tm.top_level(), 0);
u8cout << "\n\naliases:\n"; u8cout << "\n\naliases:\n";
dump_aliases(); dump_aliases();
} }
else else {
{ for (auto&& t : tm.all())
for (auto&& t : tm.all()) u8cout << " - " << join(t->names(), ", ") << "\n";
u8cout << " - " << join(t->names(), ", ") << "\n"; }
} }
}
return 0;
}
return 0; void list_command::dump(const std::vector<task*>& v, std::size_t indent) const
} {
for (auto&& t : v) {
if (!t->enabled())
continue;
void list_command::dump(const std::vector<task*>& v, std::size_t indent) const u8cout << std::string(indent * 4, ' ') << " - " << join(t->names(), ",")
{ << "\n";
for (auto&& t : v)
{
if (!t->enabled())
continue;
u8cout if (auto* pt = dynamic_cast<parallel_tasks*>(t))
<< std::string(indent*4, ' ') dump(pt->children(), indent + 1);
<< " - " << join(t->names(), ",") }
<< "\n"; }
if (auto* pt=dynamic_cast<parallel_tasks*>(t)) void list_command::dump_aliases() const
dump(pt->children(), indent + 1); {
} const auto v = task_manager::instance().aliases();
} if (v.empty())
return;
void list_command::dump_aliases() const for (auto&& [k, patterns] : v)
{ u8cout << " - " << k << ": " << join(patterns, ", ") << "\n";
const auto v = task_manager::instance().aliases(); }
if (v.empty())
return;
for (auto&& [k, patterns] : v) } // namespace mob
u8cout << " - " << k << ": " << join(patterns, ", ") << "\n";
}
} // namespace
+358 -403
View File
File diff suppressed because it is too large Load Diff
+525 -587
View File
File diff suppressed because it is too large Load Diff
+141 -166
View File
@@ -1,213 +1,188 @@
#include "pch.h" #include "pch.h"
#include "commands.h"
#include "../net.h"
#include "../utility.h"
#include "../core/conf.h" #include "../core/conf.h"
#include "../core/context.h" #include "../core/context.h"
#include "../core/env.h" #include "../core/env.h"
#include "../net.h"
#include "../tasks/tasks.h" #include "../tasks/tasks.h"
#include "../utility.h"
#include "commands.h"
namespace mob namespace mob {
{
tx_command::tx_command() tx_command::tx_command() : command(requires_options) {}
: command(requires_options)
{
}
command::meta_t tx_command::meta() const command::meta_t tx_command::meta() const
{ {
return return {"tx", "manages transifex translations"};
{ }
"tx",
"manages transifex translations"
};
}
clipp::group tx_command::do_group() clipp::group tx_command::do_group()
{ {
return clipp::group( return clipp::group(
clipp::command("tx").set(picked_), clipp::command("tx").set(picked_),
(clipp::option("-h", "--help") >> help_) (clipp::option("-h", "--help") >> help_) % ("shows this message"),
% ("shows this message"),
"get" % "get" % (clipp::command("get").set(mode_, modes::get),
(clipp::command("get").set(mode_, modes::get), (clipp::option("-k", "--key") & clipp::value("APIKEY") >> key_) %
(clipp::option("-k", "--key") "API key",
& clipp::value("APIKEY") >> key_)
% "API key",
(clipp::option("-t", "--team") (clipp::option("-t", "--team") & clipp::value("TEAM") >> team_) %
& clipp::value("TEAM") >> team_) "team name",
% "team name",
(clipp::option("-p", "--project") (clipp::option("-p", "--project") &
& clipp::value("PROJECT") >> project_) clipp::value("PROJECT") >> project_) %
% "project name", "project name",
(clipp::option("-u", "--url") (clipp::option("-u", "--url") & clipp::value("URL") >> url_) %
& clipp::value("URL") >> url_) "project URL",
% "project URL",
(clipp::option("-m", "--minimum") (clipp::option("-m", "--minimum") &
& clipp::value("PERCENT").set(min_)) clipp::value("PERCENT").set(min_)) %
% "minimum translation threshold to download [0-100]", "minimum translation threshold to download [0-100]",
(clipp::option("-f", "--force").call([&]{ force_ = true; })) (clipp::option("-f", "--force").call([&] {
% "don't check timestamps, re-download all translation files", force_ = true;
})) %
"don't check timestamps, re-download all translation files",
(clipp::value("path") >> path_) (clipp::value("path") >> path_) %
% "path that will contain the .tx directory" "path that will contain the .tx directory")
)
| |
"build" % "build" % (clipp::command("build").set(mode_, modes::build),
(clipp::command("build").set(mode_, modes::build),
(clipp::value("source") >> path_) (clipp::value("source") >> path_) %
% "path that contains the translation directories", "path that contains the translation directories",
(clipp::value("destination") >> dest_) (clipp::value("destination") >> dest_) %
% "path that will contain the .qm files" "path that will contain the .qm files"));
) }
);
}
void tx_command::convert_cl_to_conf() void tx_command::convert_cl_to_conf()
{ {
command::convert_cl_to_conf(); command::convert_cl_to_conf();
if (!key_.empty()) if (!key_.empty())
common.options.push_back("transifex/key=" + key_); common.options.push_back("transifex/key=" + key_);
if (!team_.empty()) if (!team_.empty())
common.options.push_back("transifex/team=" + team_); common.options.push_back("transifex/team=" + team_);
if (!project_.empty()) if (!project_.empty())
common.options.push_back("transifex/project=" + project_); common.options.push_back("transifex/project=" + project_);
if (!url_.empty()) if (!url_.empty())
common.options.push_back("transifex/url=" + url_); common.options.push_back("transifex/url=" + url_);
if (min_ >= 0) if (min_ >= 0)
common.options.push_back("transifex/minimum=" + std::to_string(min_)); common.options.push_back("transifex/minimum=" + std::to_string(min_));
if (force_) if (force_)
common.options.push_back("transifex/force=" + std::to_string(*force_)); common.options.push_back("transifex/force=" + std::to_string(*force_));
} }
int tx_command::do_run() int tx_command::do_run()
{ {
switch (mode_) switch (mode_) {
{ case modes::get:
case modes::get: do_get();
do_get(); break;
break;
case modes::build: case modes::build:
do_build(); do_build();
break; break;
case modes::none: case modes::none:
default: default:
u8cerr << "bad tx mode " << static_cast<int>(mode_) << "\n"; u8cerr << "bad tx mode " << static_cast<int>(mode_) << "\n";
throw bailed(); throw bailed();
} }
return 0; return 0;
} }
std::string tx_command::do_doc() std::string tx_command::do_doc()
{ {
return return "Some values will be taken from the INI file if not specified.\n"
"Some values will be taken from the INI file if not specified.\n" "\n"
"\n" "Commands:\n"
"Commands:\n" "get\n"
"get\n" " Initializes a Transifex project in the given directory if\n"
" Initializes a Transifex project in the given directory if\n" " necessary and pulls all the translation files.\n"
" necessary and pulls all the translation files.\n" "\n"
"\n" "build\n"
"build\n" " Builds all .qm files. The path can either be the transifex\n"
" Builds all .qm files. The path can either be the transifex\n" " project (where .tx is) or the `translations` directory (where the\n"
" project (where .tx is) or the `translations` directory (where the\n" " individual translation directories are).";
" individual translation directories are)."; }
}
void tx_command::do_get() void tx_command::do_get()
{ {
const url u = const url u = conf().transifex().get("url") + "/" +
conf().transifex().get("url") + "/" + conf().transifex().get("team") + "/" +
conf().transifex().get("team") + "/" + conf().transifex().get("project");
conf().transifex().get("project");
const std::string key = conf().transifex().get("key"); const std::string key = conf().transifex().get("key");
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"
u8cout << "variable doesn't exist, this will probably fail)\n\n";
"(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";
}
// copy the global context, the tools will modify it // copy the global context, the tools will modify it
context cxcopy = gcx(); context cxcopy = gcx();
u8cout << "initializing\n"; u8cout << "initializing\n";
transifex(transifex::init) transifex(transifex::init).root(path_).run(cxcopy);
.root(path_)
.run(cxcopy);
u8cout << "configuring\n"; u8cout << "configuring\n";
transifex(transifex::config) transifex(transifex::config)
.stdout_level(context::level::info) .stdout_level(context::level::info)
.root(path_) .root(path_)
.api_key(key) .api_key(key)
.url(u) .url(u)
.run(cxcopy); .run(cxcopy);
u8cout << "pulling\n"; u8cout << "pulling\n";
transifex(transifex::pull) transifex(transifex::pull)
.stdout_level(context::level::info) .stdout_level(context::level::info)
.root(path_) .root(path_)
.api_key(key) .api_key(key)
.minimum(conf().transifex().get<int>("minimum")) .minimum(conf().transifex().get<int>("minimum"))
.force(conf().transifex().get<bool>("force")) .force(conf().transifex().get<bool>("force"))
.run(cxcopy); .run(cxcopy);
} }
void tx_command::do_build() void tx_command::do_build()
{ {
fs::path root = path_; fs::path root = path_;
if (fs::exists(root / ".tx") && fs::exists(root / "translations")) if (fs::exists(root / ".tx") && fs::exists(root / "translations"))
root = root / "translations"; root = root / "translations";
tasks::translations::projects ps(root); tasks::translations::projects ps(root);
fs::path dest = dest_; fs::path dest = dest_;
op::create_directories(gcx(), dest, op::unsafe); op::create_directories(gcx(), dest, op::unsafe);
for (auto&& w : ps.warnings()) for (auto&& w : ps.warnings())
u8cerr << w << "\n"; u8cerr << w << "\n";
thread_pool tp; thread_pool tp;
for (auto& p : ps.get()) for (auto& p : ps.get()) {
{ for (auto& lg : p.langs) {
for (auto& lg : p.langs) // copy the global context, each thread must have its own
{ tp.add([&, cxcopy = gcx()]() mutable {
// copy the global context, each thread must have its own lrelease()
tp.add([&, cxcopy=gcx()]() mutable .project(p.name)
{ .sources(lg.ts_files)
lrelease() .out(dest)
.project(p.name) .run(cxcopy);
.sources(lg.ts_files) });
.out(dest) }
.run(cxcopy); }
}); }
}
}
}
} // namespace } // namespace mob
+739 -799
View File
File diff suppressed because it is too large Load Diff
+251 -253
View File
File diff suppressed because it is too large Load Diff
+455 -482
View File
File diff suppressed because it is too large Load Diff
+237 -259
View File
File diff suppressed because it is too large Load Diff
+507 -541
View File
File diff suppressed because it is too large Load Diff
+108 -122
View File
@@ -2,154 +2,140 @@
#include "../utility.h" #include "../utility.h"
namespace mob namespace mob {
{
// a set of environment variables; copy-on-write because this gets copied a lot // a set of environment variables; copy-on-write because this gets copied a lot
// //
class env class env {
{ public:
public: using map = std::map<std::wstring, std::wstring>;
using map = std::map<std::wstring, std::wstring>;
// used in set(); replaces, appends or prepends to a variable if it already // used in set(); replaces, appends or prepends to a variable if it already
// exists // exists
// //
enum flags enum flags { replace = 1, append, prepend };
{
replace = 1,
append,
prepend
};
// Visual Studio environment variables for 32-bit // Visual Studio environment variables for 32-bit
// //
static env vs_x86(); static env vs_x86();
// Visual Studio environment variables for 64-bit // Visual Studio environment variables for 64-bit
// //
static env vs_x64(); static env vs_x64();
// Visual Studio environment variables for the given architecture // Visual Studio environment variables for the given architecture
// //
static env vs(arch a); static env vs(arch a);
// empty set
//
env();
// empty set // handle ref count
// //
env(); env(const env& e);
env(env&& e);
env& operator=(const env& e);
env& operator=(env&& e);
// handle ref count // prepends to PATH
// //
env(const env& e); env& prepend_path(const fs::path& p);
env(env&& e); env& prepend_path(const std::vector<fs::path>& v);
env& operator=(const env& e);
env& operator=(env&& e);
// prepends to PATH // appends to PATH
// //
env& prepend_path(const fs::path& p); env& append_path(const fs::path& p);
env& prepend_path(const std::vector<fs::path>& v); env& append_path(const std::vector<fs::path>& v);
// appends to PATH // sets k=v
// //
env& append_path(const fs::path& p); env& set(std::string_view k, std::string_view v, flags f = replace);
env& append_path(const std::vector<fs::path>& v); env& set(std::wstring k, std::wstring v, flags f = replace);
// sets k=v // returns the variable' value, empty if not found
// //
env& set(std::string_view k, std::string_view v, flags f=replace); std::string get(std::string_view k) const;
env& set(std::wstring k, std::wstring v, flags f=replace);
// returns the variable' value, empty if not found // map of variables
// //
std::string get(std::string_view k) const; map get_map() const;
// map of variables // passed to CreateProcess() in the process class; returns a pointer to a
// // block of utf16 strings, owned by this, created on demand
map get_map() const; //
void* get_unicode_pointers() const;
// passed to CreateProcess() in the process class; returns a pointer to a private:
// block of utf16 strings, owned by this, created on demand // shared between copies
// //
void* get_unicode_pointers() const; struct data {
std::mutex m;
map vars;
private: // unicode strings, see get_unicode_pointers()
// shared between copies mutable std::wstring sys;
// };
struct data
{
std::mutex m;
map vars;
// unicode strings, see get_unicode_pointers() // shared data
mutable std::wstring sys; std::shared_ptr<data> data_;
};
// shared data // whether this instance owns the data, set to true in copy_for_write()
std::shared_ptr<data> data_; // when the data must be modified
bool own_;
// whether this instance owns the data, set to true in copy_for_write() // creates the unicode strings
// when the data must be modified //
bool own_; void create_sys() const;
// returns a pointer inside the map, null if not found
//
std::wstring* find(std::wstring_view name);
const std::wstring* find(std::wstring_view name) const;
// creates the unicode strings // called by set(), sets the value in the map
// //
void create_sys() const; void set_impl(std::wstring k, std::wstring v, flags f);
// returns a pointer inside the map, null if not found // duplicates the data, sets own_=true
// //
std::wstring* find(std::wstring_view name); void copy_for_write();
const std::wstring* find(std::wstring_view name) const;
// called by set(), sets the value in the map // called by the various *_path() functions, actually changes the PATH
// // value
void set_impl(std::wstring k, std::wstring v, flags f); //
env& change_path(const std::vector<fs::path>& v, flags f);
};
// duplicates the data, sets own_=true // represents mob's environment variables
// //
void copy_for_write(); struct this_env {
// sets a variable
//
static void set(const std::string& k, const std::string& v,
env::flags f = env::replace);
// called by the various *_path() functions, actually changes the PATH // changes PATH
// value //
// static void prepend_to_path(const fs::path& p);
env& change_path(const std::vector<fs::path>& v, flags f); static void append_to_path(const fs::path& p);
};
// returns mob's environment variables
//
static env get();
// represents mob's environment variables // returns a specific variable; bails out if it doesn't exist
// //
struct this_env static std::string get(const std::string& k);
{
// sets a variable
//
static void set(
const std::string& k,
const std::string& v,
env::flags f=env::replace);
// changes PATH // returns a specific variable, or empty if it doesn't exist
// //
static void prepend_to_path(const fs::path& p); static std::optional<std::string> get_opt(const std::string& k);
static void append_to_path(const fs::path& p);
// returns mob's environment variables private:
// // used by get() and get_opt(), does the actual work
static env get(); //
static std::optional<std::wstring> get_impl(const std::string& k);
};
// returns a specific variable; bails out if it doesn't exist } // namespace mob
//
static std::string get(const std::string& k);
// returns a specific variable, or empty if it doesn't exist
//
static std::optional<std::string> get_opt(const std::string& k);
private:
// used by get() and get_opt(), does the actual work
//
static std::optional<std::wstring> get_impl(const std::string& k);
};
} // namespace
+271 -314
View File
File diff suppressed because it is too large Load Diff
+18 -22
View File
@@ -1,32 +1,28 @@
#pragma once #pragma once
namespace mob namespace mob {
{
std::string default_ini_filename(); std::string default_ini_filename();
std::vector<fs::path> find_inis( std::vector<fs::path>
bool auto_detect, const std::vector<std::string>& from_cl, find_inis(bool auto_detect, const std::vector<std::string>& from_cl, bool verbose);
bool verbose);
struct ini_data {
using alias_patterns = std::vector<std::string>;
using aliases_map = std::map<std::string, alias_patterns>;
struct ini_data using kv_map = std::map<std::string, std::string>;
{ using sections_vector = std::vector<std::pair<std::string, kv_map>>;
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>; fs::path path;
using sections_vector = std::vector<std::pair<std::string, kv_map>>; aliases_map aliases;
sections_vector sections;
fs::path path; kv_map& get_section(std::string_view name);
aliases_map aliases; void set(std::string_view section, std::string key, std::string value);
sections_vector sections; };
kv_map& get_section(std::string_view name); ini_data parse_ini(const fs::path& ini);
void set(std::string_view section, std::string key, std::string value); std::string default_ini_filename();
};
ini_data parse_ini(const fs::path& ini); } // namespace mob
std::string default_ini_filename();
} // namespace

Some files were not shown because too many files have changed in this diff Show More