winget-cli

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

commit 6096b5e9f3ed13726e5ec36947b0ce88a040cff4
parent 511d4f9815af8070b4d0d80fe9fbd2024f5f96e3
Author: JohnMcPMS <johnmcp@microsoft.com>
Date:   Mon, 31 Mar 2025 17:04:38 -0700

Refactor ProcessMultiplePackages for clarity (#5340)

## Change
A refactor of `ProcessMultiplePackages` to increase the clarity of what
is being requested as options. This is done by passing a flags enum
rather than 5 booleans.

Also removes some extraneous `Workflow::` namespaces and improves the
logging when going backward in execution phase.
Diffstat:
Msrc/AppInstallerCLICore/Commands/InstallCommand.cpp | 42++++++++++++++++++++++--------------------
Msrc/AppInstallerCLICore/Commands/UpgradeCommand.cpp | 28+++++++++++++++-------------
Msrc/AppInstallerCLICore/ExecutionContext.cpp | 2+-
Msrc/AppInstallerCLICore/Workflows/ImportExportFlow.cpp | 6+++---
Msrc/AppInstallerCLICore/Workflows/InstallFlow.cpp | 49++++++++++++++++++++++++++++++++++++-------------
Msrc/AppInstallerCLICore/Workflows/InstallFlow.h | 30+++++++++++++++---------------
Msrc/AppInstallerCLICore/Workflows/UpdateFlow.cpp | 12+++++++++---
Msrc/AppInstallerCLITests/InstallDependenciesFlow.cpp | 6++----
8 files changed, 103 insertions(+), 72 deletions(-)

diff --git a/src/AppInstallerCLICore/Commands/InstallCommand.cpp b/src/AppInstallerCLICore/Commands/InstallCommand.cpp @@ -119,47 +119,49 @@ namespace AppInstaller::CLI { context.SetFlags(ContextFlag::ShowSearchResultsOnPartialFailure); - context << Workflow::InitializeInstallerDownloadAuthenticatorsMap; + context << InitializeInstallerDownloadAuthenticatorsMap; if (context.Args.Contains(Execution::Args::Type::Manifest)) { context << - Workflow::ReportExecutionStage(ExecutionStage::Discovery) << - Workflow::GetManifestFromArg << - Workflow::SelectInstaller << - Workflow::EnsureApplicableInstaller << - Workflow::Checkpoint("PreInstallCheckpoint", {}) << // TODO: Capture context data - Workflow::InstallSinglePackage; + ReportExecutionStage(ExecutionStage::Discovery) << + GetManifestFromArg << + SelectInstaller << + EnsureApplicableInstaller << + Checkpoint("PreInstallCheckpoint", {}) << // TODO: Capture context data + InstallSinglePackage; } else { context << - Workflow::ReportExecutionStage(ExecutionStage::Discovery) << - Workflow::OpenSource(); + ReportExecutionStage(ExecutionStage::Discovery) << + OpenSource(); if (!context.Args.Contains(Execution::Args::Type::Force)) { context << - Workflow::OpenCompositeSource(Workflow::DetermineInstalledSource(context), false, Repository::CompositeSearchBehavior::AvailablePackages); + OpenCompositeSource(DetermineInstalledSource(context), false, Repository::CompositeSearchBehavior::AvailablePackages); } if (context.Args.Contains(Execution::Args::Type::MultiQuery)) { - bool skipDependencies = Settings::User().Get<Settings::Setting::InstallSkipDependencies>() || context.Args.Contains(Execution::Args::Type::SkipDependencies); + ProcessMultiplePackages::Flags flags = ProcessMultiplePackages::Flags::None; + if (Settings::User().Get<Settings::Setting::InstallSkipDependencies>() || context.Args.Contains(Execution::Args::Type::SkipDependencies)) + { + flags = ProcessMultiplePackages::Flags::IgnoreDependencies; + } + context << - Workflow::GetMultiSearchRequests << - Workflow::SearchSubContextsForSingle() << - Workflow::ReportExecutionStage(Workflow::ExecutionStage::Execution) << - Workflow::ProcessMultiplePackages( - Resource::String::PackageRequiresDependencies, - APPINSTALLER_CLI_ERROR_MULTIPLE_INSTALL_FAILED, - {}, true, skipDependencies); + GetMultiSearchRequests << + SearchSubContextsForSingle() << + ReportExecutionStage(ExecutionStage::Execution) << + ProcessMultiplePackages(Resource::String::PackageRequiresDependencies, APPINSTALLER_CLI_ERROR_MULTIPLE_INSTALL_FAILED, flags); } else { context << - Workflow::Checkpoint("PreInstallCheckpoint", {}) << // TODO: Capture context data - Workflow::InstallOrUpgradeSinglePackage(OperationType::Install); + Checkpoint("PreInstallCheckpoint", {}) << // TODO: Capture context data + InstallOrUpgradeSinglePackage(OperationType::Install); } } } diff --git a/src/AppInstallerCLICore/Commands/UpgradeCommand.cpp b/src/AppInstallerCLICore/Commands/UpgradeCommand.cpp @@ -158,10 +158,10 @@ namespace AppInstaller::CLI } context << - Workflow::InitializeInstallerDownloadAuthenticatorsMap << - Workflow::ReportExecutionStage(ExecutionStage::Discovery) << - Workflow::OpenSource() << - Workflow::OpenCompositeSource(Workflow::DetermineInstalledSource(context)); + InitializeInstallerDownloadAuthenticatorsMap << + ReportExecutionStage(ExecutionStage::Discovery) << + OpenSource() << + OpenCompositeSource(DetermineInstalledSource(context)); if (ShouldListUpgrade(context.Args)) { @@ -200,19 +200,21 @@ namespace AppInstaller::CLI // The remaining case: search for specific packages to update if (!context.Args.Contains(Execution::Args::Type::MultiQuery)) { - context << Workflow::InstallOrUpgradeSinglePackage(OperationType::Upgrade); + context << InstallOrUpgradeSinglePackage(OperationType::Upgrade); } else { - bool skipDependencies = Settings::User().Get<Settings::Setting::InstallSkipDependencies>() || context.Args.Contains(Execution::Args::Type::SkipDependencies); + ProcessMultiplePackages::Flags flags = ProcessMultiplePackages::Flags::None; + if (Settings::User().Get<Settings::Setting::InstallSkipDependencies>() || context.Args.Contains(Execution::Args::Type::SkipDependencies)) + { + flags = ProcessMultiplePackages::Flags::IgnoreDependencies; + } + context << - Workflow::GetMultiSearchRequests << - Workflow::SearchSubContextsForSingle(OperationType::Upgrade) << - Workflow::ReportExecutionStage(Workflow::ExecutionStage::Execution) << - Workflow::ProcessMultiplePackages( - Resource::String::PackageRequiresDependencies, - APPINSTALLER_CLI_ERROR_MULTIPLE_INSTALL_FAILED, - {}, true, skipDependencies); + GetMultiSearchRequests << + SearchSubContextsForSingle(OperationType::Upgrade) << + ReportExecutionStage(ExecutionStage::Execution) << + ProcessMultiplePackages(Resource::String::PackageRequiresDependencies, APPINSTALLER_CLI_ERROR_MULTIPLE_INSTALL_FAILED, flags); } } } diff --git a/src/AppInstallerCLICore/ExecutionContext.cpp b/src/AppInstallerCLICore/ExecutionContext.cpp @@ -465,7 +465,7 @@ namespace AppInstaller::CLI::Execution } else if (m_executionStage > stage) { - THROW_HR_MSG(HRESULT_FROM_WIN32(ERROR_INVALID_STATE), "Reporting ExecutionStage to an earlier Stage without allowBackward as true"); + THROW_HR_MSG(HRESULT_FROM_WIN32(ERROR_INVALID_STATE), "Reporting ExecutionStage to an earlier Stage: current[%d], new[%d]", ToIntegral(m_executionStage), ToIntegral(stage)); } m_executionStage = stage; diff --git a/src/AppInstallerCLICore/Workflows/ImportExportFlow.cpp b/src/AppInstallerCLICore/Workflows/ImportExportFlow.cpp @@ -319,9 +319,9 @@ namespace AppInstaller::CLI::Workflow context.Add<Execution::Data::Dependencies>(allDependencies); context << - Workflow::ReportDependencies(Resource::String::ImportCommandReportDependencies) << - Workflow::ProcessMultiplePackages( - Resource::String::ImportCommandReportDependencies, APPINSTALLER_CLI_ERROR_IMPORT_INSTALL_FAILED, {}, true, true); + ReportDependencies(Resource::String::ImportCommandReportDependencies) << + ProcessMultiplePackages( + Resource::String::ImportCommandReportDependencies, APPINSTALLER_CLI_ERROR_IMPORT_INSTALL_FAILED, ProcessMultiplePackages::Flags::IgnoreDependencies); if (context.GetTerminationHR() == APPINSTALLER_CLI_ERROR_IMPORT_INSTALL_FAILED) { diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp @@ -584,6 +584,8 @@ namespace AppInstaller::CLI::Workflow void InstallDependencies(Execution::Context& context) { + using Flags = ProcessMultiplePackages::Flags; + if (Settings::User().Get<Settings::Setting::InstallSkipDependencies>() || context.Args.Contains(Execution::Args::Type::SkipDependencies)) { context.Reporter.Warn() << Resource::String::DependenciesSkippedMessage << std::endl; @@ -591,14 +593,16 @@ namespace AppInstaller::CLI::Workflow } context << - Workflow::GetDependenciesFromInstaller << - Workflow::ReportDependencies(Resource::String::PackageRequiresDependencies) << - Workflow::EnableWindowsFeaturesDependencies << - Workflow::ProcessMultiplePackages(Resource::String::PackageRequiresDependencies, APPINSTALLER_CLI_ERROR_INSTALL_DEPENDENCIES, {}, true, true, true, true); + GetDependenciesFromInstaller << + ReportDependencies(Resource::String::PackageRequiresDependencies) << + EnableWindowsFeaturesDependencies << + ProcessMultiplePackages(Resource::String::PackageRequiresDependencies, APPINSTALLER_CLI_ERROR_INSTALL_DEPENDENCIES, Flags::IgnoreDependencies | Flags::StopOnFailure | Flags::RefreshPathVariable); } void DownloadPackageDependencies(Execution::Context& context) { + using Flags = ProcessMultiplePackages::Flags; + if (Settings::User().Get<Settings::Setting::InstallSkipDependencies>() || context.Args.Contains(Execution::Args::Type::SkipDependencies)) { context.Reporter.Warn() << Resource::String::DependenciesSkippedMessage << std::endl; @@ -606,10 +610,10 @@ namespace AppInstaller::CLI::Workflow } context << - Workflow::GetDependenciesFromInstaller << - Workflow::ReportDependencies(Resource::String::PackageRequiresDependencies) << - Workflow::CreateDependencySubContexts(Resource::String::PackageRequiresDependencies) << - Workflow::ProcessMultiplePackages(Resource::String::PackageRequiresDependencies, APPINSTALLER_CLI_ERROR_DOWNLOAD_DEPENDENCIES, {}, true, true, true, false, true); + GetDependenciesFromInstaller << + ReportDependencies(Resource::String::PackageRequiresDependencies) << + CreateDependencySubContexts(Resource::String::PackageRequiresDependencies) << + ProcessMultiplePackages(Resource::String::PackageRequiresDependencies, APPINSTALLER_CLI_ERROR_DOWNLOAD_DEPENDENCIES, Flags::IgnoreDependencies | Flags::StopOnFailure | Flags::DownloadOnly); } void InstallSinglePackage(Execution::Context& context) @@ -675,6 +679,25 @@ namespace AppInstaller::CLI::Workflow Workflow::EnsureValidNestedInstallerMetadataForArchiveInstall; } + ProcessMultiplePackages::ProcessMultiplePackages( + StringResource::StringId dependenciesReportMessage, + HRESULT resultOnFailure, + Flags flags, + std::vector<HRESULT>&& ignorableInstallResults) : + WorkflowTask("ProcessMultiplePackages"), + m_dependenciesReportMessage(dependenciesReportMessage), + m_resultOnFailure(resultOnFailure), + m_ignorableInstallResults(std::move(ignorableInstallResults)) + { + // Inverted + m_ensurePackageAgreements = !WI_IsFlagSet(flags, Flags::SkipPackageAgreements); + + m_ignorePackageDependencies = WI_IsFlagSet(flags, Flags::IgnoreDependencies); + m_stopOnFailure = WI_IsFlagSet(flags, Flags::StopOnFailure); + m_refreshPathVariable = WI_IsFlagSet(flags, Flags::RefreshPathVariable); + m_downloadOnly = WI_IsFlagSet(flags, Flags::DownloadOnly); + } + void ProcessMultiplePackages::operator()(Execution::Context& context) const { if (!context.Contains(Execution::Data::PackageSubContexts)) @@ -692,11 +715,11 @@ namespace AppInstaller::CLI::Workflow return; } + auto& packageSubContexts = context.Get<Execution::Data::PackageSubContexts>(); + // Report dependencies if (!m_ignorePackageDependencies) { - auto& packageSubContexts = context.Get<Execution::Data::PackageSubContexts>(); - DependencyList allDependencies; for (auto& packageContext : packageSubContexts) @@ -721,10 +744,10 @@ namespace AppInstaller::CLI::Workflow } bool allSucceeded = true; - size_t packagesCount = context.Get<Execution::Data::PackageSubContexts>().size(); + size_t packagesCount = packageSubContexts.size(); size_t packagesProgress = 0; - for (auto& packageContext : context.Get<Execution::Data::PackageSubContexts>()) + for (auto& packageContext : packageSubContexts) { packagesProgress++; context.Reporter.Info() << '(' << packagesProgress << '/' << packagesCount << ") "_liv; @@ -744,7 +767,7 @@ namespace AppInstaller::CLI::Workflow currentContext << Workflow::EnableWindowsFeaturesDependencies << Workflow::CreateDependencySubContexts(m_dependenciesReportMessage) << - Workflow::ProcessMultiplePackages(m_dependenciesReportMessage, APPINSTALLER_CLI_ERROR_INSTALL_DEPENDENCIES, {}, true, true, true, true); + Workflow::ProcessMultiplePackages(m_dependenciesReportMessage, APPINSTALLER_CLI_ERROR_INSTALL_DEPENDENCIES, Flags::IgnoreDependencies | Flags::StopOnFailure | Flags::RefreshPathVariable); } currentContext << Workflow::DownloadInstaller; diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.h b/src/AppInstallerCLICore/Workflows/InstallFlow.h @@ -167,24 +167,22 @@ namespace AppInstaller::CLI::Workflow // Outputs: None struct ProcessMultiplePackages : public WorkflowTask { + // Flags to signal change from default behavior of the task. + enum class Flags : uint32_t + { + None = 0x00, + SkipPackageAgreements = 0x01, + IgnoreDependencies = 0x02, + StopOnFailure = 0x04, + RefreshPathVariable = 0x08, + DownloadOnly = 0x10, + }; + ProcessMultiplePackages( StringResource::StringId dependenciesReportMessage, HRESULT resultOnFailure, - std::vector<HRESULT>&& ignorableInstallResults = {}, - bool ensurePackageAgreements = true, - bool ignoreDependencies = false, - bool stopOnFailure = false, - bool refreshPathVariable = false, - bool downloadOnly = false): - WorkflowTask("ProcessMultiplePackages"), - m_dependenciesReportMessage(dependenciesReportMessage), - m_resultOnFailure(resultOnFailure), - m_ignorableInstallResults(std::move(ignorableInstallResults)), - m_ignorePackageDependencies(ignoreDependencies), - m_ensurePackageAgreements(ensurePackageAgreements), - m_stopOnFailure(stopOnFailure), - m_refreshPathVariable(refreshPathVariable), - m_downloadOnly(downloadOnly){} + Flags flags = Flags::None, + std::vector<HRESULT>&& ignorableInstallResults = {}); void operator()(Execution::Context& context) const override; @@ -199,6 +197,8 @@ namespace AppInstaller::CLI::Workflow bool m_downloadOnly; }; + DEFINE_ENUM_FLAG_OPERATORS(ProcessMultiplePackages::Flags); + // Stores the existing set of packages in ARP. // Required Args: None // Inputs: Installer diff --git a/src/AppInstallerCLICore/Workflows/UpdateFlow.cpp b/src/AppInstallerCLICore/Workflows/UpdateFlow.cpp @@ -269,13 +269,19 @@ namespace AppInstaller::CLI::Workflow { context.Add<Execution::Data::PackageSubContexts>(std::move(packageSubContexts)); context.Reporter.Info() << std::endl; - bool skipDependencies = Settings::User().Get<Settings::Setting::InstallSkipDependencies>() || context.Args.Contains(Execution::Args::Type::SkipDependencies); + + ProcessMultiplePackages::Flags flags = ProcessMultiplePackages::Flags::None; + if (Settings::User().Get<Settings::Setting::InstallSkipDependencies>() || context.Args.Contains(Execution::Args::Type::SkipDependencies)) + { + flags = ProcessMultiplePackages::Flags::IgnoreDependencies; + } + context << ProcessMultiplePackages( Resource::String::PackageRequiresDependencies, APPINSTALLER_CLI_ERROR_UPDATE_ALL_HAS_FAILURE, - { APPINSTALLER_CLI_ERROR_UPDATE_NOT_APPLICABLE }, - true, skipDependencies); + flags, + { APPINSTALLER_CLI_ERROR_UPDATE_NOT_APPLICABLE }); } if (packagesWithUnknownVersionSkipped > 0) diff --git a/src/AppInstallerCLITests/InstallDependenciesFlow.cpp b/src/AppInstallerCLITests/InstallDependenciesFlow.cpp @@ -30,12 +30,10 @@ void OverrideOpenSourceForDependencies(TestContext& context) void OverrideForProcessMultiplePackages(TestContext& context) { - context.Override({ Workflow::ProcessMultiplePackages( + context.Override({ ProcessMultiplePackages( Resource::String::PackageRequiresDependencies, APPINSTALLER_CLI_ERROR_INSTALL_DEPENDENCIES, - {}, - false, - true), [](TestContext&) + ProcessMultiplePackages::Flags::SkipPackageAgreements | ProcessMultiplePackages::Flags::IgnoreDependencies), [](TestContext&) { } });