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 }