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 =
+84 -89
View File
@@ -1,95 +1,99 @@
#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
{ {
"build", return {"build", "builds tasks"};
"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([&] {
revert_ts_ = false;
})) %
"whether to revert all the .ts files in a repo before pulling to "
"avoid merge errors; global override", "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_)
@@ -107,40 +111,35 @@ void build_command::convert_cl_to_conf()
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
@@ -149,12 +148,11 @@ void build_command::convert_cl_to_conf()
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();
@@ -165,15 +163,14 @@ int build_command::do_run()
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
@@ -181,20 +178,18 @@ void build_command::create_prefix_ini()
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)
<< "[paths]\n"
<< "prefix = .\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
+29 -47
View File
@@ -1,61 +1,44 @@
#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
{ {
"cmake", return {"cmake", "runs cmake in a directory"};
"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 use the x64 or x86 vcvars; if -G is not set, "
"whether to pass \"-A Win32\" or \"-A x64\" for the default " "whether to pass \"-A Win32\" or \"-A x64\" for the default "
"VS generator [default: x64]", "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_);
@@ -71,13 +54,12 @@ int cmake_command::do_run()
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
+143 -196
View File
@@ -1,138 +1,119 @@
#include "pch.h" #include "pch.h"
#include "commands.h" #include "commands.h"
#include "../utility.h"
#include "../net.h"
#include "../core/conf.h" #include "../core/conf.h"
#include "../core/ini.h" #include "../core/ini.h"
#include "../net.h"
#include "../tasks/task_manager.h" #include "../tasks/task_manager.h"
#include "../tools/tools.h" #include "../tools/tools.h"
#include "../utility.h"
#include "../utility/threading.h" #include "../utility/threading.h"
namespace mob namespace mob {
{
BOOL WINAPI signal_handler(DWORD) noexcept BOOL WINAPI signal_handler(DWORD) noexcept
{ {
// don't use u8cout, this would lock the global mutex, but the handler // don't use u8cout, this would lock the global mutex, but the handler
// can be called while stuff is being output and the mutex is locked // can be called while stuff is being output and the mutex is locked
std::wcout << L"sigint, interrupting...\n"; std::wcout << L"sigint, interrupting...\n";
task_manager::instance().interrupt_all(); task_manager::instance().interrupt_all();
return TRUE; return TRUE;
} }
void set_sigint_handler() void set_sigint_handler()
{ {
::SetConsoleCtrlHandler(mob::signal_handler, TRUE); ::SetConsoleCtrlHandler(mob::signal_handler, TRUE);
} }
void help(const clipp::group& g, const std::string& more)
{
auto usage_df = clipp::doc_formatting().first_column(4).doc_column(30);
void help(const clipp::group& g, const std::string& more) auto options_df = clipp::doc_formatting().first_column(4).doc_column(30);
{
auto usage_df = clipp::doc_formatting()
.first_column(4)
.doc_column(30);
auto options_df = clipp::doc_formatting() u8cout << "Usage:\n"
.first_column(4) << clipp::usage_lines(g, "mob", usage_df) << "\n\n"
.doc_column(30);
u8cout
<< "Usage:\n" << clipp::usage_lines(g, "mob", usage_df)
<< "\n\n"
<< "Options:\n" << "Options:\n"
<< clipp::documentation(g, options_df) << clipp::documentation(g, options_df) << "\n\n"
<< "\n\n"
<< "To use global options with command options, make sure command \n" << "To use global options with command options, make sure command \n"
<< "options are together, with no global options in the middle.\n"; << "options are together, with no global options in the middle.\n";
if (!more.empty()) if (!more.empty())
u8cout << "\n" << more << "\n"; u8cout << "\n" << more << "\n";
} }
command::common_options command::common;
command::common_options command::common; command::command(flags f) : picked_(false), help_(false), flags_(f), code_() {}
command::command(flags f) clipp::group command::common_options_group()
: picked_(false), help_(false), flags_(f), code_() {
{
}
clipp::group command::common_options_group()
{
auto& o = common; auto& o = common;
const auto master = default_ini_filename(); const auto master = default_ini_filename();
return return (clipp::repeatable(clipp::option("-i", "--ini") &
(clipp::repeatable(clipp::option("-i", "--ini") clipp::value("FILE") >> o.inis)) %
& clipp::value("FILE") >> o.inis)) "path to the ini file",
% "path to the ini file",
(clipp::option("--dry") >> o.dry) (clipp::option("--dry") >> o.dry) % "simulates filesystem operations",
% "simulates filesystem operations",
(clipp::option("-l", "--log-level") (clipp::option("-l", "--log-level") &
& clipp::value("LEVEL") >> o.output_log_level) clipp::value("LEVEL") >> o.output_log_level) %
% "0 is silent, 6 is max", "0 is silent, 6 is max",
(clipp::option("--file-log-level") (clipp::option("--file-log-level") &
& clipp::value("LEVEL") >> o.file_log_level) clipp::value("LEVEL") >> o.file_log_level) %
% "overrides --log-level for the log file", "overrides --log-level for the log file",
(clipp::option("--log-file") (clipp::option("--log-file") & clipp::value("FILE") >> o.log_file) %
& clipp::value("FILE") >> o.log_file) "path to log file",
% "path to log file",
(clipp::option("-d", "--destination") (clipp::option("-d", "--destination") &
& clipp::value("DIR") >> o.prefix) clipp::value("DIR") >> o.prefix) %
% ("base output directory, will contain build/, install/, etc."), ("base output directory, will contain build/, install/, etc."),
(clipp::repeatable(clipp::option("-s", "--set") (clipp::repeatable(clipp::option("-s", "--set") &
& clipp::value("OPTION", o.options))) clipp::value("OPTION", o.options))) %
% "sets an option, such as 'versions/openssl=1.2'", "sets an option, such as 'versions/openssl=1.2'",
(clipp::option("--no-default-inis") >> o.no_default_inis) (clipp::option("--no-default-inis") >> o.no_default_inis) %
% "disables auto loading of ini files, only uses --ini; the first " "disables auto loading of ini files, only uses --ini; the first "
"--ini must be the master ini file"; "--ini must be the master ini file";
} }
void command::force_exit_code(int code) void command::force_exit_code(int code)
{ {
code_ = code; code_ = code;
} }
void command::force_help() void command::force_help()
{ {
help_ = true; help_ = true;
} }
bool command::picked() const bool command::picked() const
{ {
return picked_; return picked_;
} }
clipp::group command::group() clipp::group command::group()
{ {
return do_group(); return do_group();
} }
void command::convert_cl_to_conf() void command::convert_cl_to_conf()
{ {
auto& o = common; auto& o = common;
if (o.file_log_level == -1) if (o.file_log_level == -1)
o.file_log_level = o.output_log_level; o.file_log_level = o.output_log_level;
if (o.output_log_level >= 0) if (o.output_log_level >= 0) {
{ o.options.push_back("global/output_log_level=" +
o.options.push_back(
"global/output_log_level=" +
std::to_string(o.output_log_level)); std::to_string(o.output_log_level));
} }
if (o.file_log_level > 0) if (o.file_log_level > 0) {
{ o.options.push_back("global/file_log_level=" +
o.options.push_back(
"global/file_log_level=" +
std::to_string(o.file_log_level)); std::to_string(o.file_log_level));
} }
@@ -144,34 +125,30 @@ void command::convert_cl_to_conf()
if (!o.prefix.empty()) if (!o.prefix.empty())
o.options.push_back("paths/prefix=" + o.prefix); o.options.push_back("paths/prefix=" + o.prefix);
} }
int command::gather_inis(bool verbose) int command::gather_inis(bool verbose)
{ {
auto& o = common; auto& o = common;
if (o.no_default_inis && o.inis.empty()) if (o.no_default_inis && o.inis.empty()) {
{ u8cerr << "--no-default-inis requires at least one --ini for the "
u8cerr
<< "--no-default-inis requires at least one --ini for the "
<< "master ini file\n"; << "master ini file\n";
return 1; return 1;
} }
try try {
{
inis_ = find_inis(!o.no_default_inis, o.inis, verbose); inis_ = find_inis(!o.no_default_inis, o.inis, verbose);
return 0; return 0;
} }
catch(bailed&) catch (bailed&) {
{
return 1; return 1;
} }
} }
void command::set_task_enabled_flags(const std::vector<std::string>& names) void command::set_task_enabled_flags(const std::vector<std::string>& names)
{ {
common.options.push_back("task/enabled=false"); common.options.push_back("task/enabled=false");
bool failed = false; bool failed = false;
@@ -181,24 +158,22 @@ void command::set_task_enabled_flags(const std::vector<std::string>& names)
if (failed) if (failed)
throw bailed(); throw bailed();
} }
int command::prepare_options(bool verbose) int command::prepare_options(bool verbose)
{ {
convert_cl_to_conf(); convert_cl_to_conf();
return gather_inis(verbose); return gather_inis(verbose);
} }
int command::run() int command::run()
{
if (help_)
{ {
if (help_) {
help(group(), do_doc()); help(group(), do_doc());
return 0; return 0;
} }
if (flags_ & requires_options) if (flags_ & requires_options) {
{
const auto r = load_options(); const auto r = load_options();
if (r != 0) if (r != 0)
return r; return r;
@@ -213,10 +188,10 @@ int command::run()
return *code_; return *code_;
return r; return r;
} }
int command::load_options() int command::load_options()
{ {
const int r = prepare_options(false); const int r = prepare_options(false);
if (r != 0) if (r != 0)
return r; return r;
@@ -230,66 +205,53 @@ int command::load_options()
return 1; return 1;
return 0; return 0;
} }
command::meta_t version_command::meta() const
command::meta_t version_command::meta() const
{
return
{ {
"version", return {"version", "shows the version"};
"shows the version" }
};
}
clipp::group version_command::do_group() clipp::group version_command::do_group()
{ {
return clipp::group( return clipp::group(clipp::command("version", "-v", "--version").set(picked_));
clipp::command("version", "-v", "--version").set(picked_)); }
}
int version_command::do_run() int version_command::do_run()
{ {
u8cout << mob_version() << "\n"; u8cout << mob_version() << "\n";
return 0; return 0;
} }
command::meta_t help_command::meta() const
command::meta_t help_command::meta() const
{
return
{ {
"help", return {"help", "shows this message"};
"shows this message" }
};
}
void help_command::set_commands(const std::vector<std::shared_ptr<command>>& v) void help_command::set_commands(const std::vector<std::shared_ptr<command>>& v)
{ {
std::vector<std::pair<std::string, std::string>> s; std::vector<std::pair<std::string, std::string>> s;
for (auto&& c : v) for (auto&& c : v)
s.push_back({c->meta().name, c->meta().description}); s.push_back({c->meta().name, c->meta().description});
commands_ = table(s, 4, 3); commands_ = table(s, 4, 3);
} }
clipp::group help_command::do_group() clipp::group help_command::do_group()
{ {
return clipp::group( return clipp::group(clipp::command("-h", "--help").set(picked_));
clipp::command("-h", "--help").set(picked_)); }
}
int help_command::do_run() int help_command::do_run()
{ {
#pragma warning(suppress: 4548) #pragma warning(suppress : 4548)
auto doc = (command::common_options_group(), (clipp::value("command"))); auto doc = (command::common_options_group(), (clipp::value("command")));
const auto master = default_ini_filename(); const auto master = default_ini_filename();
help(doc, help(doc,
"Commands:\n" "Commands:\n" + commands_ +
+ commands_ +
"\n\n" "\n\n"
"Invoking `mob -d some/prefix build` builds everything. Do \n" "Invoking `mob -d some/prefix build` builds everything. Do \n"
"`mob build <task name>...` to build specific tasks. See\n" "`mob build <task name>...` to build specific tasks. See\n"
@@ -297,7 +259,9 @@ int help_command::do_run()
"\n" "\n"
"INI files\n" "INI files\n"
"\n" "\n"
"By default, mob will look for a master INI `" + master + "` in the \n" "By default, mob will look for a master INI `" +
master +
"` in the \n"
"root directory (typically where mob.exe resides). Once mob has\n" "root directory (typically where mob.exe resides). Once mob has\n"
"found the master INI, it will look for the same filename in the\n" "found the master INI, it will look for the same filename in the\n"
"current directory, if different from the root. If found, both will\n" "current directory, if different from the root. If found, both will\n"
@@ -307,74 +271,57 @@ int help_command::do_run()
"disable auto detection and only use --ini."); "disable auto detection and only use --ini.");
return 0; return 0;
} }
options_command::options_command() : command(requires_options) {}
options_command::options_command() command::meta_t options_command::meta() const
: command(requires_options)
{
}
command::meta_t options_command::meta() const
{
return
{ {
"options", return {"options", "lists all options and their values from the inis"};
"lists all options and their values from the inis" }
};
}
clipp::group options_command::do_group() clipp::group options_command::do_group()
{ {
return clipp::group( return clipp::group(clipp::command("options").set(picked_),
clipp::command("options").set(picked_),
(clipp::option("-h", "--help") >> help_) (clipp::option("-h", "--help") >> help_) %
% ("shows this message") ("shows this message"));
); }
}
int options_command::do_run() int options_command::do_run()
{ {
for (auto&& line : format_options()) for (auto&& line : format_options())
u8cout << line << "\n"; u8cout << line << "\n";
return 0; return 0;
} }
std::string options_command::do_doc() std::string options_command::do_doc()
{
return "Lists the final value of all options found by loading the INIs.";
}
command::meta_t inis_command::meta() const
{
return
{ {
"inis", return "Lists the final value of all options found by loading the INIs.";
"lists the INIs used by mob" }
};
}
clipp::group inis_command::do_group() command::meta_t inis_command::meta() const
{ {
return clipp::group( return {"inis", "lists the INIs used by mob"};
clipp::command("inis").set(picked_), }
(clipp::option("-h", "--help") >> help_) clipp::group inis_command::do_group()
% ("shows this message") {
); return clipp::group(clipp::command("inis").set(picked_),
}
int inis_command::do_run() (clipp::option("-h", "--help") >> help_) %
{ ("shows this message"));
}
int inis_command::do_run()
{
return prepare_options(true); return prepare_options(true);
} }
std::string inis_command::do_doc() std::string inis_command::do_doc()
{ {
return "Shows which INIs are found."; return "Shows which INIs are found.";
} }
} // namespace } // namespace mob
+104 -160
View File
@@ -2,26 +2,22 @@
#include "../utility/enum.h" #include "../utility/enum.h"
namespace mob::tasks namespace mob::tasks {
{
class modorganizer; class modorganizer;
} }
namespace mob namespace mob {
{
class task; class task;
class url; class url;
// base class for all commands // base class for all commands
// //
class command class command {
{ public:
public:
// values of options available for all commands // values of options available for all commands
// //
struct common_options struct common_options {
{
bool dry = false; bool dry = false;
int output_log_level = -1; int output_log_level = -1;
int file_log_level = -1; int file_log_level = -1;
@@ -35,12 +31,10 @@ public:
// returned by meta() by each command // returned by meta() by each command
// //
struct meta_t struct meta_t {
{
std::string name, description; std::string name, description;
}; };
static common_options common; static common_options common;
static clipp::group common_options_group(); static clipp::group common_options_group();
@@ -66,16 +60,14 @@ public:
// //
int run(); int run();
// returns meta information about this command // returns meta information about this command
// //
virtual meta_t meta() const = 0; virtual meta_t meta() const = 0;
protected: protected:
// passed by derived classes in the constructor // passed by derived classes in the constructor
// //
enum flags enum flags {
{
noflags = 0x00, noflags = 0x00,
// this command needs the ini loaded before running // this command needs the ini loaded before running
@@ -87,15 +79,13 @@ protected:
MOB_ENUM_FRIEND_OPERATORS(flags); MOB_ENUM_FRIEND_OPERATORS(flags);
// set to true when this command is entered by the user // set to true when this command is entered by the user
bool picked_; bool picked_;
// set to true with --help or by force_help() // set to true with --help or by force_help()
bool help_; bool help_;
command(flags f = noflags);
command(flags f=noflags);
// some options have a unique version on the command line because they're // some options have a unique version on the command line because they're
// used often, such as --dry or -l; those are converted to their ini // used often, such as --dry or -l; those are converted to their ini
@@ -130,7 +120,7 @@ protected:
// //
virtual std::string do_doc() { return {}; } virtual std::string do_doc() { return {}; }
private: private:
// flags requested by this command // flags requested by this command
flags flags_; flags flags_;
@@ -140,63 +130,54 @@ private:
// list of inis found by gather_inis() // list of inis found by gather_inis()
std::vector<fs::path> inis_; std::vector<fs::path> inis_;
// finds all the inis // finds all the inis
// //
int gather_inis(bool verbose); int gather_inis(bool verbose);
}; };
// displays mob's version
// displays mob's version //
// class version_command : public command {
class version_command : public command public:
{
public:
meta_t meta() const override; meta_t meta() const override;
protected: protected:
clipp::group do_group() override; clipp::group do_group() override;
int do_run() override; int do_run() override;
}; };
// displays the usage, list of commands and some additional text
// displays the usage, list of commands and some additional text //
// class help_command : public command {
class help_command : public command public:
{
public:
meta_t meta() const override; meta_t meta() const override;
void set_commands(const std::vector<std::shared_ptr<command>>& v); void set_commands(const std::vector<std::shared_ptr<command>>& v);
protected: protected:
clipp::group do_group() override; clipp::group do_group() override;
int do_run() override; int do_run() override;
private: private:
std::string commands_; std::string commands_;
}; };
// lists all options and their values
// lists all options and their values //
// class options_command : public command {
class options_command : public command public:
{
public:
options_command(); options_command();
meta_t meta() const override; meta_t meta() const override;
protected: protected:
clipp::group do_group() override; clipp::group do_group() override;
int do_run() override; int do_run() override;
std::string do_doc() override; std::string do_doc() override;
}; };
// builds stuff
// builds stuff //
// class build_command : public command {
class build_command : public command public:
{
public:
build_command(); build_command();
meta_t meta() const override; meta_t meta() const override;
@@ -205,12 +186,12 @@ public:
// //
static void terminate_msbuild(); static void terminate_msbuild();
protected: protected:
void convert_cl_to_conf() override; void convert_cl_to_conf() override;
clipp::group do_group() override; clipp::group do_group() override;
int do_run() override; int do_run() override;
private: private:
std::vector<std::string> tasks_; std::vector<std::string> tasks_;
bool redownload_ = false; bool redownload_ = false;
bool reextract_ = false; bool reextract_ = false;
@@ -225,85 +206,75 @@ private:
bool keep_msbuild_ = false; bool keep_msbuild_ = false;
std::optional<bool> revert_ts_; std::optional<bool> revert_ts_;
// creates a bare bones ini file in the prefix so mob can be invoked in any // creates a bare bones ini file in the prefix so mob can be invoked in any
// directory below it // directory below it
// //
void create_prefix_ini(); void create_prefix_ini();
}; };
// applies a pr
// applies a pr //
// class pr_command : public command {
class pr_command : public command public:
{
public:
pr_command(); pr_command();
meta_t meta() const override; meta_t meta() const override;
protected: protected:
clipp::group do_group() override; clipp::group do_group() override;
std::string do_doc() override; std::string do_doc() override;
int do_run() override; int do_run() override;
private: private:
struct pr_info struct pr_info {
{
std::string repo, author, branch, title, number; std::string repo, author, branch, title, number;
}; };
std::string op_; std::string op_;
std::string pr_; std::string pr_;
std::string github_token_; std::string github_token_;
std::pair<const tasks::modorganizer*, std::string> parse_pr( std::pair<const tasks::modorganizer*, std::string>
const std::string& pr) const; parse_pr(const std::string& pr) const;
pr_info get_pr_info(const tasks::modorganizer* task, const std::string& pr); pr_info get_pr_info(const tasks::modorganizer* task, const std::string& pr);
std::vector<pr_command::pr_info> get_matching_prs( std::vector<pr_command::pr_info> get_matching_prs(const std::string& repo_pr);
const std::string& repo_pr);
std::vector<pr_info> search_prs( std::vector<pr_info> search_prs(const std::string& org,
const std::string& org, const std::string& author,
const std::string& author, const std::string& branch); const std::string& branch);
std::vector<pr_info> validate_prs(const std::vector<pr_info>& prs); std::vector<pr_info> validate_prs(const std::vector<pr_info>& prs);
int pull(); int pull();
int find(); int find();
int revert(); int revert();
}; };
// lists available tasks
// lists available tasks //
// class list_command : public command {
class list_command : public command public:
{
public:
meta_t meta() const override; meta_t meta() const override;
protected: protected:
clipp::group do_group() override; clipp::group do_group() override;
int do_run() override; int do_run() override;
private: private:
bool all_ = false; bool all_ = false;
bool aliases_ = false; bool aliases_ = false;
std::vector<std::string> tasks_; std::vector<std::string> tasks_;
void dump(const std::vector<task*>& v, std::size_t indent) const; void dump(const std::vector<task*>& v, std::size_t indent) const;
void dump_aliases() const; void dump_aliases() const;
}; };
// creates a devbuild or an official release
// creates a devbuild or an official release //
// class release_command : public command {
class release_command : public command public:
{
public:
release_command(); release_command();
meta_t meta() const override; meta_t meta() const override;
@@ -313,22 +284,16 @@ public:
void make_uibase(); void make_uibase();
void make_installer(); void make_installer();
protected: protected:
clipp::group do_group() override; clipp::group do_group() override;
int do_run() override; int do_run() override;
std::string do_doc() override; std::string do_doc() override;
void convert_cl_to_conf() override; void convert_cl_to_conf() override;
private: private:
enum class modes enum class modes { none = 0, devbuild, official };
{
none = 0,
devbuild,
official
};
modes mode_ = modes::none;
modes mode_= modes::none;
bool bin_ = true; bool bin_ = true;
bool src_ = true; bool src_ = true;
bool pdbs_ = true; bool pdbs_ = true;
@@ -345,7 +310,6 @@ private:
std::string suffix_; std::string suffix_;
std::string branch_; std::string branch_;
int do_devbuild(); int do_devbuild();
int do_official(); int do_official();
@@ -355,37 +319,28 @@ private:
fs::path make_filename(const std::string& what) const; fs::path make_filename(const std::string& what) const;
void walk_dir( void walk_dir(const fs::path& dir, std::vector<fs::path>& files,
const fs::path& dir, std::vector<fs::path>& files, const std::vector<std::regex>& ignore_re,
const std::vector<std::regex>& ignore_re, std::size_t& total_size); std::size_t& total_size);
std::string version_from_exe() const; std::string version_from_exe() const;
std::string version_from_rc() const; std::string version_from_rc() const;
}; };
// manages git repos
// manages git repos //
// class git_command : public command {
class git_command : public command public:
{
public:
git_command(); git_command();
meta_t meta() const override; meta_t meta() const override;
protected: protected:
clipp::group do_group() override; clipp::group do_group() override;
int do_run() override; int do_run() override;
std::string do_doc() override; std::string do_doc() override;
private: private:
enum class modes enum class modes { none = 0, set_remotes, add_remote, ignore_ts, branches };
{
none = 0,
set_remotes,
add_remote,
ignore_ts,
branches
};
modes mode_ = modes::none; modes mode_ = modes::none;
std::string username_; std::string username_;
@@ -410,66 +365,55 @@ private:
void do_branches(); void do_branches();
std::vector<fs::path> get_repos() const; std::vector<fs::path> get_repos() const;
}; };
// runs cmake in a directory with the same parameters as `build` would
// runs cmake in a directory with the same parameters as `build` would //
// class cmake_command : public command {
class cmake_command : public command public:
{
public:
cmake_command(); cmake_command();
meta_t meta() const override; meta_t meta() const override;
protected: protected:
clipp::group do_group() override; clipp::group do_group() override;
int do_run() override; int do_run() override;
std::string do_doc() override; std::string do_doc() override;
private: private:
std::string gen_; std::string gen_;
std::string cmd_; std::string cmd_;
bool x64_ = true; bool x64_ = true;
std::string prefix_; std::string prefix_;
std::string path_; std::string path_;
}; };
// lists the inis found by mob
// lists the inis found by mob //
// class inis_command : public command {
class inis_command : public command public:
{
public:
meta_t meta() const override; meta_t meta() const override;
protected: protected:
clipp::group do_group() override; clipp::group do_group() override;
int do_run() override; int do_run() override;
std::string do_doc() override; std::string do_doc() override;
}; };
// manages transifex
// manages transifex //
// class tx_command : public command {
class tx_command : public command public:
{
public:
tx_command(); tx_command();
meta_t meta() const override; meta_t meta() const override;
protected: protected:
clipp::group do_group() override; clipp::group do_group() override;
void convert_cl_to_conf() override; void convert_cl_to_conf() override;
int do_run() override; int do_run() override;
std::string do_doc() override; std::string do_doc() override;
private: private:
enum class modes enum class modes { none = 0, get, build };
{
none = 0,
get,
build
};
modes mode_ = modes::none; modes mode_ = modes::none;
std::string key_, team_, project_, url_; std::string key_, team_, project_, url_;
@@ -480,6 +424,6 @@ private:
void do_get(); void do_get();
void do_build(); void do_build();
}; };
} // namespace } // namespace mob
+87 -125
View File
@@ -1,125 +1,98 @@
#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
{ {
"git", return {"git", "manages the git repos"};
"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_)
{
case modes::set_remotes:
{ {
switch (mode_) {
case modes::set_remotes: {
do_set_remotes(); do_set_remotes();
break; 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;
} }
@@ -131,12 +104,11 @@ int git_command::do_run()
} }
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"
@@ -156,90 +128,82 @@ std::string git_command::do_doc()
"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;
@@ -251,10 +215,10 @@ void git_command::do_branches()
} }
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
@@ -264,10 +228,8 @@ std::vector<fs::path> git_command::get_repos() const
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()) if (!e.is_directory())
continue; continue;
@@ -280,6 +242,6 @@ std::vector<fs::path> git_command::get_repos() const
} }
return v; return v;
} }
} // namespace } // namespace mob
+32 -49
View File
@@ -1,55 +1,43 @@
#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
{ {
"list", return {"list", "lists available tasks"};
"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 (all_)
{
if (!tasks_.empty()) if (!tasks_.empty())
set_task_enabled_flags(tasks_); set_task_enabled_flags(tasks_);
@@ -59,42 +47,37 @@ int list_command::do_run()
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 void list_command::dump(const std::vector<task*>& v, std::size_t indent) const
{
for (auto&& t : v)
{ {
for (auto&& t : v) {
if (!t->enabled()) if (!t->enabled())
continue; continue;
u8cout u8cout << std::string(indent * 4, ' ') << " - " << join(t->names(), ",")
<< std::string(indent*4, ' ')
<< " - " << join(t->names(), ",")
<< "\n"; << "\n";
if (auto* pt=dynamic_cast<parallel_tasks*>(t)) if (auto* pt = dynamic_cast<parallel_tasks*>(t))
dump(pt->children(), indent + 1); dump(pt->children(), indent + 1);
} }
} }
void list_command::dump_aliases() const void list_command::dump_aliases() const
{ {
const auto v = task_manager::instance().aliases(); const auto v = task_manager::instance().aliases();
if (v.empty()) if (v.empty())
return; return;
for (auto&& [k, patterns] : v) for (auto&& [k, patterns] : v)
u8cout << " - " << k << ": " << join(patterns, ", ") << "\n"; u8cout << " - " << k << ": " << join(patterns, ", ") << "\n";
} }
} // namespace } // namespace mob
+103 -148
View File
@@ -1,38 +1,28 @@
#include "pch.h" #include "pch.h"
#include "commands.h"
#include "../core/conf.h" #include "../core/conf.h"
#include "../tasks/task_manager.h" #include "../tasks/task_manager.h"
#include "../tasks/tasks.h" #include "../tasks/tasks.h"
#include "../utility.h" #include "../utility.h"
#include "commands.h"
namespace mob namespace mob {
{
std::string read_file(const fs::path& p) std::string read_file(const fs::path& p)
{ {
std::ifstream t(p); std::ifstream t(p);
return {std::istreambuf_iterator<char>(t), std::istreambuf_iterator<char>()}; return {std::istreambuf_iterator<char>(t), std::istreambuf_iterator<char>()};
} }
pr_command::pr_command() : command(requires_options | handle_sigint) {}
pr_command::pr_command() command::meta_t pr_command::meta() const
: command(requires_options | handle_sigint)
{
}
command::meta_t pr_command::meta() const
{
return
{ {
"pr", return {"pr", "applies changes from PRs"};
"applies changes from PRs" }
};
}
std::string pr_command::do_doc() std::string pr_command::do_doc()
{ {
return return "Operations:\n"
"Operations:\n"
" - find: lists all the repos that would affected by `pull` or\n" " - find: lists all the repos that would affected by `pull` or\n"
" `revert`\n" " `revert`\n"
" - pull: fetches the pr's branch and checks it out; all repos\n" " - pull: fetches the pr's branch and checks it out; all repos\n"
@@ -44,29 +34,27 @@ std::string pr_command::do_doc()
" - umbrella\n" " - umbrella\n"
" - any repo that's not in modorganizer_super\n" " - any repo that's not in modorganizer_super\n"
" - modorganizer_installer"; " - modorganizer_installer";
} }
clipp::group pr_command::do_group() clipp::group pr_command::do_group()
{ {
return return (clipp::command("pr")).set(picked_),
(clipp::command("pr")).set(picked_),
(clipp::option("-h", "--help") >> help_) (clipp::option("-h", "--help") >> help_) % ("shows this message"),
% ("shows this message"),
(clipp::option("--github-token") (clipp::option("--github-token") &
& clipp::value("TOKEN") >> github_token_) clipp::value("TOKEN") >> github_token_) %
% "github api key", "github api key",
(clipp::value("OP") >> op_) (clipp::value("OP") >> op_) %
% "one of `find`, `pull` or `revert`; see below", "one of `find`, `pull` or `revert`; see below",
(clipp::value("PR") >> pr_) (clipp::value("PR") >> pr_) %
% "PR to apply, must be `task/pr`, such as `modorganizer/123`"; "PR to apply, must be `task/pr`, such as `modorganizer/123`";
} }
int pr_command::do_run() int pr_command::do_run()
{ {
if (github_token_.empty()) if (github_token_.empty())
github_token_ = conf().global().get("github_key"); github_token_ = conf().global().get("github_key");
@@ -80,17 +68,16 @@ int pr_command::do_run()
u8cerr << "bad operation '" << op_ << "'\n"; u8cerr << "bad operation '" << op_ << "'\n";
return 1; return 1;
} }
std::pair<const tasks::modorganizer*, std::string> pr_command::parse_pr( std::pair<const tasks::modorganizer*, std::string>
const std::string& pr) const pr_command::parse_pr(const std::string& pr) const
{ {
if (pr.empty()) if (pr.empty())
return {}; return {};
const auto cs = split(pr, "/"); const auto cs = split(pr, "/");
if (cs.size() != 2) if (cs.size() != 2) {
{
u8cerr << "--pr must be task/pr, such as modorganizer/123\n"; u8cerr << "--pr must be task/pr, such as modorganizer/123\n";
return {}; return {};
} }
@@ -103,17 +90,16 @@ std::pair<const tasks::modorganizer*, std::string> pr_command::parse_pr(
return {}; return {};
const auto* mo_task = dynamic_cast<const tasks::modorganizer*>(task); const auto* mo_task = dynamic_cast<const tasks::modorganizer*>(task);
if (!mo_task) if (!mo_task) {
{
u8cerr << "only modorganizer tasks are supported\n"; u8cerr << "only modorganizer tasks are supported\n";
return {}; return {};
} }
return {mo_task, pr_number}; return {mo_task, pr_number};
} }
int pr_command::pull() int pr_command::pull()
{ {
const auto prs = get_matching_prs(pr_); const auto prs = get_matching_prs(pr_);
if (prs.empty()) if (prs.empty())
return 1; return 1;
@@ -122,24 +108,20 @@ int pr_command::pull()
if (okay_prs.empty()) if (okay_prs.empty())
return 1; return 1;
try try {
{ for (auto&& pr : okay_prs) {
for (auto&& pr : okay_prs)
{
const auto* task = dynamic_cast<const tasks::modorganizer*>( const auto* task = dynamic_cast<const tasks::modorganizer*>(
task_manager::instance().find_one(pr.repo)); task_manager::instance().find_one(pr.repo));
if (!task) if (!task)
return 1; return 1;
u8cout u8cout << "checking out pr " << pr.number << " "
<< "checking out pr " << pr.number << " "
<< "in " << task->name() << "\n"; << "in " << task->name() << "\n";
git_wrap g(task->source_path()); git_wrap g(task->source_path());
g.fetch( g.fetch(task->git_url().string(),
task->git_url().string(),
fmt::format("pull/{}/head", pr.number)); fmt::format("pull/{}/head", pr.number));
g.checkout("FETCH_HEAD"); g.checkout("FETCH_HEAD");
@@ -149,20 +131,19 @@ int pr_command::pull()
return 0; return 0;
} }
catch(std::exception& e) catch (std::exception& e) {
{
u8cerr << e.what() << "\n"; u8cerr << e.what() << "\n";
return 1; return 1;
} }
} }
int pr_command::find() int pr_command::find()
{ {
return !get_matching_prs(pr_).empty(); return !get_matching_prs(pr_).empty();
} }
int pr_command::revert() int pr_command::revert()
{ {
const auto prs = get_matching_prs(pr_); const auto prs = get_matching_prs(pr_);
if (prs.empty()) if (prs.empty())
return 1; return 1;
@@ -171,10 +152,8 @@ int pr_command::revert()
if (okay_prs.empty()) if (okay_prs.empty())
return 1; return 1;
try try {
{ for (auto&& pr : okay_prs) {
for (auto&& pr : okay_prs)
{
const auto* task = dynamic_cast<const tasks::modorganizer*>( const auto* task = dynamic_cast<const tasks::modorganizer*>(
task_manager::instance().find_one(pr.repo)); task_manager::instance().find_one(pr.repo));
@@ -188,16 +167,15 @@ int pr_command::revert()
return 0; return 0;
} }
catch(std::exception& e) catch (std::exception& e) {
{
u8cerr << e.what() << "\n"; u8cerr << e.what() << "\n";
return 1; return 1;
} }
} }
std::vector<pr_command::pr_info> pr_command::get_matching_prs( std::vector<pr_command::pr_info>
const std::string& repo_pr) pr_command::get_matching_prs(const std::string& repo_pr)
{ {
auto&& [task, src_pr] = parse_pr(repo_pr); auto&& [task, src_pr] = parse_pr(repo_pr);
if (!task) if (!task)
return {}; return {};
@@ -214,29 +192,28 @@ std::vector<pr_command::pr_info> pr_command::get_matching_prs(
u8cout << "found matching prs in " << prs.size() << " repos:\n"; u8cout << "found matching prs in " << prs.size() << " repos:\n";
u8cout u8cout << table(map(prs,
<< table(map(prs, [&](auto&& pr) [&](auto&& pr) {
{
return std::pair(pr.repo + "/" + pr.number, pr.title); return std::pair(pr.repo + "/" + pr.number, pr.title);
}), 2, 5) }),
2, 5)
<< "\n"; << "\n";
return prs; return prs;
} }
std::vector<pr_command::pr_info> pr_command::search_prs( std::vector<pr_command::pr_info> pr_command::search_prs(const std::string& org,
const std::string& org, const std::string& author, const std::string& branch) const std::string& author,
{ const std::string& branch)
{
nlohmann::json json; nlohmann::json json;
constexpr auto* pattern = constexpr auto* pattern =
"https://api.github.com/search/issues?per_page=100&q=" "https://api.github.com/search/issues?per_page=100&q="
"is:pr+org:{org:}+author:{author:}+is:open+head:{branch:}"; "is:pr+org:{org:}+author:{author:}+is:open+head:{branch:}";
const auto search_url = fmt::format( const auto search_url =
pattern, fmt::format(pattern, fmt::arg("org", org), fmt::arg("author", author),
fmt::arg("org", org),
fmt::arg("author", author),
fmt::arg("branch", branch)); fmt::arg("branch", branch));
u8cout << "search url is " << search_url << "\n"; u8cout << "search url is " << search_url << "\n";
@@ -245,14 +222,12 @@ std::vector<pr_command::pr_info> pr_command::search_prs(
curl_downloader dl; curl_downloader dl;
dl dl.url(search_url)
.url(search_url)
.header("Authorization", "token " + github_token_) .header("Authorization", "token " + github_token_)
.start() .start()
.join(); .join();
if (!dl.ok()) if (!dl.ok()) {
{
u8cerr << "failed to search github\n"; u8cerr << "failed to search github\n";
return {}; return {};
} }
@@ -260,66 +235,54 @@ std::vector<pr_command::pr_info> pr_command::search_prs(
const auto output = dl.steal_output(); const auto output = dl.steal_output();
json = nlohmann::json::parse(output); json = nlohmann::json::parse(output);
std::map<std::string, pr_info> repos; std::map<std::string, pr_info> repos;
for (auto&& item : json["items"]) for (auto&& item : json["items"]) {
{
// ex: https://api.github.com/repos/ModOrganizer2/modorganizer-Installer // ex: https://api.github.com/repos/ModOrganizer2/modorganizer-Installer
const std::string url = item["repository_url"]; const std::string url = item["repository_url"];
const auto last_slash = url.find_last_of("/"); const auto last_slash = url.find_last_of("/");
if (last_slash == std::string::npos) if (last_slash == std::string::npos) {
{
u8cerr << "bad repo url in search: '" << url << "'\n"; u8cerr << "bad repo url in search: '" << url << "'\n";
return {}; return {};
} }
const auto repo = url.substr(last_slash + 1); const auto repo = url.substr(last_slash + 1);
pr_info info = { pr_info info = {repo, author, branch, item["title"],
repo, author, branch, item["title"], std::to_string(item["number"].get<int>())};
std::to_string(item["number"].get<int>())
};
if (!repos.emplace(repo, info).second) if (!repos.emplace(repo, info).second) {
{ u8cerr << "multiple prs found in repo " << repo << ", "
u8cerr
<< "multiple prs found in repo " << repo << ", "
<< "not supported\n"; << "not supported\n";
return {}; return {};
} }
} }
return map(repos, [&](auto&& pair){ return pair.second; }); return map(repos, [&](auto&& pair) {
} return pair.second;
});
}
pr_command::pr_info pr_command::get_pr_info( pr_command::pr_info pr_command::get_pr_info(const tasks::modorganizer* task,
const tasks::modorganizer* task, const std::string& pr) const std::string& pr)
{ {
nlohmann::json json; nlohmann::json json;
if (github_token_.empty()) if (github_token_.empty()) {
{
u8cerr << "missing --github-token\n"; u8cerr << "missing --github-token\n";
return {}; return {};
} }
const url u(fmt::format( const url u(fmt::format("https://api.github.com/repos/{}/{}/pulls/{}",
"https://api.github.com/repos/{}/{}/pulls/{}",
task->org(), task->repo(), pr)); task->org(), task->repo(), pr));
curl_downloader dl; curl_downloader dl;
dl dl.url(u).header("Authorization", "token " + github_token_).start().join();
.url(u)
.header("Authorization", "token " + github_token_)
.start()
.join();
if (!dl.ok()) if (!dl.ok()) {
{
u8cerr << "failed to get pr info from github\n"; u8cerr << "failed to get pr info from github\n";
return {}; return {};
} }
@@ -332,44 +295,37 @@ pr_command::pr_info pr_command::get_pr_info(
const std::string branch = json["head"]["ref"]; const std::string branch = json["head"]["ref"];
return {repo, author, branch}; return {repo, author, branch};
} }
std::vector<pr_command::pr_info> pr_command::validate_prs( std::vector<pr_command::pr_info>
const std::vector<pr_info>& prs) pr_command::validate_prs(const std::vector<pr_info>& prs)
{ {
std::vector<std::string> problems; std::vector<std::string> problems;
std::vector<pr_info> okay_prs; std::vector<pr_info> okay_prs;
for (auto&& pr : prs) for (auto&& pr : prs) {
{ if (pr.repo == "mob") {
if (pr.repo == "mob")
{
problems.push_back("there's a pr for mob itself"); problems.push_back("there's a pr for mob itself");
continue; continue;
} }
else else {
{
const auto tasks = task_manager::instance().find(pr.repo); const auto tasks = task_manager::instance().find(pr.repo);
if (tasks.empty()) if (tasks.empty()) {
{
problems.push_back("task " + pr.repo + " does not exist"); problems.push_back("task " + pr.repo + " does not exist");
continue; continue;
} }
else if (tasks.size() > 1) else if (tasks.size() > 1) {
{
problems.push_back("found more than one task for repo " + pr.repo); problems.push_back("found more than one task for repo " + pr.repo);
continue; continue;
} }
else else {
{
const auto* mo_task = const auto* mo_task =
dynamic_cast<const tasks::modorganizer*>(tasks[0]); dynamic_cast<const tasks::modorganizer*>(tasks[0]);
if (!mo_task) if (!mo_task) {
{ problems.push_back("task " + pr.repo +
problems.push_back( " is not a modorganizer repo");
"task " + pr.repo + " is not a modorganizer repo");
continue; continue;
} }
@@ -379,8 +335,7 @@ std::vector<pr_command::pr_info> pr_command::validate_prs(
okay_prs.push_back(pr); okay_prs.push_back(pr);
} }
if (!problems.empty()) if (!problems.empty()) {
{
{ {
console_color cc(console_color::yellow); console_color cc(console_color::yellow);
@@ -391,19 +346,19 @@ std::vector<pr_command::pr_info> pr_command::validate_prs(
u8cout << "\n"; u8cout << "\n";
if (okay_prs.empty()) if (okay_prs.empty()) {
{
u8cout << "all prs would be ignored, bailing out\n"; u8cout << "all prs would be ignored, bailing out\n";
return {}; return {};
} }
if (ask_yes_no("these prs will be ignored; proceed anyway?", yn::no) != yn::yes) if (ask_yes_no("these prs will be ignored; proceed anyway?", yn::no) !=
yn::yes)
return {}; return {};
u8cout << "\n"; u8cout << "\n";
} }
return okay_prs; return okay_prs;
} }
} // namespace } // namespace mob
+171 -233
View File
File diff suppressed because it is too large Load Diff
+60 -85
View File
@@ -1,82 +1,67 @@
#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
{ {
"tx", return {"tx", "manages transifex translations"};
"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())
@@ -96,12 +81,11 @@ void tx_command::convert_cl_to_conf()
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;
@@ -117,12 +101,11 @@ int tx_command::do_run()
} }
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"
@@ -133,21 +116,18 @@ std::string tx_command::do_doc()
" 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 <<
"(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"; "variable doesn't exist, this will probably fail)\n\n";
} }
@@ -155,9 +135,7 @@ void tx_command::do_get()
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)
@@ -175,10 +153,10 @@ void tx_command::do_get()
.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";
@@ -193,13 +171,10 @@ void tx_command::do_build()
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 // copy the global context, each thread must have its own
tp.add([&, cxcopy=gcx()]() mutable tp.add([&, cxcopy = gcx()]() mutable {
{
lrelease() lrelease()
.project(p.name) .project(p.name)
.sources(lg.ts_files) .sources(lg.ts_files)
@@ -208,6 +183,6 @@ void tx_command::do_build()
}); });
} }
} }
} }
} // namespace } // namespace mob
+310 -370
View File
File diff suppressed because it is too large Load Diff
+129 -131
View File
@@ -3,73 +3,77 @@
// these shouldn't be called directly, they're used by some of the template // these shouldn't be called directly, they're used by some of the template
// below // below
// //
namespace mob::details namespace mob::details {
{
// returns an option named `key` from the given `section` // returns an option named `key` from the given `section`
// //
std::string get_string(std::string_view section, std::string_view key); std::string get_string(std::string_view section, std::string_view key,
std::optional<std::string> default_ = {});
// calls get_string(), converts to bool // calls get_string(), converts to bool
// //
bool get_bool(std::string_view section, std::string_view key); bool get_bool(std::string_view section, std::string_view key,
std::optional<bool> default_ = {});
// calls get_string(), converts to in // calls get_string(), converts to in
// //
int get_int(std::string_view section, std::string_view key); int get_int(std::string_view section, std::string_view key,
std::optional<int> default_ = {});
// sets the given option, bails out if the option doesn't exist // sets the given option, bails out if the option doesn't exist
// //
void set_string( void set_string(std::string_view section, std::string_view key,
std::string_view section, std::string_view key, std::string_view value); std::string_view value);
} // namespace } // namespace mob::details
namespace mob {
namespace mob // reads options from the given inis and option strings, resolves all the paths
{ // and necessary tools, also adds a couple of things to PATH
//
void init_options(const std::vector<fs::path>& inis,
const std::vector<std::string>& opts);
// reads options from the given inis and option strings, resolves all the paths // checks some of the options once everything is loaded, returns false if
// and necessary tools, also adds a couple of things to PATH // something's wrong
// //
void init_options( bool verify_options();
const std::vector<fs::path>& inis, const std::vector<std::string>& opts);
// checks some of the options once everything is loaded, returns false if // returns all options formatted as three columns
// something's wrong //
// std::vector<std::string> format_options();
bool verify_options();
// returns all options formatted as three columns // base class for all conf structs
// //
std::vector<std::string> format_options(); template <class DefaultType>
class conf_section {
public:
// base class for all conf structs DefaultType get(std::string_view key,
// std::optional<DefaultType> default_ = {}) const
template <class DefaultType>
class conf_section
{
public:
DefaultType get(std::string_view key) const
{ {
if constexpr (std::is_same_v<DefaultType, std::string>) {
return details::get_string(name_, key, default_);
}
else {
return details::get_string(name_, key); return details::get_string(name_, key);
} }
}
// undefined // undefined
template <class T> template <class T>
T get(std::string_view key) const; T get(std::string_view key, std::optional<T> default_ = {}) const;
template <> template <>
bool get<bool>(std::string_view key) const bool get<bool>(std::string_view key, std::optional<bool> default_) const
{ {
return details::get_bool(name_, key); return details::get_bool(name_, key, default_);
} }
template <> template <>
int get<int>(std::string_view key) const int get<int>(std::string_view key, std::optional<int> default_) const
{ {
return details::get_int(name_, key); return details::get_int(name_, key, default_);
} }
void set(std::string_view key, std::string_view value) void set(std::string_view key, std::string_view value)
@@ -77,24 +81,19 @@ public:
details::set_string(name_, key, value); details::set_string(name_, key, value);
} }
protected: protected:
conf_section(std::string section_name) conf_section(std::string section_name) : name_(std::move(section_name)) {}
: name_(std::move(section_name))
{
}
const auto& name() const { return name_; } const auto& name() const { return name_; }
private: private:
std::string name_; std::string name_;
}; };
// options in [global]
// options in [global] //
// class conf_global : public conf_section<std::string> {
class conf_global : public conf_section<std::string> public:
{
public:
conf_global(); conf_global();
// convenience, doesn't need string manipulation // convenience, doesn't need string manipulation
@@ -110,14 +109,12 @@ public:
bool clean() const { return get<bool>("clean_task"); } bool clean() const { return get<bool>("clean_task"); }
bool fetch() const { return get<bool>("fetch_task"); } bool fetch() const { return get<bool>("fetch_task"); }
bool build() const { return get<bool>("build_task"); } bool build() const { return get<bool>("build_task"); }
}; };
// options in [task] or [task_name:task]
// options in [task] or [task_name:task] //
// class conf_task {
class conf_task public:
{
public:
conf_task(std::vector<std::string> names); conf_task(std::vector<std::string> names);
std::string get(std::string_view key) const; std::string get(std::string_view key) const;
@@ -136,7 +133,7 @@ public:
std::string mo_fallback_branch() const { return get("mo_fallback"); } std::string mo_fallback_branch() const { return get("mo_fallback"); }
bool no_pull() const { return get<bool>("no_pull"); } bool no_pull() const { return get<bool>("no_pull"); }
bool revert_ts() const { return get<bool>("revert_ts"); } bool revert_ts() const { return get<bool>("revert_ts"); }
bool ignore_ts()const { return get<bool>("ignore_ts"); } bool ignore_ts() const { return get<bool>("ignore_ts"); }
std::string git_url_prefix() const { return get("git_url_prefix"); } std::string git_url_prefix() const { return get("git_url_prefix"); }
bool git_shallow() const { return get<bool>("git_shallow"); } bool git_shallow() const { return get<bool>("git_shallow"); }
std::string git_user() const { return get("git_username"); } std::string git_user() const { return get("git_username"); }
@@ -144,21 +141,25 @@ public:
bool set_origin_remote() const { return get<bool>("set_origin_remote"); } bool set_origin_remote() const { return get<bool>("set_origin_remote"); }
std::string remote_org() const { return get("remote_org"); } std::string remote_org() const { return get("remote_org"); }
std::string remote_key() const { return get("remote_key"); } std::string remote_key() const { return get("remote_key"); }
bool remote_no_push_upstream() const { return get<bool>("remote_no_push_upstream"); } bool remote_no_push_upstream() const
bool remote_push_default_origin() const { return get<bool>("remote_push_default_origin"); } {
return get<bool>("remote_no_push_upstream");
}
bool remote_push_default_origin() const
{
return get<bool>("remote_push_default_origin");
}
private: private:
std::vector<std::string> names_; std::vector<std::string> names_;
bool get_bool(std::string_view name) const; bool get_bool(std::string_view name) const;
}; };
// options in [task] or [task_name:task]
// options in [task] or [task_name:task] //
// class conf_cmake : conf_section<std::string> {
class conf_cmake : conf_section<std::string> public:
{
public:
class cmake_constant { class cmake_constant {
std::string value_; std::string value_;
@@ -169,10 +170,9 @@ public:
friend class conf_cmake; friend class conf_cmake;
public: public:
constexpr cmake_constant(std::string_view value) : value_{value} { } constexpr cmake_constant(std::string_view value) : value_{value} {}
constexpr const auto& value() const { return value_; } constexpr const auto& value() const { return value_; }
constexpr operator const std::string& () const { return value(); } constexpr operator const std::string&() const { return value(); }
friend bool operator==(cmake_constant const& lhs, cmake_constant const& rhs) friend bool operator==(cmake_constant const& lhs, cmake_constant const& rhs)
{ {
@@ -182,15 +182,13 @@ public:
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
}; };
static const cmake_constant ALWAYS; static const cmake_constant ALWAYS;
static const cmake_constant LAZY; static const cmake_constant LAZY;
static const cmake_constant NEVER; static const cmake_constant NEVER;
public:
public:
conf_cmake(); conf_cmake();
// specify the value for CMAKE_INSTALL_MESSAGE // specify the value for CMAKE_INSTALL_MESSAGE
@@ -204,56 +202,58 @@ public:
// //
std::string host() const; std::string host() const;
private: private:
cmake_constant read_cmake_constant( cmake_constant
std::string_view key, std::vector<cmake_constant> const& allowed) const; read_cmake_constant(std::string_view key,
}; std::vector<cmake_constant> const& allowed) const;
};
// options in [tools]
// options in [tools] //
// class conf_tools : public conf_section<fs::path> {
class conf_tools : public conf_section<fs::path> public:
{
public:
conf_tools(); conf_tools();
}; };
// options in [transifex]
// options in [transifex] //
// class conf_transifex : public conf_section<std::string> {
class conf_transifex : public conf_section<std::string> public:
{
public:
conf_transifex(); conf_transifex();
}; };
// options in [versions]
// options in [versions] //
// class conf_versions : public conf_section<std::string> {
class conf_versions : public conf_section<std::string> public:
{
public:
conf_versions(); conf_versions();
}; };
// options in [translations]
//
class conf_translations : public conf_section<std::string> {
public:
conf_translations();
};
// options in [prebuilt] // options in [prebuilt]
// //
class conf_prebuilt : public conf_section<std::string> class conf_prebuilt : public conf_section<std::string> {
{ public:
public:
conf_prebuilt(); conf_prebuilt();
}; };
// options in [paths]
// options in [paths] //
// class conf_paths : public conf_section<fs::path> {
class conf_paths : public conf_section<fs::path> public:
{
public:
conf_paths(); conf_paths();
#define VALUE(NAME) fs::path NAME() const { return get(#NAME); } #define VALUE(NAME) \
fs::path NAME() const \
{ \
return get(#NAME); \
}
VALUE(third_party); VALUE(third_party);
VALUE(prefix); VALUE(prefix);
@@ -270,11 +270,10 @@ public:
VALUE(install_dlls); VALUE(install_dlls);
VALUE(install_loot); VALUE(install_loot);
VALUE(install_plugins); VALUE(install_extensions);
VALUE(install_stylesheets); VALUE(install_stylesheets);
VALUE(install_licenses); VALUE(install_licenses);
VALUE(install_pythoncore); VALUE(install_pythoncore);
VALUE(install_translations);
VALUE(vs); VALUE(vs);
VALUE(qt_install); VALUE(qt_install);
@@ -286,20 +285,19 @@ public:
VALUE(temp_dir); VALUE(temp_dir);
#undef VALUE #undef VALUE
}; };
// should be used as conf().global().whatever(), doesn't actually hold anything,
// should be used as conf().global().whatever(), doesn't actually hold anything, // but it's better than a bunch of static functions
// but it's better than a bunch of static functions //
// class conf {
class conf public:
{
public:
conf_global global(); conf_global global();
conf_task task(const std::vector<std::string>& names); conf_task task(const std::vector<std::string>& names);
conf_cmake cmake(); conf_cmake cmake();
conf_tools tool(); conf_tools tool();
conf_transifex transifex(); conf_transifex transifex();
conf_translations translation();
conf_prebuilt prebuilt(); conf_prebuilt prebuilt();
conf_versions version(); conf_versions version();
conf_paths path(); conf_paths path();
@@ -307,6 +305,6 @@ public:
// opens the log file, creates the directory if needed // opens the log file, creates the directory if needed
// //
void set_log_file(); void set_log_file();
}; };
} // namespace } // namespace mob
+187 -214
View File
File diff suppressed because it is too large Load Diff
+59 -81
View File
@@ -7,80 +7,66 @@
// those are kept in this namespace so they don't leak all over the place; // those are kept in this namespace so they don't leak all over the place;
// they're used directly by context::do_log() below // they're used directly by context::do_log() below
namespace mob::details namespace mob::details {
{
class mob::url; class mob::url;
template <class T, class=void> template <class T, class = void>
struct converter struct converter {
{ static const T& convert(const T& t) { return t; }
static const T& convert(const T& t) };
{
return t;
}
};
template <> template <>
struct converter<std::wstring> struct converter<std::wstring> {
{
static std::string convert(const std::wstring& s); static std::string convert(const std::wstring& s);
}; };
template <> template <>
struct converter<fs::path> struct converter<fs::path> {
{
static std::string convert(const fs::path& s); static std::string convert(const fs::path& s);
}; };
template <> template <>
struct converter<url> struct converter<url> {
{
static std::string convert(const url& u); static std::string convert(const url& u);
}; };
template <class T> template <class T>
struct converter<T, std::enable_if_t<std::is_enum_v<T>>> struct converter<T, std::enable_if_t<std::is_enum_v<T>>> {
{
static std::string convert(T e) static std::string convert(T e)
{ {
return std::to_string(static_cast<std::underlying_type_t<T>>(e)); return std::to_string(static_cast<std::underlying_type_t<T>>(e));
} }
}; };
} // namespace } // namespace mob::details
namespace mob {
namespace mob class tool;
{
class tool; // system error message
//
std::string error_message(DWORD e);
// system error message // a logger with some context, this is passed around everywhere and knows which
// // task and tool is currently running to get better context when logging
std::string error_message(DWORD e); //
// each log must have a reason, `generic` can be used if no reason makes sense
//
// a logger with some context, this is passed around everywhere and knows which // in places where there is no context available, there's a global one can that
// task and tool is currently running to get better context when logging // be retrieved with gcx() for logging
// //
// each log must have a reason, `generic` can be used if no reason makes sense // all log functions will use fmt::format() internally, so they can be used
// // like:
// in places where there is no context available, there's a global one can that //
// be retrieved with gcx() for logging // cx.log(context::generic, "eat more {}", "potatoes");
// //
// all log functions will use fmt::format() internally, so they can be used class context {
// like: public:
//
// cx.log(context::generic, "eat more {}", "potatoes");
//
class context
{
public:
// reason for a log or bailing out // reason for a log or bailing out
// //
enum reason enum reason {
{
// generic // generic
generic, generic,
@@ -120,8 +106,7 @@ public:
// level of a log entry, `dump` should only be used for really verbose // level of a log entry, `dump` should only be used for really verbose
// stuff that shouldn't be very useful, like curl's debugging logs // stuff that shouldn't be very useful, like curl's debugging logs
// //
enum class level enum class level {
{
dump = 1, dump = 1,
trace, trace,
debug, debug,
@@ -152,7 +137,6 @@ public:
// //
static void close_log_file(); static void close_log_file();
// creates a context for a task; the global context has no name // creates a context for a task; the global context has no name
// //
context(std::string task_name); context(std::string task_name);
@@ -232,14 +216,13 @@ public:
do_log(true, r, level::error, f, std::forward<Args>(args)...); do_log(true, r, level::error, f, std::forward<Args>(args)...);
} }
private: private:
// current task, may be empty // current task, may be empty
std::string task_; std::string task_;
// current tool, may be null // current tool, may be null
const tool* tool_; const tool* tool_;
// all logs above end up in here; if `bail` is true, this will throw a // all logs above end up in here; if `bail` is true, this will throw a
// bailed exception after logging // bailed exception after logging
// //
@@ -250,17 +233,15 @@ private:
if (!bail && !enabled(lv)) if (!bail && !enabled(lv))
return; return;
try try {
{
// formatting string // formatting string
const std::string s = fmt::format( const std::string s =
f, details::converter<std::decay_t<Args>>::convert( fmt::format(f, details::converter<std::decay_t<Args>>::convert(
std::forward<Args>(args))...); std::forward<Args>(args))...);
do_log_impl(bail, r, lv, s); do_log_impl(bail, r, lv, s);
} }
catch(std::exception&) catch (std::exception&) {
{
// this is typically a bad format string, but there's not a lot // this is typically a bad format string, but there's not a lot
// that can be done except logging to stderr and asserting // that can be done except logging to stderr and asserting
@@ -273,8 +254,7 @@ private:
std::wstring s; std::wstring s;
const char* p = f; const char* p = f;
while (*p) while (*p) {
{
s += (wchar_t)*p; s += (wchar_t)*p;
++p; ++p;
} }
@@ -294,27 +274,25 @@ private:
// formats the log line: adds the timestamp, task name and tool name, if // formats the log line: adds the timestamp, task name and tool name, if
// any // any
// //
std::string_view make_log_string( std::string_view make_log_string(reason r, level lv, std::string_view s) const;
reason r, level lv, std::string_view s) const;
// writes the given string to the console and the log file, and keeps all // writes the given string to the console and the log file, and keeps all
// errors and warnings in global lists so they can be dumped just before mob // errors and warnings in global lists so they can be dumped just before mob
// exits // exits
// //
void emit_log(level lv, std::string_view s) const; void emit_log(level lv, std::string_view s) const;
}; };
// global context, convenience
// global context, convenience //
// inline const context& gcx()
inline const context& gcx() {
{
return *context::global(); return *context::global();
} }
// called in main() just before mob exits, dumps all errors and warnings seen // called in main() just before mob exits, dumps all errors and warnings seen
// during the build if the console log level was high enough // during the build if the console log level was high enough
// //
void dump_logs(); void dump_logs();
} // namespace } // namespace mob
+143 -177
View File
File diff suppressed because it is too large Load Diff
+19 -33
View File
@@ -2,25 +2,18 @@
#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
// //
@@ -34,7 +27,6 @@ public:
// //
static env vs(arch a); static env vs(arch a);
// empty set // empty set
// //
env(); env();
@@ -58,8 +50,8 @@ public:
// sets k=v // sets k=v
// //
env& set(std::string_view k, std::string_view v, flags f=replace); env& set(std::string_view k, std::string_view v, flags f = replace);
env& set(std::wstring k, std::wstring v, flags f=replace); env& set(std::wstring k, std::wstring v, flags f = replace);
// returns the variable' value, empty if not found // returns the variable' value, empty if not found
// //
@@ -74,11 +66,10 @@ public:
// //
void* get_unicode_pointers() const; void* get_unicode_pointers() const;
private: private:
// shared between copies // shared between copies
// //
struct data struct data {
{
std::mutex m; std::mutex m;
map vars; map vars;
@@ -93,7 +84,6 @@ private:
// when the data must be modified // when the data must be modified
bool own_; bool own_;
// creates the unicode strings // creates the unicode strings
// //
void create_sys() const; void create_sys() const;
@@ -115,19 +105,15 @@ private:
// value // value
// //
env& change_path(const std::vector<fs::path>& v, flags f); env& change_path(const std::vector<fs::path>& v, flags f);
}; };
// represents mob's environment variables
// represents mob's environment variables //
// struct this_env {
struct this_env
{
// sets a variable // sets a variable
// //
static void set( static void set(const std::string& k, const std::string& v,
const std::string& k, env::flags f = env::replace);
const std::string& v,
env::flags f=env::replace);
// changes PATH // changes PATH
// //
@@ -146,10 +132,10 @@ struct this_env
// //
static std::optional<std::string> get_opt(const std::string& k); static std::optional<std::string> get_opt(const std::string& k);
private: private:
// used by get() and get_opt(), does the actual work // used by get() and get_opt(), does the actual work
// //
static std::optional<std::wstring> get_impl(const std::string& k); static std::optional<std::wstring> get_impl(const std::string& k);
}; };
} // namespace } // namespace mob
+78 -121
View File
@@ -1,65 +1,55 @@
#include "pch.h" #include "pch.h"
#include "ini.h" #include "ini.h"
#include "paths.h"
#include "context.h"
#include "env.h"
#include "conf.h"
#include "../tasks/task_manager.h" #include "../tasks/task_manager.h"
#include "../utility/string.h" #include "../utility/string.h"
#include "conf.h"
#include "context.h"
#include "env.h"
#include "paths.h"
namespace mob namespace mob {
{
template <class... Args> template <class... Args>
void ini_error( void ini_error(const ini_data& ini, std::size_t line, std::string_view f,
const ini_data& ini, std::size_t line, std::string_view f, Args&&... args) Args&&... args)
{
gcx().bail_out(context::conf,
"{}:{}: {}",
path_to_utf8(ini.path), (line + 1),
fmt::format(f, std::forward<Args>(args)...));
}
ini_data::kv_map& ini_data::get_section(std::string_view name)
{
for (auto itor=sections.begin(); itor!=sections.end(); ++itor)
{ {
gcx().bail_out(context::conf, "{}:{}: {}", path_to_utf8(ini.path), (line + 1),
fmt::format(f, std::forward<Args>(args)...));
}
ini_data::kv_map& ini_data::get_section(std::string_view name)
{
for (auto itor = sections.begin(); itor != sections.end(); ++itor) {
if (itor->first == name) if (itor->first == name)
return itor->second; return itor->second;
} }
sections.push_back({std::string(name), kv_map()}); sections.push_back({std::string(name), kv_map()});
return sections.back().second; return sections.back().second;
} }
void ini_data::set(std::string_view section, std::string key, std::string value) void ini_data::set(std::string_view section, std::string key, std::string value)
{ {
auto& s = get_section(section); auto& s = get_section(section);
s.emplace(std::move(key), std::move(value)); s.emplace(std::move(key), std::move(value));
} }
std::string default_ini_filename()
{
std::string default_ini_filename()
{
return "mob.ini"; return "mob.ini";
} }
std::vector<fs::path> find_inis( std::vector<fs::path>
bool auto_detect, const std::vector<std::string>& from_cl, bool verbose) find_inis(bool auto_detect, const std::vector<std::string>& from_cl, bool verbose)
{ {
// the string is just for verbose // the string is just for verbose
std::vector<std::pair<std::string, fs::path>> v; std::vector<std::pair<std::string, fs::path>> v;
// adds a path to the vector; if the path already exists, moves it to // adds a path to the vector; if the path already exists, moves it to
// the last element // the last element
auto add_or_move_up = [&](std::string where, fs::path p) auto add_or_move_up = [&](std::string where, fs::path p) {
{ for (auto itor = v.begin(); itor != v.end(); ++itor) {
for (auto itor=v.begin(); itor!=v.end(); ++itor) if (fs::equivalent(p, itor->second)) {
{
if (fs::equivalent(p, itor->second))
{
auto pair = std::move(*itor); auto pair = std::move(*itor);
v.erase(itor); v.erase(itor);
v.push_back({where + ", was " + pair.first, p}); v.push_back({where + ", was " + pair.first, p});
@@ -71,10 +61,8 @@ std::vector<fs::path> find_inis(
}; };
// whether the ini is already in the list // whether the ini is already in the list
auto ini_already_found = [&](auto&& p) auto ini_already_found = [&](auto&& p) {
{ for (auto itor = v.begin(); itor != v.end(); ++itor) {
for (auto itor=v.begin(); itor!=v.end(); ++itor)
{
if (fs::equivalent(p, itor->second)) if (fs::equivalent(p, itor->second))
return true; return true;
} }
@@ -82,14 +70,11 @@ std::vector<fs::path> find_inis(
return false; return false;
}; };
fs::path master; fs::path master;
// auto detect from exe directory // auto detect from exe directory
if (auto_detect) if (auto_detect) {
{ if (verbose) {
if (verbose)
{
const auto r = find_root(verbose); const auto r = find_root(verbose);
u8cout << "root is " << path_to_utf8(r) << "\n"; u8cout << "root is " << path_to_utf8(r) << "\n";
} }
@@ -102,18 +87,14 @@ std::vector<fs::path> find_inis(
v.push_back({"master", master}); v.push_back({"master", master});
} }
// MOBINI environment variable // MOBINI environment variable
if (auto e=this_env::get_opt("MOBINI")) if (auto e = this_env::get_opt("MOBINI")) {
{
if (verbose) if (verbose)
u8cout << "found env MOBINI: '" << *e << "'\n"; u8cout << "found env MOBINI: '" << *e << "'\n";
for (auto&& i : split(*e, ";")) for (auto&& i : split(*e, ";")) {
{
auto p = fs::path(i); auto p = fs::path(i);
if (!fs::exists(p)) if (!fs::exists(p)) {
{
u8cerr << "ini from env MOBINI " << i << " not found\n"; u8cerr << "ini from env MOBINI " << i << " not found\n";
throw bailed(); throw bailed();
} }
@@ -127,24 +108,20 @@ std::vector<fs::path> find_inis(
} }
} }
// auto detect from the current directory // auto detect from the current directory
if (auto_detect) if (auto_detect) {
{
MOB_ASSERT(!master.empty()); MOB_ASSERT(!master.empty());
auto cwd = fs::current_path(); auto cwd = fs::current_path();
while (!cwd.empty()) while (!cwd.empty()) {
{
const auto in_cwd = cwd / default_ini_filename(); const auto in_cwd = cwd / default_ini_filename();
if (fs::exists(in_cwd) && !ini_already_found(in_cwd)) if (fs::exists(in_cwd) && !ini_already_found(in_cwd)) {
{
if (verbose) if (verbose)
u8cout << "also found in cwd " << path_to_utf8(in_cwd) << "\n"; u8cout << "also found in cwd " << path_to_utf8(in_cwd) << "\n";
v.push_back({ "cwd", fs::canonical(in_cwd) }); v.push_back({"cwd", fs::canonical(in_cwd)});
break; break;
} }
@@ -156,13 +133,10 @@ std::vector<fs::path> find_inis(
} }
} }
// command line // command line
for (auto&& i : from_cl) for (auto&& i : from_cl) {
{
auto p = fs::path(i); auto p = fs::path(i);
if (!fs::exists(p)) if (!fs::exists(p)) {
{
u8cerr << "ini " << i << " not found\n"; u8cerr << "ini " << i << " not found\n";
throw bailed(); throw bailed();
} }
@@ -175,31 +149,27 @@ std::vector<fs::path> find_inis(
add_or_move_up("cl", p); add_or_move_up("cl", p);
} }
if (verbose) {
if (verbose)
{
u8cout << "\nhigher number overrides lower\n"; u8cout << "\nhigher number overrides lower\n";
for (std::size_t i=0; i<v.size(); ++i) for (std::size_t i = 0; i < v.size(); ++i) {
u8cout << " " << (i + 1) << ") " << path_to_utf8(v[i].second) << " ("
<< v[i].first << ")\n";
}
}
return map(v, [&](auto&& p) {
return p.second;
});
}
std::vector<std::string> read_ini(const fs::path& ini)
{ {
u8cout
<< " " << (i + 1) << ") "
<< path_to_utf8(v[i].second) << " (" << v[i].first << ")\n";
}
}
return map(v, [&](auto&& p){ return p.second; });
}
std::vector<std::string> read_ini(const fs::path& ini)
{
std::ifstream in(ini); std::ifstream in(ini);
std::vector<std::string> lines; std::vector<std::string> lines;
for (;;) for (;;) {
{
std::string line; std::string line;
std::getline(in, line); std::getline(in, line);
trim(line); trim(line);
@@ -214,12 +184,11 @@ std::vector<std::string> read_ini(const fs::path& ini)
gcx().bail_out(context::conf, "failed to read ini {}", ini); gcx().bail_out(context::conf, "failed to read ini {}", ini);
return lines; return lines;
} }
void parse_line( void parse_line(ini_data& ini, std::size_t i, const std::string& line,
ini_data& ini, std::size_t i, const std::string& line,
const std::string& task, const std::string& section) const std::string& task, const std::string& section)
{ {
auto& tm = task_manager::instance(); auto& tm = task_manager::instance();
const auto sep = line.find("="); const auto sep = line.find("=");
@@ -232,54 +201,46 @@ void parse_line(
if (k.empty()) if (k.empty())
ini_error(ini, i, "bad line '{}'", line); ini_error(ini, i, "bad line '{}'", line);
if (section == "aliases") if (section == "aliases") {
{
tm.add_alias(k, split_quoted(v, " ")); tm.add_alias(k, split_quoted(v, " "));
} }
else if (task.empty()) else if (task.empty()) {
{
ini.set(section, k, v); ini.set(section, k, v);
} }
else else {
{
if (!tm.valid_task_name(task)) if (!tm.valid_task_name(task))
ini_error(ini, i, "no task matching '{}' found", task); ini_error(ini, i, "no task matching '{}' found", task);
ini.set(task + ":" + section, k, v); ini.set(task + ":" + section, k, v);
} }
} }
void parse_section( void parse_section(ini_data& ini, std::size_t& i,
ini_data& ini, std::size_t& i, const std::vector<std::string>& lines, const std::vector<std::string>& lines,
const std::string& section_string) const std::string& section_string)
{ {
std::string task, section; std::string task, section;
const auto col = section_string.find(":"); const auto col = section_string.find(":");
if (col == std::string::npos) if (col == std::string::npos) {
{
section = section_string; section = section_string;
} }
else else {
{
task = section_string.substr(0, col); task = section_string.substr(0, col);
section = section_string.substr(col + 1); section = section_string.substr(col + 1);
} }
++i; ++i;
for (;;) for (;;) {
{
if (i >= lines.size() || lines[i][0] == '[') if (i >= lines.size() || lines[i][0] == '[')
break; break;
const auto& line = lines[i]; const auto& line = lines[i];
// empty or comment // empty or comment
if (line.empty() || line[0] == '#' || line[0] == ';') if (line.empty() || line[0] == '#' || line[0] == ';') {
{
++i; ++i;
continue; continue;
} }
@@ -287,10 +248,10 @@ void parse_section(
parse_line(ini, i, line, task, section); parse_line(ini, i, line, task, section);
++i; ++i;
} }
} }
ini_data parse_ini(const fs::path& path) ini_data parse_ini(const fs::path& path)
{ {
gcx().debug(context::conf, "using ini at {}", path); gcx().debug(context::conf, "using ini at {}", path);
ini_data ini; ini_data ini;
@@ -299,32 +260,28 @@ ini_data parse_ini(const fs::path& path)
const auto lines = read_ini(path); const auto lines = read_ini(path);
std::size_t i = 0; std::size_t i = 0;
for (;;) for (;;) {
{
if (i >= lines.size()) if (i >= lines.size())
break; break;
const auto& line = lines[i]; const auto& line = lines[i];
// empty or comment // empty or comment
if (line.empty() || line[0] == '#' || line[0] == ';') if (line.empty() || line[0] == '#' || line[0] == ';') {
{
++i; ++i;
continue; continue;
} }
if (line.starts_with("[") && line.ends_with("]")) if (line.starts_with("[") && line.ends_with("]")) {
{
const std::string name = line.substr(1, line.size() - 2); const std::string name = line.substr(1, line.size() - 2);
parse_section(ini, i, lines, name); parse_section(ini, i, lines, name);
} }
else else {
{
ini_error(ini, i, "bad line '{}'", line); ini_error(ini, i, "bad line '{}'", line);
} }
} }
return ini; return ini;
} }
} // namespace } // namespace mob
+9 -13
View File
@@ -1,17 +1,13 @@
#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 {
struct ini_data
{
using alias_patterns = std::vector<std::string>; using alias_patterns = std::vector<std::string>;
using aliases_map = std::map<std::string, alias_patterns>; using aliases_map = std::map<std::string, alias_patterns>;
@@ -24,9 +20,9 @@ struct ini_data
kv_map& get_section(std::string_view name); kv_map& get_section(std::string_view name);
void set(std::string_view section, std::string key, std::string value); void set(std::string_view section, std::string key, std::string value);
}; };
ini_data parse_ini(const fs::path& ini); ini_data parse_ini(const fs::path& ini);
std::string default_ini_filename(); std::string default_ini_filename();
} // namespace } // namespace mob

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