Handle plugin metadata errors better

This commit is contained in:
Mm2PL 2023-02-14 11:44:52 +01:00
parent d1bcede492
commit cf9d0af105
3 changed files with 119 additions and 58 deletions

View file

@ -30,27 +30,42 @@ struct PluginMeta {
QString homepage;
std::vector<QString> tags;
bool valid{};
std::vector<QString> invalidWhy;
std::vector<QString> errors;
bool isValid() const
{
return this->errors.empty();
}
explicit PluginMeta(const QJsonObject &obj)
: homepage(obj.value("homepage").toString(""))
{
auto nameObj = obj.value("name");
if (!nameObj.isString())
if (nameObj.isString())
{
this->invalidWhy.emplace_back("name is not a string");
this->valid = false;
}
this->name = nameObj.toString();
}
else
{
auto type = QString::fromStdString(
std::string(magic_enum::enum_name(nameObj.type())));
this->errors.emplace_back(
QString("name is not a string (its type is %1)").arg(type));
}
auto descrObj = obj.value("description");
if (!descrObj.isString())
if (descrObj.isString())
{
this->invalidWhy.emplace_back("description is not a string");
this->valid = false;
}
this->description = descrObj.toString();
}
else
{
auto type = QString::fromStdString(
std::string(magic_enum::enum_name(descrObj.type())));
this->errors.emplace_back(
QString("description is not a string (its type is %1)")
.arg(type));
}
auto authorsObj = obj.value("authors");
if (authorsObj.isArray())
@ -61,42 +76,60 @@ struct PluginMeta {
const auto &t = authorsArr.at(i);
if (!t.isString())
{
this->invalidWhy.push_back(
this->errors.push_back(
QString(
"authors element #%1 is not a string (it is a %2)")
.arg(i)
.arg(QString::fromStdString(
std::string(magic_enum::enum_name(t.type())))));
this->valid = false;
return;
break;
}
this->authors.push_back(t.toString());
}
}
else
{
this->invalidWhy.emplace_back("authors is not an array");
this->valid = false;
auto type = QString::fromStdString(
std::string(magic_enum::enum_name(authorsObj.type())));
this->errors.emplace_back(
QString("authors is not an array (its type is %1)").arg(type));
}
auto licenseObj = obj.value("license");
if (!licenseObj.isString())
if (licenseObj.isString())
{
this->invalidWhy.emplace_back("license is not a string");
this->valid = false;
}
this->license = licenseObj.toString();
}
else
{
auto type = QString::fromStdString(
std::string(magic_enum::enum_name(licenseObj.type())));
this->errors.emplace_back(
QString("license is not a string (its type is %1)").arg(type));
}
auto v = semver::from_string_noexcept(
obj.value("version").toString().toStdString());
auto verObj = obj.value("version");
if (verObj.isString())
{
auto v =
semver::from_string_noexcept(verObj.toString().toStdString());
if (v.has_value())
{
this->version = v.value();
}
else
{
this->invalidWhy.emplace_back("unable to parse version");
this->valid = false;
this->errors.emplace_back(
"unable to parse version (use semver)");
this->version = semver::version(0, 0, 0);
}
}
else
{
auto type = QString::fromStdString(
std::string(magic_enum::enum_name(verObj.type())));
this->errors.emplace_back(
QString("version is not a string (its type is %1)").arg(type));
this->version = semver::version(0, 0, 0);
}
auto tagsObj = obj.value("tags");
@ -104,8 +137,10 @@ struct PluginMeta {
{
if (!tagsObj.isArray())
{
this->invalidWhy.emplace_back("tags is not an array");
this->valid = false;
auto type = QString::fromStdString(
std::string(magic_enum::enum_name(licenseObj.type())));
this->errors.emplace_back(
QString("tags is not an array (its type is %1)").arg(type));
return;
}
@ -115,12 +150,12 @@ struct PluginMeta {
const auto &t = tagsArr.at(i);
if (!t.isString())
{
this->invalidWhy.push_back(
QString("tags element #%1 is not a string (it is a %2)")
this->errors.push_back(
QString(
"tags element #%1 is not a string (its type is %2)")
.arg(i)
.arg(QString::fromStdString(
std::string(magic_enum::enum_name(t.type())))));
this->valid = false;
return;
}
this->tags.push_back(t.toString());

View file

@ -92,14 +92,17 @@ bool PluginController::tryLoadFromDir(const QDir &pluginDir)
}
auto meta = PluginMeta(doc.object());
if (!meta.invalidWhy.empty())
if (!meta.isValid())
{
qCDebug(chatterinoLua)
<< "Plugin from" << pluginDir << "is invalid because:";
for (const auto &why : meta.invalidWhy)
for (const auto &why : meta.errors)
{
qCDebug(chatterinoLua) << "- " << why;
}
auto plugin = std::make_unique<Plugin>(pluginDir.dirName(), nullptr,
meta, pluginDir);
this->plugins_.insert({pluginDir.dirName(), std::move(plugin)});
return false;
}
this->load(index, pluginDir, meta);

View file

@ -87,6 +87,25 @@ void PluginsPage::rebuildContent()
}
auto plgroup = layout.emplace<QGroupBox>(headerText);
auto pl = plgroup.setLayoutType<QFormLayout>();
if (!plugin->meta.isValid())
{
QString errors = "<ul>";
for (const auto &err : plugin->meta.errors)
{
errors += "<li>" + err.toHtmlEscaped() + "</li>";
}
errors += "</ul>";
auto *warningLabel = new QLabel(
"There were errors while loading metadata for this plugin:" +
errors);
warningLabel->setTextFormat(Qt::RichText);
warningLabel->setParent(this->dataFrame_);
warningLabel->setStyleSheet("color: #f00");
pl->addRow(warningLabel);
}
auto *descrText = new QLabel(plugin->meta.description);
descrText->setWordWrap(true);
descrText->setStyleSheet("color: #bbb");
@ -122,6 +141,8 @@ void PluginsPage::rebuildContent()
}
pl->addRow("Commands", new QLabel(cmds));
if (plugin->meta.isValid())
{
QString enableOrDisableStr = "Enable";
if (PluginController::isEnabled(codename))
{
@ -130,7 +151,8 @@ void PluginsPage::rebuildContent()
auto *enableDisable = new QPushButton(enableOrDisableStr);
QObject::connect(
enableDisable, &QPushButton::pressed, [name = codename, this]() {
enableDisable, &QPushButton::pressed,
[name = codename, this]() {
std::vector<QString> val =
getSettings()->enabledPlugins.getValue();
if (PluginController::isEnabled(name))
@ -147,6 +169,7 @@ void PluginsPage::rebuildContent()
this->rebuildContent();
});
pl->addRow(enableDisable);
}
auto *reload = new QPushButton("Reload");
QObject::connect(reload, &QPushButton::pressed,