UpgradeCommand.cpp (9807B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #include "pch.h" 4 #include "UpgradeCommand.h" 5 #include "Workflows/CompletionFlow.h" 6 #include "Workflows/DownloadFlow.h" 7 #include "Workflows/InstallFlow.h" 8 #include "Workflows/MultiQueryFlow.h" 9 #include "Workflows/UpdateFlow.h" 10 #include "Workflows/WorkflowBase.h" 11 #include "Workflows/DependenciesFlow.h" 12 #include "Resources.h" 13 #include <winget/LocIndependent.h> 14 15 namespace AppInstaller::CLI 16 { 17 using namespace AppInstaller::CLI::Execution; 18 using namespace AppInstaller::Manifest; 19 using namespace AppInstaller::CLI::Workflow; 20 using namespace AppInstaller::Utility::literals; 21 22 namespace 23 { 24 // Determines whether we should list available upgrades, instead 25 // of performing an upgrade 26 bool ShouldListUpgrade(const Execution::Args& args, ArgTypeCategory argCategories = ArgTypeCategory::None) 27 { 28 if (argCategories == ArgTypeCategory::None) 29 { 30 argCategories = Argument::GetCategoriesPresent(args); 31 } 32 33 // Valid arguments for list are only those related to the sources and which packages to include (e.g. --include-unknown). 34 // Instead of checking for them, we check that there aren't any other arguments present. 35 return !args.Contains(Args::Type::All) && 36 WI_AreAllFlagsClear(argCategories, ArgTypeCategory::Manifest | ArgTypeCategory::PackageQuery | ArgTypeCategory::InstallerBehavior); 37 } 38 } 39 40 std::vector<Argument> UpgradeCommand::GetArguments() const 41 { 42 return { 43 Argument::ForType(Args::Type::MultiQuery), // -q 44 Argument::ForType(Args::Type::Manifest), // -m 45 Argument::ForType(Args::Type::Id), 46 Argument::ForType(Args::Type::Name), 47 Argument::ForType(Args::Type::Moniker), 48 Argument::ForType(Args::Type::Version), // -v 49 Argument::ForType(Args::Type::Channel), 50 Argument::ForType(Args::Type::Source), // -s 51 Argument::ForType(Args::Type::Exact), // -e 52 Argument::ForType(Args::Type::Interactive), // -i 53 Argument::ForType(Args::Type::Silent), // -h 54 Argument::ForType(Args::Type::Purge), 55 Argument::ForType(Args::Type::Log), // -o 56 Argument::ForType(Args::Type::CustomSwitches), 57 Argument::ForType(Args::Type::Override), 58 Argument::ForType(Args::Type::InstallLocation), // -l 59 Argument{ Args::Type::InstallScope, Resource::String::InstalledScopeArgumentDescription, ArgumentType::Standard, Argument::Visibility::Help }, 60 Argument::ForType(Args::Type::InstallArchitecture), // -a 61 Argument::ForType(Args::Type::InstallerType), 62 Argument::ForType(Args::Type::Locale), 63 Argument::ForType(Args::Type::HashOverride), 64 Argument::ForType(Args::Type::AllowReboot), 65 Argument::ForType(Args::Type::SkipDependencies), 66 Argument::ForType(Args::Type::IgnoreLocalArchiveMalwareScan), 67 Argument::ForType(Args::Type::AcceptPackageAgreements), 68 Argument::ForType(Args::Type::AcceptSourceAgreements), 69 Argument::ForType(Args::Type::CustomHeader), 70 Argument::ForType(Args::Type::AuthenticationMode), 71 Argument::ForType(Args::Type::AuthenticationAccount), 72 Argument{ Args::Type::All, Resource::String::UpdateAllArgumentDescription, ArgumentType::Flag }, 73 Argument{ Args::Type::IncludeUnknown, Resource::String::IncludeUnknownArgumentDescription, ArgumentType::Flag }, 74 Argument{ Args::Type::IncludePinned, Resource::String::IncludePinnedArgumentDescription, ArgumentType::Flag}, 75 Argument::ForType(Args::Type::UninstallPrevious), 76 Argument::ForType(Args::Type::Force), 77 }; 78 } 79 80 Resource::LocString UpgradeCommand::ShortDescription() const 81 { 82 return { Resource::String::UpgradeCommandShortDescription }; 83 } 84 85 Resource::LocString UpgradeCommand::LongDescription() const 86 { 87 return { Resource::String::UpgradeCommandLongDescription }; 88 } 89 90 void UpgradeCommand::Complete(Execution::Context& context, Execution::Args::Type valueType) const 91 { 92 if (valueType == Execution::Args::Type::Manifest || 93 valueType == Execution::Args::Type::Log || 94 valueType == Execution::Args::Type::Override || 95 valueType == Execution::Args::Type::InstallLocation) 96 { 97 // Intentionally output nothing to allow pass through to filesystem. 98 return; 99 } 100 101 context << 102 OpenSource() << 103 OpenCompositeSource(Repository::PredefinedSource::Installed); 104 105 switch (valueType) 106 { 107 case Execution::Args::Type::MultiQuery: 108 context << 109 RequireCompletionWordNonEmpty << 110 SearchSourceForManyCompletion << 111 CompleteWithMatchedField; 112 break; 113 case Execution::Args::Type::Id: 114 case Execution::Args::Type::Name: 115 case Execution::Args::Type::Moniker: 116 case Execution::Args::Type::Version: 117 case Execution::Args::Type::Channel: 118 case Execution::Args::Type::Source: 119 context << 120 CompleteWithSingleSemanticsForValueUsingExistingSource(valueType); 121 break; 122 case Args::Type::InstallArchitecture: 123 case Args::Type::Locale: 124 // May well move to CompleteWithSingleSemanticsForValue, 125 // but for now output nothing. 126 context << 127 Workflow::CompleteWithEmptySet; 128 break; 129 } 130 } 131 132 Utility::LocIndView UpgradeCommand::HelpLink() const 133 { 134 return "https://aka.ms/winget-command-upgrade"_liv; 135 } 136 137 void UpgradeCommand::ValidateArgumentsInternal(Execution::Args& execArgs) const 138 { 139 const auto argCategories = Argument::GetCategoriesAndValidateCommonArguments(execArgs, /* requirePackageSelectionArg */ false); 140 141 if (!ShouldListUpgrade(execArgs, argCategories) && 142 WI_IsFlagClear(argCategories, ArgTypeCategory::PackageQuery) && 143 WI_IsFlagSet(argCategories, ArgTypeCategory::SingleInstallerBehavior)) 144 { 145 throw CommandException(Resource::String::InvalidArgumentWithoutQueryError); 146 } 147 } 148 149 void UpgradeCommand::ExecuteInternal(Execution::Context& context) const 150 { 151 context.SetFlags(Execution::ContextFlag::InstallerExecutionUseUpdate); 152 153 // Only allow for source failures when doing a list of available upgrades. 154 // We have to set it now to allow for source open failures to also just warn. 155 if (ShouldListUpgrade(context.Args)) 156 { 157 context.SetFlags(Execution::ContextFlag::TreatSourceFailuresAsWarning); 158 } 159 160 context << 161 InitializeInstallerDownloadAuthenticatorsMap << 162 ReportExecutionStage(ExecutionStage::Discovery) << 163 OpenSource() << 164 OpenCompositeSource(DetermineInstalledSource(context)); 165 166 if (ShouldListUpgrade(context.Args)) 167 { 168 // Upgrade with no args list packages with updates available 169 context << 170 SearchSourceForMany << 171 HandleSearchResultFailures << 172 EnsureMatchesFromSearchResult(OperationType::Upgrade) << 173 ReportListResult(true); 174 } 175 else if (context.Args.Contains(Execution::Args::Type::All)) 176 { 177 // --all switch updates all packages found 178 context << 179 SearchSourceForMany << 180 HandleSearchResultFailures << 181 EnsureMatchesFromSearchResult(OperationType::Upgrade) << 182 ReportListResult(true) << 183 UpdateAllApplicable; 184 } 185 else if (context.Args.Contains(Execution::Args::Type::Manifest)) 186 { 187 // --manifest case where new manifest is provided 188 context << 189 GetManifestFromArg << 190 SearchSourceUsingManifest << 191 EnsureOneMatchFromSearchResult(OperationType::Upgrade) << 192 GetInstalledPackageVersion << 193 EnsureUpdateVersionApplicable << 194 SelectInstaller << 195 EnsureApplicableInstaller << 196 InstallSinglePackage; 197 } 198 else 199 { 200 // The remaining case: search for specific packages to update 201 if (!context.Args.Contains(Execution::Args::Type::MultiQuery)) 202 { 203 context << InstallOrUpgradeSinglePackage(OperationType::Upgrade); 204 } 205 else 206 { 207 ProcessMultiplePackages::Flags flags = ProcessMultiplePackages::Flags::None; 208 if (Settings::User().Get<Settings::Setting::InstallSkipDependencies>() || context.Args.Contains(Execution::Args::Type::SkipDependencies)) 209 { 210 flags = ProcessMultiplePackages::Flags::IgnoreDependencies; 211 } 212 213 context << 214 GetMultiSearchRequests << 215 SearchSubContextsForSingle(OperationType::Upgrade) << 216 ReportExecutionStage(ExecutionStage::Execution) << 217 ProcessMultiplePackages(Resource::String::PackageRequiresDependencies, APPINSTALLER_CLI_ERROR_MULTIPLE_INSTALL_FAILED, flags); 218 } 219 } 220 } 221 }