Argument.h (15011B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #pragma once 4 #include "ExecutionContext.h" 5 #include "Resources.h" 6 #include <winget/UserSettings.h> 7 #include <winget/ExperimentalFeature.h> 8 #include <winget/GroupPolicy.h> 9 #include <winget/AdminSettings.h> 10 #include <winget/LocIndependent.h> 11 12 #include <string> 13 #include <string_view> 14 15 16 #define APPINSTALLER_CLI_ARGUMENT_IDENTIFIER_CHAR '-' 17 #define APPINSTALLER_CLI_ARGUMENT_IDENTIFIER_STRING "-" 18 #define APPINSTALLER_CLI_ARGUMENT_SPLIT_CHAR '=' 19 #define APPINSTALLER_CLI_HELP_ARGUMENT_TEXT_CHAR '?' 20 #define APPINSTALLER_CLI_HELP_ARGUMENT_TEXT_STRING "?" 21 #define APPINSTALLER_CLI_HELP_ARGUMENT APPINSTALLER_CLI_ARGUMENT_IDENTIFIER_STRING APPINSTALLER_CLI_HELP_ARGUMENT_TEXT_STRING 22 23 namespace AppInstaller::CLI 24 { 25 using namespace AppInstaller::Utility::literals; 26 27 // The type of argument. 28 enum class ArgumentType 29 { 30 // Argument requires specifying the name before the value. 31 Standard, 32 // Argument value can be specified alone; position indicates argument name. 33 Positional, 34 // Only argument name can be specified and indicates a bool value. 35 Flag, 36 }; 37 38 // Categories an arg type can belong to. 39 // Used to reason about the arguments present without having to repeat the same 40 // lists every time. 41 enum class ArgTypeCategory 42 { 43 None = 0, 44 // The --manifest argument. 45 Manifest = 0x1, 46 // Arguments for querying or selecting a package. 47 // E.g.: --query 48 PackageQuery = 0x2, 49 // Arguments for querying or selecting a package, which do not work for multiple packages. 50 // E.g.: --version 51 SinglePackageQuery = 0x4, 52 // Arguments for installer or uninstaller selection. 53 // E.g.: --scope 54 InstallerSelection = 0x8, 55 // Arguments for installer or uninstaller behavior. 56 // E.g.: --interactive 57 InstallerBehavior = 0x10, 58 // Arguments for installer or uninstaller behavior, which do not work for multiple packages. 59 // E.g.: --override 60 SingleInstallerBehavior = 0x20, 61 // Arguments for selecting or interacting with the source used for initial querying 62 // E.g.: --header 63 QuerySource = 0x40, 64 // Arguments that only make sense when talking about multiple packages 65 MultiplePackages = 0x80, 66 // Flag arguments that should be copied over when creating a sub-context 67 CopyFlagToSubContext = 0x100, 68 // Arguments with associated values that should be copied over when creating a sub-context 69 CopyValueToSubContext = 0x200, 70 // Arguments for selecting or interacting with dependencies or setting specific source behaviors 71 // E.g.: --dependency-source 72 // E.g.: --accept-source-agreements 73 ExtendedSource = 0x400, 74 // Arguments for selecting a configuration set (file or history). 75 ConfigurationSetChoice = 0x800, 76 }; 77 78 DEFINE_ENUM_FLAG_OPERATORS(ArgTypeCategory); 79 80 // Exclusive sets an argument can belong to. 81 // Only one argument from each exclusive set is allowed at a time. 82 enum class ArgTypeExclusiveSet : uint32_t 83 { 84 None = 0x0, 85 ProgressBarOption = 0x1, 86 EnableDisable = 0x2, 87 PurgePreserve = 0x4, 88 PinType = 0x8, 89 StubType = 0x10, 90 Proxy = 0x20, 91 AllAndTargetVersion = 0x40, 92 ConfigurationSetChoice = 0x80, 93 DscResourceFunction = 0x100, 94 95 // This must always be at the end 96 Max 97 }; 98 99 DEFINE_ENUM_FLAG_OPERATORS(ArgTypeExclusiveSet); 100 101 // An argument to a command; containing only data that is common to all its uses. 102 // Argument extends this by adding command-specific values, like help strings. 103 struct ArgumentCommon 104 { 105 // Defines an argument with no alias. 106 constexpr static char NoAlias = '\0'; 107 108 ArgumentCommon(Execution::Args::Type execArgType, Utility::LocIndView name, char alias, Utility::LocIndView alternateName, ArgTypeCategory typeCategory = ArgTypeCategory::None, ArgTypeExclusiveSet exclusiveSet = ArgTypeExclusiveSet::None) 109 : Type(execArgType), Name(name), Alias(alias), AlternateName(alternateName), TypeCategory(typeCategory), ExclusiveSet(exclusiveSet) {} 110 111 ArgumentCommon(Execution::Args::Type execArgType, Utility::LocIndView name, char alias, ArgTypeCategory typeCategory = ArgTypeCategory::None, ArgTypeExclusiveSet exclusiveSet = ArgTypeExclusiveSet::None) 112 : Type(execArgType), Name(name), Alias(alias), TypeCategory(typeCategory), ExclusiveSet(exclusiveSet) {} 113 114 ArgumentCommon(Execution::Args::Type execArgType, Utility::LocIndView name, Utility::LocIndView alternateName, ArgTypeCategory typeCategory = ArgTypeCategory::None, ArgTypeExclusiveSet exclusiveSet = ArgTypeExclusiveSet::None) 115 : Type(execArgType), Name(name), Alias(NoAlias), AlternateName(alternateName), TypeCategory(typeCategory), ExclusiveSet(exclusiveSet) {} 116 117 ArgumentCommon(Execution::Args::Type execArgType, Utility::LocIndView name, ArgTypeCategory typeCategory = ArgTypeCategory::None, ArgTypeExclusiveSet exclusiveSet = ArgTypeExclusiveSet::None) 118 : Type(execArgType), Name(name), Alias(NoAlias), TypeCategory(typeCategory), ExclusiveSet(exclusiveSet) {} 119 120 // Gets the argument for the given type. 121 static ArgumentCommon ForType(Execution::Args::Type execArgType); 122 123 static std::vector<ArgumentCommon> GetFromExecArgs(const Execution::Args& execArgs); 124 125 Execution::Args::Type Type; 126 Utility::LocIndView Name; 127 char Alias; 128 Utility::LocIndView AlternateName; 129 ArgTypeCategory TypeCategory; 130 ArgTypeExclusiveSet ExclusiveSet; 131 }; 132 133 // An argument to a command. 134 struct Argument 135 { 136 // Controls the visibility of the field. 137 enum class Visibility 138 { 139 // Shown in the example. 140 Example, 141 // Shown only in the table below the example. 142 Help, 143 // Not shown in help. 144 Hidden, 145 }; 146 147 // Defines an argument with no alternate name 148 constexpr static std::string_view NoAlternateName = ""; 149 150 Argument(Execution::Args::Type execArgType, Resource::StringId desc) : 151 m_argCommon(ArgumentCommon::ForType(execArgType)), m_desc(std::move(desc)) {} 152 153 Argument(Execution::Args::Type execArgType, Resource::StringId desc, bool required) : 154 m_argCommon(ArgumentCommon::ForType(execArgType)), m_desc(std::move(desc)), m_required(required) {} 155 156 Argument(Execution::Args::Type execArgType, Resource::StringId desc, ArgumentType type) : 157 m_argCommon(ArgumentCommon::ForType(execArgType)), m_desc(std::move(desc)), m_type(type) {} 158 159 Argument(Execution::Args::Type execArgType, Resource::StringId desc, ArgumentType type, Argument::Visibility visibility) : 160 m_argCommon(ArgumentCommon::ForType(execArgType)), m_desc(std::move(desc)), m_type(type), m_visibility(visibility) {} 161 162 Argument(Execution::Args::Type execArgType, Resource::StringId desc, ArgumentType type, bool required) : 163 m_argCommon(ArgumentCommon::ForType(execArgType)), m_desc(std::move(desc)), m_type(type), m_required(required) {} 164 165 Argument(Execution::Args::Type execArgType, Resource::StringId desc, ArgumentType type, Argument::Visibility visibility, bool required) : 166 m_argCommon(ArgumentCommon::ForType(execArgType)), m_desc(std::move(desc)), m_type(type), m_visibility(visibility), m_required(required) {} 167 168 #ifndef AICLI_DISABLE_TEST_HOOKS 169 // Constructors for arguments with custom names and aliases to use in tests 170 Argument(std::string_view name, char alias, Execution::Args::Type execArgType, Resource::StringId desc, ArgumentType type) : 171 m_argCommon(execArgType, Utility::LocIndView{ name }, alias), m_desc(std::move(desc)), m_type(type) {} 172 173 Argument(std::string_view name, char alias, std::string_view alternateName, Execution::Args::Type execArgType, Resource::StringId desc, ArgumentType type) : 174 m_argCommon(execArgType, Utility::LocIndView{ name }, alias, Utility::LocIndView{ alternateName }), m_desc(std::move(desc)), m_type(type) {} 175 #endif 176 177 ~Argument() = default; 178 179 Argument(const Argument&) = default; 180 Argument& operator=(const Argument&) = default; 181 182 Argument(Argument&&) = default; 183 Argument& operator=(Argument&&) = default; 184 185 // Gets the argument for the given type. 186 static Argument ForType(Execution::Args::Type type); 187 188 // Gets the common arguments for all commands. 189 static void GetCommon(std::vector<Argument>& args); 190 191 // Static argument validation helpers; throw CommandException when validation fails. 192 193 // Requires that at most one argument from the list is present. 194 static void ValidateExclusiveArguments(const Execution::Args& args); 195 196 // Requires that if an argument depends on another one, it is not present without the dependency. 197 static void ValidateArgumentDependency(const Execution::Args& args, Execution::Args::Type type, Execution::Args::Type dependencyArgType); 198 199 static ArgTypeCategory GetCategoriesPresent(const Execution::Args& arg); 200 201 // Requires that arguments meet common requirements 202 static ArgTypeCategory GetCategoriesAndValidateCommonArguments(const Execution::Args& args, bool requirePackageSelectionArg = true); 203 static void ValidateCommonArguments(const Execution::Args& args, bool requirePackageSelectionArg = true) { std::ignore = GetCategoriesAndValidateCommonArguments(args, requirePackageSelectionArg); } 204 205 // Gets the argument usage string in the format of "-alias,--name". 206 std::string GetUsageString() const; 207 208 // Arguments are not localized at this time. 209 Utility::LocIndView Name() const { return m_argCommon.Name; } 210 char Alias() const { return m_argCommon.Alias; } 211 std::string_view AlternateName() const { return m_argCommon.AlternateName; } 212 Execution::Args::Type ExecArgType() const { return m_argCommon.Type; } 213 const Resource::StringId& Description() const { return m_desc; } 214 bool Required() const { return m_required; } 215 ArgumentType Type() const { return m_type; } 216 size_t Limit() const { return m_countLimit; } 217 Argument::Visibility GetVisibility() const; 218 Settings::ExperimentalFeature::Feature Feature() const { return m_feature; } 219 Settings::TogglePolicy::Policy GroupPolicy() const { return m_groupPolicy; } 220 Settings::BoolAdminSetting AdminSetting() const { return m_adminSetting; } 221 222 Argument& SetRequired(bool required) { m_required = required; return *this; } 223 Argument& SetCountLimit(size_t countLimit) { m_countLimit = countLimit; return *this; } 224 225 private: 226 // Constructors that set a Feature or Policy are private to force callers to go through the ForType() function. 227 // This helps keep it all in one place to reduce chances of missing it somewhere. 228 Argument(Execution::Args::Type execArgType, Resource::StringId desc, Settings::ExperimentalFeature::Feature feature) : 229 m_argCommon(ArgumentCommon::ForType(execArgType)), m_desc(std::move(desc)), m_feature(feature) {} 230 231 Argument(Execution::Args::Type execArgType, Resource::StringId desc, bool required, Settings::ExperimentalFeature::Feature feature) : 232 m_argCommon(ArgumentCommon::ForType(execArgType)), m_desc(std::move(desc)), m_required(required), m_feature(feature) {} 233 234 Argument(Execution::Args::Type execArgType, Resource::StringId desc, ArgumentType type, Settings::ExperimentalFeature::Feature feature) : 235 m_argCommon(ArgumentCommon::ForType(execArgType)), m_desc(std::move(desc)), m_type(type), m_feature(feature) {} 236 237 Argument(Execution::Args::Type execArgType, Resource::StringId desc, ArgumentType type, Argument::Visibility visibility, Settings::ExperimentalFeature::Feature feature) : 238 m_argCommon(ArgumentCommon::ForType(execArgType)), m_desc(std::move(desc)), m_type(type), m_visibility(visibility), m_feature(feature) {} 239 240 Argument(Execution::Args::Type execArgType, Resource::StringId desc, ArgumentType type, bool required, Settings::ExperimentalFeature::Feature feature) : 241 m_argCommon(ArgumentCommon::ForType(execArgType)), m_desc(std::move(desc)), m_type(type), m_required(required), m_feature(feature) {} 242 243 Argument(Execution::Args::Type execArgType, Resource::StringId desc, ArgumentType type, Argument::Visibility visibility, bool required, Settings::ExperimentalFeature::Feature feature) : 244 m_argCommon(ArgumentCommon::ForType(execArgType)), m_desc(std::move(desc)), m_type(type), m_visibility(visibility), m_required(required), m_feature(feature) {} 245 246 Argument(Execution::Args::Type execArgType, Resource::StringId desc, ArgumentType type, Settings::TogglePolicy::Policy groupPolicy, Settings::BoolAdminSetting adminSetting) : 247 m_argCommon(ArgumentCommon::ForType(execArgType)), m_desc(std::move(desc)), m_type(type), m_groupPolicy(groupPolicy), m_adminSetting(adminSetting) {} 248 249 Argument(Execution::Args::Type execArgType, Resource::StringId desc, ArgumentType type, Argument::Visibility visibility, Settings::TogglePolicy::Policy groupPolicy, Settings::BoolAdminSetting adminSetting) : 250 m_argCommon(ArgumentCommon::ForType(execArgType)), m_desc(std::move(desc)), m_type(type), m_visibility(visibility), m_groupPolicy(groupPolicy), m_adminSetting(adminSetting) {} 251 252 Argument(Execution::Args::Type execArgType, Resource::StringId desc, ArgumentType type, Settings::ExperimentalFeature::Feature feature, Settings::TogglePolicy::Policy groupPolicy, Settings::BoolAdminSetting adminSetting) : 253 m_argCommon(ArgumentCommon::ForType(execArgType)), m_desc(std::move(desc)), m_type(type), m_feature(feature), m_groupPolicy(groupPolicy), m_adminSetting(adminSetting) {} 254 255 ArgumentCommon m_argCommon; 256 Resource::StringId m_desc; 257 bool m_required = false; 258 ArgumentType m_type = ArgumentType::Standard; 259 Argument::Visibility m_visibility = Argument::Visibility::Example; 260 size_t m_countLimit = 1; 261 Settings::ExperimentalFeature::Feature m_feature = Settings::ExperimentalFeature::Feature::None; 262 Settings::TogglePolicy::Policy m_groupPolicy = Settings::TogglePolicy::Policy::None; 263 Settings::BoolAdminSetting m_adminSetting = Settings::BoolAdminSetting::Unknown; 264 }; 265 }