winget-cli

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

WorkflowBase.h (17122B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #pragma once
      4 #include "ExecutionArgs.h"
      5 #include "ExecutionReporter.h"
      6 #include <winget/ExperimentalFeature.h>
      7 #include <winget/RepositorySearch.h>
      8 #include <winget/RepositorySource.h>
      9 #include <winget/Authentication.h>
     10 #include <winget/ManifestComparator.h>
     11 
     12 #include <string>
     13 #include <string_view>
     14 
     15 namespace AppInstaller::CLI::Execution
     16 {
     17     struct Context;
     18 }
     19 
     20 namespace AppInstaller::CLI::Workflow
     21 {
     22     // Values are ordered in a typical workflow stages
     23     enum class ExecutionStage : uint32_t
     24     {
     25         Initial = 0,
     26         ParseArgs = 1000,
     27         Discovery = 2000,
     28         Download = 3000,
     29         PreExecution = 3500,
     30         Execution = 4000,
     31         PostExecution = 5000,
     32     };
     33 
     34     enum class OperationType
     35     {
     36         Completion,
     37         Export,
     38         Install,
     39         List,
     40         Pin,
     41         Search,
     42         Show,
     43         Uninstall,
     44         Upgrade,
     45         Download,
     46         Repair,
     47     };
     48 
     49     // A task in the workflow.
     50     struct WorkflowTask
     51     {
     52         using Func = void (*)(Execution::Context&);
     53 
     54         WorkflowTask(Func f) : m_isFunc(true), m_func(f) {}
     55         WorkflowTask(std::string_view name, bool executeAlways = false) : m_name(name), m_executeAlways(executeAlways) {}
     56 
     57         virtual ~WorkflowTask() = default;
     58 
     59         WorkflowTask(const WorkflowTask&) = default;
     60         WorkflowTask& operator=(const WorkflowTask&) = default;
     61 
     62         WorkflowTask(WorkflowTask&&) = default;
     63         WorkflowTask& operator=(WorkflowTask&&) = default;
     64 
     65         bool operator==(const WorkflowTask& other) const;
     66 
     67         virtual void operator()(Execution::Context& context) const;
     68 
     69         const std::string& GetName() const { return m_name; }
     70         bool IsFunction() const { return m_isFunc; }
     71         Func Function() const { return m_func; }
     72         bool ExecuteAlways() const { return m_executeAlways; }
     73         void Log() const;
     74 
     75     private:
     76         bool m_isFunc = false;
     77         Func m_func = nullptr;
     78         std::string m_name;
     79         bool m_executeAlways = false;
     80     };
     81 
     82     // Helper to determine installed source to use based on context input.
     83     Repository::PredefinedSource DetermineInstalledSource(const Execution::Context& context);
     84 
     85     // Helper to create authentication arguments from context input.
     86     Authentication::AuthenticationArguments GetAuthenticationArguments(const Execution::Context& context);
     87 
     88     // Helper to report exceptions and return the HRESULT.
     89     // If context is null, no output will be attempted.
     90     HRESULT HandleException(Execution::Context* context, std::exception_ptr exception);
     91 
     92     // Helper to report exceptions and return the HRESULT.
     93     HRESULT HandleException(Execution::Context& context, std::exception_ptr exception);
     94 
     95     // Fills the options from the given context and metadata.
     96     AppInstaller::Manifest::ManifestComparator::Options GetManifestComparatorOptions(const Execution::Context& context, const Repository::IPackageVersion::Metadata& metadata);
     97 
     98     // Creates the source object.
     99     // Required Args: None
    100     // Inputs: None
    101     // Outputs: Source
    102     struct OpenSource : public WorkflowTask
    103     {
    104         OpenSource(bool forDependencies = false) : WorkflowTask("OpenSource"), m_forDependencies(forDependencies) {}
    105 
    106         void operator()(Execution::Context& context) const override;
    107     
    108     private:
    109         bool m_forDependencies;
    110     };
    111 
    112     // Creates a source object for a source specified by name, and adds it to the list of open sources.
    113     // Required Args: None
    114     // Inputs: Sources?
    115     // Outputs: Sources
    116     struct OpenNamedSourceForSources : public WorkflowTask
    117     {
    118         OpenNamedSourceForSources(std::string_view sourceName) : WorkflowTask("OpenNamedSourceForSources"), m_sourceName(sourceName) {}
    119 
    120         void operator()(Execution::Context& context) const override;
    121 
    122     private:
    123         Utility::LocIndView m_sourceName;
    124     };
    125 
    126     // Creates a source object for a predefined source.
    127     // Required Args: None
    128     // Inputs: None
    129     // Outputs: Source
    130     struct OpenPredefinedSource : public WorkflowTask
    131     {
    132         OpenPredefinedSource(Repository::PredefinedSource source, bool forDependencies = false) : WorkflowTask("OpenPredefinedSource"), m_predefinedSource(source), m_forDependencies(forDependencies) {}
    133 
    134         void operator()(Execution::Context& context) const override;
    135 
    136     private:
    137         Repository::PredefinedSource m_predefinedSource;
    138         bool m_forDependencies;
    139     };
    140 
    141     // Creates a composite source from the given predefined source and the existing source.
    142     // Required Args: None
    143     // Inputs: Source
    144     // Outputs: Source
    145     struct OpenCompositeSource : public WorkflowTask
    146     {
    147         OpenCompositeSource(
    148             Repository::PredefinedSource source,
    149             bool forDependencies = false,
    150             Repository::CompositeSearchBehavior searchBehavior = Repository::CompositeSearchBehavior::Installed) :
    151             WorkflowTask("OpenCompositeSource"), m_predefinedSource(source), m_forDependencies(forDependencies), m_searchBehavior(searchBehavior) {}
    152 
    153         void operator()(Execution::Context& context) const override;
    154 
    155     private:
    156         Repository::PredefinedSource m_predefinedSource;
    157         bool m_forDependencies;
    158         Repository::CompositeSearchBehavior m_searchBehavior;
    159     };
    160 
    161     // Performs a search on the source.
    162     // Required Args: None
    163     // Inputs: Source
    164     // Outputs: SearchResult
    165     void SearchSourceForMany(Execution::Context& context);
    166 
    167     // Creates a search request object with the semantics of targeting a single package.
    168     // Required Args: None
    169     // Inputs: Query, search filters (Id, Name, etc.)
    170     // Outputs: SearchRequest
    171     void GetSearchRequestForSingle(Execution::Context& context);
    172 
    173     // Performs a search on the source with the semantics of targeting a single package.
    174     // Required Args: None
    175     // Inputs: Source, SearchRequest
    176     // Outputs: SearchResult
    177     void SearchSourceForSingle(Execution::Context& context);
    178 
    179     // Performs a search on the source with the semantics of targeting many packages,
    180     // but for completion purposes.
    181     // Required Args: None
    182     // Inputs: Source, CompletionData
    183     // Outputs: SearchResult
    184     void SearchSourceForManyCompletion(Execution::Context& context);
    185 
    186     // Performs a search on the source with the semantics of targeting a single package,
    187     // but for completion purposes.
    188     // Required Args: None
    189     // Inputs: Source, CompletionData
    190     // Outputs: SearchResult
    191     void SearchSourceForSingleCompletion(Execution::Context& context);
    192 
    193     // Searches the source for the specific field as a completion.
    194     // Required Args: None
    195     // Inputs: CompletionData, Source
    196     // Outputs: None
    197     struct SearchSourceForCompletionField : public WorkflowTask
    198     {
    199         SearchSourceForCompletionField(Repository::PackageMatchField field) : WorkflowTask("SearchSourceForCompletionField"), m_field(field) {}
    200 
    201         void operator()(Execution::Context& context) const override;
    202 
    203     private:
    204         Repository::PackageMatchField m_field;
    205     };
    206 
    207     // Outputs the search results.
    208     // Required Args: None
    209     // Inputs: SearchResult
    210     // Outputs: None
    211     void ReportSearchResult(Execution::Context& context);
    212 
    213     // Outputs the search results as the list command would show.
    214     // Required Args: None
    215     // Inputs: SearchResult
    216     // Outputs: None
    217     struct ReportListResult : public WorkflowTask
    218     {
    219         ReportListResult(bool onlyShowUpgrades = false) : WorkflowTask("ReportListResult"), m_onlyShowUpgrades(onlyShowUpgrades) {}
    220 
    221         void operator()(Execution::Context& context) const override;
    222 
    223     private:
    224         bool m_onlyShowUpgrades;
    225     };
    226 
    227     // Handles failures in the SearchResult either by warning or failing.
    228     // Required Args: None
    229     // Inputs: SearchResult
    230     // Outputs: None
    231     void HandleSearchResultFailures(Execution::Context& context);
    232 
    233     // Outputs the search results when multiple packages found but only one expected.
    234     // Required Args: None
    235     // Inputs: SearchResult
    236     // Outputs: None
    237     void ReportMultiplePackageFoundResult(Execution::Context& context);
    238 
    239     // Outputs the search results when multiple packages found but only one expected.
    240     // Required Args: None
    241     // Inputs: SearchResult
    242     // Outputs: None
    243     void ReportMultiplePackageFoundResultWithSource(Execution::Context& context);
    244 
    245     // Ensures that there is at least one result in the search.
    246     // Required Args: bool indicating if the search result is from installed source
    247     // Inputs: SearchResult
    248     // Outputs: None
    249     struct EnsureMatchesFromSearchResult : public WorkflowTask
    250     {
    251         EnsureMatchesFromSearchResult(OperationType operation) :
    252             WorkflowTask("EnsureMatchesFromSearchResult"), m_operationType(operation) {}
    253 
    254         void operator()(Execution::Context& context) const override;
    255 
    256     private:
    257         OperationType m_operationType;
    258     };
    259 
    260     // Ensures that there is only one result in the search.
    261     // Required Args: bool indicating if the search result is from installed source
    262     // Inputs: SearchResult
    263     // Outputs: Package
    264     struct EnsureOneMatchFromSearchResult : public WorkflowTask
    265     {
    266         EnsureOneMatchFromSearchResult(OperationType operation) :
    267             WorkflowTask("EnsureOneMatchFromSearchResult"), m_operationType(operation) {}
    268 
    269         void operator()(Execution::Context& context) const override;
    270 
    271     private:
    272         OperationType m_operationType;
    273     };
    274 
    275     // Gets the manifest from package.
    276     // Required Args: Version and channel; can be empty. A flag indicating whether to consider package pins
    277     // Inputs: Package
    278     // Outputs: Manifest, PackageVersion
    279     struct GetManifestWithVersionFromPackage : public WorkflowTask
    280     {
    281         GetManifestWithVersionFromPackage(std::string_view version, std::string_view channel, bool considerPins) :
    282             WorkflowTask("GetManifestWithVersionFromPackage"), m_version(version), m_channel(channel), m_considerPins(considerPins) {}
    283 
    284         GetManifestWithVersionFromPackage(const Utility::VersionAndChannel& versionAndChannel, bool considerPins) :
    285             GetManifestWithVersionFromPackage(versionAndChannel.GetVersion().ToString(), versionAndChannel.GetChannel().ToString(), considerPins) {}
    286 
    287         void operator()(Execution::Context& context) const override;
    288 
    289     private:
    290         std::string_view m_version;
    291         std::string_view m_channel;
    292         bool m_considerPins;
    293     };
    294 
    295     // Gets the manifest from package.
    296     // Required Args: A value indicating whether to consider pins
    297     // Inputs: Package. Optionally Version and Channel
    298     // Outputs: Manifest, PackageVersion
    299     struct GetManifestFromPackage : public WorkflowTask
    300     {
    301         GetManifestFromPackage(bool considerPins) : WorkflowTask("GetManifestFromPackage"), m_considerPins(considerPins) {}
    302 
    303         void operator()(Execution::Context& context) const override;
    304 
    305     private:
    306         bool m_considerPins;
    307     };
    308 
    309     // Ensures the file exists and is not a directory.
    310     // Required Args: the one given
    311     // Inputs: None
    312     // Outputs: None
    313     struct VerifyFile : public WorkflowTask
    314     {
    315         VerifyFile(Execution::Args::Type arg) : WorkflowTask("VerifyFile"), m_arg(arg) {}
    316 
    317         void operator()(Execution::Context& context) const override;
    318 
    319     private:
    320         Execution::Args::Type m_arg;
    321     };
    322 
    323     // Ensures the path exists.
    324     // Required Args: the one given
    325     // Inputs: None
    326     // Outputs: None
    327     struct VerifyPath : public WorkflowTask
    328     {
    329         VerifyPath(Execution::Args::Type arg) : WorkflowTask("VerifyPath"), m_arg(arg) {}
    330 
    331         void operator()(Execution::Context& context) const override;
    332 
    333     private:
    334         Execution::Args::Type m_arg;
    335     };
    336 
    337     // Ensures the local file exists and is not a directory. Or it's a Uri. Default only https is supported at the moment.
    338     // Required Args: the one given
    339     // Inputs: None
    340     // Outputs: None
    341     struct VerifyFileOrUri : public WorkflowTask
    342     {
    343         VerifyFileOrUri(Execution::Args::Type arg, std::vector<std::wstring> supportedSchemes = { L"https" }) :
    344             WorkflowTask("VerifyFileOrUri"), m_arg(arg), m_supportedSchemes(std::move(supportedSchemes)) {}
    345 
    346         void operator()(Execution::Context& context) const override;
    347 
    348     private:
    349         Execution::Args::Type m_arg;
    350         std::vector<std::wstring> m_supportedSchemes;
    351     };
    352 
    353     // Opens the manifest file provided on the command line.
    354     // Required Args: Manifest
    355     // Inputs: None
    356     // Outputs: Manifest
    357     void GetManifestFromArg(Execution::Context& context);
    358 
    359     // Reports the search result's package identity.
    360     // Required Args: None
    361     // Inputs: Package
    362     // Outputs: None
    363     void ReportPackageIdentity(Execution::Context& context);
    364 
    365     // Reports the installed package version identity.
    366     // Required Args: None
    367     // Inputs: InstalledPackageVersion
    368     // Outputs: None
    369     void ReportInstalledPackageVersionIdentity(Execution::Context& context);
    370 
    371     // Reports the manifest's identity.
    372     // Required Args: None
    373     // Inputs: Manifest
    374     // Outputs: None
    375     void ReportManifestIdentity(Execution::Context& context);
    376 
    377     // Reports the manifest's identity with version.
    378     // Required Args: None
    379     // Inputs: Manifest
    380     // Outputs: None
    381     struct ReportManifestIdentityWithVersion : public WorkflowTask
    382     {
    383         ReportManifestIdentityWithVersion(Utility::LocIndView prefix, Execution::Reporter::Level level = Execution::Reporter::Level::Info) :
    384             WorkflowTask("ReportManifestIdentityWithVersion"), m_prefix(prefix), m_level(level) {}
    385         ReportManifestIdentityWithVersion(Resource::StringId label = Resource::String::ReportIdentityFound, Execution::Reporter::Level level = Execution::Reporter::Level::Info) :
    386             WorkflowTask("ReportManifestIdentityWithVersion"), m_label(label), m_level(level) {}
    387 
    388         void operator()(Execution::Context& context) const override;
    389 
    390     private:
    391         Utility::LocIndView m_prefix;
    392         std::optional<Resource::StringId> m_label;
    393         Execution::Reporter::Level m_level;
    394     };
    395 
    396     // Selects the installer from the manifest, if one is applicable.
    397     // Required Args: None
    398     // Inputs: Manifest
    399     // Outputs: Installer
    400     void SelectInstaller(Execution::Context& context);
    401 
    402     // Ensures that the process is running as admin.
    403     // Required Args: None
    404     // Inputs: None
    405     // Outputs: None
    406     void EnsureRunningAsAdmin(Execution::Context& context);
    407 
    408     // Ensures that the feature is enabled.
    409     // Required Args: the desired feature
    410     // Inputs: None
    411     // Outputs: None
    412     struct EnsureFeatureEnabled : public WorkflowTask
    413     {
    414         EnsureFeatureEnabled(Settings::ExperimentalFeature::Feature feature) : WorkflowTask("EnsureFeatureEnabled"), m_feature(feature) {}
    415 
    416         void operator()(Execution::Context& context) const override;
    417 
    418     private:
    419         Settings::ExperimentalFeature::Feature m_feature;
    420     };
    421 
    422     // Performs a search on the source with the semantics of targeting packages matching input manifest
    423     // Required Args: None
    424     // Inputs: Source, Manifest
    425     // Outputs: SearchResult
    426     void SearchSourceUsingManifest(Execution::Context& context);
    427 
    428     // Gets the installed package version
    429     // Required Args: None
    430     // Inputs: Package
    431     // Outputs: InstalledPackageVersion
    432     void GetInstalledPackageVersion(Execution::Context& context);
    433 
    434     // Shows all versions for an application.
    435     // Required Args: None
    436     // Inputs: SearchResult [only operates on first match]
    437     // Outputs: None
    438     void ShowAppVersions(Execution::Context& context);
    439 
    440     // Reports execution stage in a workflow
    441     // Required Args: ExecutionStage
    442     // Inputs: ExecutionStage?
    443     // Outputs: ExecutionStage
    444     struct ReportExecutionStage : public WorkflowTask
    445     {
    446         ReportExecutionStage(ExecutionStage stage) : WorkflowTask("ReportExecutionStage"), m_stage(stage) {}
    447 
    448         void operator()(Execution::Context& context) const override;
    449 
    450     private:
    451         ExecutionStage m_stage;
    452     };
    453 }
    454 
    455 // Passes the context to the function if it has not been terminated; returns the context.
    456 AppInstaller::CLI::Execution::Context& operator<<(AppInstaller::CLI::Execution::Context& context, AppInstaller::CLI::Workflow::WorkflowTask::Func f);
    457 
    458 // Passes the context to the task if it has not been terminated; returns the context.
    459 AppInstaller::CLI::Execution::Context& operator<<(AppInstaller::CLI::Execution::Context& context, const AppInstaller::CLI::Workflow::WorkflowTask& task);