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 =
+68 -73
View File
@@ -1,90 +1,94 @@
#include "pch.h" #include "pch.h"
#include "commands.h"
#include "../core/ini.h"
#include "../core/conf.h" #include "../core/conf.h"
#include "../core/context.h" #include "../core/context.h"
#include "../core/ini.h"
#include "../core/op.h" #include "../core/op.h"
#include "../tasks/task_manager.h" #include "../tasks/task_manager.h"
#include "commands.h"
namespace mob namespace mob {
{
build_command::build_command() build_command::build_command() : command(requires_options | handle_sigint) {}
: command(requires_options | handle_sigint)
{
}
command::meta_t build_command::meta() const command::meta_t build_command::meta() const
{ {
return return {"build", "builds tasks"};
{
"build",
"builds tasks"
};
} }
clipp::group build_command::do_group() clipp::group build_command::do_group()
{ {
return return (clipp::command("build")).set(picked_),
(clipp::command("build")).set(picked_),
(clipp::option("-h", "--help") >> help_) (clipp::option("-h", "--help") >> help_) % ("shows this message"),
% ("shows this message"),
(clipp::option("-g", "--redownload") >> redownload_) (clipp::option("-g", "--redownload") >> redownload_) %
% "redownloads archives, see --reextract", "redownloads archives, see --reextract",
(clipp::option("-e", "--reextract") >> reextract_) (clipp::option("-e", "--reextract") >> reextract_) %
% "deletes source directories and re-extracts archives", "deletes source directories and re-extracts archives",
(clipp::option("-c", "--reconfigure") >> reconfigure_) (clipp::option("-c", "--reconfigure") >> reconfigure_) %
% "reconfigures the task by running cmake, configure scripts, " "reconfigures the task by running cmake, configure scripts, "
"etc.; some tasks might have to delete the whole source " "etc.; some tasks might have to delete the whole source "
"directory", "directory",
(clipp::option("-b", "--rebuild") >> rebuild_) (clipp::option("-b", "--rebuild") >> rebuild_) %
% "cleans and rebuilds projects; some tasks might have to " "cleans and rebuilds projects; some tasks might have to "
"delete the whole source directory", "delete the whole source directory",
(clipp::option("-n", "--new") >> new_) (clipp::option("-n", "--new") >> new_) %
% "deletes everything and starts from scratch", "deletes everything and starts from scratch",
( (clipp::option("--clean-task").call([&] {
clipp::option("--clean-task").call([&]{ clean_ = true; }) | clean_ = true;
clipp::option("--no-clean-task").call([&]{ clean_ = false; }) }) |
) % "sets whether tasks are cleaned", clipp::option("--no-clean-task").call([&] {
clean_ = false;
})) %
"sets whether tasks are cleaned",
( (clipp::option("--fetch-task").call([&] {
clipp::option("--fetch-task").call([&]{ fetch_ = true; }) | fetch_ = true;
clipp::option("--no-fetch-task").call([&]{ fetch_ = false; }) }) |
) % "sets whether tasks are fetched", clipp::option("--no-fetch-task").call([&] {
fetch_ = false;
})) %
"sets whether tasks are fetched",
( (clipp::option("--build-task").call([&] {
clipp::option("--build-task").call([&]{ build_ = true; }) | build_ = true;
clipp::option("--no-build-task").call([&]{ build_ = false; }) }) |
) % "sets whether tasks are built", clipp::option("--no-build-task").call([&] {
build_ = false;
})) %
"sets whether tasks are built",
( (clipp::option("--pull").call([&] {
clipp::option("--pull").call([&]{ nopull_ = false; }) | nopull_ = false;
clipp::option("--no-pull").call([&]{ nopull_ = true; }) }) |
) % "whether to pull repos that are already cloned; global override", clipp::option("--no-pull").call([&] {
nopull_ = true;
})) %
"whether to pull repos that are already cloned; global override",
( (clipp::option("--revert-ts").call([&] {
clipp::option("--revert-ts").call([&]{ revert_ts_ = true; }) | revert_ts_ = true;
clipp::option("--no-revert-ts").call([&]{ revert_ts_ = false; }) }) |
) % "whether to revert all the .ts files in a repo before pulling to " clipp::option("--no-revert-ts").call([&] {
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";
} }
@@ -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
@@ -153,8 +152,7 @@ void build_command::convert_cl_to_conf()
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,8 +163,7 @@ 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;
} }
@@ -181,10 +178,8 @@ 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";
} }
} }
@@ -197,4 +192,4 @@ void build_command::terminate_msbuild()
system("taskkill /im msbuild.exe /f > NUL 2>&1"); system("taskkill /im msbuild.exe /f > NUL 2>&1");
} }
} // namespace } // namespace mob
+18 -36
View File
@@ -1,22 +1,14 @@
#include "pch.h" #include "pch.h"
#include "commands.h"
#include "../tasks/tasks.h" #include "../tasks/tasks.h"
#include "commands.h"
namespace mob namespace mob {
{
cmake_command::cmake_command() cmake_command::cmake_command() : command(requires_options) {}
: command(requires_options)
{
}
command::meta_t cmake_command::meta() const command::meta_t cmake_command::meta() const
{ {
return return {"cmake", "runs cmake in a directory"};
{
"cmake",
"runs cmake in a directory"
};
} }
clipp::group cmake_command::do_group() clipp::group cmake_command::do_group()
@@ -24,38 +16,29 @@ 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_);
@@ -75,9 +58,8 @@ int cmake_command::do_run()
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
+57 -110
View File
@@ -1,15 +1,14 @@
#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
{ {
@@ -25,23 +24,16 @@ void set_sigint_handler()
::SetConsoleCtrlHandler(mob::signal_handler, TRUE); ::SetConsoleCtrlHandler(mob::signal_handler, TRUE);
} }
void help(const clipp::group& g, const std::string& more) void help(const clipp::group& g, const std::string& more)
{ {
auto usage_df = clipp::doc_formatting() auto usage_df = clipp::doc_formatting().first_column(4).doc_column(30);
.first_column(4)
.doc_column(30);
auto options_df = clipp::doc_formatting() auto options_df = clipp::doc_formatting().first_column(4).doc_column(30);
.first_column(4)
.doc_column(30);
u8cout u8cout << "Usage:\n"
<< "Usage:\n" << clipp::usage_lines(g, "mob", usage_df) << clipp::usage_lines(g, "mob", usage_df) << "\n\n"
<< "\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";
@@ -49,49 +41,42 @@ void help(const clipp::group& g, const std::string& more)
u8cout << "\n" << more << "\n"; u8cout << "\n" << more << "\n";
} }
command::common_options command::common; command::common_options command::common;
command::command(flags f) command::command(flags f) : picked_(false), help_(false), flags_(f), code_() {}
: picked_(false), help_(false), flags_(f), code_()
{
}
clipp::group command::common_options_group() 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";
} }
@@ -122,17 +107,13 @@ void command::convert_cl_to_conf()
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));
} }
@@ -150,22 +131,18 @@ 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;
} }
} }
@@ -191,14 +168,12 @@ int command::prepare_options(bool 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;
@@ -232,20 +207,14 @@ int command::load_options()
return 0; return 0;
} }
command::meta_t version_command::meta() const command::meta_t version_command::meta() const
{ {
return return {"version", "shows the version"};
{
"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()
@@ -254,14 +223,9 @@ int version_command::do_run()
return 0; return 0;
} }
command::meta_t help_command::meta() const command::meta_t help_command::meta() const
{ {
return return {"help", "shows this message"};
{
"help",
"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)
@@ -276,8 +240,7 @@ void help_command::set_commands(const std::vector<std::shared_ptr<command>>& v)
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()
@@ -288,8 +251,7 @@ int help_command::do_run()
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"
@@ -309,29 +273,19 @@ int help_command::do_run()
return 0; return 0;
} }
options_command::options_command() : command(requires_options) {}
options_command::options_command()
: command(requires_options)
{
}
command::meta_t options_command::meta() const command::meta_t options_command::meta() const
{ {
return return {"options", "lists all options and their values from the inis"};
{
"options",
"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()
@@ -347,24 +301,17 @@ std::string options_command::do_doc()
return "Lists the final value of all options found by loading the INIs."; return "Lists the final value of all options found by loading the INIs.";
} }
command::meta_t inis_command::meta() const command::meta_t inis_command::meta() const
{ {
return return {"inis", "lists the INIs used by mob"};
{
"inis",
"lists the INIs used by mob"
};
} }
clipp::group inis_command::do_group() clipp::group inis_command::do_group()
{ {
return clipp::group( return clipp::group(clipp::command("inis").set(picked_),
clipp::command("inis").set(picked_),
(clipp::option("-h", "--help") >> help_) (clipp::option("-h", "--help") >> help_) %
% ("shows this message") ("shows this message"));
);
} }
int inis_command::do_run() int inis_command::do_run()
@@ -377,4 +324,4 @@ std::string inis_command::do_doc()
return "Shows which INIs are found."; return "Shows which INIs are found.";
} }
} // namespace } // namespace mob
+31 -87
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,7 +60,6 @@ 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;
@@ -74,8 +67,7 @@ public:
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,14 +79,12 @@ 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
@@ -140,17 +130,14 @@ 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;
@@ -159,11 +146,9 @@ protected:
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);
@@ -176,11 +161,9 @@ 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;
@@ -191,11 +174,9 @@ protected:
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();
@@ -225,18 +206,15 @@ 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();
@@ -248,27 +226,24 @@ protected:
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);
@@ -277,11 +252,9 @@ private:
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;
@@ -298,11 +271,9 @@ private:
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;
@@ -320,13 +291,7 @@ protected:
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;
@@ -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,19 +319,17 @@ 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;
@@ -378,14 +340,7 @@ protected:
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_;
@@ -412,11 +367,9 @@ private:
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;
@@ -434,11 +387,9 @@ private:
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;
@@ -448,11 +399,9 @@ protected:
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;
@@ -464,12 +413,7 @@ protected:
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_;
@@ -482,4 +426,4 @@ private:
void do_build(); void do_build();
}; };
} // namespace } // namespace mob
+54 -92
View File
@@ -1,23 +1,15 @@
#include "pch.h" #include "pch.h"
#include "commands.h"
#include "../tasks/tasks.h" #include "../tasks/tasks.h"
#include "../tools/tools.h" #include "../tools/tools.h"
#include "commands.h"
namespace mob namespace mob {
{
git_command::git_command() git_command::git_command() : command(requires_options) {}
: command(requires_options)
{
}
command::meta_t git_command::meta() const command::meta_t git_command::meta() const
{ {
return return {"git", "manages the git repos"};
{
"git",
"manages the git repos"
};
} }
clipp::group git_command::do_group() clipp::group git_command::do_group()
@@ -25,101 +17,82 @@ clipp::group git_command::do_group()
return clipp::group( return clipp::group(
clipp::command("git").set(picked_), clipp::command("git").set(picked_),
(clipp::option("-h", "--help") >> help_) (clipp::option("-h", "--help") >> help_) % ("shows this message"),
% ("shows this message"),
"set-remotes" % "set-remotes" %
(clipp::command("set-remotes").set(mode_, modes::set_remotes), (clipp::command("set-remotes").set(mode_, modes::set_remotes),
(clipp::required("-u", "--username") (clipp::required("-u", "--username") &
& clipp::value("USERNAME") >> username_) clipp::value("USERNAME") >> username_) %
% "git username", "git username",
(clipp::required("-e", "--email") (clipp::required("-e", "--email") &
& clipp::value("EMAIL") >> email_) clipp::value("EMAIL") >> email_) %
% "git email", "git email",
(clipp::option("-k", "--key") (clipp::option("-k", "--key") & clipp::value("PATH") >> key_) %
& clipp::value("PATH") >> key_) "path to putty key",
% "path to putty key",
(clipp::option("-s", "--no-push").set(nopush_) (clipp::option("-s", "--no-push").set(nopush_) %
% "disables pushing to 'upstream' by changing the push url " "disables pushing to 'upstream' by changing the push url "
"to 'nopushurl' to avoid accidental pushes"), "to 'nopushurl' to avoid accidental pushes"),
(clipp::option("-p", "--push-origin").set(push_default_) (clipp::option("-p", "--push-origin").set(push_default_) %
% "sets the new 'origin' remote as the default push target"), "sets the new 'origin' remote as the default push target"),
(clipp::opt_value("path") >> path_) (clipp::opt_value("path") >> path_) % "only use this repo")
% "only use this repo"
)
| |
"add-remote" % "add-remote" %
(clipp::command("add-remote").set(mode_, modes::add_remote), (clipp::command("add-remote").set(mode_, modes::add_remote),
(clipp::required("-n", "--name") (clipp::required("-n", "--name") &
& clipp::value("NAME") >> remote_) clipp::value("NAME") >> remote_) %
% "name of new remote", "name of new remote",
(clipp::required("-u", "--username") (clipp::required("-u", "--username") &
& clipp::value("USERNAME") >> username_) clipp::value("USERNAME") >> username_) %
% "git username", "git username",
(clipp::option("-k", "--key") (clipp::option("-k", "--key") & clipp::value("PATH") >> key_) %
& clipp::value("PATH") >> key_) "path to putty key",
% "path to putty key",
(clipp::option("-p", "--push-origin").set(push_default_) (clipp::option("-p", "--push-origin").set(push_default_) %
% "sets this new remote as the default push target"), "sets this new remote as the default push target"),
(clipp::opt_value("path") >> path_) (clipp::opt_value("path") >> path_) % "only use this repo")
% "only use this repo"
)
| |
"ignore-ts" % "ignore-ts" % (clipp::command("ignore-ts").set(mode_, modes::ignore_ts),
(clipp::command("ignore-ts").set(mode_, modes::ignore_ts), (clipp::command("on").set(tson_, true) |
( clipp::command("off").set(tson_, false)))
clipp::command("on").set(tson_, true) |
clipp::command("off").set(tson_, false)
)
)
| |
"branches" % "branches" % (clipp::command("branches").set(mode_, modes::branches),
(clipp::command("branches").set(mode_, modes::branches), clipp::option("-a", "--all").set(all_branches_) %
clipp::option("-a", "--all").set(all_branches_) "shows all branches, including those on master"));
% "shows all branches, including those on master"
)
);
} }
int git_command::do_run() int git_command::do_run()
{ {
switch (mode_) switch (mode_) {
{ case modes::set_remotes: {
case modes::set_remotes:
{
do_set_remotes(); 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;
} }
@@ -135,8 +108,7 @@ int git_command::do_run()
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"
@@ -160,15 +132,13 @@ std::string git_command::do_doc()
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_);
} }
} }
@@ -179,25 +149,22 @@ void git_command::do_set_remotes(const fs::path& r)
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_);
} }
} }
@@ -215,15 +182,13 @@ void git_command::do_ignore_ts()
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_);
} }
} }
@@ -238,8 +203,7 @@ 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;
@@ -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;
@@ -282,4 +244,4 @@ std::vector<fs::path> git_command::get_repos() const
return v; return v;
} }
} // namespace } // namespace mob
+18 -35
View File
@@ -1,19 +1,14 @@
#include "pch.h" #include "pch.h"
#include "commands.h"
#include "../tasks/task_manager.h"
#include "../tasks/task.h" #include "../tasks/task.h"
#include "../tasks/task_manager.h"
#include "../utility/io.h" #include "../utility/io.h"
#include "commands.h"
namespace mob namespace mob {
{
command::meta_t list_command::meta() const command::meta_t list_command::meta() const
{ {
return return {"list", "lists available tasks"};
{
"list",
"lists available tasks"
};
} }
clipp::group list_command::do_group() clipp::group list_command::do_group()
@@ -21,35 +16,28 @@ 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,27 +47,22 @@ 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))
@@ -97,4 +80,4 @@ void list_command::dump_aliases() const
u8cout << " - " << k << ": " << join(patterns, ", ") << "\n"; u8cout << " - " << k << ": " << join(patterns, ", ") << "\n";
} }
} // namespace } // namespace mob
+70 -115
View File
@@ -1,12 +1,11 @@
#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)
{ {
@@ -14,25 +13,16 @@ std::string read_file(const fs::path& 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(requires_options | handle_sigint)
{
}
command::meta_t pr_command::meta() const command::meta_t pr_command::meta() const
{ {
return return {"pr", "applies changes from PRs"};
{
"pr",
"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"
@@ -48,21 +38,19 @@ std::string pr_command::do_doc()
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()
@@ -82,15 +70,14 @@ int pr_command::do_run()
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,8 +90,7 @@ 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 {};
} }
@@ -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,8 +131,7 @@ 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;
} }
@@ -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,15 +167,14 @@ 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)
@@ -214,18 +192,19 @@ 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;
@@ -233,10 +212,8 @@ std::vector<pr_command::pr_info> pr_command::search_prs(
"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 {};
} }
@@ -334,42 +297,35 @@ pr_command::pr_info pr_command::get_pr_info(
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,13 +346,13 @@ 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";
@@ -406,4 +361,4 @@ std::vector<pr_command::pr_info> pr_command::validate_prs(
return okay_prs; return okay_prs;
} }
} // namespace } // namespace mob
+113 -175
View File
File diff suppressed because it is too large Load Diff
+41 -66
View File
@@ -1,27 +1,19 @@
#include "pch.h" #include "pch.h"
#include "commands.h"
#include "../net.h"
#include "../utility.h"
#include "../core/conf.h" #include "../core/conf.h"
#include "../core/context.h" #include "../core/context.h"
#include "../core/env.h" #include "../core/env.h"
#include "../net.h"
#include "../tasks/tasks.h" #include "../tasks/tasks.h"
#include "../utility.h"
#include "commands.h"
namespace mob namespace mob {
{
tx_command::tx_command() tx_command::tx_command() : command(requires_options) {}
: command(requires_options)
{
}
command::meta_t tx_command::meta() const command::meta_t tx_command::meta() const
{ {
return return {"tx", "manages transifex translations"};
{
"tx",
"manages transifex translations"
};
} }
clipp::group tx_command::do_group() clipp::group tx_command::do_group()
@@ -29,50 +21,43 @@ 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()
@@ -100,8 +85,7 @@ void tx_command::convert_cl_to_conf()
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;
@@ -121,8 +105,7 @@ int tx_command::do_run()
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"
@@ -137,17 +120,14 @@ std::string tx_command::do_doc()
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)
@@ -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)
@@ -210,4 +185,4 @@ void tx_command::do_build()
} }
} }
} // namespace } // namespace mob
+117 -177
View File
File diff suppressed because it is too large Load Diff
+61 -63
View File
@@ -3,37 +3,37 @@
// 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 // reads options from the given inis and option strings, resolves all the paths
// and necessary tools, also adds a couple of things to PATH // and necessary tools, also adds a couple of things to PATH
// //
void init_options( void init_options(const std::vector<fs::path>& inis,
const std::vector<fs::path>& inis, const std::vector<std::string>& opts); const std::vector<std::string>& opts);
// checks some of the options once everything is loaded, returns false if // checks some of the options once everything is loaded, returns false if
// something's wrong // something's wrong
@@ -44,32 +44,36 @@ bool verify_options();
// //
std::vector<std::string> format_options(); std::vector<std::string> format_options();
// base class for all conf structs // base class for all conf structs
// //
template <class DefaultType> template <class DefaultType>
class conf_section class conf_section {
{
public: public:
DefaultType get(std::string_view key) const DefaultType get(std::string_view key,
std::optional<DefaultType> default_ = {}) 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)
@@ -78,10 +82,7 @@ public:
} }
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_; }
@@ -89,11 +90,9 @@ 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();
@@ -112,11 +111,9 @@ public:
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);
@@ -144,8 +141,14 @@ 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_;
@@ -153,11 +156,9 @@ private:
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_;
@@ -173,7 +174,6 @@ public:
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)
{ {
return lhs.is_equivalent(rhs.value()); return lhs.is_equivalent(rhs.value());
@@ -182,14 +182,12 @@ 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();
@@ -205,55 +203,57 @@ 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);
@@ -288,18 +287,17 @@ public:
#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();
@@ -309,4 +307,4 @@ public:
void set_log_file(); void set_log_file();
}; };
} // namespace } // namespace mob
+73 -100
View File
@@ -1,12 +1,11 @@
#include "pch.h" #include "pch.h"
#include "context.h" #include "context.h"
#include "conf.h"
#include "../utility.h"
#include "../tasks/task.h" #include "../tasks/task.h"
#include "../tools/tools.h" #include "../tools/tools.h"
#include "../utility.h"
#include "conf.h"
namespace mob::details namespace mob::details {
{
std::string converter<std::wstring>::convert(const std::wstring& s) std::string converter<std::wstring>::convert(const std::wstring& s)
{ {
@@ -23,11 +22,9 @@ std::string converter<url>::convert(const url& u)
return u.string(); return u.string();
} }
} // namespace } // namespace mob::details
namespace mob {
namespace mob
{
// timestamps are relative to this // timestamps are relative to this
static hr_clock::time_point g_start_time = hr_clock::now(); static hr_clock::time_point g_start_time = hr_clock::now();
@@ -42,13 +39,11 @@ static handle_ptr g_log_file;
// global output mutex to avoid interleaving, but also mixing colors // global output mutex to avoid interleaving, but also mixing colors
static std::mutex g_mutex; static std::mutex g_mutex;
// returns the color associated with the given level // returns the color associated with the given level
// //
console_color level_color(context::level lv) console_color level_color(context::level lv)
{ {
switch (lv) switch (lv) {
{
case context::level::dump: case context::level::dump:
case context::level::trace: case context::level::trace:
case context::level::debug: case context::level::debug:
@@ -70,21 +65,33 @@ console_color level_color(context::level lv)
// //
const char* reason_string(context::reason r) const char* reason_string(context::reason r)
{ {
switch (r) switch (r) {
{ case context::bypass:
case context::bypass: return "bypass"; return "bypass";
case context::redownload: return "re-dl"; case context::redownload:
case context::rebuild: return "re-bd"; return "re-dl";
case context::reextract: return "re-ex"; case context::rebuild:
case context::interruption: return "int"; return "re-bd";
case context::cmd: return "cmd"; case context::reextract:
case context::std_out: return "stdout"; return "re-ex";
case context::std_err: return "stderr"; case context::interruption:
case context::fs: return (conf().global().dry() ? "fs-dry" : "fs"); return "int";
case context::net: return "net"; case context::cmd:
case context::generic: return ""; return "cmd";
case context::conf: return "conf"; case context::std_out:
default: return "?"; return "stdout";
case context::std_err:
return "stderr";
case context::fs:
return (conf().global().dry() ? "fs-dry" : "fs");
case context::net:
return "net";
case context::generic:
return "";
case context::conf:
return "conf";
default:
return "?";
} }
} }
@@ -94,15 +101,11 @@ std::string error_message(DWORD id)
{ {
wchar_t* message = nullptr; wchar_t* message = nullptr;
const auto ret = FormatMessageW( const auto ret =
FORMAT_MESSAGE_ALLOCATE_BUFFER | FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS, FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, NULL, id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
id, reinterpret_cast<LPWSTR>(&message), 0, NULL);
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPWSTR>(&message),
0, NULL);
std::wstring s; std::wstring s;
@@ -114,7 +117,8 @@ std::string error_message(DWORD id)
if (ret == 0 || !message) { if (ret == 0 || !message) {
// error message not found, just use the hex error code // error message not found, just use the hex error code
s = oss.str(); s = oss.str();
} else { }
else {
// FormatMessage() includes a newline, trim it and put the hex code too // FormatMessage() includes a newline, trim it and put the hex code too
s = trim_copy(message) + L" (" + oss.str() + L")"; s = trim_copy(message) + L" (" + oss.str() + L")";
} }
@@ -141,8 +145,7 @@ std::string_view timestamp_string()
const auto frac = static_cast<float>(ms.count()) / 1000.0; const auto frac = static_cast<float>(ms.count()) / 1000.0;
// to string with 2 digits precision // to string with 2 digits precision
const auto r = std::to_chars( const auto r = std::to_chars(std::begin(buffer), std::end(buffer), frac,
std::begin(buffer), std::end(buffer), frac,
std::chars_format::fixed, 2); std::chars_format::fixed, 2);
if (r.ec != std::errc()) if (r.ec != std::errc())
@@ -159,8 +162,7 @@ std::string_view timestamp_string()
// //
bool log_enabled(context::level lv, int conf_lv) bool log_enabled(context::level lv, int conf_lv)
{ {
switch (lv) switch (lv) {
{
case context::level::dump: case context::level::dump:
return conf_lv > 5; return conf_lv > 5;
@@ -192,12 +194,9 @@ bool log_enabled(context::level lv, int conf_lv)
// //
bool should_dump_logs() bool should_dump_logs()
{ {
return log_enabled( return log_enabled(context::level::debug, conf().global().output_log_level());
context::level::debug,
conf().global().output_log_level());
} }
context::context(std::string task_name) context::context(std::string task_name)
: task_(std::move(task_name)), tool_(nullptr) : task_(std::move(task_name)), tool_(nullptr)
{ {
@@ -218,8 +217,7 @@ bool context::enabled(level lv)
{ {
// a log level is enabled if it's included in either the console or the log // a log level is enabled if it's included in either the console or the log
// file, which have independent levels // file, which have independent levels
const int minimum_log_level = std::max( const int minimum_log_level = std::max(mob::conf().global().output_log_level(),
mob::conf().global().output_log_level(),
mob::conf().global().file_log_level()); mob::conf().global().file_log_level());
return log_enabled(lv, minimum_log_level); return log_enabled(lv, minimum_log_level);
@@ -227,21 +225,18 @@ bool context::enabled(level lv)
void context::set_log_file(const fs::path& p) void context::set_log_file(const fs::path& p)
{ {
if (!mob::conf().global().dry() && !p.empty()) if (!mob::conf().global().dry() && !p.empty()) {
{
// creating directory // creating directory
if (!exists(p.parent_path())) if (!exists(p.parent_path()))
op::create_directories(gcx(), mob::conf().path().prefix()); op::create_directories(gcx(), mob::conf().path().prefix());
HANDLE h = CreateFileW( HANDLE h = CreateFileW(p.native().c_str(), GENERIC_WRITE, FILE_SHARE_READ,
p.native().c_str(), GENERIC_WRITE, FILE_SHARE_READ,
nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (h == INVALID_HANDLE_VALUE) if (h == INVALID_HANDLE_VALUE) {
{
const auto e = GetLastError(); const auto e = GetLastError();
gcx().bail_out(context::generic, gcx().bail_out(context::generic, "failed to open log file {}, {}", p,
"failed to open log file {}, {}", p, error_message(e)); error_message(e));
} }
g_log_file.reset(h); g_log_file.reset(h);
@@ -261,21 +256,19 @@ void context::log_string(reason r, level lv, std::string_view s) const
do_log_impl(false, r, lv, s); do_log_impl(false, r, lv, s);
} }
void context::do_log_impl( void context::do_log_impl(bool bail, reason r, level lv,
bool bail, reason r, level lv, std::string_view utf8) const std::string_view utf8) const
{ {
std::string_view sv = make_log_string(r, lv, utf8); std::string_view sv = make_log_string(r, lv, utf8);
if (bail) if (bail) {
{
// log the string with "(bailing out)" at the end, but throw the // log the string with "(bailing out)" at the end, but throw the
// original, it's prettier that way // original, it's prettier that way
const std::string s(sv); const std::string s(sv);
emit_log(lv, s + " (bailing out)"); emit_log(lv, s + " (bailing out)");
throw bailed(s); throw bailed(s);
} }
else else {
{
emit_log(lv, sv); emit_log(lv, sv);
} }
} }
@@ -285,28 +278,24 @@ void context::emit_log(level lv, std::string_view utf8) const
std::scoped_lock lock(g_mutex); std::scoped_lock lock(g_mutex);
// console // console
if (log_enabled(lv, mob::conf().global().output_log_level())) if (log_enabled(lv, mob::conf().global().output_log_level())) {
{
// will revert color in dtor // will revert color in dtor
console_color c = level_color(lv); console_color c = level_color(lv);
u8cout.write_ln(utf8); u8cout.write_ln(utf8);
} }
// log file // log file
if (g_log_file && log_enabled(lv, mob::conf().global().file_log_level())) if (g_log_file && log_enabled(lv, mob::conf().global().file_log_level())) {
{
DWORD written = 0; DWORD written = 0;
::WriteFile( ::WriteFile(g_log_file.get(), utf8.data(), static_cast<DWORD>(utf8.size()),
g_log_file.get(), utf8.data(), static_cast<DWORD>(utf8.size()),
&written, nullptr); &written, nullptr);
::WriteFile(g_log_file.get(), "\r\n", 2, &written, nullptr); ::WriteFile(g_log_file.get(), "\r\n", 2, &written, nullptr);
} }
// remember warnings and errors // remember warnings and errors
if (should_dump_logs()) if (should_dump_logs()) {
{
if (lv == level::error) if (lv == level::error)
g_errors.emplace_back(utf8); g_errors.emplace_back(utf8);
else if (lv == level::warning) else if (lv == level::warning)
@@ -319,12 +308,10 @@ void context::emit_log(level lv, std::string_view utf8) const
// //
void append(std::string& s, std::string_view what, std::size_t max_length) void append(std::string& s, std::string_view what, std::size_t max_length)
{ {
if (what.empty()) if (what.empty()) {
{
s.append(max_length, ' '); s.append(max_length, ' ');
} }
else else {
{
s.append(what); s.append(what);
// padding // padding
@@ -339,15 +326,13 @@ void append(std::string& s, std::string_view what, std::size_t max_length)
// //
// avoids unnecessary memory allocations by appending the brackets directly // avoids unnecessary memory allocations by appending the brackets directly
// //
void append_with_brackets( void append_with_brackets(std::string& s, std::string_view what,
std::string& s, std::string_view what, std::size_t max_length) std::size_t max_length)
{
if (what.empty())
{ {
if (what.empty()) {
s.append(max_length, ' '); s.append(max_length, ' ');
} }
else else {
{
s.append(1, '['); s.append(1, '[');
s.append(what); s.append(what);
s.append(1, ']'); s.append(1, ']');
@@ -363,22 +348,18 @@ void append_with_brackets(
// //
void append_context(std::string& ls, context::reason r) void append_context(std::string& ls, context::reason r)
{ {
switch (r) switch (r) {
{ case context::redownload: {
case context::redownload:
{
ls.append(" (happened because of --redownload)"); ls.append(" (happened because of --redownload)");
break; break;
} }
case context::rebuild: case context::rebuild: {
{
ls.append(" (happened because of --rebuild)"); ls.append(" (happened because of --rebuild)");
break; break;
} }
case context::reextract: case context::reextract: {
{
ls.append(" (happened because of --reextract)"); ls.append(" (happened because of --reextract)");
break; break;
} }
@@ -416,34 +397,28 @@ std::string_view context::make_log_string(reason r, level, std::string_view s) c
const std::size_t longest_reason = 7; const std::size_t longest_reason = 7;
const std::size_t reason_max_length = longest_reason + 3; const std::size_t reason_max_length = longest_reason + 3;
// keep a thread local string to avoid memory allocations // keep a thread local string to avoid memory allocations
static thread_local std::string ls; static thread_local std::string ls;
// clear previous log // clear previous log
ls.clear(); ls.clear();
// a full log line might look like: // a full log line might look like:
// "2.77 [cmake_common] [git] [cmd] creating process" // "2.77 [cmake_common] [git] [cmd] creating process"
// timestamp // timestamp
append(ls, timestamp_string(), timestamp_max_length); append(ls, timestamp_string(), timestamp_max_length);
// task name // task name
append_with_brackets( append_with_brackets(ls, task_.substr(0, longest_task_name),
ls, task_.substr(0, longest_task_name), task_name_max_length); task_name_max_length);
// tool // tool
if (tool_) if (tool_) {
{ append_with_brackets(ls, tool_->name().substr(0, longest_tool_name),
append_with_brackets(
ls, tool_->name().substr(0, longest_tool_name),
tool_name_max_length); tool_name_max_length);
} }
else else {
{
ls.append(tool_name_max_length, ' '); ls.append(tool_name_max_length, ' ');
} }
@@ -456,7 +431,6 @@ std::string_view context::make_log_string(reason r, level, std::string_view s) c
// context // context
append_context(ls, r); append_context(ls, r);
return ls; return ls;
} }
@@ -465,8 +439,7 @@ void dump_logs()
if (!should_dump_logs()) if (!should_dump_logs())
return; return;
if (!g_warnings.empty() || !g_errors.empty()) if (!g_warnings.empty() || !g_errors.empty()) {
{
u8cout << "\n\nthere were problems:\n"; u8cout << "\n\nthere were problems:\n";
{ {
@@ -483,4 +456,4 @@ void dump_logs()
} }
} }
} // namespace } // namespace mob
+19 -41
View File
@@ -7,52 +7,41 @@
// 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;
@@ -60,7 +49,6 @@ class tool;
// //
std::string error_message(DWORD e); std::string error_message(DWORD e);
// a logger with some context, this is passed around everywhere and knows which // 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 // task and tool is currently running to get better context when logging
// //
@@ -74,13 +62,11 @@ std::string error_message(DWORD e);
// //
// cx.log(context::generic, "eat more {}", "potatoes"); // cx.log(context::generic, "eat more {}", "potatoes");
// //
class context class context {
{
public: 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);
@@ -239,7 +223,6 @@ private:
// 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,8 +274,7 @@ 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
@@ -304,7 +283,6 @@ private:
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()
@@ -317,4 +295,4 @@ inline const context& gcx()
// //
void dump_logs(); void dump_logs();
} // namespace } // namespace mob
+46 -80
View File
@@ -1,14 +1,13 @@
#include "pch.h" #include "pch.h"
#include "env.h" #include "env.h"
#include "conf.h"
#include "process.h"
#include "op.h"
#include "context.h"
#include "../utility.h"
#include "../tools/tools.h" #include "../tools/tools.h"
#include "../utility.h"
#include "conf.h"
#include "context.h"
#include "op.h"
#include "process.h"
namespace mob namespace mob {
{
// retrieves the Visual Studio environment variables for the given architecture; // retrieves the Visual Studio environment variables for the given architecture;
// this is pretty expensive, so it's called on demand and only once, and is // this is pretty expensive, so it's called on demand and only once, and is
@@ -19,8 +18,7 @@ env get_vcvars_env(arch a)
// translate arch to the string needed by vcvars // translate arch to the string needed by vcvars
std::string arch_s; std::string arch_s;
switch (a) switch (a) {
{
case arch::x86: case arch::x86:
arch_s = "x86"; arch_s = "x86";
break; break;
@@ -36,7 +34,6 @@ env get_vcvars_env(arch a)
gcx().trace(context::generic, "looking for vcvars for {}", arch_s); gcx().trace(context::generic, "looking for vcvars for {}", arch_s);
// the only way to get these variables is to // the only way to get these variables is to
// 1) run vcvars in a cmd instance, // 1) run vcvars in a cmd instance,
// 2) call `set`, which outputs all the variables to stdout, and // 2) call `set`, which outputs all the variables to stdout, and
@@ -50,14 +47,11 @@ env get_vcvars_env(arch a)
const fs::path tmp = make_temp_file(); const fs::path tmp = make_temp_file();
// runs `"vcvarsall.bat" amd64 && set > temp_file` // runs `"vcvarsall.bat" amd64 && set > temp_file`
const std::string cmd = const std::string cmd = "\"" + path_to_utf8(vs::vcvars()) + "\" " + arch_s +
"\"" + path_to_utf8(vs::vcvars()) + "\" " + arch_s +
" && set > \"" + path_to_utf8(tmp) + "\""; " && set > \"" + path_to_utf8(tmp) + "\"";
// cmd_unicode() is necessary so `set` outputs in utf16 instead of codepage // cmd_unicode() is necessary so `set` outputs in utf16 instead of codepage
process::raw(gcx(), cmd) process::raw(gcx(), cmd).cmd_unicode(true).run();
.cmd_unicode(true)
.run();
gcx().trace(context::generic, "reading from {}", tmp); gcx().trace(context::generic, "reading from {}", tmp);
@@ -71,8 +65,7 @@ env get_vcvars_env(arch a)
gcx().trace(context::generic, "parsing variables"); gcx().trace(context::generic, "parsing variables");
for (;;) for (;;) {
{
std::string line; std::string line;
std::getline(ss, line); std::getline(ss, line);
if (!ss) if (!ss)
@@ -93,7 +86,6 @@ env get_vcvars_env(arch a)
return e; return e;
} }
env env::vs_x86() env env::vs_x86()
{ {
static env e = get_vcvars_env(arch::x86); static env e = get_vcvars_env(arch::x86);
@@ -108,8 +100,7 @@ env env::vs_x64()
env env::vs(arch a) env env::vs(arch a)
{ {
switch (a) switch (a) {
{
case arch::x86: case arch::x86:
return vs_x86(); return vs_x86();
@@ -124,21 +115,17 @@ env env::vs(arch a)
} }
} }
env::env() : own_(false)
env::env()
: own_(false)
{ {
// empty env, does not own // empty env, does not own
} }
env::env(const env& e) env::env(const env& e) : data_(e.data_), own_(false)
: data_(e.data_), own_(false)
{ {
// copy data, does not own // copy data, does not own
} }
env::env(env&& e) env::env(env&& e) : data_(std::move(e.data_)), own_(e.own_)
: data_(std::move(e.data_)), own_(e.own_)
{ {
// move data, owns if `e` did // move data, owns if `e` did
} }
@@ -189,28 +176,25 @@ env& env::change_path(const std::vector<fs::path>& v, flags f)
std::wstring path; std::wstring path;
switch (f) switch (f) {
{ case replace: {
case replace:
{
// convert to utf16 strings, join with ; // convert to utf16 strings, join with ;
const auto strings = const auto strings = mob::map(v, [&](auto&& p) {
mob::map(v, [&](auto&& p){ return p.native(); }); return p.native();
});
path = join(strings, L";"); path = join(strings, L";");
break; break;
} }
case append: case append: {
{
auto current = find(L"PATH"); auto current = find(L"PATH");
if (current) if (current)
path = *current; path = *current;
// append all paths as utf16 strings to the current value, if any // append all paths as utf16 strings to the current value, if any
for (auto&& p : v) for (auto&& p : v) {
{
if (!path.empty()) if (!path.empty())
path += L";"; path += L";";
@@ -220,15 +204,13 @@ env& env::change_path(const std::vector<fs::path>& v, flags f)
break; break;
} }
case prepend: case prepend: {
{
auto current = find(L"PATH"); auto current = find(L"PATH");
if (current) if (current)
path = *current; path = *current;
// prepend all paths as utf16 strings to the current value, if any // prepend all paths as utf16 strings to the current value, if any
for (auto&& p : v) for (auto&& p : v) {
{
if (!path.empty()) if (!path.empty())
path = L";" + path; path = L";" + path;
@@ -262,14 +244,12 @@ void env::set_impl(std::wstring k, std::wstring v, flags f)
{ {
auto current = find(k); auto current = find(k);
if (!current) if (!current) {
{
data_->vars.emplace(std::move(k), std::move(v)); data_->vars.emplace(std::move(k), std::move(v));
return; return;
} }
switch (f) switch (f) {
{
case replace: case replace:
*current = std::move(v); *current = std::move(v);
break; break;
@@ -313,8 +293,7 @@ void env::create_sys() const
data_->sys.clear(); data_->sys.clear();
for (auto&& v : data_->vars) for (auto&& v : data_->vars) {
{
data_->sys += v.first + L"=" + v.second; data_->sys += v.first + L"=" + v.second;
data_->sys.append(1, L'\0'); data_->sys.append(1, L'\0');
} }
@@ -332,8 +311,7 @@ const std::wstring* env::find(std::wstring_view name) const
if (!data_) if (!data_)
return {}; return {};
for (auto itor=data_->vars.begin(); itor!=data_->vars.end(); ++itor) for (auto itor = data_->vars.begin(); itor != data_->vars.end(); ++itor) {
{
if (_wcsicmp(itor->first.c_str(), name.data()) == 0) if (_wcsicmp(itor->first.c_str(), name.data()) == 0)
return &itor->second; return &itor->second;
} }
@@ -358,8 +336,7 @@ void* env::get_unicode_pointers() const
void env::copy_for_write() void env::copy_for_write()
{ {
if (own_) if (own_) {
{
// this is called every time something is about to change; if this // this is called every time something is about to change; if this
// instance already owns the data, the sys strings must still be cleared // instance already owns the data, the sys strings must still be cleared
// out so they're recreated if get_unicode_pointers() is every called // out so they're recreated if get_unicode_pointers() is every called
@@ -369,8 +346,7 @@ void env::copy_for_write()
return; return;
} }
if (data_) if (data_) {
{
// remember the shared data // remember the shared data
auto shared = data_; auto shared = data_;
@@ -381,8 +357,7 @@ void env::copy_for_write()
std::scoped_lock lock(shared->m); std::scoped_lock lock(shared->m);
data_->vars = shared->vars; data_->vars = shared->vars;
} }
else else {
{
// creating own, empty data // creating own, empty data
data_.reset(new data); data_.reset(new data);
} }
@@ -391,37 +366,34 @@ void env::copy_for_write()
own_ = true; own_ = true;
} }
// mob's environment variables are only retrieved once and are kept in sync // mob's environment variables are only retrieved once and are kept in sync
// after that; this must also be thread-safe // after that; this must also be thread-safe
static std::mutex g_sys_env_mutex; static std::mutex g_sys_env_mutex;
static env g_sys_env; static env g_sys_env;
static bool g_sys_env_inited; static bool g_sys_env_inited;
env this_env::get() env this_env::get()
{ {
std::scoped_lock lock(g_sys_env_mutex); std::scoped_lock lock(g_sys_env_mutex);
if (g_sys_env_inited) if (g_sys_env_inited) {
{
// already done // already done
return g_sys_env; return g_sys_env;
} }
// first time, get the variables from the system // first time, get the variables from the system
auto free = [](wchar_t* p) { FreeEnvironmentStringsW(p); }; auto free = [](wchar_t* p) {
FreeEnvironmentStringsW(p);
};
auto env_block = std::unique_ptr<wchar_t, decltype(free)>{ auto env_block =
GetEnvironmentStringsW(), free}; std::unique_ptr<wchar_t, decltype(free)>{GetEnvironmentStringsW(), free};
// GetEnvironmentStringsW() returns a string where each variable=value // GetEnvironmentStringsW() returns a string where each variable=value
// is separated by a null character // is separated by a null character
for (const wchar_t* name = env_block.get(); *name != L'\0'; ) for (const wchar_t* name = env_block.get(); *name != L'\0';) {
{
// equal sign // equal sign
const wchar_t* equal = std::wcschr(name, '='); const wchar_t* equal = std::wcschr(name, '=');
@@ -452,24 +424,20 @@ void this_env::set(const std::string& k, const std::string& v, env::flags f)
const std::wstring wk = utf8_to_utf16(k); const std::wstring wk = utf8_to_utf16(k);
std::wstring wv = utf8_to_utf16(v); std::wstring wv = utf8_to_utf16(v);
switch (f) switch (f) {
{ case env::replace: {
case env::replace:
{
::SetEnvironmentVariableW(wk.c_str(), wv.c_str()); ::SetEnvironmentVariableW(wk.c_str(), wv.c_str());
break; break;
} }
case env::append: case env::append: {
{
const std::wstring current = get_impl(k).value_or(L""); const std::wstring current = get_impl(k).value_or(L"");
wv = current + wv; wv = current + wv;
::SetEnvironmentVariableW(wk.c_str(), wv.c_str()); ::SetEnvironmentVariableW(wk.c_str(), wv.c_str());
break; break;
} }
case env::prepend: case env::prepend: {
{
const std::wstring current = get_impl(k).value_or(L""); const std::wstring current = get_impl(k).value_or(L"");
wv = wv + current; wv = wv + current;
::SetEnvironmentVariableW(wk.c_str(), wv.c_str()); ::SetEnvironmentVariableW(wk.c_str(), wv.c_str());
@@ -500,10 +468,9 @@ void this_env::append_to_path(const fs::path& p)
std::string this_env::get(const std::string& name) std::string this_env::get(const std::string& name)
{ {
auto v = get_impl(name); auto v = get_impl(name);
if (!v) if (!v) {
{ gcx().bail_out(context::generic, "environment variable {} doesn't exist",
gcx().bail_out(context::generic, name);
"environment variable {} doesn't exist", name);
} }
return utf16_to_utf8(*v); return utf16_to_utf8(*v);
@@ -522,8 +489,7 @@ std::optional<std::wstring> this_env::get_impl(const std::string& k)
{ {
const std::wstring wk = utf8_to_utf16(k); const std::wstring wk = utf8_to_utf16(k);
const std::size_t buffer_size = GetEnvironmentVariableW( const std::size_t buffer_size = GetEnvironmentVariableW(wk.c_str(), nullptr, 0);
wk.c_str(), nullptr, 0);
if (buffer_size == 0) if (buffer_size == 0)
return {}; return {};
@@ -542,4 +508,4 @@ std::optional<std::wstring> this_env::get_impl(const std::string& k)
return std::wstring(buffer.get(), buffer.get() + written); return std::wstring(buffer.get(), buffer.get() + written);
} }
} // namespace } // namespace mob
+7 -21
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();
@@ -77,8 +69,7 @@ public:
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;
@@ -117,16 +107,12 @@ private:
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,
const std::string& v,
env::flags f = env::replace); env::flags f = env::replace);
// changes PATH // changes PATH
@@ -152,4 +138,4 @@ private:
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
+49 -92
View File
@@ -1,30 +1,25 @@
#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, gcx().bail_out(context::conf, "{}:{}: {}", path_to_utf8(ini.path), (line + 1),
"{}:{}: {}",
path_to_utf8(ini.path), (line + 1),
fmt::format(f, std::forward<Args>(args)...)); fmt::format(f, std::forward<Args>(args)...));
} }
ini_data::kv_map& ini_data::get_section(std::string_view name) ini_data::kv_map& ini_data::get_section(std::string_view name)
{ {
for (auto itor=sections.begin(); itor!=sections.end(); ++itor) for (auto itor = sections.begin(); itor != sections.end(); ++itor) {
{
if (itor->first == name) if (itor->first == name)
return itor->second; return itor->second;
} }
@@ -39,27 +34,22 @@ void ini_data::set(std::string_view section, std::string key, std::string value)
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,20 +108,16 @@ 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";
@@ -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,21 +149,18 @@ 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) << " ("
u8cout << v[i].first << ")\n";
<< " " << (i + 1) << ") "
<< path_to_utf8(v[i].second) << " (" << v[i].first << ")\n";
} }
} }
return map(v, [&](auto&& p) {
return map(v, [&](auto&& p){ return p.second; }); return p.second;
});
} }
std::vector<std::string> read_ini(const fs::path& ini) std::vector<std::string> read_ini(const fs::path& ini)
@@ -198,8 +169,7 @@ std::vector<std::string> read_ini(const fs::path& 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);
@@ -216,8 +186,7 @@ std::vector<std::string> read_ini(const fs::path& 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();
@@ -232,16 +201,13 @@ 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);
@@ -249,37 +215,32 @@ void parse_line(
} }
} }
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;
} }
@@ -299,27 +260,23 @@ 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);
} }
} }
@@ -327,4 +284,4 @@ ini_data parse_ini(const fs::path& path)
return ini; return ini;
} }
} // namespace } // namespace mob
+5 -9
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>;
@@ -29,4 +25,4 @@ struct ini_data
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