winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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 }