mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-21 22:24:07 +01:00
Handle plugin metadata errors better
This commit is contained in:
parent
d1bcede492
commit
cf9d0af105
3 changed files with 119 additions and 58 deletions
|
@ -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));
|
||||
}
|
||||
this->name = nameObj.toString();
|
||||
|
||||
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));
|
||||
}
|
||||
this->description = descrObj.toString();
|
||||
|
||||
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();
|
||||
|
||||
auto v = semver::from_string_noexcept(
|
||||
obj.value("version").toString().toStdString());
|
||||
if (v.has_value())
|
||||
{
|
||||
this->version = v.value();
|
||||
this->license = licenseObj.toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->invalidWhy.emplace_back("unable to parse version");
|
||||
this->valid = false;
|
||||
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 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->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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,31 +141,35 @@ void PluginsPage::rebuildContent()
|
|||
}
|
||||
pl->addRow("Commands", new QLabel(cmds));
|
||||
|
||||
QString enableOrDisableStr = "Enable";
|
||||
if (PluginController::isEnabled(codename))
|
||||
if (plugin->meta.isValid())
|
||||
{
|
||||
enableOrDisableStr = "Disable";
|
||||
}
|
||||
QString enableOrDisableStr = "Enable";
|
||||
if (PluginController::isEnabled(codename))
|
||||
{
|
||||
enableOrDisableStr = "Disable";
|
||||
}
|
||||
|
||||
auto *enableDisable = new QPushButton(enableOrDisableStr);
|
||||
QObject::connect(
|
||||
enableDisable, &QPushButton::pressed, [name = codename, this]() {
|
||||
std::vector<QString> val =
|
||||
getSettings()->enabledPlugins.getValue();
|
||||
if (PluginController::isEnabled(name))
|
||||
{
|
||||
val.erase(std::remove(val.begin(), val.end(), name),
|
||||
val.end());
|
||||
}
|
||||
else
|
||||
{
|
||||
val.push_back(name);
|
||||
}
|
||||
getSettings()->enabledPlugins.setValue(val);
|
||||
getApp()->plugins->reload(name);
|
||||
this->rebuildContent();
|
||||
});
|
||||
pl->addRow(enableDisable);
|
||||
auto *enableDisable = new QPushButton(enableOrDisableStr);
|
||||
QObject::connect(
|
||||
enableDisable, &QPushButton::pressed,
|
||||
[name = codename, this]() {
|
||||
std::vector<QString> val =
|
||||
getSettings()->enabledPlugins.getValue();
|
||||
if (PluginController::isEnabled(name))
|
||||
{
|
||||
val.erase(std::remove(val.begin(), val.end(), name),
|
||||
val.end());
|
||||
}
|
||||
else
|
||||
{
|
||||
val.push_back(name);
|
||||
}
|
||||
getSettings()->enabledPlugins.setValue(val);
|
||||
getApp()->plugins->reload(name);
|
||||
this->rebuildContent();
|
||||
});
|
||||
pl->addRow(enableDisable);
|
||||
}
|
||||
|
||||
auto *reload = new QPushButton("Reload");
|
||||
QObject::connect(reload, &QPushButton::pressed,
|
||||
|
|
Loading…
Reference in a new issue