ConfigurationSetSerializer.cpp (11175B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #include "pch.h" 4 5 #include <AppInstallerLogging.h> 6 #include <AppInstallerVersions.h> 7 #include <AppInstallerStrings.h> 8 9 #include "ConfigurationSetSerializer.h" 10 #include "ConfigurationSetSerializer_0_2.h" 11 #include "ConfigurationSetSerializer_0_3.h" 12 #include "ConfigurationSetUtilities.h" 13 14 using namespace AppInstaller::Utility; 15 using namespace AppInstaller::YAML; 16 using namespace winrt::Windows::Foundation; 17 18 namespace winrt::Microsoft::Management::Configuration::implementation 19 { 20 namespace anon 21 { 22 static constexpr std::string_view s_nullValue = "null"; 23 24 struct ValueSetWriter 25 { 26 ValueSetWriter(const Windows::Foundation::Collections::ValueSet& valueSet, const std::vector<std::pair<ConfigurationField, Windows::Foundation::IInspectable>>& overrides) : 27 m_valueSet(valueSet), m_overrides(overrides) 28 { 29 // Create a sorted list of the field names to exclude 30 for (const auto & override : m_overrides) 31 { 32 m_exclusionStrings.push_back(GetConfigurationFieldNameHString(override.first)); 33 } 34 std::sort(m_exclusionStrings.begin(), m_exclusionStrings.end()); 35 } 36 37 bool IsResultEmpty() 38 { 39 size_t nullOverrides = 0; 40 41 for (const auto& override : m_overrides) 42 { 43 // A non-null override will always be output 44 if (override.second) 45 { 46 return false; 47 } 48 else 49 { 50 ++nullOverrides; 51 } 52 } 53 54 if (m_valueSet) 55 { 56 // If there are more values than null overrides, something will be output 57 if (static_cast<size_t>(m_valueSet.Size()) > nullOverrides) 58 { 59 return false; 60 } 61 62 // Check for a value that we would output 63 for (const auto& [key, value] : m_valueSet) 64 { 65 if (value != nullptr && 66 !std::binary_search(m_exclusionStrings.begin(), m_exclusionStrings.end(), key)) 67 { 68 return false; 69 } 70 } 71 } 72 73 return true; 74 } 75 76 void Write(AppInstaller::YAML::Emitter& emitter, void(* WriteYamlValue)(AppInstaller::YAML::Emitter& emitter, const winrt::Windows::Foundation::IInspectable& value)) 77 { 78 emitter << BeginMap; 79 80 WriteValues(emitter, WriteYamlValue); 81 82 emitter << EndMap; 83 } 84 85 void WriteValues(AppInstaller::YAML::Emitter& emitter, void(*WriteYamlValue)(AppInstaller::YAML::Emitter& emitter, const winrt::Windows::Foundation::IInspectable& value)) 86 { 87 if (m_valueSet) 88 { 89 for (const auto& [key, value] : m_valueSet) 90 { 91 if (value != nullptr && 92 !std::binary_search(m_exclusionStrings.begin(), m_exclusionStrings.end(), key)) 93 { 94 std::string keyName = winrt::to_string(key); 95 emitter << Key << keyName << Value; 96 WriteYamlValue(emitter, value); 97 } 98 } 99 } 100 101 for (const auto & override : m_overrides) 102 { 103 if (override.second != nullptr) 104 { 105 std::string_view keyName = GetConfigurationFieldName(override.first); 106 emitter << Key << keyName << Value; 107 WriteYamlValue(emitter, override.second); 108 } 109 } 110 } 111 112 private: 113 const Windows::Foundation::Collections::ValueSet& m_valueSet; 114 const std::vector<std::pair<ConfigurationField, Windows::Foundation::IInspectable>>& m_overrides; 115 std::vector<winrt::hstring> m_exclusionStrings; 116 }; 117 } 118 119 std::unique_ptr<ConfigurationSetSerializer> ConfigurationSetSerializer::CreateSerializer(hstring version, bool strictVersionMatching) 120 { 121 // Create the parser based on the version selected 122 SemanticVersion schemaVersion(std::move(winrt::to_string(version))); 123 124 // TODO: Consider having the version/uri/type information all together in the future 125 if (schemaVersion.PartAt(0).Integer == 0 && schemaVersion.PartAt(1).Integer == 1) 126 { 127 // Remove this once the 0.1 serializer is implemented. 128 THROW_HR_IF(E_NOTIMPL, strictVersionMatching); 129 130 return std::make_unique<ConfigurationSetSerializer_0_2>(); 131 132 } 133 else if (schemaVersion.PartAt(0).Integer == 0 && schemaVersion.PartAt(1).Integer == 2) 134 { 135 return std::make_unique<ConfigurationSetSerializer_0_2>(); 136 } 137 else if (schemaVersion.PartAt(0).Integer == 0 && schemaVersion.PartAt(1).Integer == 3) 138 { 139 return std::make_unique<ConfigurationSetSerializer_0_3>(); 140 } 141 else 142 { 143 AICLI_LOG(Config, Error, << "Unknown configuration version: " << schemaVersion.ToString()); 144 THROW_HR(E_UNEXPECTED); 145 } 146 } 147 148 std::string ConfigurationSetSerializer::SerializeValueSet(const Windows::Foundation::Collections::ValueSet& valueSet) 149 { 150 Emitter emitter; 151 WriteYamlValueSet(emitter, valueSet); 152 return emitter.str(); 153 } 154 155 std::string ConfigurationSetSerializer::SerializeStringArray(const Windows::Foundation::Collections::IVector<hstring>& stringArray) 156 { 157 Emitter emitter; 158 WriteYamlStringArray(emitter, stringArray); 159 return emitter.str(); 160 } 161 162 void ConfigurationSetSerializer::WriteYamlValueSetIfNotEmpty(AppInstaller::YAML::Emitter& emitter, ConfigurationField key, const Windows::Foundation::Collections::ValueSet& valueSet, const OverrideMap& overrides) 163 { 164 anon::ValueSetWriter writer{ valueSet, overrides }; 165 166 if (!writer.IsResultEmpty()) 167 { 168 emitter << Key << GetConfigurationFieldName(key); 169 writer.Write(emitter, WriteYamlValue); 170 } 171 } 172 173 void ConfigurationSetSerializer::WriteYamlValueSet(AppInstaller::YAML::Emitter& emitter, const Windows::Foundation::Collections::ValueSet& valueSet, const OverrideMap& overrides) 174 { 175 anon::ValueSetWriter writer{ valueSet, overrides }; 176 writer.Write(emitter, WriteYamlValue); 177 } 178 179 void ConfigurationSetSerializer::WriteYamlValueSetValues(AppInstaller::YAML::Emitter& emitter, const Windows::Foundation::Collections::ValueSet& valueSet, const OverrideMap& overrides) 180 { 181 anon::ValueSetWriter writer{ valueSet, overrides }; 182 writer.WriteValues(emitter, WriteYamlValue); 183 } 184 185 void ConfigurationSetSerializer::WriteYamlStringArray(AppInstaller::YAML::Emitter& emitter, const Windows::Foundation::Collections::IVector<hstring>& values) 186 { 187 emitter << BeginSeq; 188 189 for (const auto& value : values) 190 { 191 emitter << ConvertToUTF8(value); 192 } 193 194 emitter << EndSeq; 195 } 196 197 void ConfigurationSetSerializer::WriteYamlValue(AppInstaller::YAML::Emitter& emitter, const winrt::Windows::Foundation::IInspectable& value) 198 { 199 if (value == nullptr) 200 { 201 emitter << anon::s_nullValue; 202 } 203 else 204 { 205 const auto& currentValueSet = value.try_as<Windows::Foundation::Collections::ValueSet>(); 206 if (currentValueSet) 207 { 208 if (currentValueSet.HasKey(L"treatAsArray")) 209 { 210 WriteYamlValueSetAsArray(emitter, currentValueSet); 211 } 212 else 213 { 214 WriteYamlValueSet(emitter, currentValueSet); 215 } 216 } 217 else 218 { 219 IPropertyValue property = value.as<IPropertyValue>(); 220 auto type = property.Type(); 221 222 if (type == PropertyType::Boolean) 223 { 224 emitter << property.GetBoolean(); 225 } 226 else if (type == PropertyType::String) 227 { 228 emitter << ScalarStyle::DoubleQuoted << ConvertToUTF8(property.GetString()); 229 } 230 else if (type == PropertyType::Int64) 231 { 232 emitter << property.GetInt64(); 233 } 234 else 235 { 236 THROW_HR(E_NOTIMPL); 237 } 238 } 239 } 240 } 241 242 void ConfigurationSetSerializer::WriteYamlValueIfNotEmpty(AppInstaller::YAML::Emitter& emitter, ConfigurationField key, const winrt::Windows::Foundation::IInspectable& value) 243 { 244 if (value != nullptr) 245 { 246 emitter << Key << GetConfigurationFieldName(key) << Value; 247 WriteYamlValue(emitter, value); 248 } 249 } 250 251 void ConfigurationSetSerializer::WriteYamlStringValueIfNotEmpty(AppInstaller::YAML::Emitter& emitter, ConfigurationField key, hstring value) 252 { 253 if (!value.empty()) 254 { 255 emitter << Key << GetConfigurationFieldName(key) << Value << ConvertToUTF8(value); 256 } 257 } 258 259 void ConfigurationSetSerializer::WriteYamlValueSetAsArray(AppInstaller::YAML::Emitter& emitter, const Windows::Foundation::Collections::ValueSet& valueSetArray) 260 { 261 std::vector<std::pair<int, winrt::Windows::Foundation::IInspectable>> arrayValues; 262 for (const auto& arrayValue : valueSetArray) 263 { 264 if (arrayValue.Key() != L"treatAsArray") 265 { 266 arrayValues.emplace_back(std::make_pair(std::stoi(arrayValue.Key().c_str()), arrayValue.Value())); 267 } 268 } 269 270 std::sort( 271 arrayValues.begin(), 272 arrayValues.end(), 273 [](const std::pair<int, winrt::Windows::Foundation::IInspectable>& a, const std::pair<int, winrt::Windows::Foundation::IInspectable>& b) 274 { 275 return a.first < b.first; 276 }); 277 278 emitter << BeginSeq; 279 280 for (const auto& arrayValue : arrayValues) 281 { 282 WriteYamlValue(emitter, arrayValue.second); 283 } 284 285 emitter << EndSeq; 286 } 287 288 std::wstring_view ConfigurationSetSerializer::GetSchemaVersionCommentPrefix() 289 { 290 return L"# yaml-language-server: $schema=https://aka.ms/configuration-dsc-schema/"sv; 291 } 292 }