winget-cli

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

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 }