mirror of
https://github.com/ModOrganizer2/modorganizer.git
synced 2026-07-27 13:58:24 -07:00
handles changes in lootcli for a more formal communication protocol
This commit is contained in:
@@ -569,11 +569,13 @@ INCLUDE_DIRECTORIES(${project_path}/uibase/src
|
||||
${project_path}/bsatk/src
|
||||
${project_path}/esptk/src
|
||||
${project_path}/archive/src
|
||||
${project_path}/lootcli/include
|
||||
${dependency_project_path}/usvfs/include
|
||||
${project_path}/game_gamebryo/src/gamebryo
|
||||
${project_path}/game_gamebryo/src/creation
|
||||
${project_path}/game_features/src
|
||||
${project_path}/githubpp/src
|
||||
${SPDLOG_ROOT}/include
|
||||
${LZ4_ROOT}/lib)
|
||||
|
||||
INCLUDE_DIRECTORIES(shared ${ZLIB_INCLUDE_DIRS})
|
||||
|
||||
+88
-37
@@ -22,20 +22,16 @@ public:
|
||||
|
||||
QObject::connect(
|
||||
&m_loot, &Loot::progress,
|
||||
this, [&](auto&& s){ setText(s); }, Qt::QueuedConnection);
|
||||
this, [&](auto&& p){ setProgress(p); }, Qt::QueuedConnection);
|
||||
|
||||
QObject::connect(
|
||||
&m_loot, &Loot::log, this,
|
||||
[&](auto&& lv, auto&& s){ log(lv, s); }, Qt::QueuedConnection);
|
||||
|
||||
QObject::connect(
|
||||
&m_loot, &Loot::information, this,
|
||||
[&](auto&& mod, auto&& i){ setInfo(mod, i); }, Qt::QueuedConnection);
|
||||
|
||||
QObject::connect(
|
||||
&m_loot, &Loot::errorMessage, this,
|
||||
[&](auto&& s){ onErrorMessage(s); }, Qt::QueuedConnection);
|
||||
|
||||
QObject::connect(
|
||||
&m_loot, &Loot::error, this,
|
||||
[&](auto&& s){ onError(s); }, Qt::QueuedConnection);
|
||||
|
||||
QObject::connect(
|
||||
&m_loot, &Loot::finished, this,
|
||||
[&]{ onFinished(); }, Qt::QueuedConnection);
|
||||
@@ -46,6 +42,29 @@ public:
|
||||
m_label->setText(s);
|
||||
}
|
||||
|
||||
void setProgress(lootcli::Progress p)
|
||||
{
|
||||
setText(progressToString(p));
|
||||
}
|
||||
|
||||
QString progressToString(lootcli::Progress p)
|
||||
{
|
||||
using P = lootcli::Progress;
|
||||
|
||||
switch (p)
|
||||
{
|
||||
case P::CheckingMasterlistExistence: return tr("Checking masterlist existence");
|
||||
case P::UpdatingMasterlist: return tr("Updating masterlist");
|
||||
case P::LoadingLists: return tr("Loading lists");
|
||||
case P::ReadingPlugins: return tr("Reading plugins");
|
||||
case P::SortingPlugins: return tr("Sorting plugins");
|
||||
case P::WritingLoadorder: return tr("Writing loadorder.txt");
|
||||
case P::ParsingLootMessages: return tr("Parsing loot messages");
|
||||
case P::Done: return tr("Done");
|
||||
default: return QString("unknown progress %1").arg(static_cast<int>(p));
|
||||
}
|
||||
}
|
||||
|
||||
void setIndeterminate()
|
||||
{
|
||||
m_progress->setMaximum(0);
|
||||
@@ -153,10 +172,6 @@ private:
|
||||
|
||||
void addLineOutput(const QString& line)
|
||||
{
|
||||
if (line == m_lastLine) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_output->appendPlainText(line);
|
||||
m_lastLine = line;
|
||||
}
|
||||
@@ -164,12 +179,19 @@ private:
|
||||
void onFinished()
|
||||
{
|
||||
m_finished = true;
|
||||
close();
|
||||
}
|
||||
|
||||
void onErrorMessage(const QString& s)
|
||||
void log(log::Levels lv, const QString& s)
|
||||
{
|
||||
m_errorMessages += s;
|
||||
if (lv == log::Levels::Error) {
|
||||
MOBase::log::error("{}", s);
|
||||
|
||||
if (!m_errorMessages.isEmpty()) {
|
||||
m_errorMessages += "\n";
|
||||
}
|
||||
|
||||
m_errorMessages += s;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -235,7 +257,7 @@ bool Loot::start(QWidget* parent, OrganizerCore& core, bool didUpdateMasterList)
|
||||
|
||||
HANDLE lootHandle = spawn::startBinary(parent, sp);
|
||||
if (lootHandle == INVALID_HANDLE_VALUE) {
|
||||
emit error(tr("failed to start loot"));
|
||||
emit log(log::Levels::Error, tr("failed to start loot"));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -275,7 +297,7 @@ void Loot::lootThread()
|
||||
m_result = true;
|
||||
processOutputFile();
|
||||
} catch (const std::exception &e) {
|
||||
emit error(tr("failed to run loot: %1").arg(e.what()));
|
||||
emit log(log::Levels::Error, tr("failed to run loot: %1").arg(e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,7 +338,7 @@ bool Loot::waitForCompletion()
|
||||
}
|
||||
|
||||
if (exitCode != 0UL) {
|
||||
emit error(tr("Loot failed. Exit code was: %1").arg(exitCode));
|
||||
emit log(log::Levels::Error, tr("Loot failed. Exit code was: %1").arg(exitCode));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -350,40 +372,69 @@ void Loot::processStdout(const std::string &lootOut)
|
||||
{
|
||||
emit output(QString::fromStdString(lootOut));
|
||||
|
||||
std::vector<std::string> lines;
|
||||
boost::split(lines, lootOut, boost::is_any_of("\r\n"));
|
||||
m_outputBuffer += lootOut;
|
||||
std::size_t start = 0;
|
||||
|
||||
std::regex exRequires("\"([^\"]*)\" requires \"([^\"]*)\", but it is missing\\.");
|
||||
std::regex exIncompatible("\"([^\"]*)\" is incompatible with \"([^\"]*)\", but both are present\\.");
|
||||
for (;;) {
|
||||
const auto newline = m_outputBuffer.find("\n", start);
|
||||
if (newline == std::string::npos) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (const std::string &line : lines) {
|
||||
if (line.length() > 0) {
|
||||
size_t progidx = line.find("[progress]");
|
||||
size_t erroridx = line.find("[error]");
|
||||
if (progidx != std::string::npos) {
|
||||
emit progress(line.substr(progidx + 11).c_str());
|
||||
} else if (erroridx != std::string::npos) {
|
||||
log::warn("{}", line);
|
||||
emit errorMessage(QString::fromStdString(
|
||||
boost::algorithm::trim_copy(line.substr(erroridx + 8)) + "\n"));
|
||||
} else {
|
||||
const std::string_view line(m_outputBuffer.c_str() + start, newline - start);
|
||||
const auto m = lootcli::parseMessage(line);
|
||||
|
||||
if (m.type == lootcli::MessageType::None) {
|
||||
log::error("unrecognised loot output: '{}'", line);
|
||||
continue;
|
||||
}
|
||||
|
||||
processMessage(m);
|
||||
|
||||
start = newline + 1;
|
||||
}
|
||||
|
||||
m_outputBuffer.erase(0, start);
|
||||
}
|
||||
|
||||
void Loot::processMessage(const lootcli::Message& m)
|
||||
{
|
||||
static const std::regex exRequires("\"([^\"]*)\" requires \"([^\"]*)\", but it is missing\\.");
|
||||
static const std::regex exIncompatible("\"([^\"]*)\" is incompatible with \"([^\"]*)\", but both are present\\.");
|
||||
|
||||
switch (m.type)
|
||||
{
|
||||
case lootcli::MessageType::Log:
|
||||
{
|
||||
if (m.logLevel == spdlog::level::err) {
|
||||
std::smatch match;
|
||||
if (std::regex_match(line, match, exRequires)) {
|
||||
|
||||
if (std::regex_match(m.log, match, exRequires)) {
|
||||
std::string modName(match[1].first, match[1].second);
|
||||
std::string dependency(match[2].first, match[2].second);
|
||||
emit information(
|
||||
QString::fromStdString(modName),
|
||||
tr("depends on missing \"%1\"").arg(dependency.c_str()));
|
||||
} else if (std::regex_match(line, match, exIncompatible)) {
|
||||
} else if (std::regex_match(m.log, match, exIncompatible)) {
|
||||
std::string modName(match[1].first, match[1].second);
|
||||
std::string dependency(match[2].first, match[2].second);
|
||||
emit information(
|
||||
QString::fromStdString(modName),
|
||||
tr("incompatible with \"%1\"").arg(dependency.c_str()));
|
||||
} else {
|
||||
log::debug("[loot] {}", line);
|
||||
emit log(log::levelFromSpdlog(m.logLevel), QString::fromStdString(m.log));
|
||||
}
|
||||
} else {
|
||||
emit log(log::levelFromSpdlog(m.logLevel), QString::fromStdString(m.log));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case lootcli::MessageType::Progress:
|
||||
{
|
||||
emit progress(m.progress);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-3
@@ -3,9 +3,13 @@
|
||||
|
||||
#include "envmodule.h"
|
||||
#include <log.h>
|
||||
#include <lootcli/lootcli.h>
|
||||
#include <windows.h>
|
||||
#include <QWidget>
|
||||
|
||||
Q_DECLARE_METATYPE(lootcli::Progress);
|
||||
Q_DECLARE_METATYPE(MOBase::log::Levels);
|
||||
|
||||
class OrganizerCore;
|
||||
|
||||
class Loot : public QObject
|
||||
@@ -22,10 +26,9 @@ public:
|
||||
|
||||
signals:
|
||||
void output(const QString& s);
|
||||
void progress(const QString& s);
|
||||
void progress(const lootcli::Progress p);
|
||||
void log(MOBase::log::Levels level, const QString& s);
|
||||
void information(const QString& mod, const QString& info);
|
||||
void errorMessage(const QString& s);
|
||||
void error(const QString& s);
|
||||
void finished();
|
||||
|
||||
private:
|
||||
@@ -35,12 +38,15 @@ private:
|
||||
QString m_outPath;
|
||||
env::HandlePtr m_lootProcess;
|
||||
env::HandlePtr m_stdout;
|
||||
std::string m_outputBuffer;
|
||||
|
||||
std::string readFromPipe();
|
||||
|
||||
void lootThread();
|
||||
bool waitForCompletion();
|
||||
|
||||
void processStdout(const std::string &lootOut);
|
||||
void processMessage(const lootcli::Message& m);
|
||||
|
||||
void processOutputFile();
|
||||
bool processOutputPlugin(const QJsonValue& pluginValue);
|
||||
|
||||
Reference in New Issue
Block a user