Improve PluginMetadata YAML serialisation

- Move "url" before "group"
- Serialise single-element lists using the flow style if their element will be written as a scalar value
- Uppercase letters in CRC hex values
- Pad CRC hex values so they're always 8 characters long (excluding the 0x prefix).
This commit is contained in:
Oliver Hamlet
2022-03-26 15:30:49 +00:00
parent 781403b853
commit 46c8b875df
10 changed files with 79 additions and 44 deletions
+5
View File
@@ -25,6 +25,7 @@
#include "api/helpers/crc.h"
#include <boost/crc.hpp>
#include <boost/format.hpp>
#include <fstream>
#include "api/helpers/logging.h"
@@ -81,4 +82,8 @@ uint32_t GetCrc32(const std::filesystem::path& filename) {
"\" for CRC calulation: " + e.what());
}
}
std::string CrcToString(uint32_t crc) {
return (boost::format("%08X") % crc).str();
}
}
+2
View File
@@ -30,6 +30,8 @@
namespace loot {
uint32_t GetCrc32(const std::filesystem::path& filename);
std::string CrcToString(uint32_t crc);
}
#endif
+1 -7
View File
@@ -82,12 +82,6 @@ int mapGameType(GameType gameType) {
}
}
std::string IntToHexString(const uint32_t value) {
std::stringstream stream;
stream << std::hex << value;
return stream.str();
}
ConditionEvaluator::ConditionEvaluator(const GameType gameType,
const std::filesystem::path& dataPath) :
lciState_(std::unique_ptr<lci_state, decltype(&lci_state_destroy)>(
@@ -256,7 +250,7 @@ bool ConditionEvaluator::Evaluate(const PluginCleaningData& cleaningData,
return false;
return Evaluate("checksum(\"" + pluginName + "\", " +
IntToHexString(cleaningData.GetCRC()) + ")");
CrcToString(cleaningData.GetCRC()) + ")");
}
void ParseCondition(const std::string& condition) {
+9 -3
View File
@@ -35,6 +35,13 @@
#include "api/metadata/yaml/message_content.h"
#include "loot/metadata/file.h"
namespace loot {
inline bool emitAsScalar(const File& file) {
return !file.IsConditional() && file.GetDetail().empty() &&
file.GetDisplayName().empty();
}
}
namespace YAML {
template<>
struct convert<loot::File> {
@@ -116,10 +123,9 @@ struct convert<loot::File> {
};
inline Emitter& operator<<(Emitter& out, const loot::File& rhs) {
if (!rhs.IsConditional() && rhs.GetDetail().empty() &&
rhs.GetDisplayName().empty())
if (loot::emitAsScalar(rhs)) {
out << YAML::SingleQuoted << std::string(rhs.GetName());
else {
} else {
out << BeginMap << Key << "name" << Value << YAML::SingleQuoted
<< std::string(rhs.GetName());
+8 -2
View File
@@ -33,6 +33,12 @@
#include "loot/metadata/location.h"
namespace loot {
inline bool emitAsScalar(const Location& location) {
return location.GetName().empty();
}
}
namespace YAML {
template<>
struct convert<loot::Location> {
@@ -74,9 +80,9 @@ struct convert<loot::Location> {
};
inline Emitter& operator<<(Emitter& out, const loot::Location& rhs) {
if (rhs.GetName().empty())
if (emitAsScalar(rhs)) {
out << YAML::SingleQuoted << rhs.GetURL();
else {
} else {
out << BeginMap << Key << "link" << Value << YAML::SingleQuoted
<< rhs.GetURL() << Key << "name" << Value << YAML::SingleQuoted
<< rhs.GetName() << EndMap;
+4 -2
View File
@@ -32,6 +32,7 @@
#include <cstdint>
#include <string>
#include "api/helpers/crc.h"
#include "loot/metadata/plugin_cleaning_data.h"
namespace YAML {
@@ -109,8 +110,9 @@ struct convert<loot::PluginCleaningData> {
};
inline Emitter& operator<<(Emitter& out, const loot::PluginCleaningData& rhs) {
out << BeginMap << Key << "crc" << Value << Hex << rhs.GetCRC() << Dec << Key
<< "util" << Value << YAML::SingleQuoted << rhs.GetCleaningUtility();
out << BeginMap << Key << "crc" << Value
<< "0x" + loot::CrcToString(rhs.GetCRC()) << Key << "util" << Value
<< YAML::SingleQuoted << rhs.GetCleaningUtility();
if (!rhs.GetDetail().empty()) {
if (rhs.GetDetail().size() == 1)
+35 -12
View File
@@ -44,6 +44,17 @@
#include "api/metadata/yaml/tag.h"
#include "loot/metadata/plugin_metadata.h"
namespace loot {
template<typename T>
inline ::YAML::EMITTER_MANIP getNodeStyle(const std::vector<T>& objects) {
if (objects.size() == 1 && emitAsScalar(objects.at(0))) {
return YAML::Flow;
}
return YAML::Block;
}
}
namespace YAML {
template<>
struct convert<loot::PluginMetadata> {
@@ -126,24 +137,39 @@ inline Emitter& operator<<(Emitter& out, const loot::PluginMetadata& rhs) {
out << BeginMap << Key << "name" << Value << YAML::SingleQuoted
<< rhs.GetName();
if (rhs.GetGroup())
const auto locations = rhs.GetLocations();
if (!locations.empty()) {
out << Key << "url" << Value << loot::getNodeStyle(locations)
<< locations;
}
if (rhs.GetGroup()) {
out << Key << "group" << Value << YAML::SingleQuoted
<< rhs.GetGroup().value();
}
if (!rhs.GetLoadAfterFiles().empty())
out << Key << "after" << Value << rhs.GetLoadAfterFiles();
const auto after = rhs.GetLoadAfterFiles();
if (!after.empty()) {
out << Key << "after" << Value << loot::getNodeStyle(after) << after;
}
if (!rhs.GetRequirements().empty())
out << Key << "req" << Value << rhs.GetRequirements();
const auto req = rhs.GetRequirements();
if (!req.empty()) {
out << Key << "req" << Value << loot::getNodeStyle(req) << req;
}
if (!rhs.GetIncompatibilities().empty())
out << Key << "inc" << Value << rhs.GetIncompatibilities();
const auto inc = rhs.GetIncompatibilities();
if (!inc.empty()) {
out << Key << "inc" << Value << loot::getNodeStyle(inc) << inc;
}
if (!rhs.GetMessages().empty())
out << Key << "msg" << Value << rhs.GetMessages();
if (!rhs.GetTags().empty())
out << Key << "tag" << Value << rhs.GetTags();
const auto tags = rhs.GetTags();
if (!tags.empty()) {
out << Key << "tag" << Value << loot::getNodeStyle(tags) << tags;
}
if (!rhs.GetDirtyInfo().empty())
out << Key << "dirty" << Value << rhs.GetDirtyInfo();
@@ -151,9 +177,6 @@ inline Emitter& operator<<(Emitter& out, const loot::PluginMetadata& rhs) {
if (!rhs.GetCleanInfo().empty())
out << Key << "clean" << Value << rhs.GetCleanInfo();
if (!rhs.GetLocations().empty())
out << Key << "url" << Value << rhs.GetLocations();
out << EndMap;
}
+5 -1
View File
@@ -33,6 +33,10 @@
#include "api/metadata/condition_evaluator.h"
#include "loot/metadata/tag.h"
namespace loot {
inline bool emitAsScalar(const Tag& tag) { return !tag.IsConditional(); }
}
namespace YAML {
template<>
struct convert<loot::Tag> {
@@ -84,7 +88,7 @@ struct convert<loot::Tag> {
};
inline Emitter& operator<<(Emitter& out, const loot::Tag& rhs) {
if (!rhs.IsConditional()) {
if (emitAsScalar(rhs)) {
if (rhs.IsAddition())
out << rhs.GetName();
else
@@ -50,7 +50,7 @@ protected:
expectedContent << "plugins:" << endl
<< " - name: '" << blankDifferentEsm << "'" << endl
<< " dirty:" << endl
<< " - crc: 0x7d22f9df" << endl
<< " - crc: 0x7D22F9DF" << endl
<< " util: 'TES4Edit'" << endl
<< " udr: 4" << endl
<< " - name: '" << blankEsm << "'" << endl
@@ -394,8 +394,7 @@ TEST_P(PluginMetadataTest,
EXPECT_EQ(
"name: 'Blank.esm'\n"
"after:\n"
" - 'Blank.esm'",
"after: ['Blank.esm']",
plugin.AsYaml());
}
@@ -418,8 +417,7 @@ TEST_P(PluginMetadataTest,
EXPECT_STREQ(
"name: 'Blank.esm'\n"
"after:\n"
" - 'Blank.esm'",
"after: ['Blank.esm']",
emitter.c_str());
}
@@ -447,8 +445,7 @@ TEST_P(PluginMetadataTest,
EXPECT_STREQ(
"name: 'Blank.esp'\n"
"after:\n"
" - 'Blank.esm'",
"after: ['Blank.esm']",
emitter.c_str());
}
@@ -462,8 +459,7 @@ TEST_P(PluginMetadataTest,
EXPECT_STREQ(
"name: 'Blank.esp'\n"
"req:\n"
" - 'Blank.esm'",
"req: ['Blank.esm']",
emitter.c_str());
}
@@ -477,8 +473,7 @@ TEST_P(PluginMetadataTest,
EXPECT_STREQ(
"name: 'Blank.esp'\n"
"inc:\n"
" - 'Blank.esm'",
"inc: ['Blank.esm']",
emitter.c_str());
}
@@ -507,8 +502,7 @@ TEST_P(PluginMetadataTest, emittingAsYamlShouldOutputAPluginWithTagsCorrectly) {
EXPECT_STREQ(
"name: 'Blank.esp'\n"
"tag:\n"
" - Relev",
"tag: [Relev]",
emitter.c_str());
}
@@ -523,7 +517,7 @@ TEST_P(PluginMetadataTest,
EXPECT_STREQ(
"name: 'Blank.esp'\n"
"dirty:\n"
" - crc: 0x5\n"
" - crc: 0x00000005\n"
" util: 'utility'\n"
" detail: 'info'\n"
" udr: 1\n"
@@ -542,7 +536,7 @@ TEST_P(PluginMetadataTest,
EXPECT_STREQ(
"name: 'Blank.esp'\n"
"clean:\n"
" - crc: 0x5\n"
" - crc: 0x00000005\n"
" util: 'utility'",
emitter.c_str());
}
@@ -557,8 +551,7 @@ TEST_P(PluginMetadataTest,
EXPECT_STREQ(
"name: 'Blank.esp'\n"
"url:\n"
" - 'http://www.example.com'",
"url: ['http://www.example.com']",
emitter.c_str());
}