winget-cli

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

commit 21f3c96a23e6f2c1c9593237f8fe971549d74a6f
parent 965c05d0730770646fa2348b38375b2a93b50f25
Author: JohnMcPMS <johnmcp@microsoft.com>
Date:   Mon, 23 Mar 2020 12:43:58 -0700

Shorten auto-update time, retry on update failure, don't call deployment if no change (#65)


Diffstat:
Msrc/AppInstallerCLITests/Sources.cpp | 37+++++++++++++++++++++++++++++++++++++
Msrc/AppInstallerRepositoryCore/Microsoft/PreIndexedPackageSourceFactory.cpp | 38+++++++++++++++++++++++++++++++++++++-
Msrc/AppInstallerRepositoryCore/RepositorySource.cpp | 22++++++++++++++++++----
Msrc/AppInstallerRepositoryCore/pch.h | 1+
4 files changed, 93 insertions(+), 5 deletions(-)

diff --git a/src/AppInstallerCLITests/Sources.cpp b/src/AppInstallerCLITests/Sources.cpp @@ -328,6 +328,43 @@ TEST_CASE("RepoSources_UpdateSource", "[sources]") REQUIRE((now - sources[0].LastUpdateTime) < 1s); } +TEST_CASE("RepoSources_UpdateSourceRetries", "[sources]") +{ + using namespace std::chrono_literals; + + RemoveSetting(s_RepositorySettings_UserSources); + TestHook_ClearSourceFactoryOverrides(); + + std::string name = "thisIsTheName"; + std::string type = "thisIsTheType"; + std::string arg = "thisIsTheArg"; + std::string data = "thisIsTheData"; + + TestSourceFactory factory; + TestHook_SetSourceFactoryOverride(type, factory); + + ProgressCallback progress; + AddSource(name, type, arg, progress); + + // Reset for a call to update + bool updateShouldThrow = false; + bool updateCalledOnFactoryAgain = false; + factory.m_Update = [&](SourceDetails& sd) + { + if (updateShouldThrow) + { + updateShouldThrow = false; + THROW_HR(E_ACCESSDENIED); + } + updateCalledOnFactoryAgain = true; + sd.Data = data; + }; + + UpdateSource(name, progress); + + REQUIRE(updateCalledOnFactoryAgain); +} + TEST_CASE("RepoSources_RemoveSource", "[sources]") { RemoveSetting(s_RepositorySettings_UserSources); diff --git a/src/AppInstallerRepositoryCore/Microsoft/PreIndexedPackageSourceFactory.cpp b/src/AppInstallerRepositoryCore/Microsoft/PreIndexedPackageSourceFactory.cpp @@ -160,8 +160,38 @@ namespace AppInstaller::Repository::Microsoft return std::make_shared<SQLiteIndexSource>(details, std::move(index), std::move(lock)); } - void UpdateInternal(std::string packageLocation, SourceDetails&, IProgressCallback& progress) override + void UpdateInternal(std::string packageLocation, SourceDetails& details, IProgressCallback& progress) override { + // Check if the package is newer before calling into deployment. + // This can save us a lot of time over letting deployment detect same version. + auto optionalPackage = GetPackageFromDetails(details); + if (optionalPackage) + { + Msix::MsixInfo packageInfo(packageLocation); + THROW_HR_IF(APPINSTALLER_CLI_ERROR_PACKAGE_IS_BUNDLE, packageInfo.GetIsBundle()); + + if (progress.IsCancelled()) + { + AICLI_LOG(Repo, Info, << "Cancelling update upon request"); + return; + } + + std::filesystem::path packagePath = optionalPackage.InstalledLocation().Path().c_str(); + std::filesystem::path manifestPath = packagePath / s_PreIndexedPackageSourceFactory_AppxManifestFileName; + + if (!packageInfo.IsNewerThan(manifestPath)) + { + AICLI_LOG(Repo, Info, << "Remote source data was not newer than existing, no update needed"); + return; + } + } + + if (progress.IsCancelled()) + { + AICLI_LOG(Repo, Info, << "Cancelling update upon request"); + return; + } + winrt::Windows::Foundation::Uri uri(Utility::ConvertToUTF16(packageLocation)); Deployment::RequestAddPackageAsync(uri, winrt::Windows::Management::Deployment::DeploymentOptions::None, progress); } @@ -200,6 +230,12 @@ namespace AppInstaller::Repository::Microsoft std::filesystem::path packageLocation = GetStatePathFromDetails(details); packageLocation /= s_PreIndexedPackageSourceFactory_IndexFileName; + if (!std::filesystem::exists(packageLocation)) + { + AICLI_LOG(Repo, Info, << "Data not found by family name " << details.Data); + THROW_HR(APPINSTALLER_CLI_ERROR_SOURCE_DATA_MISSING); + } + SQLiteIndex index = SQLiteIndex::Open(packageLocation.u8string(), SQLiteIndex::OpenDisposition::Read); return std::make_shared<SQLiteIndexSource>(details, std::move(index), std::move(lock)); diff --git a/src/AppInstallerRepositoryCore/RepositorySource.cpp b/src/AppInstallerRepositoryCore/RepositorySource.cpp @@ -194,7 +194,21 @@ namespace AppInstaller::Repository void UpdateSourceFromDetails(SourceDetails& details, IProgressCallback& progress) { - GetFactoryForType(details.Type)->Update(details, progress); + auto factory = GetFactoryForType(details.Type); + + // Attempt to update; if it fails, wait a short time and retry. + try + { + factory->Update(details, progress); + return; + } + CATCH_LOG(); + + AICLI_LOG(Repo, Info, << "Source update failed, waiting a bit and retrying: " << details.Name); + std::this_thread::sleep_for(2s); + + // If this one fails, maybe the problem is persistent. + factory->Update(details, progress); } void RemoveSourceFromDetails(const SourceDetails& details, IProgressCallback& progress) @@ -221,14 +235,14 @@ namespace AppInstaller::Repository } // TODO: Enable some amount of user control over this. - constexpr static auto s_DefaultAutoUpdateTime = 12h; + constexpr static auto s_DefaultAutoUpdateTime = 5min; auto timeSinceLastUpdate = std::chrono::system_clock::now() - details.LastUpdateTime; if (timeSinceLastUpdate > s_DefaultAutoUpdateTime) { AICLI_LOG(Repo, Info, << "Source past auto update time [" << - std::chrono::duration_cast<std::chrono::hours>(s_DefaultAutoUpdateTime).count() << " hours]; it has been at least " << - std::chrono::duration_cast<std::chrono::hours>(timeSinceLastUpdate).count() << " hours"); + std::chrono::duration_cast<std::chrono::minutes>(s_DefaultAutoUpdateTime).count() << " mins]; it has been at least " << + std::chrono::duration_cast<std::chrono::minutes>(timeSinceLastUpdate).count() << " mins"); return true; } diff --git a/src/AppInstallerRepositoryCore/pch.h b/src/AppInstallerRepositoryCore/pch.h @@ -37,6 +37,7 @@ #include <string_view> #include <sstream> #include <system_error> +#include <thread> #include <tuple> #include <type_traits> #include <utility>