MySQL 8.3.0
Source Code Documentation
arg_handler.h
Go to the documentation of this file.
1/*
2 Copyright (c) 2015, 2023, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23*/
24
25#ifndef HARNESS_ARG_HANDLER_INCLUDED
26#define HARNESS_ARG_HANDLER_INCLUDED
27
28/** @file
29 * @brief Defining the commandline argument handler class CmdArgHandler
30 *
31 * This file defines the commandline argument handler class CmdArgHandler.
32 */
33
34#include "harness_export.h"
35
36#include <cstdint>
37#include <functional>
38#include <map>
39#include <memory>
40#include <string>
41#include <vector>
42
44 none = 0x01,
45 required = 0x02,
46 optional = 0x03,
47};
48
49/** @brief CmdOption stores information about command line options
50 *
51 * The CmdOption structure stores information about command line options.
52 *
53 */
54struct CmdOption {
55 using ActionFunc = std::function<void(const std::string &)>;
56 using AtEndActionFunc = std::function<void(const std::string &)>;
57 using OptionNames = std::vector<std::string>;
58
60 std::string description;
62 std::string value;
63 std::string metavar;
66 bool required{false};
67
69 OptionNames names_, std::string description_,
70 CmdOptionValueReq value_req_, const std::string metavar_,
71 ActionFunc action_,
72 AtEndActionFunc at_end_action_ = [](const std::string &) {})
73 : names(names_),
74 description(description_),
75 value_req(value_req_),
76 metavar(metavar_),
77 action(action_),
78 at_end_action(at_end_action_) {}
79};
80
81/** @brief Definition of a vector holding unique pointers to CmdOption
82 * objects **/
83using OptionContainer = std::vector<CmdOption>;
84
85/** @class CmdArgHandler
86 * @brief Handles command line arguments
87 *
88 * The CmdArgHandler class handles command line arguments. It is a
89 * replacement and supports most of the POSIX GNU getopt library.
90 *
91 * Command line options can have multiple aliases. For example, the
92 * typical `--help` can be also called `-h`, or even `--help-me`. Long
93 * names starting with one dash are not supported.
94 *
95 * Command line options are added through the `add_option()` method
96 * and can be given 1 or more names and a description. It is also
97 * possible to require the option to have a value, or make the value
98 * optional.
99 *
100 * During processing of the command line arguments, actions will be
101 * executed when the option (and it's potential value) was found.
102 *
103 * Usage example:
104 *
105 * #include "arg_handler.h"
106 *
107 * void MyApp::prepare_command_line_options() {
108 * // CmdArgHandler handler_;
109 * handler_.add_option(OptionNames({"-h", "--help", "--sos"}), "Show help
110 * screen", CmdOptionValueReq::none, "", [this](const string &) {
111 * this->show_help(); } handler_.add_option(OptionNames({"--config"}),
112 * "Configuration file", CmdOptionValueReq::none, "", [this](const string
113 * &value) { this->set_config_file(value); },
114 * []{});
115 *
116 * void MyApp::init(const vector<string> arguments) {
117 * prepare_command_line_options();
118 * handler_.process(arguments);
119 * }
120 *
121 * All arguments which are not valid option names are are not values of options
122 * are considered rest arguments. By default, rest arguments are not allowed and
123 * will raise a std::invalid_argument exception. It is possible to allow them
124 * through the constructor.
125 *
126 * The CmdArgHandler class also provides functionality to help creating help
127 * screen or show how to use the the command line application. The method
128 * `usage_lines()` produces a usage line showing all the option names, their
129 * required or optional value with a meta variable. Similar, method
130 * `option_descriptions()` will get all options and their descriptions. All this
131 * is text wrapped at a configurable margin as well as, if needed, indented.
132 *
133 * @internal
134 * The command line argument handling in CmdArgHandler is the bare minimum
135 * needed for MySQL Router. It was needed to make sure that the application
136 * would compile on system where the getopt library is not available.
137 * @endinternal
138 *
139 */
140class HARNESS_EXPORT CmdArgHandler {
141 public:
142 /** @brief Constructor
143 *
144 * @param allow_rest_arguments_ whether we allow rest arguments or not
145 * @param ignore_unknown_arguments_ whether we ignore unknown arguments or
146 * give an error
147 */
148 explicit CmdArgHandler(bool allow_rest_arguments_,
149 bool ignore_unknown_arguments_ = false)
150 : allow_rest_arguments(allow_rest_arguments_),
151 ignore_unknown_arguments(ignore_unknown_arguments_) {}
152
153 /** @brief Default constructor
154 *
155 * By default, rest arguments are not allowed and unknown arguments are not
156 * ignored.
157 */
158 CmdArgHandler() : CmdArgHandler(false, false) {}
159
160 /** @brief Adds a command line option
161 *
162 * Adds a command line option given names, description, value
163 * requirement and optional action.
164 *
165 * `names` is a vector of strings which contains names starting
166 * with either a single or double dash, `-` or `--`. It is possible
167 * to add more than one name for an option.
168 *
169 * The description text will be used in the help output. Note that
170 * this can be a very long as text will be wrapped (and optionally
171 * indented). New lines in the description will be respected.
172 *
173 * The `metavar` argument is used in the usage text as a placeholder
174 * for the (optional) value of the option, for example, when `metavar`
175 * is set to `path`, the usage would show:
176 *
177 * --config=<path>
178 *
179 * The value_req argument should be either:
180 *
181 * * `CmdOptionValueReq::none` : option has no value
182 * * `CmdOptionValueReq::required` : option requires value
183 * * `CmdOptionValueReq::optional` : option has optional value
184 *
185 * The `action` argument should be a `std::function` and is called
186 * with the (optional) value of the option. The function should
187 * accept only a `const std::string`.
188 *
189 * The `at_end_action` argument should be a `std::function`. This is optional
190 * argument, if not provided then []{} is used as at_end_action. The
191 * `at_end_action` is meant to be used for additional validation, if
192 * particular set of options has to be used together, or if particular set of
193 * options cannot be used together.
194 *
195 * Example usage:
196 *
197 * handler_.add_option(OptionNames({"--config"}), "Configuration file",
198 * CmdOptionValueReq::none, "",
199 * [this](const string &value) {
200 * this->set_config_file(value); },
201 * []{});
202 *
203 * @internal
204 * The `add_option` method will assert when `names` is empty,
205 * one of the names is not valid or when a name was already used with
206 * another option.
207 * @endinternal
208 *
209 * @param names vector of string with option names, each starting with - or --
210 * @param description descriptive text explaining the option
211 * @param value_req value requirement of the option
212 * @param metavar for formatting help text when option accepts a value
213 * @param action action to perform when the option was found
214 * @param at_end_action task to perform after all actions have been done
215 */
216 void add_option(
217 const CmdOption::OptionNames &names, const std::string &description,
218 const CmdOptionValueReq &value_req, const std::string &metavar,
220 CmdOption::AtEndActionFunc at_end_action = [](const std::string &) {
221 }) noexcept;
222
223 void add_option(const CmdOption &other) noexcept;
224
225 /** @brief Processes given command line arguments
226 *
227 * Processes given command line argument provided as a vector
228 * of strings. It uses the stored option information added through the
229 * `add_option()` method.
230 *
231 * Typically, the vector passed to process() are the argc and argv
232 * arguments of the main() function:
233 *
234 * process({argv + 1, argv + argc})
235 *
236 * When an option is found which requires an argument, optional or
237 * not, process() will exit the application with an error message.
238 *
239 * If the option has an action defined, the function will be
240 * executed with the (optional) value as argument.
241 *
242 * @param arguments vector of strings
243 */
244 void process(const std::vector<std::string> &arguments);
245
246#ifndef NDEBUG
247 bool debug_check_option_names(const CmdOption::OptionNames &names) const;
248#endif
249
250 /** @brief Checks whether given name is a valid option name
251 *
252 * Checks whether the given name is a valid option name.
253 *
254 * A valid option name should:
255 *
256 * * have at least consist of 2 characters
257 * * start with a dash '-'
258 * * match the reqular expression ^--[A-Za-z]{2}[A-Za-z_-]+$
259 *
260 * It is allowed to use the equal sign when giving value. Following options
261 * are equal:
262 * --config /path/to/mysqlrouter.conf
263 * --config=/path/to/mysqlrouter.conf
264 *
265 * Throws std::invalid_argument when option name is not valid or
266 * option was not registered.
267 *
268 * Examples of valid option names:
269 *
270 * -h
271 * --with-ham
272 * --with_spam
273 *
274 * Example of invalid option names:
275 *
276 * -help
277 * ---spam
278 * --x-ham
279 *
280 * @param name option name to check
281 * @return true if name is valid; false otherwise
282 */
283 bool is_valid_option_name(const std::string &name) const noexcept;
284
285 /** @brief Finds the option by name
286 *
287 * Finds the option by one of its name. The name should include the the dash
288 * prefix.
289 *
290 * Example usage:
291 * // check if option name is already present
292 * assert(end() == find_option(name))
293 *
294 * @param name name of the option as string
295 * @returns iterator object
296 */
297 OptionContainer::const_iterator find_option(
298 const std::string &name) const noexcept;
299
301 std::function<std::pair<bool, CmdOption>(const CmdOption &)>;
302
303 /** @brief Produces lines of text suitable to show usage
304 *
305 * Produces lines of text suitable to show usage of the command line
306 * appliation. Each option is shown with all its names and with optional
307 * or required value.
308 *
309 * The `prefix` argument can be used to add text, usually the name
310 * of the command, in front of the options. The lines are indented
311 * using the size of the prefix.
312 *
313 * The `rest_metavar` can be used to name non-options arguments.
314 *
315 * The `width` argument is used to set the maximum length of the lines.
316 *
317 * Example output when all lines are printed:
318 *
319 * usage: mysqlrouter [-v|--version] [-h|--help] [-c|--config=<path>]
320 * [-a=[<foo>]] [rest..]
321 *
322 *
323 * @param prefix text in front of options (usually command name)
324 * @param rest_metavar name of rest arguments (empty if not needed)
325 * @param width maximum length of each line
326 * @return vector of strings
327 */
328 std::vector<std::string> usage_lines(const std::string &prefix,
329 const std::string &rest_metavar,
330 size_t width) const noexcept {
331 return usage_lines_if(
332 prefix, rest_metavar, width,
333 [](const CmdOption &opt) -> std::pair<bool, CmdOption> {
334 return {true, opt};
335 });
336 }
337
338 std::vector<std::string> usage_lines_if(
339 const std::string &prefix, const std::string &rest_metavar, size_t width,
340 UsagePredicate predicate) const noexcept;
341
342 /** @brief Produces description of all options
343 *
344 * Produces description of all options. The result is typically shown
345 * when the help screen is requested, for example when the `--help`
346 * option is given.
347 *
348 * The `width` argument is used to set the maximum length of the lines. Text
349 * is wrapped accordingly.
350 *
351 * Each description can be indented using space. The amount is given
352 * by `indent` option.
353 *
354 * Example output when lines are printed:
355 *
356 * -v, --version
357 * Show version
358 * -h, --help
359 * Show help
360 * -c <path>, --config <path>
361 * Path to the configuration file
362 *
363 * @param width maximum length of each line
364 * @param indent how much the description should be indented.
365 * @return vector of strings
366 */
367 std::vector<std::string> option_descriptions(
368 const size_t width, const size_t indent) const noexcept;
369
370 /** @brief Returns an iterator to first option
371 *
372 * Returns an iterator to the first option.
373 *
374 * @returns iterator
375 */
376 OptionContainer::const_iterator begin() { return options_.begin(); }
377
378 /** @brief Returns an iterator to end of the option container
379 *
380 * Returns an iterator to the end of the option container.
381 *
382 * @returns iterator
383 */
384 OptionContainer::const_iterator end() { return options_.end(); }
385
386 /** @brief Clears registered options
387 *
388 * Clears the registered options.
389 *
390 */
391 void clear_options() { options_.clear(); }
392
393 /** @brief Gets all registered options
394 *
395 * Returns as a reference to a vector of CmdOption objects.
396 *
397 * @return std::vector<CmdOption>
398 */
399 const std::vector<CmdOption> &get_options() const noexcept {
400 return options_;
401 }
402
403 /** @brief Returns the rest arguments
404 *
405 * Returns the rest arguments.
406 *
407 * If rest arguments are not allow or there were no rest arguments,
408 * an empty vector is returned.
409 *
410 * @return vector of strings
411 */
412 const std::vector<std::string> &get_rest_arguments() const noexcept {
413 return rest_arguments_;
414 }
415
416 /** @brief Whether to allow rest arguments or not **/
418
419 /** @brief Whether to ignore unknown arguments **/
421
422 /** @brief The key is a section identificator (section name and optional
423 * section key), the value is a map of all the overrides for a given section
424 * (option/value pairs) **/
425 using ConfigOverwrites = std::map<std::pair<std::string, std::string>,
426 std::map<std::string, std::string>>;
427 const ConfigOverwrites &get_config_overwrites() const noexcept {
428 return config_overwrites_;
429 }
430
431 private:
432 /** @brief Vector with registered options **/
433 std::vector<CmdOption> options_;
434 /** @brief Vector with arguments as strings not processed as options **/
435 std::vector<std::string> rest_arguments_;
436 /** @brief Keeps configuration options overwrites **/
438};
439
440#endif // HARNESS_ARG_HANDLER_INCLUDED
std::vector< CmdOption > OptionContainer
Definition of a vector holding unique pointers to CmdOption objects.
Definition: arg_handler.h:83
CmdOptionValueReq
Definition: arg_handler.h:43
Handles command line arguments.
Definition: arg_handler.h:140
ConfigOverwrites config_overwrites_
Keeps configuration options overwrites.
Definition: arg_handler.h:437
std::vector< std::string > rest_arguments_
Vector with arguments as strings not processed as options.
Definition: arg_handler.h:435
const std::vector< std::string > & get_rest_arguments() const noexcept
Returns the rest arguments.
Definition: arg_handler.h:412
std::map< std::pair< std::string, std::string >, std::map< std::string, std::string > > ConfigOverwrites
The key is a section identificator (section name and optional section key), the value is a map of all...
Definition: arg_handler.h:426
std::vector< CmdOption > options_
Vector with registered options.
Definition: arg_handler.h:433
void clear_options()
Clears registered options.
Definition: arg_handler.h:391
const ConfigOverwrites & get_config_overwrites() const noexcept
Definition: arg_handler.h:427
OptionContainer::const_iterator begin()
Returns an iterator to first option.
Definition: arg_handler.h:376
bool allow_rest_arguments
Whether to allow rest arguments or not.
Definition: arg_handler.h:417
CmdArgHandler(bool allow_rest_arguments_, bool ignore_unknown_arguments_=false)
Constructor.
Definition: arg_handler.h:148
OptionContainer::const_iterator end()
Returns an iterator to end of the option container.
Definition: arg_handler.h:384
const std::vector< CmdOption > & get_options() const noexcept
Gets all registered options.
Definition: arg_handler.h:399
bool ignore_unknown_arguments
Whether to ignore unknown arguments.
Definition: arg_handler.h:420
std::vector< std::string > usage_lines(const std::string &prefix, const std::string &rest_metavar, size_t width) const noexcept
Produces lines of text suitable to show usage.
Definition: arg_handler.h:328
CmdArgHandler()
Default constructor.
Definition: arg_handler.h:158
std::function< std::pair< bool, CmdOption >(const CmdOption &)> UsagePredicate
Definition: arg_handler.h:301
repeated Action action
Definition: replication_group_member_actions.proto:42
case opt name
Definition: sslopt-case.h:32
CmdOption stores information about command line options.
Definition: arg_handler.h:54
std::function< void(const std::string &)> AtEndActionFunc
Definition: arg_handler.h:56
std::string metavar
Definition: arg_handler.h:63
CmdOptionValueReq value_req
Definition: arg_handler.h:61
CmdOption(OptionNames names_, std::string description_, CmdOptionValueReq value_req_, const std::string metavar_, ActionFunc action_, AtEndActionFunc at_end_action_=[](const std::string &) {})
Definition: arg_handler.h:68
std::function< void(const std::string &)> ActionFunc
Definition: arg_handler.h:55
std::string description
Definition: arg_handler.h:60
std::string value
Definition: arg_handler.h:62
bool required
Definition: arg_handler.h:66
OptionNames names
Definition: arg_handler.h:59
ActionFunc action
Definition: arg_handler.h:64
std::vector< std::string > OptionNames
Definition: arg_handler.h:57
AtEndActionFunc at_end_action
Definition: arg_handler.h:65