winget-cli

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

ExecutionReporter.h (8990B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #pragma once
      4 #include "ExecutionProgress.h"
      5 #include "ChannelStreams.h"
      6 #include "Resources.h"
      7 #include "VTSupport.h"
      8 #include <AppInstallerProgress.h>
      9 #include <winget/LocIndependent.h>
     10 
     11 #include <wil/resource.h>
     12 
     13 #include <atomic>
     14 #include <iomanip>
     15 #include <istream>
     16 #include <memory>
     17 #include <optional>
     18 #include <ostream>
     19 #include <string>
     20 
     21 
     22 namespace AppInstaller::CLI::Execution
     23 {
     24 #define WINGET_OSTREAM_FORMAT_HRESULT(hr) "0x" << Logging::SetHRFormat << hr
     25 
     26     // One of the options available to the users when prompting for something.
     27     struct BoolPromptOption
     28     {
     29         BoolPromptOption(Resource::StringId labelId, char hotkey, bool value)
     30             : Label(labelId), Hotkey(std::string(1, hotkey)), Value(value) {}
     31 
     32         Utility::LocIndString Hotkey;
     33         Resource::LocString Label;
     34 
     35         // Value associated with this option.
     36         bool Value;
     37     };
     38 
     39     // Reporter should be the central place to show workflow status to user.
     40     struct Reporter : public IProgressSink
     41     {
     42         // The channel that the reporter is targeting.
     43         // Based on commands/arguments, only one of these channels can be chosen.
     44         enum class Channel
     45         {
     46             Output,
     47             Completion,
     48             Json,
     49             Disabled,
     50         };
     51 
     52         // The level for the Output channel.
     53         enum class Level : uint32_t
     54         {
     55             None = 0x0,
     56             Verbose = 0x1,
     57             Info = 0x2,
     58             Warning = 0x4,
     59             Error = 0x8,
     60             All = Verbose | Info | Warning | Error,
     61         };
     62 
     63         Reporter();
     64         Reporter(std::ostream& outStream, std::istream& inStream);
     65         Reporter(const Reporter&) = delete;
     66         Reporter& operator=(const Reporter&) = delete;
     67 
     68         Reporter(Reporter&&) = default;
     69         Reporter& operator=(Reporter&&) = default;
     70 
     71         // Request that a clone be constructed from the given reporter.
     72         struct clone_t {};
     73         Reporter(const Reporter& other, clone_t);
     74 
     75         ~Reporter();
     76 
     77         // Gets the primary device attributes if available.
     78         std::optional<VirtualTerminal::PrimaryDeviceAttributes> GetPrimaryDeviceAttributes();
     79 
     80         // Get a stream for verbose output.
     81         OutputStream Verbose() { return GetOutputStream(Level::Verbose); }
     82 
     83         // Get a stream for informational output.
     84         OutputStream Info() { return GetOutputStream(Level::Info); }
     85 
     86         // Get a stream for warning output.
     87         OutputStream Warn() { return GetOutputStream(Level::Warning); }
     88 
     89         // Get a stream for error output.
     90         OutputStream Error() { return GetOutputStream(Level::Error); }
     91 
     92         // Get a stream for outputting completion words.
     93         OutputStream Completion() { return OutputStream(*m_out, m_channel == Channel::Completion, false); }
     94 
     95         // Get a stream for outputting completion words.
     96         OutputStream Json() { return OutputStream(*m_out, m_channel == Channel::Json, false); }
     97 
     98         // Gets a stream for output of the given level.
     99         OutputStream GetOutputStream(Level level);
    100 
    101         void EmptyLine() { GetBasicOutputStream() << std::endl; }
    102 
    103         // Sets the channel that will be reported to.
    104         // Only do this once and as soon as the channel is determined.
    105         void SetChannel(Channel channel);
    106 
    107         // Sets the visual style (mostly for progress currently)
    108         void SetStyle(AppInstaller::Settings::VisualStyle style);
    109 
    110         // Get the raw input stream.
    111         std::istream& RawInputStream();
    112 
    113         // Check if the input stream is interactive or not.
    114         bool InputStreamIsInteractive() const;
    115 
    116         // Prompts the user, return true if they consented.
    117         bool PromptForBoolResponse(Resource::LocString message, Level level = Level::Info, bool resultIfDisabled = false);
    118 
    119         // Prompts the user, continues when Enter is pressed
    120         void PromptForEnter(Level level = Level::Info);
    121 
    122         // Prompts the user for a path.
    123         std::filesystem::path PromptForPath(Resource::LocString message, Level level = Level::Info, std::filesystem::path resultIfDisabled = std::filesystem::path::path());
    124 
    125         // IProgressSink
    126         void BeginProgress() override;
    127         void OnProgress(uint64_t current, uint64_t maximum, ProgressType type) override;
    128         void SetProgressMessage(std::string_view message) override;
    129         void EndProgress(bool hideProgressWhenDone) override;
    130 
    131         // Contains the objects used for async progress and the lifetime of said progress.
    132         struct AsyncProgressScope
    133         {
    134             AsyncProgressScope(Reporter& reporter, IProgressSink* sink, bool hideProgressWhenDone);
    135             ~AsyncProgressScope();
    136 
    137             AsyncProgressScope(const AsyncProgressScope&) = delete;
    138             AsyncProgressScope& operator=(const AsyncProgressScope&) = delete;
    139 
    140             AsyncProgressScope(AsyncProgressScope&&) = delete;
    141             AsyncProgressScope& operator=(AsyncProgressScope&&) = delete;
    142 
    143             ProgressCallback& Callback();
    144             IProgressCallback* operator->();
    145 
    146             bool HideProgressWhenDone() const;
    147             void HideProgressWhenDone(bool value);
    148 
    149         private:
    150             std::reference_wrapper<Reporter> m_reporter;
    151             ProgressCallback m_callback;
    152             std::atomic_bool m_hideProgressWhenDone;
    153         };
    154 
    155         // Runs the given callable of type: auto(IProgressCallback&)
    156         template <typename F>
    157         auto ExecuteWithProgress(F&& f, bool hideProgressWhenDone = false)
    158         {
    159             auto progressScope = BeginAsyncProgress(hideProgressWhenDone);
    160             return f(progressScope->Callback());
    161         }
    162 
    163         // Begins an asynchronous progress operation.
    164         std::unique_ptr<AsyncProgressScope> BeginAsyncProgress(bool hideProgressWhenDone = false);
    165 
    166         // Sets the in progress callback.
    167         void SetProgressCallback(ProgressCallback* callback);
    168 
    169         // Cancels the in progress task.
    170         void CancelInProgressTask(bool force, CancelReason reason);
    171 
    172         void CloseOutputStream(bool forceDisable = false);
    173 
    174         void SetProgressSink(IProgressSink* sink)
    175         {
    176             m_progressSink = sink;
    177         }
    178 
    179         bool IsLevelEnabled(Level reporterLevel)
    180         {
    181             return WI_AreAllFlagsSet(m_enabledLevels, reporterLevel);
    182         }
    183 
    184         void SetLevelMask(Level reporterLevel, bool setEnabled = true);
    185 
    186         // Determines if sixels are supported by the current instance.
    187         bool SixelsSupported();
    188 
    189         // Determines if sixels are enabled; they must be both supported and enabled by user settings.
    190         bool SixelsEnabled();
    191 
    192     private:
    193         Reporter(std::shared_ptr<BaseStream> outStream, std::istream& inStream);
    194         // Gets a stream for output for internal use.
    195         OutputStream GetBasicOutputStream();
    196 
    197         // Used to show indefinite progress. Currently an indefinite spinner is the form of
    198         // showing indefinite progress.
    199         // running: shows indefinite progress if set to true, stops indefinite progress if set to false
    200         void ShowIndefiniteProgress(bool running);
    201 
    202         Channel m_channel = Channel::Output;
    203         std::shared_ptr<BaseStream> m_out;
    204         std::istream& m_in;
    205         std::optional<AppInstaller::Settings::VisualStyle> m_style;
    206         std::unique_ptr<IIndefiniteSpinner> m_spinner;
    207         std::unique_ptr<IProgressBar> m_progressBar;
    208         wil::srwlock m_progressCallbackLock;
    209         std::atomic<ProgressCallback*> m_progressCallback;
    210         std::atomic<IProgressSink*> m_progressSink;
    211         DWORD m_outStreamFileType = FILE_TYPE_UNKNOWN;
    212         DWORD m_inStreamFileType = FILE_TYPE_UNKNOWN;
    213 
    214         // Enable all levels by default
    215         Level m_enabledLevels = Level::All;
    216     };
    217 
    218     DEFINE_ENUM_FLAG_OPERATORS(Reporter::Level);
    219 
    220     // Indirection to enable change without tracking down every place
    221     extern const VirtualTerminal::Sequence& HelpCommandEmphasis;
    222     extern const VirtualTerminal::Sequence& HelpArgumentEmphasis;
    223     extern const VirtualTerminal::Sequence& ManifestInfoEmphasis;
    224     extern const VirtualTerminal::Sequence& SourceInfoEmphasis;
    225     extern const VirtualTerminal::Sequence& NameEmphasis;
    226     extern const VirtualTerminal::Sequence& IdEmphasis;
    227     extern const VirtualTerminal::Sequence& UrlEmphasis;
    228     extern const VirtualTerminal::Sequence& PromptEmphasis;
    229     extern const VirtualTerminal::Sequence& ConvertToUpgradeFlowEmphasis;
    230     extern const VirtualTerminal::Sequence& ConfigurationIntentEmphasis;
    231     extern const VirtualTerminal::Sequence& ConfigurationUnitEmphasis;
    232     extern const VirtualTerminal::Sequence& AuthenticationEmphasis;
    233 }