File indexing completed on 2024-05-19 15:46:01
0001 /* 0002 SPDX-FileCopyrightText: 2019 Daniel Mensinger <daniel@mensinger-ka.de> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "mesonoptions.h" 0008 0009 #include <debug.h> 0010 0011 #include <QHash> 0012 #include <QJsonArray> 0013 #include <QJsonObject> 0014 #include <QList> 0015 #include <QWidget> 0016 0017 #include <algorithm> 0018 #include <vector> 0019 0020 using namespace std; 0021 0022 static const QHash<QString, MesonOptionBase::Section> STRING2SECTION = { 0023 { QStringLiteral("core"), MesonOptionBase::CORE }, 0024 { QStringLiteral("backend"), MesonOptionBase::BACKEND }, 0025 { QStringLiteral("base"), MesonOptionBase::BASE }, 0026 { QStringLiteral("compiler"), MesonOptionBase::COMPILER }, 0027 { QStringLiteral("directory"), MesonOptionBase::DIRECTORY }, 0028 { QStringLiteral("user"), MesonOptionBase::USER }, 0029 { QStringLiteral("test"), MesonOptionBase::TEST }, 0030 }; 0031 0032 static const QHash<QString, MesonOptionBase::Type> STRING2TYPE = { 0033 { QStringLiteral("array"), MesonOptionBase::ARRAY }, { QStringLiteral("boolean"), MesonOptionBase::BOOLEAN }, 0034 { QStringLiteral("combo"), MesonOptionBase::COMBO }, { QStringLiteral("integer"), MesonOptionBase::INTEGER }, 0035 { QStringLiteral("string"), MesonOptionBase::STRING }, 0036 }; 0037 0038 MesonOptions::MesonOptions(const QJsonArray& arr) 0039 { 0040 fromJSON(arr); 0041 } 0042 0043 // Option constructors 0044 0045 MesonOptionBase::MesonOptionBase(const QString& name, const QString& description, MesonOptionBase::Section section) 0046 : m_name(name) 0047 , m_description(description) 0048 , m_section(section) 0049 { 0050 } 0051 0052 MesonOptionArray::MesonOptionArray(const QString& name, const QString& description, MesonOptionBase::Section section, 0053 QStringList value) 0054 : MesonOptionBase(name, description, section) 0055 , m_value(value) 0056 , m_initialValue(value) 0057 { 0058 } 0059 0060 MesonOptionBool::MesonOptionBool(const QString& name, const QString& description, MesonOptionBase::Section section, 0061 bool value) 0062 : MesonOptionBase(name, description, section) 0063 , m_value(value) 0064 , m_initialValue(value) 0065 { 0066 } 0067 0068 MesonOptionCombo::MesonOptionCombo(const QString& name, const QString& description, MesonOptionBase::Section section, 0069 QString value, QStringList choices) 0070 : MesonOptionBase(name, description, section) 0071 , m_value(value) 0072 , m_initialValue(value) 0073 , m_choices(choices) 0074 { 0075 } 0076 0077 MesonOptionInteger::MesonOptionInteger(const QString& name, const QString& description, 0078 MesonOptionBase::Section section, int value) 0079 : MesonOptionBase(name, description, section) 0080 , m_value(value) 0081 , m_initialValue(value) 0082 { 0083 } 0084 0085 MesonOptionString::MesonOptionString(const QString& name, const QString& description, MesonOptionBase::Section section, 0086 QString value) 0087 : MesonOptionBase(name, description, section) 0088 , m_value(value) 0089 , m_initialValue(value) 0090 { 0091 } 0092 0093 QStringList MesonOptionCombo::choices() const 0094 { 0095 return m_choices; 0096 } 0097 0098 // Type functions 0099 0100 MesonOptionBase::Type MesonOptionArray::type() const 0101 { 0102 return ARRAY; 0103 } 0104 0105 MesonOptionBase::Type MesonOptionBool::type() const 0106 { 0107 return BOOLEAN; 0108 } 0109 0110 MesonOptionBase::Type MesonOptionCombo::type() const 0111 { 0112 return COMBO; 0113 } 0114 0115 MesonOptionBase::Type MesonOptionInteger::type() const 0116 { 0117 return INTEGER; 0118 } 0119 0120 MesonOptionBase::Type MesonOptionString::type() const 0121 { 0122 return STRING; 0123 } 0124 0125 // Value functions 0126 0127 QString MesonOptionArray::value() const 0128 { 0129 QStringList tmp; 0130 tmp.reserve(m_value.size()); 0131 transform(begin(m_value), end(m_value), back_inserter(tmp), 0132 [](const QString& str) -> QString { return QStringLiteral("'") + str + QStringLiteral("'"); }); 0133 return QStringLiteral("[") + tmp.join(QStringLiteral(", ")) + QStringLiteral("]"); 0134 } 0135 0136 QString MesonOptionBool::value() const 0137 { 0138 return m_value ? QStringLiteral("true") : QStringLiteral("false"); 0139 } 0140 0141 QString MesonOptionCombo::value() const 0142 { 0143 return m_value; 0144 } 0145 0146 QString MesonOptionInteger::value() const 0147 { 0148 return QString::number(m_value); 0149 } 0150 0151 QString MesonOptionString::value() const 0152 { 0153 return m_value; 0154 } 0155 0156 // Initial value functions 0157 0158 QString MesonOptionArray::initialValue() const 0159 { 0160 QStringList tmp; 0161 tmp.reserve(m_initialValue.size()); 0162 transform(begin(m_initialValue), end(m_initialValue), back_inserter(tmp), 0163 [](const QString& str) -> QString { return QStringLiteral("'") + str + QStringLiteral("'"); }); 0164 return QStringLiteral("[") + tmp.join(QStringLiteral(", ")) + QStringLiteral("]"); 0165 } 0166 0167 QString MesonOptionBool::initialValue() const 0168 { 0169 return m_initialValue ? QStringLiteral("true") : QStringLiteral("false"); 0170 } 0171 0172 QString MesonOptionCombo::initialValue() const 0173 { 0174 return m_initialValue; 0175 } 0176 0177 QString MesonOptionInteger::initialValue() const 0178 { 0179 return QString::number(m_initialValue); 0180 } 0181 0182 QString MesonOptionString::initialValue() const 0183 { 0184 return m_initialValue; 0185 } 0186 0187 // Reset functions 0188 0189 void MesonOptionArray::reset() 0190 { 0191 m_value = m_initialValue; 0192 } 0193 0194 void MesonOptionBool::reset() 0195 { 0196 m_value = m_initialValue; 0197 } 0198 0199 void MesonOptionCombo::reset() 0200 { 0201 m_value = m_initialValue; 0202 } 0203 0204 void MesonOptionInteger::reset() 0205 { 0206 m_value = m_initialValue; 0207 } 0208 0209 void MesonOptionString::reset() 0210 { 0211 m_value = m_initialValue; 0212 } 0213 0214 // Raw value functions 0215 0216 QStringList MesonOptionArray::rawValue() const 0217 { 0218 return m_value; 0219 } 0220 0221 bool MesonOptionBool::rawValue() const 0222 { 0223 return m_value; 0224 } 0225 0226 QString MesonOptionCombo::rawValue() const 0227 { 0228 return m_value; 0229 } 0230 0231 int MesonOptionInteger::rawValue() const 0232 { 0233 return m_value; 0234 } 0235 0236 QString MesonOptionString::rawValue() const 0237 { 0238 return m_value; 0239 } 0240 0241 // Set value functions 0242 0243 void MesonOptionArray::setValue(const QStringList& val) 0244 { 0245 m_value = val; 0246 } 0247 0248 void MesonOptionBool::setValue(bool val) 0249 { 0250 m_value = val; 0251 } 0252 0253 void MesonOptionCombo::setValue(const QString& val) 0254 { 0255 m_value = val; 0256 } 0257 0258 void MesonOptionInteger::setValue(int val) 0259 { 0260 m_value = val; 0261 } 0262 0263 void MesonOptionString::setValue(const QString& val) 0264 { 0265 m_value = val; 0266 } 0267 0268 // Set value from string 0269 0270 void MesonOptionArray::setFromString(const QString& value) 0271 { 0272 setValue({ value }); 0273 } 0274 0275 void MesonOptionBool::setFromString(const QString& value) 0276 { 0277 setValue(value.toLower() == QLatin1String("true")); 0278 } 0279 0280 void MesonOptionCombo::setFromString(const QString& value) 0281 { 0282 setValue(value); 0283 } 0284 0285 void MesonOptionInteger::setFromString(const QString& value) 0286 { 0287 setValue(value.toInt()); 0288 } 0289 0290 void MesonOptionString::setFromString(const QString& value) 0291 { 0292 setValue(value); 0293 } 0294 0295 // Base option functions 0296 0297 MesonOptionBase::~MesonOptionBase() {} 0298 0299 QString MesonOptionBase::name() const 0300 { 0301 return m_name; 0302 } 0303 0304 QString MesonOptionBase::description() const 0305 { 0306 return m_description; 0307 } 0308 0309 MesonOptionBase::Section MesonOptionBase::section() const 0310 { 0311 return m_section; 0312 } 0313 0314 QString MesonOptionBase::mesonArg() const 0315 { 0316 return QStringLiteral("-D") + m_name + QStringLiteral("=") + value(); 0317 } 0318 0319 bool MesonOptionBase::isUpdated() const 0320 { 0321 return value() != initialValue(); 0322 } 0323 0324 MesonOptionPtr MesonOptionBase::fromJSON(const QJsonObject& obj) 0325 { 0326 auto nameJV = obj[QStringLiteral("name")]; 0327 auto descriptionJV = obj[QStringLiteral("description")]; 0328 auto sectionJV = obj[QStringLiteral("section")]; 0329 auto typeJV = obj[QStringLiteral("type")]; 0330 auto valueJV = obj[QStringLiteral("value")]; 0331 0332 // Check all values 0333 for (const auto& i : { nameJV, descriptionJV, sectionJV, typeJV }) { 0334 if (!i.isString()) { 0335 qCWarning(KDEV_Meson) << "OPT: Base type validation failed" << typeJV.toString(); 0336 return nullptr; 0337 } 0338 } 0339 0340 // Work around meson bug https://github.com/mesonbuild/meson/pull/5646 by 0341 // removing the first space and everything after that. 0342 QString sectionStr = sectionJV.toString(); 0343 int spacePos = sectionStr.indexOf(QLatin1Char(' ')); 0344 if (spacePos > 0) { 0345 sectionStr = sectionStr.left(spacePos); 0346 } 0347 0348 auto sectionIter = STRING2SECTION.find(sectionStr); 0349 auto typeIter = STRING2TYPE.find(typeJV.toString()); 0350 0351 if (sectionIter == end(STRING2SECTION) || typeIter == end(STRING2TYPE)) { 0352 qCWarning(KDEV_Meson) << "OPT: Unknown type or section " << typeJV.toString() << " / " << sectionJV.toString(); 0353 return nullptr; 0354 } 0355 0356 Section section = *sectionIter; 0357 Type type = *typeIter; 0358 QString name = nameJV.toString(); 0359 QString description = descriptionJV.toString(); 0360 0361 switch (type) { 0362 case ARRAY: { 0363 if (!valueJV.isArray()) { 0364 return nullptr; 0365 } 0366 0367 QJsonArray raw = valueJV.toArray(); 0368 QStringList values; 0369 values.reserve(raw.size()); 0370 transform(begin(raw), end(raw), back_inserter(values), [](const QJsonValue& v) { return v.toString(); }); 0371 return make_shared<MesonOptionArray>(name, description, section, values); 0372 } 0373 0374 case BOOLEAN: 0375 if (!valueJV.isBool()) { 0376 return nullptr; 0377 } 0378 return make_shared<MesonOptionBool>(name, description, section, valueJV.toBool()); 0379 0380 case COMBO: { 0381 auto choicesJV = obj[QStringLiteral("choices")]; 0382 if (!valueJV.isString() || !choicesJV.isArray()) { 0383 return nullptr; 0384 } 0385 0386 QJsonArray raw = choicesJV.toArray(); 0387 QStringList choices; 0388 choices.reserve(raw.size()); 0389 transform(begin(raw), end(raw), back_inserter(choices), [](const QJsonValue& v) { return v.toString(); }); 0390 return make_shared<MesonOptionCombo>(name, description, section, valueJV.toString(), choices); 0391 } 0392 0393 case INTEGER: 0394 if (!valueJV.isDouble()) { 0395 return nullptr; 0396 } 0397 return make_shared<MesonOptionInteger>(name, description, section, valueJV.toInt()); 0398 0399 case STRING: 0400 if (!valueJV.isString()) { 0401 return nullptr; 0402 } 0403 return make_shared<MesonOptionString>(name, description, section, valueJV.toString()); 0404 } 0405 0406 qCWarning(KDEV_Meson) << "OPT: Unknown type " << typeJV.toString(); 0407 return nullptr; 0408 } 0409 0410 int MesonOptions::numChanged() const 0411 { 0412 int sum = 0; 0413 for (auto i : m_options) { 0414 if (i && i->isUpdated()) { 0415 ++sum; 0416 } 0417 } 0418 return sum; 0419 } 0420 0421 QStringList MesonOptions::getMesonArgs() const 0422 { 0423 QStringList result; 0424 result.reserve(m_options.size()); 0425 0426 for (auto i : m_options) { 0427 if (i && i->isUpdated()) { 0428 result << i->mesonArg(); 0429 } 0430 } 0431 return result; 0432 } 0433 0434 void MesonOptions::fromJSON(const QJsonArray& arr) 0435 { 0436 m_options.clear(); 0437 m_options.reserve(arr.size()); 0438 0439 for (const QJsonValue& i : arr) { 0440 if (!i.isObject()) { 0441 continue; 0442 } 0443 0444 auto ptr = MesonOptionBase::fromJSON(i.toObject()); 0445 if (ptr) { 0446 m_options += ptr; 0447 } else { 0448 qCWarning(KDEV_Meson) << "OPT: Failed to parse " << i.toObject(); 0449 } 0450 } 0451 } 0452 0453 void MesonOptions::print() const 0454 { 0455 for (const auto& i : m_options) { 0456 qCDebug(KDEV_Meson) << i->name() << " = " << i->value() << " [" << i->type() << "] -- " << i->section(); 0457 } 0458 } 0459 0460 QVector<MesonOptionPtr> MesonOptions::options() 0461 { 0462 return m_options; 0463 }