winget-cli

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

PackageVersionDataManifest.cpp (7558B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #include "pch.h"
      4 #include "Public/winget/PackageVersionDataManifest.h"
      5 #include "Public/winget/Yaml.h"
      6 #include <AppInstallerErrors.h>
      7 #include <AppInstallerLogging.h>
      8 #include <AppInstallerStrings.h>
      9 
     10 using namespace std::string_view_literals;
     11 
     12 namespace AppInstaller::Manifest
     13 {
     14     // These shortened names save some bytes since humans are neither authoring them nor reading them (except to debug).
     15     static constexpr std::string_view s_FieldName_SchemaVersion = "sV"sv;
     16     static constexpr std::string_view s_FieldName_VersionData = "vD"sv;
     17     static constexpr std::string_view s_FieldName_Version = "v"sv;
     18     static constexpr std::string_view s_FieldName_ArpMinVersion = "aMiV"sv;
     19     static constexpr std::string_view s_FieldName_ArpMaxVersion = "aMaV"sv;
     20     static constexpr std::string_view s_FieldName_RelativePath = "rP"sv;
     21     static constexpr std::string_view s_FieldName_Sha256Hash = "s256H"sv;
     22 
     23     static constexpr std::string_view s_SchemaVersion_1_0 = "1.0"sv;
     24 
     25     static constexpr DWORD CompressionAlgorithm = COMPRESS_ALGORITHM_MSZIP;
     26     static constexpr bool CompressionSetLevel1 = false;
     27 
     28     namespace anon
     29     {
     30         std::string GetRequiredChildString(const YAML::Node& node, std::string_view childName)
     31         {
     32             const YAML::Node& childNode = node.GetChildNode(childName);
     33             THROW_HR_IF(APPINSTALLER_CLI_ERROR_INVALID_MANIFEST, !childNode.IsScalar());
     34             return childNode.as<std::string>();
     35         }
     36 
     37         std::optional<std::string> GetOptionalChildString(const YAML::Node& node, std::string_view childName)
     38         {
     39             const YAML::Node& childNode = node.GetChildNode(childName);
     40             return childNode.IsScalar() ? std::make_optional(childNode.as<std::string>()) : std::nullopt;
     41         }
     42 
     43         void Deserialize_1_0(const YAML::Node& document, PackageVersionDataManifest& manifest)
     44         {
     45             const YAML::Node& versionDataItems = document.GetChildNode(s_FieldName_VersionData);
     46             THROW_HR_IF(APPINSTALLER_CLI_ERROR_INVALID_MANIFEST, !versionDataItems.IsSequence());
     47 
     48             for (const YAML::Node& item : versionDataItems.Sequence())
     49             {
     50                 THROW_HR_IF(APPINSTALLER_CLI_ERROR_INVALID_MANIFEST, !item.IsMap());
     51 
     52                 PackageVersionDataManifest::VersionData versionData;
     53 
     54                 versionData.Version.Assign(GetRequiredChildString(item, s_FieldName_Version));
     55                 versionData.ArpMinVersion = GetOptionalChildString(item, s_FieldName_ArpMinVersion);
     56                 versionData.ArpMaxVersion = GetOptionalChildString(item, s_FieldName_ArpMaxVersion);
     57                 versionData.ManifestRelativePath = GetRequiredChildString(item, s_FieldName_RelativePath);
     58                 versionData.ManifestHash = GetRequiredChildString(item, s_FieldName_Sha256Hash);
     59 
     60                 manifest.AddVersion(std::move(versionData));
     61             }
     62         }
     63     }
     64 
     65     std::string_view PackageVersionDataManifest::VersionManifestFileName()
     66     {
     67         return "versionData.yml"sv;
     68     }
     69 
     70     std::string_view PackageVersionDataManifest::VersionManifestCompressedFileName()
     71     {
     72         return "versionData.mszyml"sv;
     73     }
     74 
     75     std::filesystem::path PackageVersionDataManifest::GetRelativeDirectoryPath(std::string_view packageIdentifier, std::string_view manifestHash)
     76     {
     77         std::filesystem::path result = "packages";
     78         result /= Utility::ConvertToUTF16(packageIdentifier);
     79         result /= manifestHash.substr(0, 8);
     80         return result;
     81     }
     82 
     83     Compression::Compressor PackageVersionDataManifest::CreateCompressor()
     84     {
     85         Compression::Compressor result(CompressionAlgorithm);
     86         if constexpr (CompressionSetLevel1)
     87         {
     88             result.SetInformation(COMPRESS_INFORMATION_CLASS_LEVEL, 1);
     89         }
     90         return result;
     91     }
     92 
     93     Compression::Decompressor PackageVersionDataManifest::CreateDecompressor()
     94     {
     95         return Compression::Decompressor(CompressionAlgorithm);
     96     }
     97 
     98     PackageVersionDataManifest::VersionData::VersionData(
     99         const Utility::VersionAndChannel& versionAndChannel,
    100         std::optional<std::string> arpMinVersion,
    101         std::optional<std::string> arpMaxVersion,
    102         std::optional<std::string> relativePath,
    103         std::optional<std::string> manifestHash) :
    104         Version(versionAndChannel.GetVersion()),
    105         ArpMinVersion(std::move(arpMinVersion)),
    106         ArpMaxVersion(std::move(arpMaxVersion)),
    107         ManifestRelativePath(std::move(relativePath).value_or("")),
    108         ManifestHash(std::move(manifestHash).value_or(""))
    109     {
    110         if (ArpMinVersion && ArpMinVersion->empty())
    111         {
    112             ArpMinVersion.reset();
    113         }
    114 
    115         if (ArpMaxVersion && ArpMaxVersion->empty())
    116         {
    117             ArpMaxVersion.reset();
    118         }
    119     }
    120 
    121     void PackageVersionDataManifest::AddVersion(VersionData&& versionData)
    122     {
    123         m_versions.emplace_back(std::move(versionData));
    124     }
    125 
    126     const std::vector<PackageVersionDataManifest::VersionData>& PackageVersionDataManifest::Versions() const
    127     {
    128         return m_versions;
    129     }
    130 
    131     std::string PackageVersionDataManifest::Serialize()
    132     {
    133         YAML::Emitter out;
    134         out << YAML::BeginMap;
    135         out << YAML::Key << s_FieldName_SchemaVersion << YAML::Value << s_SchemaVersion_1_0;
    136 
    137         out << YAML::Key << s_FieldName_VersionData;
    138         out << YAML::BeginSeq;
    139 
    140         for (const auto& version : m_versions)
    141         {
    142             out << YAML::BeginMap;
    143             out << YAML::Key << s_FieldName_Version << YAML::Value << version.Version.ToString();
    144             if (version.ArpMinVersion)
    145             {
    146                 out << YAML::Key << s_FieldName_ArpMinVersion << YAML::Value << version.ArpMinVersion.value();
    147             }
    148             if (version.ArpMaxVersion)
    149             {
    150                 out << YAML::Key << s_FieldName_ArpMaxVersion << YAML::Value << version.ArpMaxVersion.value();
    151             }
    152             out << YAML::Key << s_FieldName_RelativePath << YAML::Value << version.ManifestRelativePath;
    153             out << YAML::Key << s_FieldName_Sha256Hash << YAML::Value << version.ManifestHash;
    154             out << YAML::EndMap;
    155         }
    156 
    157         out << YAML::EndSeq;
    158         out << YAML::EndMap;
    159 
    160         return out.str();
    161     }
    162 
    163     void PackageVersionDataManifest::Deserialize(std::string_view input)
    164     {
    165         AICLI_LOG_LARGE_STRING(Core, Verbose, << "PackageVersionDataManifest deserializing:", input);
    166 
    167         YAML::Node document = YAML::Load(input);
    168         THROW_HR_IF(APPINSTALLER_CLI_ERROR_INVALID_MANIFEST, !document.IsMap());
    169 
    170         const YAML::Node& schemaVersionNode = document.GetChildNode(s_FieldName_SchemaVersion);
    171         THROW_HR_IF(APPINSTALLER_CLI_ERROR_INVALID_MANIFEST, !schemaVersionNode.IsScalar());
    172 
    173         Utility::Version schemaVersion{ schemaVersionNode.as<std::string>() };
    174 
    175         if (schemaVersion.PartAt(0).Integer == 1)
    176         {
    177             anon::Deserialize_1_0(document, *this);
    178         }
    179         else
    180         {
    181             THROW_HR(APPINSTALLER_CLI_ERROR_UNSUPPORTED_MANIFESTVERSION);
    182         }
    183     }
    184 
    185     void PackageVersionDataManifest::Deserialize(const std::vector<uint8_t>& input)
    186     {
    187         Deserialize(std::string_view{ reinterpret_cast<const char*>(input.data()), input.size() });
    188     }
    189 }