winget-cli

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

SQLiteIndex.cpp (15094B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #include "pch.h"
      4 #include "SQLiteIndex.h"
      5 #include <winget/SQLiteStorageBase.h>
      6 #include "ArpVersionValidation.h"
      7 #include <winget/ManifestYamlParser.h>
      8 
      9 namespace AppInstaller::Repository::Microsoft
     10 {
     11     SQLiteIndex SQLiteIndex::CreateNew(const std::string& filePath, SQLite::Version version, CreateOptions options)
     12     {
     13         AICLI_LOG(Repo, Info, << "Creating new SQLite Index with version [" << version << "] at '" << filePath << "'");
     14         SQLiteIndex result{ filePath, version };
     15 
     16         SQLite::Savepoint savepoint = SQLite::Savepoint::Create(result.m_dbconn, "sqliteindex_createnew");
     17 
     18         // Use calculated version, as incoming version could be 'latest'
     19         result.m_version.SetSchemaVersion(result.m_dbconn);
     20 
     21         result.m_interface->CreateTables(result.m_dbconn, options);
     22 
     23         result.SetLastWriteTime();
     24 
     25         savepoint.Commit();
     26 
     27         return result;
     28     }
     29 
     30     SQLiteIndex SQLiteIndex::Open(const std::string& filePath, OpenDisposition disposition, Utility::ManagedFile&& indexFile)
     31     {
     32         return { filePath, disposition, std::move(indexFile) };
     33     }
     34 
     35     SQLiteIndex SQLiteIndex::CopyFrom(const std::string& filePath, SQLiteIndex& source)
     36     {
     37         return { filePath, source };
     38     }
     39 
     40     SQLiteIndex::SQLiteIndex(const std::string& target, const SQLite::Version& version) : SQLiteStorageBase(target, version)
     41     {
     42         m_dbconn.EnableICU();
     43         m_interface = Schema::CreateISQLiteIndex(version);
     44         m_version = m_interface->GetVersion();
     45         SetDatabaseFilePath(target);
     46     }
     47 
     48     SQLiteIndex::SQLiteIndex(const std::string& target, SQLiteStorageBase::OpenDisposition disposition, Utility::ManagedFile&& indexFile) :
     49         SQLiteStorageBase(target, disposition, std::move(indexFile))
     50     {
     51         m_dbconn.EnableICU();
     52         AICLI_LOG(Repo, Info, << "Opened SQLite Index with version [" << m_version << "], last write [" << GetLastWriteTime() << "]");
     53         m_interface = Schema::CreateISQLiteIndex(m_version);
     54         THROW_HR_IF(APPINSTALLER_CLI_ERROR_CANNOT_WRITE_TO_UPLEVEL_INDEX, disposition == SQLiteStorageBase::OpenDisposition::ReadWrite && m_version != m_interface->GetVersion());
     55         SetDatabaseFilePath(target);
     56     }
     57 
     58     SQLiteIndex::SQLiteIndex(const std::string& target, SQLiteIndex& source) :
     59         SQLiteStorageBase(target, source)
     60     {
     61         m_dbconn.EnableICU();
     62         m_interface = Schema::CreateISQLiteIndex(m_version);
     63         SetDatabaseFilePath(target);
     64     }
     65 
     66     void SQLiteIndex::SetDatabaseFilePath(const std::string& target)
     67     {
     68         if (target != SQLITE_MEMORY_DB_CONNECTION_TARGET)
     69         {
     70             m_contextData.Add<Schema::Property::DatabaseFilePath>(Utility::ConvertToUTF16(target));
     71         }
     72     }
     73 
     74 #ifndef AICLI_DISABLE_TEST_HOOKS
     75     void SQLiteIndex::ForceVersion(const SQLite::Version& version)
     76     {
     77         m_interface = Schema::CreateISQLiteIndex(version);
     78     }
     79 
     80     SQLite::Version SQLiteIndex::GetLatestVersion()
     81     {
     82         return Schema::CreateISQLiteIndex(SQLite::Version::Latest())->GetVersion();
     83     }
     84 
     85     const Schema::SQLiteIndexContextData& SQLiteIndex::GetContextData() const
     86     {
     87         return m_contextData;
     88     }
     89 #endif
     90 
     91     SQLiteIndex::IdType SQLiteIndex::AddManifest(const std::filesystem::path& manifestPath, const std::filesystem::path& relativePath)
     92     {
     93         AICLI_LOG(Repo, Verbose, << "Adding manifest from file [" << manifestPath << "]");
     94 
     95         Manifest::Manifest manifest = Manifest::YamlParser::CreateFromPath(manifestPath);
     96         return AddManifestInternal(manifest, relativePath);
     97     }
     98 
     99     SQLiteIndex::IdType SQLiteIndex::AddManifest(const Manifest::Manifest& manifest, const std::filesystem::path& relativePath)
    100     {
    101         return AddManifestInternal(manifest, relativePath);
    102     }
    103 
    104     SQLiteIndex::IdType SQLiteIndex::AddManifest(const Manifest::Manifest& manifest)
    105     {
    106         return AddManifestInternal(manifest, {});
    107     }
    108 
    109     SQLiteIndex::IdType SQLiteIndex::AddManifestInternal(const Manifest::Manifest& manifest, const std::optional<std::filesystem::path>& relativePath)
    110     {
    111         std::lock_guard<std::mutex> lockInterface{ *m_interfaceLock };
    112         return AddManifestInternalHoldingLock(manifest, relativePath);
    113     }
    114 
    115     SQLiteIndex::IdType SQLiteIndex::AddManifestInternalHoldingLock(const Manifest::Manifest& manifest, const std::optional<std::filesystem::path>& relativePath)
    116     {
    117         AICLI_LOG(Repo, Verbose, << "Adding manifest for [" << manifest.Id << ", " << manifest.Version << "] at relative path [" << relativePath.value_or("") << "]");
    118 
    119         SQLite::Savepoint savepoint = SQLite::Savepoint::Create(m_dbconn, "sqliteindex_addmanifest");
    120 
    121         IdType result = m_interface->AddManifest(m_dbconn, manifest, relativePath);
    122 
    123         SetLastWriteTime();
    124 
    125         savepoint.Commit();
    126 
    127         return result;
    128     }
    129 
    130     bool SQLiteIndex::UpdateManifest(const std::filesystem::path& manifestPath, const std::filesystem::path& relativePath)
    131     {
    132         AICLI_LOG(Repo, Verbose, << "Updating manifest from file [" << manifestPath << "]");
    133 
    134         Manifest::Manifest manifest = Manifest::YamlParser::CreateFromPath(manifestPath);
    135         return UpdateManifestInternal(manifest, relativePath);
    136     }
    137 
    138     bool SQLiteIndex::UpdateManifest(const Manifest::Manifest& manifest, const std::filesystem::path& relativePath)
    139     {
    140         return UpdateManifestInternal(manifest, relativePath);
    141     }
    142 
    143     bool SQLiteIndex::UpdateManifest(const Manifest::Manifest& manifest)
    144     {
    145         return UpdateManifestInternal(manifest, {});
    146     }
    147 
    148     bool SQLiteIndex::UpdateManifestInternal(const Manifest::Manifest& manifest, const std::optional<std::filesystem::path>& relativePath)
    149     {
    150         std::lock_guard<std::mutex> lockInterface{ *m_interfaceLock };
    151         return UpdateManifestInternalHoldingLock(manifest, relativePath);
    152     }
    153 
    154     bool SQLiteIndex::UpdateManifestInternalHoldingLock(const Manifest::Manifest& manifest, const std::optional<std::filesystem::path>& relativePath)
    155     {
    156         AICLI_LOG(Repo, Verbose, << "Updating manifest for [" << manifest.Id << ", " << manifest.Version << "] at relative path [" << relativePath.value_or("") << "]");
    157 
    158         SQLite::Savepoint savepoint = SQLite::Savepoint::Create(m_dbconn, "sqliteindex_updatemanifest");
    159 
    160         bool result = m_interface->UpdateManifest(m_dbconn, manifest, relativePath).first;
    161 
    162         if (result)
    163         {
    164             SetLastWriteTime();
    165 
    166             savepoint.Commit();
    167         }
    168 
    169         return result;
    170     }
    171 
    172     bool SQLiteIndex::AddOrUpdateManifest(const std::filesystem::path& manifestPath, const std::filesystem::path& relativePath)
    173     {
    174         AICLI_LOG(Repo, Verbose, << "Adding or Updating manifest from file [" << manifestPath << "]");
    175 
    176         Manifest::Manifest manifest = Manifest::YamlParser::CreateFromPath(manifestPath);
    177         return AddOrUpdateManifestInternal(manifest, relativePath);
    178     }
    179 
    180     bool SQLiteIndex::AddOrUpdateManifest(const Manifest::Manifest& manifest, const std::filesystem::path& relativePath)
    181     {
    182         return AddOrUpdateManifestInternal(manifest, relativePath);
    183     }
    184 
    185     bool SQLiteIndex::AddOrUpdateManifest(const Manifest::Manifest& manifest)
    186     {
    187         return AddOrUpdateManifestInternal(manifest, {});
    188     }
    189 
    190     bool SQLiteIndex::AddOrUpdateManifestInternal(const Manifest::Manifest& manifest, const std::optional<std::filesystem::path>& relativePath)
    191     {
    192         std::lock_guard<std::mutex> lockInterface{ *m_interfaceLock };
    193         AICLI_LOG(Repo, Verbose, << "Adding or Updating manifest for [" << manifest.Id << ", " << manifest.Version << "] at relative path [" << relativePath.value_or("") << "]");
    194 
    195         if (m_interface->GetManifestIdByManifest(m_dbconn, manifest))
    196         {
    197             UpdateManifestInternalHoldingLock(manifest, relativePath);
    198             return false;
    199         }
    200         else
    201         {
    202             AddManifestInternalHoldingLock(manifest, relativePath);
    203             return true;
    204         }
    205     }
    206 
    207     void SQLiteIndex::RemoveManifest(const std::filesystem::path& manifestPath, const std::filesystem::path& relativePath)
    208     {
    209         AICLI_LOG(Repo, Verbose, << "Removing manifest from file [" << manifestPath << "]");
    210 
    211         Manifest::Manifest manifest = Manifest::YamlParser::CreateFromPath(manifestPath);
    212         RemoveManifest(manifest, relativePath);
    213     }
    214 
    215     void SQLiteIndex::RemoveManifest(const Manifest::Manifest& manifest, const std::filesystem::path& relativePath)
    216     {
    217         AICLI_LOG(Repo, Verbose, << "Removing manifest for [" << manifest.Id << ", " << manifest.Version << "] at relative path [" << relativePath << "]");
    218         RemoveManifest(manifest);
    219     }
    220 
    221     void SQLiteIndex::RemoveManifest(const Manifest::Manifest& manifest)
    222     {
    223         std::lock_guard<std::mutex> lockInterface{ *m_interfaceLock };
    224         SQLite::Savepoint savepoint = SQLite::Savepoint::Create(m_dbconn, "sqliteindex_removemanifest");
    225 
    226         m_interface->RemoveManifest(m_dbconn, manifest);
    227 
    228         SetLastWriteTime();
    229 
    230         savepoint.Commit();
    231     }
    232 
    233     void SQLiteIndex::RemoveManifestById(IdType manifestId)
    234     {
    235         SQLite::Savepoint savepoint = SQLite::Savepoint::Create(m_dbconn, "SQLiteIndex_RemoveManifestById");
    236 
    237         m_interface->RemoveManifestById(m_dbconn, manifestId);
    238 
    239         SetLastWriteTime();
    240 
    241         savepoint.Commit();
    242     }
    243 
    244     void SQLiteIndex::PrepareForPackaging()
    245     {
    246         std::lock_guard<std::mutex> lockInterface{ *m_interfaceLock };
    247         AICLI_LOG(Repo, Info, << "Preparing index for packaging");
    248 
    249         m_interface->PrepareForPackaging(Schema::SQLiteIndexContext{ m_dbconn, m_contextData });
    250     }
    251 
    252     bool SQLiteIndex::CheckConsistency(bool log) const
    253     {
    254         std::lock_guard<std::mutex> lockInterface{ *m_interfaceLock };
    255         AICLI_LOG(Repo, Info, << "Checking index consistency...");
    256 
    257         bool result = m_interface->CheckConsistency(m_dbconn, log);
    258 
    259         AICLI_LOG(Repo, Info, << "...index *WAS" << (result ? "*" : " NOT*") << " consistent.");
    260 
    261         return result;
    262     }
    263 
    264     Schema::ISQLiteIndex::SearchResult SQLiteIndex::Search(const SearchRequest& request) const
    265     {
    266         std::lock_guard<std::mutex> lockInterface{ *m_interfaceLock };
    267         AICLI_LOG(Repo, Verbose, << "Performing search: " << request.ToString());
    268 
    269         return m_interface->Search(m_dbconn, request);
    270     }
    271 
    272     std::optional<std::string> SQLiteIndex::GetPropertyByPrimaryId(IdType primaryId, PackageVersionProperty property) const
    273     {
    274         std::lock_guard<std::mutex> lockInterface{ *m_interfaceLock };
    275         return m_interface->GetPropertyByPrimaryId(m_dbconn, primaryId, property);
    276     }
    277 
    278     std::vector<std::string> SQLiteIndex::GetMultiPropertyByPrimaryId(IdType primaryId, PackageVersionMultiProperty property) const
    279     {
    280         std::lock_guard<std::mutex> lockInterface{ *m_interfaceLock };
    281         return m_interface->GetMultiPropertyByPrimaryId(m_dbconn, primaryId, property);
    282     }
    283 
    284     std::optional<SQLiteIndex::IdType> SQLiteIndex::GetManifestIdByKey(IdType id, std::string_view version, std::string_view channel) const
    285     {
    286         std::lock_guard<std::mutex> lockInterface{ *m_interfaceLock };
    287         return m_interface->GetManifestIdByKey(m_dbconn, id, version, channel);
    288     }
    289 
    290     std::optional<SQLiteIndex::IdType> SQLiteIndex::GetManifestIdByManifest(const Manifest::Manifest& manifest) const
    291     {
    292         return m_interface->GetManifestIdByManifest(m_dbconn, manifest);
    293     }
    294 
    295     std::vector<SQLiteIndex::VersionKey> SQLiteIndex::GetVersionKeysById(IdType id) const
    296     {
    297         std::lock_guard<std::mutex> lockInterface{ *m_interfaceLock };
    298         return m_interface->GetVersionKeysById(m_dbconn, id);
    299     }
    300 
    301     SQLiteIndex::MetadataResult SQLiteIndex::GetMetadataByManifestId(SQLite::rowid_t manifestId) const
    302     {
    303         std::lock_guard<std::mutex> lockInterface{ *m_interfaceLock };
    304         return m_interface->GetMetadataByManifestId(m_dbconn, manifestId);
    305     }
    306 
    307     void SQLiteIndex::SetMetadataByManifestId(IdType manifestId, PackageVersionMetadata metadata, std::string_view value)
    308     {
    309         std::lock_guard<std::mutex> lockInterface{ *m_interfaceLock };
    310         m_interface->SetMetadataByManifestId(m_dbconn, manifestId, metadata, value);
    311     }
    312 
    313     Utility::NormalizedName SQLiteIndex::NormalizeName(std::string_view name, std::string_view publisher) const
    314     {
    315         std::lock_guard<std::mutex> lockInterface{ *m_interfaceLock };
    316         return m_interface->NormalizeName(name, publisher);
    317     }
    318 
    319     std::set<std::pair<SQLite::rowid_t, Utility::NormalizedString>> SQLiteIndex::GetDependenciesByManifestRowId(SQLite::rowid_t manifestRowId) const
    320     {
    321         return m_interface->GetDependenciesByManifestRowId(m_dbconn, manifestRowId);
    322     }
    323 
    324     std::vector<std::pair<SQLite::rowid_t, Utility::NormalizedString>> SQLiteIndex::GetDependentsById(AppInstaller::Manifest::string_t packageId) const
    325     {
    326         return m_interface->GetDependentsById(m_dbconn, packageId);
    327     }
    328 
    329     bool SQLiteIndex::MigrateTo(SQLite::Version version)
    330     {
    331         std::lock_guard<std::mutex> lockInterface{ *m_interfaceLock };
    332         SQLite::Savepoint savepoint = SQLite::Savepoint::Create(m_dbconn, "sqliteindex_migrate_to");
    333 
    334         AICLI_LOG(Repo, Info, << "Attempting to migrate index from [" << m_interface->GetVersion() << "] to [" << version << "]...");
    335         std::unique_ptr<Schema::ISQLiteIndex> newInterface = Schema::CreateISQLiteIndex(version);
    336 
    337         bool result = newInterface->MigrateFrom(m_dbconn, m_interface.get());
    338 
    339         AICLI_LOG(Repo, Info, << "...migration was " << (result ? "" : "NOT ") << "successful");
    340         if (result)
    341         {
    342             version.SetSchemaVersion(m_dbconn);
    343             SetLastWriteTime();
    344             savepoint.Commit();
    345 
    346             m_version = version;
    347             m_interface = std::move(newInterface);
    348         }
    349 
    350         return result;
    351     }
    352 
    353     void SQLiteIndex::SetProperty(Property property, const std::string& value)
    354     {
    355         std::lock_guard<std::mutex> lockInterface{ *m_interfaceLock };
    356 
    357         switch (property)
    358         {
    359         case Property::PackageUpdateTrackingBaseTime:
    360             m_interface->SetProperty(m_dbconn, Schema::Property::PackageUpdateTrackingBaseTime, value);
    361             break;
    362         case Property::IntermediateFileOutputPath:
    363         {
    364             std::filesystem::path pathValue{ Utility::ConvertToUTF16(value) };
    365             THROW_HR_IF(E_INVALIDARG, pathValue.empty() || pathValue.is_relative());
    366             m_contextData.Add<Schema::Property::IntermediateFileOutputPath>(std::move(pathValue));
    367         }
    368             break;
    369         }
    370     }
    371 }