winget-cli

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

SQLiteIndexSourceV2.cpp (23534B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #include "pch.h"
      4 #include "Microsoft/SQLiteIndexSourceV2.h"
      5 #include <winget/ManifestYamlParser.h>
      6 
      7 using namespace AppInstaller::Utility;
      8 
      9 
     10 namespace AppInstaller::Repository::Microsoft::details::V2
     11 {
     12     // Get the relative path and hash for the package version data manifest.
     13     std::pair<std::filesystem::path, std::string> CreatePackageVersionDataRelativePath(const std::shared_ptr<SQLiteIndexSource>& source, SQLiteIndex::IdType packageRowId)
     14     {
     15         const SQLiteIndex& index = source->GetIndex();
     16 
     17         std::string identifier = index.GetPropertyByPrimaryId(packageRowId, PackageVersionProperty::Id).value();
     18         std::string hash = index.GetPropertyByPrimaryId(packageRowId, PackageVersionProperty::ManifestSHA256Hash).value();
     19         std::filesystem::path relativePath = Manifest::PackageVersionDataManifest::GetRelativeDirectoryPath(identifier, hash) / Manifest::PackageVersionDataManifest::VersionManifestCompressedFileName();
     20 
     21         return std::make_pair(std::move(relativePath), std::move(hash));
     22     }
     23 
     24     // Gets package version data for the given package in the index.
     25     Manifest::PackageVersionDataManifest GetPackageVersionData(const std::shared_ptr<SQLiteIndexSource>& source, SQLiteIndex::IdType packageRowId, const Caching::FileCache& fileCache)
     26     {
     27         auto pathAndHash = CreatePackageVersionDataRelativePath(source, packageRowId);
     28         auto fileStream = fileCache.GetFile(pathAndHash.first, SHA256::ConvertToBytes(pathAndHash.second));
     29         auto fileBytes = ReadEntireStreamAsByteArray(*fileStream);
     30 
     31         Manifest::PackageVersionDataManifest result;
     32         result.Deserialize(Manifest::PackageVersionDataManifest::CreateDecompressor().Decompress(fileBytes));
     33 
     34         return result;
     35     }
     36 
     37     // The IPackageVersion implementation for V2 index.
     38     struct PackageVersion : public SourceReference, public IPackageVersion
     39     {
     40         PackageVersion(
     41             const std::shared_ptr<SQLiteIndexSource>& source,
     42             SQLiteIndex::IdType packageRowId,
     43             std::optional<Manifest::PackageVersionDataManifest::VersionData> packageVersionData,
     44             const std::shared_ptr<Caching::FileCache>& manifestCache,
     45             const std::shared_ptr<Caching::FileCache>& packageVersionDataCache) :
     46                 SourceReference(source),
     47                 m_packageRowId(packageRowId),
     48                 m_packageVersionData(std::move(packageVersionData)),
     49                 m_manifestCache(manifestCache),
     50                 m_packageVersionDataCache(packageVersionDataCache)
     51         {}
     52 
     53         // Inherited via IPackageVersion
     54         LocIndString GetProperty(PackageVersionProperty property) const override
     55         {
     56             switch (property)
     57             {
     58             case PackageVersionProperty::SourceIdentifier:
     59                 return LocIndString{ GetReferenceSource()->GetIdentifier() };
     60             case PackageVersionProperty::SourceName:
     61                 return LocIndString{ GetReferenceSource()->GetDetails().Name };
     62             case PackageVersionProperty::RelativePath:
     63             case PackageVersionProperty::ManifestSHA256Hash:
     64             {
     65                 // These values can only come from the version data.
     66                 EnsurePackageVersionData();
     67                 return GetPropertyFromVersionData(property);
     68             }
     69                 break;
     70             case PackageVersionProperty::Publisher:
     71             {
     72                 // These values can only come from the manifest.
     73                 EnsureManifest();
     74                 return GetPropertyFromManifest(property);
     75             }
     76                 break;
     77             case PackageVersionProperty::Id:
     78             case PackageVersionProperty::Name:
     79             case PackageVersionProperty::Moniker:
     80             {
     81                 // These properties can come from the manifest or the index.
     82                 // The index values will be for the latest version rather than this specific one though.
     83                 auto sharedLock = m_versionAndManifestLock.lock_shared();
     84 
     85                 if (m_manifest)
     86                 {
     87                     return GetPropertyFromManifestWithLock(property);
     88                 }
     89                 else
     90                 {
     91                     return GetPropertyFromIndex(property);
     92                 }
     93             }
     94                 break;
     95             case PackageVersionProperty::Version:
     96             case PackageVersionProperty::Channel:
     97             case PackageVersionProperty::ArpMinVersion:
     98             case PackageVersionProperty::ArpMaxVersion:
     99             {
    100                 // These properties can come from the manifest, version data, or the index.
    101                 // The index values are only for the latest version, but we should always already have the version data
    102                 // for any version that is not the latest.
    103                 auto sharedLock = m_versionAndManifestLock.lock_shared();
    104 
    105                 if (m_manifest)
    106                 {
    107                     return GetPropertyFromManifestWithLock(property);
    108                 }
    109                 else if (m_packageVersionData)
    110                 {
    111                     return GetPropertyFromVersionDataWithLock(property);
    112                 }
    113                 else
    114                 {
    115                     return GetPropertyFromIndex(property);
    116                 }
    117             }
    118                 break;
    119             default:
    120                 THROW_HR(E_UNEXPECTED);
    121             }
    122         }
    123 
    124         std::vector<LocIndString> GetMultiProperty(PackageVersionMultiProperty property) const override
    125         {
    126             switch (property)
    127             {
    128             case PackageVersionMultiProperty::Locale:
    129             {
    130                 // These values can only come from the manifest.
    131                 EnsureManifest();
    132                 return GetMultiPropertyFromManifest(property);
    133             }
    134                 break;
    135             case PackageVersionMultiProperty::PackageFamilyName:
    136             case PackageVersionMultiProperty::ProductCode:
    137             case PackageVersionMultiProperty::UpgradeCode:
    138             case PackageVersionMultiProperty::Name:
    139             case PackageVersionMultiProperty::Publisher:
    140             case PackageVersionMultiProperty::Tag:
    141             case PackageVersionMultiProperty::Command:
    142             {
    143                 // These properties can come from the manifest or the index.
    144                 // The index values will be for all versions rather than this specific one though.
    145                 auto sharedLock = m_versionAndManifestLock.lock_shared();
    146 
    147                 if (m_manifest)
    148                 {
    149                     return GetMultiPropertyFromManifestWithLock(property);
    150                 }
    151                 else
    152                 {
    153                     return GetMultiPropertyFromIndex(property);
    154                 }
    155             }
    156             break;
    157             default:
    158                 THROW_HR(E_UNEXPECTED);
    159             }
    160         }
    161 
    162         Manifest::Manifest GetManifest() override
    163         {
    164             EnsureManifest();
    165             auto sharedLock = m_versionAndManifestLock.lock_shared();
    166             return m_manifest.value();
    167         }
    168 
    169         Source GetSource() const override
    170         {
    171             return Source{ GetReferenceSource() };
    172         }
    173 
    174         IPackageVersion::Metadata GetMetadata() const override
    175         {
    176             return {};
    177         }
    178 
    179     private:
    180         // Ensures that the package version data is present.
    181         void EnsurePackageVersionData() const
    182         {
    183             {
    184                 auto sharedLock = m_versionAndManifestLock.lock_shared();
    185                 if (m_packageVersionData)
    186                 {
    187                     return;
    188                 }
    189             }
    190 
    191             auto exclusiveLock = m_versionAndManifestLock.lock_exclusive();
    192             if (m_packageVersionData)
    193             {
    194                 return;
    195             }
    196 
    197             Manifest::PackageVersionDataManifest packageVersionDataManifest = GetPackageVersionData(GetReferenceSource(), m_packageRowId, *m_packageVersionDataCache);
    198 
    199             for (const auto& versionData : packageVersionDataManifest.Versions())
    200             {
    201                 // We should only ever be looking for the latest version here.
    202                 if (!m_packageVersionData || m_packageVersionData->Version < versionData.Version)
    203                 {
    204                     m_packageVersionData = versionData;
    205                 }
    206             }
    207         }
    208 
    209         // Ensures that the manifest is present.
    210         void EnsureManifest() const
    211         {
    212             {
    213                 auto sharedLock = m_versionAndManifestLock.lock_shared();
    214                 if (m_manifest)
    215                 {
    216                     return;
    217                 }
    218             }
    219 
    220             // We will need the package version data to get the manifest.
    221             EnsurePackageVersionData();
    222 
    223             auto exclusiveLock = m_versionAndManifestLock.lock_exclusive();
    224             if (m_manifest)
    225             {
    226                 return;
    227             }
    228 
    229             std::unique_ptr<std::istream> manifestStream =
    230                 m_manifestCache->GetFile(ConvertToUTF16(m_packageVersionData->ManifestRelativePath), SHA256::ConvertToBytes(m_packageVersionData->ManifestHash));
    231             m_manifest = Manifest::YamlParser::Create(ReadEntireStream(*manifestStream));
    232             m_manifest->ApplyLocale();
    233         }
    234 
    235         LocIndString GetPropertyFromIndex(PackageVersionProperty property) const
    236         {
    237             switch (property)
    238             {
    239             case PackageVersionProperty::Id:
    240             case PackageVersionProperty::Name:
    241             case PackageVersionProperty::Moniker:
    242             case PackageVersionProperty::Version:
    243             case PackageVersionProperty::ArpMinVersion:
    244             case PackageVersionProperty::ArpMaxVersion:
    245             {
    246                 // Values coming from the index will always be localized/independent.
    247                 std::optional<std::string> optValue = GetReferenceSource()->GetIndex().GetPropertyByPrimaryId(m_packageRowId, property);
    248                 return LocIndString{ optValue ? optValue.value() : std::string{} };
    249             }
    250             default:
    251                 return {};
    252             }
    253         }
    254 
    255         LocIndString GetPropertyFromVersionData(PackageVersionProperty property) const
    256         {
    257             auto sharedLock = m_versionAndManifestLock.lock_shared();
    258             return GetPropertyFromVersionDataWithLock(property);
    259         }
    260 
    261         LocIndString GetPropertyFromVersionDataWithLock(PackageVersionProperty property) const
    262         {
    263             std::string result;
    264 
    265             switch (property)
    266             {
    267             case PackageVersionProperty::RelativePath:
    268                 result = m_packageVersionData->ManifestRelativePath;
    269                 break;
    270             case PackageVersionProperty::ManifestSHA256Hash:
    271                 result = m_packageVersionData->ManifestHash;
    272                 break;
    273             case PackageVersionProperty::Version:
    274                 result = m_packageVersionData->Version.ToString();
    275                 break;
    276             case PackageVersionProperty::ArpMinVersion:
    277                 result = m_packageVersionData->ArpMinVersion.value_or("");
    278                 break;
    279             case PackageVersionProperty::ArpMaxVersion:
    280                 result = m_packageVersionData->ArpMaxVersion.value_or("");
    281                 break;
    282             }
    283 
    284             return LocIndString{ std::move(result) };
    285         }
    286 
    287         LocIndString GetPropertyFromManifest(PackageVersionProperty property) const
    288         {
    289             auto sharedLock = m_versionAndManifestLock.lock_shared();
    290             return GetPropertyFromManifestWithLock(property);
    291         }
    292 
    293         LocIndString GetPropertyFromManifestWithLock(PackageVersionProperty property) const
    294         {
    295             std::string result;
    296 
    297             switch (property)
    298             {
    299             case PackageVersionProperty::Publisher:
    300                 result = m_manifest->CurrentLocalization.Get<Manifest::Localization::Publisher>();
    301                 break;
    302             case PackageVersionProperty::Id:
    303                 result = m_manifest->Id;
    304                 break;
    305             case PackageVersionProperty::Name:
    306                 result = m_manifest->CurrentLocalization.Get<Manifest::Localization::PackageName>();
    307                 break;
    308             case PackageVersionProperty::Moniker:
    309                 result = m_manifest->Moniker;
    310                 break;
    311             case PackageVersionProperty::Version:
    312                 result = m_manifest->Version;
    313                 break;
    314             case PackageVersionProperty::Channel:
    315                 result = m_manifest->Channel;
    316                 break;
    317             case PackageVersionProperty::ArpMinVersion:
    318             {
    319                 auto versionRange = m_manifest->GetArpVersionRange();
    320                 if (!versionRange.IsEmpty())
    321                 {
    322                     result = versionRange.GetMinVersion().ToString();
    323                 }
    324             }
    325                 break;
    326             case PackageVersionProperty::ArpMaxVersion:
    327             {
    328                 auto versionRange = m_manifest->GetArpVersionRange();
    329                 if (!versionRange.IsEmpty())
    330                 {
    331                     result = versionRange.GetMaxVersion().ToString();
    332                 }
    333             }
    334                 break;
    335             }
    336 
    337             return LocIndString{ std::move(result) };
    338         }
    339 
    340         std::vector<LocIndString> GetMultiPropertyFromIndex(PackageVersionMultiProperty property) const
    341         {
    342             std::vector<LocIndString> result;
    343 
    344             for (auto&& value : GetReferenceSource()->GetIndex().GetMultiPropertyByPrimaryId(m_packageRowId, property))
    345             {
    346                 // Values coming from the index will always be localized/independent.
    347                 result.emplace_back(std::move(value));
    348             }
    349 
    350             return result;
    351         }
    352 
    353         std::vector<LocIndString> GetMultiPropertyFromManifest(PackageVersionMultiProperty property) const
    354         {
    355             auto sharedLock = m_versionAndManifestLock.lock_shared();
    356             return GetMultiPropertyFromManifestWithLock(property);
    357         }
    358 
    359         std::vector<LocIndString> GetMultiPropertyFromManifestWithLock(PackageVersionMultiProperty property) const
    360         {
    361             std::vector<Manifest::string_t> intermediate;
    362 
    363             switch (property)
    364             {
    365             case PackageVersionMultiProperty::PackageFamilyName:
    366                 intermediate = m_manifest->GetPackageFamilyNames();
    367                 break;
    368             case PackageVersionMultiProperty::ProductCode:
    369                 intermediate = m_manifest->GetProductCodes();
    370                 break;
    371             case PackageVersionMultiProperty::UpgradeCode:
    372                 intermediate = m_manifest->GetUpgradeCodes();
    373                 break;
    374             case PackageVersionMultiProperty::Name:
    375                 intermediate = m_manifest->GetPackageNames();
    376                 break;
    377             case PackageVersionMultiProperty::Publisher:
    378                 intermediate = m_manifest->GetPublishers();
    379                 break;
    380             case PackageVersionMultiProperty::Locale:
    381                 for (const auto& localization : m_manifest->Localizations)
    382                 {
    383                     intermediate.emplace_back(localization.Locale);
    384                 }
    385                 break;
    386             case PackageVersionMultiProperty::Tag:
    387                 intermediate = m_manifest->GetAggregatedTags();
    388                 break;
    389             case PackageVersionMultiProperty::Command:
    390                 intermediate = m_manifest->GetAggregatedCommands();
    391                 break;
    392             }
    393 
    394             std::vector<LocIndString> result;
    395 
    396             for (auto&& value : intermediate)
    397             {
    398                 // Values coming from the manifest will always be localized/independent.
    399                 result.emplace_back(std::move(value));
    400             }
    401 
    402             return result;
    403         }
    404 
    405         SQLiteIndex::IdType m_packageRowId;
    406 
    407         mutable wil::srwlock m_versionAndManifestLock;
    408         mutable std::optional<Manifest::PackageVersionDataManifest::VersionData> m_packageVersionData;
    409         mutable std::optional<Manifest::Manifest> m_manifest;
    410 
    411         std::shared_ptr<Caching::FileCache> m_manifestCache;
    412         std::shared_ptr<Caching::FileCache> m_packageVersionDataCache;
    413     };
    414 
    415     SQLitePackage::SQLitePackage(
    416         const std::shared_ptr<SQLiteIndexSource>& source,
    417         SQLiteIndex::IdType packageRowId,
    418         const std::shared_ptr<Caching::FileCache>& manifestCache,
    419         const std::shared_ptr<Caching::FileCache>& packageVersionDataCache,
    420         bool isInstalled) :
    421         SourceReference(source),
    422         m_packageRowId(packageRowId),
    423         m_manifestCache(manifestCache),
    424         m_packageVersionDataCache(packageVersionDataCache),
    425         m_isInstalled(isInstalled)
    426     {}
    427 
    428     LocIndString SQLitePackage::GetProperty(PackageProperty property) const
    429     {
    430         std::optional<std::string> result;
    431         std::shared_ptr<SQLiteIndexSource> source = GetReferenceSource();
    432 
    433         switch (property)
    434         {
    435         case PackageProperty::Id:
    436             result = source->GetIndex().GetPropertyByPrimaryId(m_packageRowId, PackageVersionProperty::Id);
    437             break;
    438         case PackageProperty::Name:
    439             result = source->GetIndex().GetPropertyByPrimaryId(m_packageRowId, PackageVersionProperty::Name);
    440             break;
    441         default:
    442             THROW_HR(E_UNEXPECTED);
    443         }
    444 
    445         return LocIndString{ result ? std::move(result).value() : std::string{} };
    446     }
    447 
    448     std::vector<Utility::LocIndString> SQLitePackage::GetMultiProperty(PackageMultiProperty property) const
    449     {
    450         std::vector<LocIndString> result;
    451 
    452         for (auto&& value : GetReferenceSource()->GetIndex().GetMultiPropertyByPrimaryId(m_packageRowId, PackageMultiPropertyToPackageVersionMultiProperty(property)))
    453         {
    454             // Values coming from the index will always be localized/independent.
    455             result.emplace_back(std::move(value));
    456         }
    457 
    458         return result;
    459     }
    460 
    461     std::vector<PackageVersionKey> SQLitePackage::GetVersionKeys() const
    462     {
    463         std::shared_ptr<SQLiteIndexSource> source = GetReferenceSource();
    464 
    465         {
    466             auto sharedLock = m_versionKeysLock.lock_shared();
    467 
    468             if (!m_versionKeys.empty())
    469             {
    470                 return m_versionKeys;
    471             }
    472         }
    473 
    474         EnsurePackageVersionData(source);
    475 
    476         auto sharedLock = m_versionKeysLock.lock_shared();
    477         return m_versionKeys;
    478     }
    479 
    480     std::shared_ptr<IPackageVersion> SQLitePackage::GetLatestVersion() const
    481     {
    482         std::shared_ptr<SQLiteIndexSource> source = GetReferenceSource();
    483         auto sharedLock = m_versionKeysLock.lock_shared();
    484         return std::make_shared<PackageVersion>(source, m_packageRowId, m_latestVersionData, m_manifestCache, m_packageVersionDataCache);
    485     }
    486 
    487     std::shared_ptr<IPackageVersion> SQLitePackage::GetVersion(const PackageVersionKey& versionKey) const
    488     {
    489         std::shared_ptr<SQLiteIndexSource> source = GetReferenceSource();
    490 
    491         // Ensure that this key targets this (or any) source
    492         if (!versionKey.SourceId.empty() && versionKey.SourceId != source->GetIdentifier())
    493         {
    494             return {};
    495         }
    496 
    497         std::optional<Manifest::PackageVersionDataManifest::VersionData> versionData;
    498 
    499         // Check for a latest version request.
    500         if (versionKey.IsDefaultLatest())
    501         {
    502             auto sharedLock = m_versionKeysLock.lock_shared();
    503             return std::make_shared<PackageVersion>(source, m_packageRowId, m_latestVersionData, m_manifestCache, m_packageVersionDataCache);
    504         }
    505 
    506         EnsurePackageVersionData(source);
    507 
    508         {
    509             MapKey requested{ versionKey.Version, versionKey.Channel };
    510             auto sharedLock = m_versionKeysLock.lock_shared();
    511 
    512             auto itr = m_versionKeysMap.find(requested);
    513             if (itr != m_versionKeysMap.end())
    514             {
    515                 versionData = itr->second;
    516             }
    517         }
    518 
    519         if (versionData)
    520         {
    521             return std::make_shared<PackageVersion>(source, m_packageRowId, std::move(versionData), m_manifestCache, m_packageVersionDataCache);
    522         }
    523 
    524         return {};
    525     }
    526 
    527     Source SQLitePackage::GetSource() const
    528     {
    529         return Source{ GetReferenceSource() };
    530     }
    531 
    532     bool SQLitePackage::IsSame(const IPackage* other) const
    533     {
    534         const SQLitePackage* otherSQLite = PackageCast<const SQLitePackage*>(other);
    535 
    536         if (otherSQLite)
    537         {
    538             return GetReferenceSource()->IsSame(otherSQLite->GetReferenceSource().get()) && m_packageRowId == otherSQLite->m_packageRowId;
    539         }
    540 
    541         return false;
    542     }
    543 
    544     const void* SQLitePackage::CastTo(IPackageType type) const
    545     {
    546         if (type == PackageType)
    547         {
    548             return this;
    549         }
    550 
    551         return nullptr;
    552     }
    553 
    554     std::shared_ptr<IPackage> SQLitePackage::GetInstalled()
    555     {
    556         return m_isInstalled ? shared_from_this() : std::shared_ptr<IPackage>{};
    557     }
    558 
    559     std::vector<std::shared_ptr<IPackage>> SQLitePackage::GetAvailable()
    560     {
    561         return m_isInstalled ? std::vector<std::shared_ptr<IPackage>>{} : std::vector<std::shared_ptr<IPackage>>{ shared_from_this() };
    562     }
    563 
    564     bool SQLitePackage::MapKey::operator<(const MapKey& other) const
    565     {
    566         if (Version < other.Version)
    567         {
    568             return true;
    569         }
    570         else if (Version == other.Version)
    571         {
    572             return Channel < other.Channel;
    573         }
    574         else
    575         {
    576             return false;
    577         }
    578     }
    579 
    580     // Ensures that we have the package version data present.
    581     void SQLitePackage::EnsurePackageVersionData(const std::shared_ptr<SQLiteIndexSource>& source) const
    582     {
    583         {
    584             auto sharedLock = m_versionKeysLock.lock_shared();
    585 
    586             if (!m_versionKeys.empty())
    587             {
    588                 return;
    589             }
    590         }
    591 
    592         auto exclusiveLock = m_versionKeysLock.lock_exclusive();
    593 
    594         if (!m_versionKeys.empty())
    595         {
    596             return;
    597         }
    598 
    599         Manifest::PackageVersionDataManifest packageVersionDataManifest = GetPackageVersionData(source, m_packageRowId, *m_packageVersionDataCache);
    600 
    601         for (const auto& versionData : packageVersionDataManifest.Versions())
    602         {
    603             std::string version = versionData.Version.ToString();
    604             std::string channel;
    605             m_versionKeys.emplace_back(source->GetIdentifier(), version, channel);
    606             m_versionKeysMap.emplace(MapKey{ std::move(version), std::move(channel) }, versionData);
    607 
    608             if (!m_latestVersionData || m_latestVersionData->Version < versionData.Version)
    609             {
    610                 m_latestVersionData = versionData;
    611             }
    612         }
    613     }
    614 }