winget-cli

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

ArpVersionValidation.cpp (4235B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #pragma once
      4 #include "pch.h"
      5 #include "ArpVersionValidation.h"
      6 #include <winget/ManifestValidation.h>
      7 
      8 namespace AppInstaller::Repository
      9 {
     10     namespace
     11     {
     12         std::vector<Utility::VersionRange> GetArpVersionRangesByPackageRowId(const Microsoft::SQLiteIndex* index, Microsoft::SQLiteIndex::IdType packageRowId, const Utility::VersionAndChannel& excludeVersionAndChannel = {})
     13         {
     14             std::vector<Utility::VersionRange> result;
     15 
     16             auto versionKeys = index->GetVersionKeysById(packageRowId);
     17             for (auto const& versionKey : versionKeys)
     18             {
     19                 // For manifest update, the manifest to be updated does not need to be checked.
     20                 // In unlikely cases if both version 1.0.0 and 1.0 of the same package exist, we compare raw values here as what sqlite index does.
     21                 if (versionKey.VersionAndChannel.GetVersion().ToString() == excludeVersionAndChannel.GetVersion().ToString() &&
     22                     versionKey.VersionAndChannel.GetChannel().ToString() == excludeVersionAndChannel.GetChannel().ToString())
     23                 {
     24                     continue;
     25                 }
     26 
     27                 auto arpMinVersion = index->GetPropertyByPrimaryId(versionKey.ManifestId, PackageVersionProperty::ArpMinVersion).value_or("");
     28                 auto arpMaxVersion = index->GetPropertyByPrimaryId(versionKey.ManifestId, PackageVersionProperty::ArpMaxVersion).value_or("");
     29 
     30                 // Either both empty or both not empty
     31                 THROW_HR_IF(E_UNEXPECTED, arpMinVersion.empty() != arpMaxVersion.empty());
     32 
     33                 if (!arpMinVersion.empty() && !arpMaxVersion.empty())
     34                 {
     35                     result.emplace_back(Utility::VersionRange{ Utility::Version{ std::move(arpMinVersion) }, Utility::Version{ std::move(arpMaxVersion) } });
     36                 }
     37             }
     38 
     39             return result;
     40         }
     41     }
     42 
     43     void ValidateManifestArpVersion(const Microsoft::SQLiteIndex* index, const Manifest::Manifest& manifest)
     44     {
     45         try
     46         {
     47             auto manifestArpVersionRange = manifest.GetArpVersionRange();
     48             if (manifestArpVersionRange.IsEmpty())
     49             {
     50                 return;
     51             }
     52 
     53             SearchRequest request;
     54             request.Filters.emplace_back(PackageMatchField::Id, MatchType::CaseInsensitive, manifest.Id);
     55             auto searchResult = index->Search(request);
     56             if (searchResult.Matches.empty())
     57             {
     58                 return;
     59             }
     60 
     61             auto arpVersionRangesInIndex = GetArpVersionRangesByPackageRowId(index, searchResult.Matches[0].first, { Utility::Version{ manifest.Version }, Utility::Channel{ manifest.Channel } });
     62             for (auto const& arpInIndex : arpVersionRangesInIndex)
     63             {
     64                 if (manifestArpVersionRange.Overlaps(arpInIndex))
     65                 {
     66                     std::string context = (" [" + arpInIndex.GetMinVersion().ToString() + ", " + arpInIndex.GetMaxVersion().ToString() + "]");
     67                     auto validationError = Manifest::ValidationError(Manifest::ManifestError::ArpVersionOverlapWithIndex, context);
     68                     
     69                     AICLI_LOG(Repo, Error, << validationError.GetErrorMessage() << context);
     70                     THROW_EXCEPTION(Manifest::ManifestException(
     71                         { validationError },
     72                         APPINSTALLER_CLI_ERROR_DEPENDENCIES_VALIDATION_FAILED));
     73                 }
     74             }
     75         }
     76         catch (const Manifest::ManifestException&)
     77         {
     78             // Prevent ManifestException from being wrapped in another ManifestException
     79             throw;
     80         }
     81         catch (...)
     82         {
     83             AICLI_LOG(Repo, Error, << "ValidateManifestArpVersion() encountered internal error.");
     84             THROW_EXCEPTION(Manifest::ManifestException(
     85                 { Manifest::ValidationError(Manifest::ManifestError::ArpVersionValidationInternalError) },
     86                 APPINSTALLER_CLI_ERROR_DEPENDENCIES_VALIDATION_FAILED));
     87         }
     88     }
     89 }