glob match is now case insensitive and considers - and _ equivalent

added gamebryo flag to mo tasks so translations now to merge the .ts files
don't handle sigint for commands except for build, which requires killing a lot of children
tx build
This commit is contained in:
isanae
2020-07-11 19:58:41 -04:00
parent eca4a2d82e
commit fffeafce11
12 changed files with 367 additions and 71 deletions
+18 -15
View File
@@ -37,24 +37,27 @@ git_shallow = false
git_shallow = false
[tools]
sevenz = 7z.exe
jom = jom.exe
patch = patch.exe
git = git.exe
cmake = cmake.exe
perl = perl.exe
devenv = devenv.exe
msbuild = msbuild.exe
nuget = nuget.exe
vswhere = vswhere.exe
nasm = nasm.exe
tx = tx.py37-x64.exe
vcvars =
sevenz = 7z.exe
jom = jom.exe
patch = patch.exe
git = git.exe
cmake = cmake.exe
perl = perl.exe
devenv = devenv.exe
msbuild = msbuild.exe
nuget = nuget.exe
vswhere = vswhere.exe
nasm = nasm.exe
tx = tx.py37-x64.exe
lrelease = lrelease.exe
vcvars =
[transifex]
enabled = true
key =
url = https://www.transifex.com/mod-organizer-2-team/mod-organizer-2/
key =
team = mod-organizer-2-team
project = mod-organizer-2
url = https://www.transifex.com
minimum = 60
[prebuilt]
+137 -3
View File
@@ -9,6 +9,10 @@
namespace mob
{
// in main.cpp
void set_sigint_handler();
std::string version()
{
return "mob 4.0";
@@ -219,6 +223,9 @@ int command::run()
return r;
}
if (flags_ & handle_sigint)
set_sigint_handler();
const auto r = do_run();
if (code_)
@@ -362,7 +369,7 @@ std::string options_command::do_doc()
build_command::build_command()
: command(requires_options)
: command(flags(requires_options | handle_sigint))
{
}
@@ -1368,6 +1375,18 @@ clipp::group tx_command::do_group()
(clipp::value("path") >> path_)
% "path that will contain the .tx directory"
)
|
"build" %
(clipp::command("build").set(mode_, modes::build),
(clipp::value("source") >> path_)
% "path that contains the translation directories",
(clipp::value("destination") >> dest_)
% "path that will contain the .qm files"
)
);
}
@@ -1379,6 +1398,10 @@ int tx_command::do_run()
do_get();
break;
case modes::build:
do_build();
break;
case modes::none:
default:
u8cerr << "bad tx mode " << static_cast<int>(mode_) << "\n";
@@ -1397,7 +1420,12 @@ std::string tx_command::do_doc()
"Commands:\n"
"get\n"
" Initializes a Transifex project in the given directory if\n"
" necessary and pulls all the translation files.";
" necessary and pulls all the translation files.\n"
"\n"
"build\n"
" Builds all .qm files. The path can either be the transifex\n"
" project (where .tx is) or the `translations` directory (where the\n"
" individual translation directories are).";
}
void tx_command::do_get()
@@ -1421,7 +1449,12 @@ void tx_command::do_get()
key_ = conf::get_global("transifex", "key");
if (url_.empty())
url_ = conf::get_global("transifex", "url");
{
url_ =
conf::get_global("transifex", "url") + "/" +
conf::get_global("transifex", "team") + "/" +
conf::get_global("transifex", "project");
}
if (key_.empty() && !this_env::get_opt("TX_TOKEN"))
{
@@ -1456,4 +1489,105 @@ void tx_command::do_get()
.run(cxcopy);
}
void tx_command::do_build()
{
fs::path root = path_;
if (fs::exists(root / ".tx") && fs::exists(root / "translations"))
root = root / "translations";
fs::path dest = dest_;
op::create_directories(gcx(), dest, op::unsafe);
std::set<fs::path> warned;
for (auto e : fs::directory_iterator(root))
{
if (!e.is_directory())
continue;
const auto dir = path_to_utf8(e.path().filename());
const auto dir_cs = split(dir, ".");
if (dir_cs.size() != 2)
{
u8cerr << "bad directory name '" << dir << "'; skipping\n";
continue;
}
const auto project = trim_copy(dir_cs[1]);
if (project.empty())
{
u8cerr << "bad directory name '" << dir << "'; skipping\n";
continue;
}
u8cout << project << "\n";
const bool is_gamebryo_plugin = [&]
{
auto tasks = find_tasks(project);
if (tasks.empty())
{
u8cerr
<< "directory '" << dir << "' was parsed as project "
<< "'" << project << "', but there's no task with this "
<< "name\n";
return false;
}
const task& t = *tasks[0];
if (!t.is_super())
return false;
const auto& mo_task = static_cast<const modorganizer&>(t);
return mo_task.is_gamebryo_plugin();
}();
const fs::path gamebryo_dir =
conf::get_global("transifex", "project") + "." +
"game_gamebryo";
for (auto f : fs::directory_iterator(e.path()))
{
if (!f.is_regular_file())
continue;
lrelease lr;
lr
.project(project)
.add_source(f.path())
.out(dest_);
if (is_gamebryo_plugin)
{
const auto gb_f = root / gamebryo_dir / f.path().filename();
if (fs::exists(gb_f))
{
lr.add_source(gb_f);
}
else
{
if (!warned.contains(gb_f))
{
u8cerr
<< "this is a gamebryo plugin but there is no "
<< "'" << path_to_utf8(gb_f) << "'; "
<< "the .qm file will be missing some "
<< "translations (will only warn once)\n";
warned.insert(gb_f);
}
}
}
context cxcopy = gcx();
lr.run(cxcopy);
}
}
}
} // namespace
+5 -1
View File
@@ -50,6 +50,7 @@ protected:
{
noflags = 0x00,
requires_options = 0x01,
handle_sigint = 0x02
};
bool picked_;
@@ -293,7 +294,8 @@ private:
enum class modes
{
none = 0,
get
get,
build
};
modes mode_ = modes::none;
@@ -302,8 +304,10 @@ private:
std::string url_;
bool force_ = false;
std::string path_;
std::string dest_;
void do_get();
void do_build();
};
} // namespace
+59 -46
View File
@@ -113,59 +113,68 @@ void add_tasks()
.add_task<licenses>()
.add_task<explorerpp>();
add_task<parallel_tasks>(true)
.add_task<modorganizer>("cmake_common")
.add_task<modorganizer>("modorganizer-uibase");
using mo = modorganizer;
// most of the alternate names below are from the transifex slugs, which
// are sometimes different from the project names, for whatever reason
add_task<parallel_tasks>(true)
.add_task<modorganizer>("modorganizer-game_features")
.add_task<modorganizer>("modorganizer-archive")
.add_task<modorganizer>("modorganizer-lootcli")
.add_task<modorganizer>("modorganizer-esptk")
.add_task<modorganizer>("modorganizer-bsatk")
.add_task<modorganizer>("modorganizer-nxmhandler")
.add_task<modorganizer>("modorganizer-helper")
.add_task<modorganizer>("githubpp")
.add_task<modorganizer>("modorganizer-game_gamebryo")
.add_task<modorganizer>("modorganizer-bsapacker")
.add_task<modorganizer>("modorganizer-preview_bsa");
.add_task<mo>("cmake_common")
.add_task<mo>("modorganizer-uibase");
add_task<parallel_tasks>(true)
.add_task<modorganizer>("modorganizer-game_oblivion")
.add_task<modorganizer>("modorganizer-game_fallout3")
.add_task<modorganizer>("modorganizer-game_fallout4")
.add_task<modorganizer>("modorganizer-game_fallout4vr")
.add_task<modorganizer>("modorganizer-game_falloutnv")
.add_task<modorganizer>("modorganizer-game_morrowind")
.add_task<modorganizer>("modorganizer-game_skyrim")
.add_task<modorganizer>("modorganizer-game_skyrimse")
.add_task<modorganizer>("modorganizer-game_skyrimvr")
.add_task<modorganizer>("modorganizer-game_ttw")
.add_task<modorganizer>("modorganizer-game_enderal");
.add_task<mo>("modorganizer-game_features")
.add_task<mo>("modorganizer-archive")
.add_task<mo>("modorganizer-lootcli")
.add_task<mo>("modorganizer-esptk")
.add_task<mo>("modorganizer-bsatk")
.add_task<mo>("modorganizer-nxmhandler")
.add_task<mo>("modorganizer-helper")
.add_task<mo>("githubpp")
.add_task<mo>("modorganizer-game_gamebryo")
.add_task<mo>({"modorganizer-bsapacker", "bsa_packer"})
.add_task<mo>("modorganizer-preview_bsa");
add_task<parallel_tasks>(true)
.add_task<modorganizer>("modorganizer-tool_inieditor")
.add_task<modorganizer>("modorganizer-tool_inibakery")
.add_task<modorganizer>("modorganizer-preview_base")
.add_task<modorganizer>("modorganizer-diagnose_basic")
.add_task<modorganizer>("modorganizer-check_fnis")
.add_task<modorganizer>("modorganizer-installer_bain")
.add_task<modorganizer>("modorganizer-installer_manual")
.add_task<modorganizer>("modorganizer-installer_bundle")
.add_task<modorganizer>("modorganizer-installer_quick")
.add_task<modorganizer>("modorganizer-installer_fomod")
.add_task<modorganizer>("modorganizer-installer_fomod_csharp")
.add_task<modorganizer>("modorganizer-installer_ncc")
.add_task<modorganizer>("modorganizer-bsa_extractor")
.add_task<modorganizer>("modorganizer-plugin_python");
.add_task<mo>("modorganizer-game_oblivion", mo::gamebryo)
.add_task<mo>("modorganizer-game_fallout3", mo::gamebryo)
.add_task<mo>("modorganizer-game_fallout4", mo::gamebryo)
.add_task<mo>("modorganizer-game_fallout4vr", mo::gamebryo)
.add_task<mo>("modorganizer-game_falloutnv", mo::gamebryo)
.add_task<mo>("modorganizer-game_morrowind", mo::gamebryo)
.add_task<mo>("modorganizer-game_skyrim", mo::gamebryo)
.add_task<mo>("modorganizer-game_skyrimse", mo::gamebryo)
.add_task<mo>("modorganizer-game_skyrimvr", mo::gamebryo)
.add_task<mo>("modorganizer-game_ttw", mo::gamebryo)
.add_task<mo>("modorganizer-game_enderal", mo::gamebryo);
add_task<parallel_tasks>(true)
.add_task<modorganizer>("modorganizer-tool_configurator")
.add_task<modorganizer>("modorganizer-fnistool")
.add_task<modorganizer>("modorganizer-script_extender_plugin_checker")
.add_task<modorganizer>("modorganizer-form43_checker")
.add_task<modorganizer>("modorganizer-preview_dds")
.add_task<modorganizer>("modorganizer");
.add_task<mo>({"modorganizer-tool_inieditor", "inieditor"})
.add_task<mo>("modorganizer-tool_inibakery")
.add_task<mo>("modorganizer-preview_base")
.add_task<mo>("modorganizer-diagnose_basic")
.add_task<mo>("modorganizer-check_fnis")
.add_task<mo>("modorganizer-installer_bain")
.add_task<mo>("modorganizer-installer_manual")
.add_task<mo>("modorganizer-installer_bundle")
.add_task<mo>("modorganizer-installer_quick")
.add_task<mo>("modorganizer-installer_fomod")
.add_task<mo>("modorganizer-installer_fomod_csharp")
.add_task<mo>("modorganizer-installer_ncc")
.add_task<mo>("modorganizer-bsa_extractor")
.add_task<mo>("modorganizer-plugin_python");
add_task<parallel_tasks>(true)
.add_task<mo>({"modorganizer-tool_configurator", "pycfg"})
.add_task<mo>("modorganizer-fnistool")
.add_task<mo>({
"modorganizer-script_extender_plugin_checker",
"diagnose-script_extender_plugin_checker",
})
.add_task<mo>({"modorganizer-form43_checker", "form43checker"})
.add_task<mo>({"modorganizer-preview_dds", "ddspreview"})
.add_task<mo>({"modorganizer", "organizer"});
}
@@ -211,6 +220,11 @@ private:
bool restore_;
};
void set_sigint_handler()
{
::SetConsoleCtrlHandler(mob::signal_handler, TRUE);
}
int run(const std::vector<std::string>& args)
{
@@ -240,7 +254,6 @@ int wmain(int argc, wchar_t** argv)
{
mob::set_std_streams();
mob::set_thread_exception_handlers();
::SetConsoleCtrlHandler(mob::signal_handler, TRUE);
std::vector<std::string> args;
for (int i=1; i<argc; ++i)
+19 -4
View File
@@ -17,11 +17,21 @@ std::string make_short_name(const std::string& name)
}
modorganizer::modorganizer(std::string long_name)
: basic_task(make_short_name(long_name)), repo_(long_name)
modorganizer::modorganizer(std::string long_name, flags f)
: modorganizer(std::vector<std::string>{long_name}, f)
{
if (long_name != name())
add_name(long_name);
}
modorganizer::modorganizer(std::vector<const char*> names, flags f)
: modorganizer(std::vector<std::string>(names.begin(), names.end()), f)
{
}
modorganizer::modorganizer(std::vector<std::string> names, flags f)
: basic_task(make_short_name(names[0])), repo_(names[0]), flags_(f)
{
for (auto&& n : names)
add_name(std::move(n));
}
std::string modorganizer::version()
@@ -39,6 +49,11 @@ bool modorganizer::is_super() const
return true;
}
bool modorganizer::is_gamebryo_plugin() const
{
return is_set(flags_, gamebryo);
}
fs::path modorganizer::source_path()
{
return {};
+4
View File
@@ -330,6 +330,10 @@ const context& task::cx() const
void task::add_name(std::string s)
{
auto itor = std::find(names_.begin(), names_.end(), s);
if (itor != names_.end())
return;
names_.push_back(s);
}
+9
View File
@@ -213,6 +213,15 @@ public:
return *this;
}
template <class Task, class T, class... Args>
parallel_tasks& add_task(std::initializer_list<T> il, Args&&... args)
{
children_.push_back(
std::make_unique<Task>(std::move(il), std::forward<Args>(args)...));
return *this;
}
fs::path get_source_path() const override
{
return {};
+11 -1
View File
@@ -276,7 +276,15 @@ private:
class modorganizer : public basic_task<modorganizer>
{
public:
modorganizer(std::string name);
enum flags
{
noflags = 0x00,
gamebryo = 0x01
};
modorganizer(std::string name, flags f=noflags);
modorganizer(std::vector<std::string> names, flags f=noflags);
modorganizer(std::vector<const char*> names, flags f=noflags);
static std::string version();
static bool prebuilt();
@@ -288,6 +296,7 @@ public:
const fs::path& root, cmake::ops o=cmake::generate);
bool is_super() const override;
bool is_gamebryo_plugin() const;
protected:
void do_clean(clean c) override;
@@ -296,6 +305,7 @@ protected:
private:
std::string repo_;
flags flags_;
cmake create_this_cmake_tool(cmake::ops o=cmake::generate);
msbuild create_this_msbuild_tool(msbuild::ops o=msbuild::build);
+69
View File
@@ -384,4 +384,73 @@ void transifex::do_pull()
execute_and_join();
}
lrelease::lrelease()
: basic_process_runner("lrelease")
{
}
fs::path lrelease::binary()
{
return conf::path_by_name("qt_bin") / conf::tool_by_name("lrelease");
}
lrelease& lrelease::project(const std::string& name)
{
project_ = name;
return *this;
}
lrelease& lrelease::add_source(const fs::path& ts_file)
{
sources_.push_back(ts_file);
return *this;
}
lrelease& lrelease::out(const fs::path& dir)
{
out_ = dir;
return *this;
}
fs::path lrelease::qm_file() const
{
if (sources_.empty())
cx().bail_out(context::generic, "lrelease: no sources");
const auto lang = trim_copy(path_to_utf8(sources_[0].stem()));
if (lang.empty())
{
cx().bail_out(context::generic,
"lrelease: bad file name '{}'", sources_[0]);
}
return project_ + "_" + lang + ".qm";
}
void lrelease::do_run()
{
const auto qm = qm_file();
process_ = process()
.binary(binary())
.arg("-silent")
.stderr_filter([](auto&& f)
{
if (f.line.find("dropping duplicate") != -1)
f.lv = context::level::debug;
else if (f.line.find("try -verbose") != -1)
f.lv = context::level::debug;
});
for (auto&& s : sources_)
process_.arg(s);
process_
.arg("-qm", (out_ / qm));
execute_and_join();
}
} // namespace
+23
View File
@@ -598,4 +598,27 @@ private:
void do_pull();
};
class lrelease : public basic_process_runner
{
public:
static fs::path binary();
lrelease();
lrelease& project(const std::string& name);
lrelease& add_source(const fs::path& ts_file);
lrelease& out(const fs::path& dir);
fs::path qm_file() const;
protected:
void do_run() override;
private:
std::string project_;
std::vector<fs::path> sources_;
fs::path out_;
};
} // namespace
+10 -1
View File
@@ -322,7 +322,16 @@ bool glob_match(const std::string& pattern, const std::string& s)
{
try
{
return std::regex_match(s, std::regex(replace_all(pattern, "*", ".*")));
std::string fixed_pattern = pattern;
fixed_pattern = replace_all(fixed_pattern, "*", ".*");
fixed_pattern = replace_all(fixed_pattern, "_", "-");
std::string fixed_string = s;
fixed_string = replace_all(fixed_string, "_", "-");
std::regex re(fixed_pattern, std::regex::icase);
return std::regex_match(fixed_string, re);
}
catch(std::exception&)
{
+3
View File
@@ -310,6 +310,9 @@ url make_prebuilt_url(const std::string& filename);
url make_appveyor_artifact_url(
arch a, const std::string& project, const std::string& filename);
// case insensitive, underscores and dashes are equivalent; gets converted to
// a regex where * becomes .*
//
bool glob_match(const std::string& pattern, const std::string& s);
std::string replace_all(