Command.h (7480B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #pragma once 4 #include "Argument.h" 5 #include "ExecutionContext.h" 6 #include "Invocation.h" 7 #include "Resources.h" 8 #include <winget/UserSettings.h> 9 #include <winget/ExperimentalFeature.h> 10 #include <winget/GroupPolicy.h> 11 12 #include <initializer_list> 13 #include <memory> 14 #include <optional> 15 #include <ostream> 16 #include <string> 17 #include <string_view> 18 #include <type_traits> 19 #include <vector> 20 21 namespace AppInstaller::CLI 22 { 23 struct CommandException 24 { 25 CommandException(Resource::LocString message) : m_message(std::move(message)) {} 26 const Utility::LocIndString Message() const { return m_message; } 27 28 private: 29 Resource::LocString m_message; 30 }; 31 32 // Flags to control the behavior of the command output. 33 enum class CommandOutputFlags : int 34 { 35 None = 0x0, 36 IgnoreSettingsWarnings = 0x1, 37 }; 38 39 DEFINE_ENUM_FLAG_OPERATORS(CommandOutputFlags); 40 41 struct Command 42 { 43 // Controls the visibility of the field. 44 enum class Visibility 45 { 46 // Shown in help. 47 Show, 48 // Not shown in help. 49 Hidden, 50 }; 51 52 Command(std::string_view name, std::string_view parent) : 53 Command(name, {}, parent) {} 54 Command(std::string_view name, std::vector<std::string_view> aliases, std::string_view parent) : 55 Command(name, aliases, parent, Settings::ExperimentalFeature::Feature::None) {} 56 Command(std::string_view name, std::string_view parent, CommandOutputFlags outputFlags) : 57 Command(name, {}, parent, Command::Visibility::Show, Settings::ExperimentalFeature::Feature::None, Settings::TogglePolicy::Policy::None, outputFlags) {} 58 Command(std::string_view name, std::vector<std::string_view> aliases, std::string_view parent, Command::Visibility visibility) : 59 Command(name, aliases, parent, visibility, Settings::ExperimentalFeature::Feature::None) {} 60 Command(std::string_view name, std::string_view parent, Settings::ExperimentalFeature::Feature feature) : 61 Command(name, {}, parent, Command::Visibility::Show, feature) {} 62 Command(std::string_view name, std::string_view parent, Settings::ExperimentalFeature::Feature feature, CommandOutputFlags outputFlags) : 63 Command(name, {}, parent, Command::Visibility::Show, feature, Settings::TogglePolicy::Policy::None, outputFlags) {} 64 Command(std::string_view name, std::vector<std::string_view> aliases, std::string_view parent, Settings::ExperimentalFeature::Feature feature) : 65 Command(name, aliases, parent, Command::Visibility::Show, feature) {} 66 Command(std::string_view name, std::vector<std::string_view> aliases, std::string_view parent, Settings::TogglePolicy::Policy groupPolicy) : 67 Command(name, aliases, parent, Command::Visibility::Show, Settings::ExperimentalFeature::Feature::None, groupPolicy, CommandOutputFlags::None) {} 68 Command(std::string_view name, std::vector<std::string_view> aliases, std::string_view parent, Command::Visibility visibility, Settings::ExperimentalFeature::Feature feature) : 69 Command(name, aliases, parent, visibility, feature, Settings::TogglePolicy::Policy::None, CommandOutputFlags::None) {} 70 Command(std::string_view name, std::vector<std::string_view> aliases, std::string_view parent, Command::Visibility visibility, Settings::TogglePolicy::Policy groupPolicy) : 71 Command(name, aliases, parent, visibility, Settings::ExperimentalFeature::Feature::None, groupPolicy, CommandOutputFlags::None) {} 72 73 Command(std::string_view name, 74 std::vector<std::string_view> aliases, 75 std::string_view parent, 76 Command::Visibility visibility, 77 Settings::ExperimentalFeature::Feature feature, 78 Settings::TogglePolicy::Policy groupPolicy, 79 CommandOutputFlags outputFlags); 80 81 virtual ~Command() = default; 82 83 Command(const Command&) = default; 84 Command& operator=(const Command&) = default; 85 86 Command(Command&&) = default; 87 Command& operator=(Command&&) = default; 88 89 // The character used to split between commands and their parents in FullName. 90 constexpr static char ParentSplitChar = ':'; 91 92 std::string_view Name() const { return m_name; } 93 const std::vector<std::string_view>& Aliases() const& { return m_aliases; } 94 const std::string& FullName() const { return m_fullName; } 95 Command::Visibility GetVisibility() const; 96 Settings::ExperimentalFeature::Feature Feature() const { return m_feature; } 97 Settings::TogglePolicy::Policy GroupPolicy() const { return m_groupPolicy; } 98 CommandOutputFlags GetOutputFlags() const { return m_outputFlags; } 99 100 virtual std::vector<std::unique_ptr<Command>> GetCommands() const { return {}; } 101 virtual std::vector<Argument> GetArguments() const { return {}; } 102 std::vector<std::unique_ptr<Command>> GetVisibleCommands() const; 103 std::vector<Argument> GetVisibleArguments() const; 104 105 virtual Resource::LocString ShortDescription() const = 0; 106 virtual Resource::LocString LongDescription() const = 0; 107 108 virtual void OutputIntroHeader(Execution::Reporter& reporter) const; 109 virtual void OutputHelp(Execution::Reporter& reporter, const CommandException* exception = nullptr) const; 110 virtual Utility::LocIndView HelpLink() const { return {}; } 111 112 virtual std::unique_ptr<Command> FindSubCommand(Invocation& inv) const; 113 virtual void ParseArguments(Invocation& inv, Execution::Args& execArgs) const; 114 virtual void ValidateArguments(Execution::Args& execArgs) const; 115 116 virtual void Complete(Execution::Context& context) const; 117 virtual void Complete(Execution::Context& context, Execution::Args::Type valueType) const; 118 119 virtual void Execute(Execution::Context& context) const; 120 121 virtual void Resume(Execution::Context& context) const; 122 123 protected: 124 void SelectCurrentCommandIfUnrecognizedSubcommandFound(bool value); 125 126 virtual void ValidateArgumentsInternal(Execution::Args& execArgs) const; 127 virtual void ExecuteInternal(Execution::Context& context) const; 128 129 private: 130 std::string_view m_name; 131 std::string m_fullName; 132 std::vector<std::string_view> m_aliases; 133 Command::Visibility m_visibility; 134 Settings::ExperimentalFeature::Feature m_feature; 135 Settings::TogglePolicy::Policy m_groupPolicy; 136 CommandOutputFlags m_outputFlags; 137 bool m_selectCurrentCommandIfUnrecognizedSubcommandFound = false; 138 std::string m_commandArguments; 139 }; 140 141 template <typename Container> 142 Container InitializeFromMoveOnly(std::initializer_list<typename Container::value_type> il) 143 { 144 using Value = typename Container::value_type; 145 Container result; 146 147 for (const auto& v : il) 148 { 149 result.emplace_back(std::move(*const_cast<Value*>(&v))); 150 } 151 152 return result; 153 } 154 155 void ExecuteWithoutLoggingSuccess(Execution::Context& context, Command* command); 156 157 int Execute(Execution::Context& context, std::unique_ptr<Command>& command); 158 }