mirror of
https://github.com/ModOrganizer2/mob.git
synced 2026-07-27 14:07:05 -07:00
tx command
added tx binary
This commit is contained in:
@@ -48,8 +48,15 @@ msbuild = msbuild.exe
|
||||
nuget = nuget.exe
|
||||
vswhere = vswhere.exe
|
||||
nasm = nasm.exe
|
||||
tx = tx.py37-x64.exe
|
||||
vcvars =
|
||||
|
||||
[transifex]
|
||||
enabled = true
|
||||
key =
|
||||
url = https://www.transifex.com/mod-organizer-2-team/mod-organizer-2/
|
||||
minimum = 60
|
||||
|
||||
[prebuilt]
|
||||
boost = true
|
||||
lz4 = true
|
||||
|
||||
+111
-10
@@ -1103,18 +1103,19 @@ std::string git_command::do_doc()
|
||||
"All the commands will go through all modorganizer repos, plus usvfs\n"
|
||||
"and NCC.\n"
|
||||
"\n"
|
||||
"Commands:\n"
|
||||
"set-remotes\n"
|
||||
"For each repo, this first sets the username and email. Then, it\n"
|
||||
"will rename the remote 'origin' to 'upstream' and create a new\n"
|
||||
"remote 'origin' with the given information. If the remote\n"
|
||||
"'upstream' already exists in a repo, nothing happens.\n"
|
||||
" For each repo, this first sets the username and email. Then, it\n"
|
||||
" will rename the remote 'origin' to 'upstream' and create a new\n"
|
||||
" remote 'origin' with the given information. If the remote\n"
|
||||
" 'upstream' already exists in a repo, nothing happens.\n"
|
||||
"\n"
|
||||
"add-remote\n"
|
||||
"For each repo, adds a new remote with the given information. If a\n"
|
||||
"remote with the same name already exists, nothing happens.\n"
|
||||
" For each repo, adds a new remote with the given information. If a\n"
|
||||
" remote with the same name already exists, nothing happens.\n"
|
||||
"\n"
|
||||
"ignore-ts\n"
|
||||
"Toggles the --assume-changed status of all .ts files in all repos.";
|
||||
" Toggles the --assume-changed status of all .ts files in all repos.";
|
||||
}
|
||||
|
||||
void git_command::do_set_remotes()
|
||||
@@ -1325,6 +1326,10 @@ std::string inis_command::do_doc()
|
||||
}
|
||||
|
||||
|
||||
tx_command::tx_command()
|
||||
: command(requires_options)
|
||||
{
|
||||
}
|
||||
|
||||
command::meta_t tx_command::meta() const
|
||||
{
|
||||
@@ -1341,18 +1346,114 @@ clipp::group tx_command::do_group()
|
||||
clipp::command("tx").set(picked_),
|
||||
|
||||
(clipp::option("-h", "--help") >> help_)
|
||||
% ("shows this message")
|
||||
% ("shows this message"),
|
||||
|
||||
"get" %
|
||||
(clipp::command("get").set(mode_, modes::get),
|
||||
(clipp::option("-m", "--minimum")
|
||||
& clipp::value("PERCENT") >> min_)
|
||||
% "minimum translation threshold to download [0-100]",
|
||||
|
||||
(clipp::option("-k", "--key")
|
||||
& clipp::value("APIKEY") >> key_)
|
||||
% "API key",
|
||||
|
||||
(clipp::option("-f", "--force").set(force_)
|
||||
% "don't check timestamps, re-download all translation files"),
|
||||
|
||||
(clipp::option("-u", "--url")
|
||||
& clipp::value("URL") >> url_)
|
||||
% "project URL",
|
||||
|
||||
(clipp::value("path") >> path_)
|
||||
% "path that will contain the .tx directory"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
int tx_command::do_run()
|
||||
{
|
||||
return prepare_options(true);
|
||||
switch (mode_)
|
||||
{
|
||||
case modes::get:
|
||||
do_get();
|
||||
break;
|
||||
|
||||
case modes::none:
|
||||
default:
|
||||
u8cerr << "bad tx mode " << static_cast<int>(mode_) << "\n";
|
||||
throw bailed();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string tx_command::do_doc()
|
||||
{
|
||||
return "";
|
||||
return
|
||||
"Values for --key, --minimum and --url will be taken from the INI\n"
|
||||
"file if not specified.\n"
|
||||
"\n"
|
||||
"Commands:\n"
|
||||
"get\n"
|
||||
" Initializes a Transifex project in the given directory if\n"
|
||||
" necessary and pulls all the translation files.";
|
||||
}
|
||||
|
||||
void tx_command::do_get()
|
||||
{
|
||||
if (min_ < 0)
|
||||
{
|
||||
const auto s = conf::get_global("transifex", "minimum");
|
||||
|
||||
try
|
||||
{
|
||||
min_ = std::stoi(s);
|
||||
}
|
||||
catch(std::exception&)
|
||||
{
|
||||
gcx().bail_out(context::generic,
|
||||
"bad transifex minimum percentage '{}'", s);
|
||||
}
|
||||
}
|
||||
|
||||
if (key_.empty())
|
||||
key_ = conf::get_global("transifex", "key");
|
||||
|
||||
if (url_.empty())
|
||||
url_ = conf::get_global("transifex", "url");
|
||||
|
||||
if (key_.empty() && !this_env::get_opt("TX_TOKEN"))
|
||||
{
|
||||
u8cout <<
|
||||
"(no key was in the INI, --key wasn't given and TX_TOKEN env\n"
|
||||
"variable doesn't exist, this will probably fail)\n\n";
|
||||
}
|
||||
|
||||
|
||||
context cxcopy = gcx();
|
||||
|
||||
u8cout << "initializing\n";
|
||||
transifex(transifex::init)
|
||||
.root(path_)
|
||||
.run(cxcopy);
|
||||
|
||||
u8cout << "configuring\n";
|
||||
transifex(transifex::config)
|
||||
.stdout_level(context::level::info)
|
||||
.root(path_)
|
||||
.api_key(key_)
|
||||
.url(url_)
|
||||
.run(cxcopy);
|
||||
|
||||
u8cout << "pulling\n";
|
||||
transifex(transifex::pull)
|
||||
.stdout_level(context::level::info)
|
||||
.root(path_)
|
||||
.api_key(key_)
|
||||
.minimum(min_)
|
||||
.force(force_)
|
||||
.run(cxcopy);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -281,12 +281,29 @@ protected:
|
||||
class tx_command : public command
|
||||
{
|
||||
public:
|
||||
tx_command();
|
||||
meta_t meta() const override;
|
||||
|
||||
protected:
|
||||
clipp::group do_group() override;
|
||||
int do_run() override;
|
||||
std::string do_doc() override;
|
||||
|
||||
private:
|
||||
enum class modes
|
||||
{
|
||||
none = 0,
|
||||
get
|
||||
};
|
||||
|
||||
modes mode_ = modes::none;
|
||||
int min_ = -1;
|
||||
std::string key_;
|
||||
std::string url_;
|
||||
bool force_ = false;
|
||||
std::string path_;
|
||||
|
||||
void do_get();
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
+4
-2
@@ -29,10 +29,12 @@ void touch(const context& cx, const fs::path& p)
|
||||
do_touch(cx ,p);
|
||||
}
|
||||
|
||||
void create_directories(const context& cx, const fs::path& p)
|
||||
void create_directories(const context& cx, const fs::path& p, flags f)
|
||||
{
|
||||
cx.trace(context::fs, "creating dir {}", p);
|
||||
check(cx, p);
|
||||
|
||||
if (!is_set(f, unsafe))
|
||||
check(cx, p);
|
||||
|
||||
if (!conf::dry())
|
||||
do_create_directories(cx, p);
|
||||
|
||||
@@ -22,7 +22,7 @@ MOB_ENUM_OPERATORS(flags);
|
||||
void touch(const context& cx, const fs::path& p);
|
||||
|
||||
void create_directories(
|
||||
const context& cx, const fs::path& p);
|
||||
const context& cx, const fs::path& p, flags f=noflags);
|
||||
|
||||
void delete_directory(
|
||||
const context& cx, const fs::path& p, flags f=noflags);
|
||||
|
||||
+25
-8
@@ -257,6 +257,7 @@ process::process() :
|
||||
cx_(&gcx()), unicode_(false), chcp_(-1), flags_(process::noflags),
|
||||
stdout_(context::level::trace), stderr_(context::level::error), code_(0)
|
||||
{
|
||||
success_.insert(0);
|
||||
}
|
||||
|
||||
process::~process()
|
||||
@@ -398,6 +399,12 @@ process::flags_t process::flags() const
|
||||
return flags_;
|
||||
}
|
||||
|
||||
process& process::success_exit_codes(std::set<int> v)
|
||||
{
|
||||
success_ = v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
process& process::env(const mob::env& e)
|
||||
{
|
||||
env_ = e;
|
||||
@@ -663,7 +670,9 @@ void process::read_pipe(
|
||||
return;
|
||||
}
|
||||
|
||||
cx_->log_string(f.r, f.lv, f.line);
|
||||
if (!is_set(flags_, ignore_output_on_success))
|
||||
cx_->log_string(f.r, f.lv, f.line);
|
||||
|
||||
logs_[f.lv].emplace_back(std::move(line));
|
||||
});
|
||||
|
||||
@@ -706,16 +715,23 @@ void process::on_completed()
|
||||
}
|
||||
|
||||
// success
|
||||
if (code_ == 0)
|
||||
if (success_.contains(static_cast<int>(code_)))
|
||||
{
|
||||
const bool ignore_output = is_set(flags_, ignore_output_on_success);
|
||||
const auto& warnings = logs_[context::level::warning];
|
||||
const auto& errors = logs_[context::level::error];
|
||||
|
||||
if (!warnings.empty() || !errors.empty())
|
||||
if (ignore_output || (warnings.empty() && errors.empty()))
|
||||
{
|
||||
cx_->trace(context::cmd,
|
||||
"process exit code is {} (considered success)", code_);
|
||||
}
|
||||
else
|
||||
{
|
||||
cx_->warning(
|
||||
context::cmd,
|
||||
"process exit code is 0, but stderr had something");
|
||||
"process exit code is {} (considered success), "
|
||||
"but stderr had something", code_);
|
||||
|
||||
cx_->warning(context::cmd, "process was: {}", make_cmd());
|
||||
cx_->warning(context::cmd, "stderr:");
|
||||
@@ -726,10 +742,6 @@ void process::on_completed()
|
||||
for (auto&& line : errors)
|
||||
cx_->warning(context::std_err, " {}", line);
|
||||
}
|
||||
else
|
||||
{
|
||||
cx_->trace(context::cmd, "process exit code is 0");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -940,6 +952,11 @@ std::string process::arg_to_string(const url& u, arg_flags f)
|
||||
return u.string();
|
||||
}
|
||||
|
||||
std::string process::arg_to_string(int i, arg_flags)
|
||||
{
|
||||
return std::to_string(i);
|
||||
}
|
||||
|
||||
|
||||
encoded_buffer::encoded_buffer(encodings e, std::string bytes)
|
||||
: e_(e), bytes_(std::move(bytes)), last_(0)
|
||||
|
||||
+8
-3
@@ -164,9 +164,10 @@ class process
|
||||
public:
|
||||
enum flags_t
|
||||
{
|
||||
noflags = 0x00,
|
||||
allow_failure = 0x01,
|
||||
terminate_on_interrupt = 0x02
|
||||
noflags = 0x00,
|
||||
allow_failure = 0x01,
|
||||
terminate_on_interrupt = 0x02,
|
||||
ignore_output_on_success = 0x04
|
||||
};
|
||||
|
||||
enum arg_flags
|
||||
@@ -261,6 +262,8 @@ public:
|
||||
process& flags(flags_t f);
|
||||
flags_t flags() const;
|
||||
|
||||
process& success_exit_codes(std::set<int> v);
|
||||
|
||||
template <class T, class=std::enable_if_t<!std::is_same_v<T, arg_flags>>>
|
||||
process& arg(const T& value, arg_flags f=noargflags)
|
||||
{
|
||||
@@ -338,6 +341,7 @@ private:
|
||||
bool unicode_;
|
||||
int chcp_;
|
||||
flags_t flags_;
|
||||
std::set<int> success_;
|
||||
stream stdout_;
|
||||
stream stderr_;
|
||||
mob::env env_;
|
||||
@@ -371,6 +375,7 @@ private:
|
||||
std::string arg_to_string(const std::string& s, arg_flags f);
|
||||
std::string arg_to_string(const fs::path& p, arg_flags f);
|
||||
std::string arg_to_string(const url& u, arg_flags f);
|
||||
std::string arg_to_string(int i, arg_flags f);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -256,4 +256,132 @@ void pip_install::do_run()
|
||||
execute_and_join();
|
||||
}
|
||||
|
||||
|
||||
transifex::transifex(ops o) :
|
||||
basic_process_runner("transifex"), op_(o),
|
||||
stdout_(context::level::trace), min_(100), force_(false)
|
||||
{
|
||||
}
|
||||
|
||||
fs::path transifex::binary()
|
||||
{
|
||||
return conf::tool_by_name("tx");
|
||||
}
|
||||
|
||||
transifex& transifex::root(const fs::path& p)
|
||||
{
|
||||
root_ = p;
|
||||
return *this;
|
||||
}
|
||||
|
||||
transifex& transifex::api_key(const std::string& key)
|
||||
{
|
||||
key_ = key;
|
||||
return *this;
|
||||
}
|
||||
|
||||
transifex& transifex::url(const mob::url& u)
|
||||
{
|
||||
url_ = u;
|
||||
return *this;
|
||||
}
|
||||
|
||||
transifex& transifex::minimum(int percent)
|
||||
{
|
||||
min_ = percent;
|
||||
return *this;
|
||||
}
|
||||
|
||||
transifex& transifex::stdout_level(context::level lv)
|
||||
{
|
||||
stdout_ = lv;
|
||||
return *this;
|
||||
}
|
||||
|
||||
transifex& transifex::force(bool b)
|
||||
{
|
||||
force_ = b;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void transifex::do_run()
|
||||
{
|
||||
switch (op_)
|
||||
{
|
||||
case init:
|
||||
do_init();
|
||||
break;
|
||||
|
||||
case config:
|
||||
do_config();
|
||||
break;
|
||||
|
||||
case pull:
|
||||
do_pull();
|
||||
break;
|
||||
|
||||
default:
|
||||
cx().bail_out(context::generic, "tx unknown op {}", op_);
|
||||
}
|
||||
}
|
||||
|
||||
void transifex::do_init()
|
||||
{
|
||||
op::create_directories(cx(), root_, op::unsafe);
|
||||
|
||||
// exit code is 2 when the directory already contains a .tx
|
||||
|
||||
process_ = process()
|
||||
.binary(binary())
|
||||
.success_exit_codes({0, 2})
|
||||
.flags(process::ignore_output_on_success)
|
||||
.arg("init")
|
||||
.arg("--no-interactive")
|
||||
.cwd(root_);
|
||||
|
||||
execute_and_join();
|
||||
}
|
||||
|
||||
void transifex::do_config()
|
||||
{
|
||||
if (url_.empty())
|
||||
cx().bail_out(context::generic, "missing transifex url");
|
||||
|
||||
op::create_directories(cx(), root_, op::unsafe);
|
||||
|
||||
process_ = process()
|
||||
.binary(binary())
|
||||
.stdout_level(stdout_)
|
||||
.arg("config")
|
||||
.arg("mapping-remote")
|
||||
.arg(url_)
|
||||
.env(this_env::get()
|
||||
.set("TX_TOKEN", key_))
|
||||
.cwd(root_);
|
||||
|
||||
execute_and_join();
|
||||
}
|
||||
|
||||
void transifex::do_pull()
|
||||
{
|
||||
op::create_directories(cx(), root_, op::unsafe);
|
||||
|
||||
process_ = process()
|
||||
.binary(binary())
|
||||
.stdout_level(stdout_)
|
||||
.arg("pull")
|
||||
.arg("--all")
|
||||
.arg("--parallel")
|
||||
.arg("--no-interactive")
|
||||
.arg("--minimum-perc", min_)
|
||||
.env(this_env::get()
|
||||
.set("TX_TOKEN", key_))
|
||||
.cwd(root_);
|
||||
|
||||
if (force_)
|
||||
process_.arg("--force");
|
||||
|
||||
execute_and_join();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -558,4 +558,44 @@ private:
|
||||
fs::path file_;
|
||||
};
|
||||
|
||||
|
||||
class transifex : public basic_process_runner
|
||||
{
|
||||
public:
|
||||
enum ops
|
||||
{
|
||||
init = 1,
|
||||
config,
|
||||
pull
|
||||
};
|
||||
|
||||
static fs::path binary();
|
||||
|
||||
|
||||
transifex(ops op);
|
||||
|
||||
transifex& root(const fs::path& p);
|
||||
transifex& api_key(const std::string& key);
|
||||
transifex& url(const mob::url& u);
|
||||
transifex& minimum(int percent);
|
||||
transifex& stdout_level(context::level lv);
|
||||
transifex& force(bool b);
|
||||
|
||||
protected:
|
||||
void do_run() override;
|
||||
|
||||
private:
|
||||
ops op_;
|
||||
context::level stdout_;
|
||||
fs::path root_;
|
||||
std::string key_;
|
||||
mob::url url_;
|
||||
int min_;
|
||||
bool force_;
|
||||
|
||||
void do_init();
|
||||
void do_config();
|
||||
void do_pull();
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
Vendored
BIN
Binary file not shown.
Reference in New Issue
Block a user