master
h 172 lines 5.19 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 Command.h
8
9 Abstract:
10
11 Declaration of command class.
12
13 --*/
14 #pragma once
15 #include "Argument.h"
16 #include "Exceptions.h"
17 #include "ArgMap.h"
18 #include "CLIExecutionContext.h"
19 #include "Invocation.h"
20 #include "ArgumentParser.h"
21 #include "Terminal.h"
22
23 #include <initializer_list>
24 #include <memory>
25 #include <optional>
26 #include <span>
27 #include <string>
28 #include <string_view>
29 #include <vector>
30
31 using namespace wsl::windows::wslc::execution;
32 using namespace wsl::windows::wslc::argument;
33
34 namespace wsl::windows::wslc {
35
36 enum class HelpOutput
37 {
38 Full,
39 Command,
40 Argument,
41 };
42
43 // The executable name shown in usage/help output, set from argv[0] at startup.
44 extern std::wstring s_ExecutableName;
45
46 struct Command
47 {
48 // The character used to split between commands and their parents in FullName.
49 constexpr static wchar_t ParentSplitChar = L':';
50
51 Command(std::wstring_view name, const std::wstring& parent) : Command(name, {}, parent)
52 {
53 }
54 Command(std::wstring_view name, std::vector<std::wstring_view>&& aliases, const std::wstring& parent);
55
56 virtual ~Command() = default;
57
58 Command(const Command&) = default;
59 Command& operator=(const Command&) = default;
60
61 Command(Command&&) = default;
62 Command& operator=(Command&&) = default;
63
64 std::wstring_view Name() const
65 {
66 return m_name;
67 }
68 const std::wstring& FullName() const
69 {
70 return m_fullName;
71 }
72 const std::vector<std::wstring_view>& Aliases() const
73 {
74 return m_aliases;
75 }
76
77 virtual std::vector<std::unique_ptr<Command>> GetCommands() const
78 {
79 return {};
80 }
81 virtual std::vector<Argument> GetArguments() const
82 {
83 return {};
84 }
85
86 virtual std::vector<Argument> GetAllArguments() const
87 {
88 auto args = GetArguments();
89 args.emplace_back(Argument::Create(ArgType::Help));
90 return args;
91 }
92
93 // Options accepted before any subcommand on the command line.
94 virtual std::vector<Argument> GetGlobalArguments() const
95 {
96 return {};
97 }
98
99 // Args eligible for environment binding.
100 virtual std::vector<Argument> GetEnvArguments() const
101 {
102 return {};
103 }
104
105 // Union of GetGlobalArguments() and GetEnvArguments(), deduped by ArgType
106 // (globals win on conflict). Use this anywhere the two sets are combined
107 // so duplicates are not parsed/validated twice.
108 std::vector<Argument> GetGlobalsAndEnvArguments() const;
109
110 virtual std::wstring ShortDescription() const = 0;
111 virtual std::wstring LongDescription() const = 0;
112
113 void OutputHelp(
114 Terminal& terminal,
115 HelpOutput output = HelpOutput::Full,
116 const CommandException* exception = nullptr,
117 std::span<const Argument> relevantArguments = {}) const;
118
119 std::unique_ptr<Command> FindSubCommand(Invocation& inv) const;
120
121 // optionsOnly: stop (without consuming) at the first positional token.
122 // stopOnUnknown: stop (without consuming) at the first unknown option
123 // token instead of throwing. Note: applies per-token; a
124 // bundled short chain (e.g. "-Dv") whose leading alias
125 // is recognized is treated as claimed, and an unknown
126 // alias later in the chain still throws.
127 // overridableDefaults: args whose preloaded entries in target are treated
128 // as defaults (e.g. env-applied) and may be replaced
129 // by the first CLI occurrence.
130 void ParseArguments(
131 Invocation& inv,
132 ArgMap& target,
133 std::vector<Argument> definedArgs,
134 bool optionsOnly = false,
135 bool stopOnUnknown = false,
136 const std::vector<Argument>& overridableDefaults = {}) const;
137
138 void ParseArguments(Invocation& inv, ArgMap& target) const
139 {
140 ParseArguments(inv, target, GetAllArguments());
141 }
142
143 void ValidateArguments(ArgMap& source, const std::vector<Argument>& definedArgs, bool runInternalHook) const;
144
145 void ValidateArguments(ArgMap& source) const
146 {
147 ValidateArguments(source, GetAllArguments(), true);
148 }
149
150 virtual void Execute(CLIExecutionContext& context) const;
151
152 protected:
153 // Command-specific validation hook, run after the shared per-argument Argument::Validate pass.
154 // Override to enforce cross-argument rules that per-argument validation cannot express, such as
155 // mutually-exclusive arguments or required argument combinations.
156 //
157 // Contract: this hook enforces relationships between already-validated arguments. It receives a
158 // GetValue/GetAllValues make the selected argument immutable after returning it. Converted
159 // arguments are validated on demand if needed.
160 virtual void ValidateArgumentsInternal(ArgMap& source) const;
161 virtual void ExecuteInternal(CLIExecutionContext& context) const = 0;
162
163 std::vector<Argument> GetArgumentsForHelp(std::initializer_list<ArgType> types) const;
164
165 private:
166 std::wstring_view m_name;
167 std::vector<std::wstring_view> m_aliases;
168 std::wstring m_fullName;
169 };
170
171 void Execute(CLIExecutionContext& context, std::unique_ptr<Command>& command);
172 } // namespace wsl::windows::wslc