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 }