https://mooseframework.inl.gov
Loading...
Searching...
No Matches
CommandLine.h
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://mooseframework.inl.gov
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9
10#pragma once
11
12#include "MooseError.h"
13#include "Conversion.h"
14#include "MooseEnum.h"
15#include "InputParameters.h"
16#include "MooseUtils.h"
17
18#include <list>
19#include <string>
20#include <map>
21#include <memory>
22#include <set>
23#include <optional>
24#include <regex>
25
30{
31public:
36 struct Entry
37 {
39 std::string name;
41 std::optional<std::string> subapp_name;
43 std::optional<std::string> value;
45 std::optional<std::string> value_separator;
47 std::vector<std::string> raw_args;
49 bool used = false;
51 bool global = false;
53 bool hit_param = false;
54 };
55
66
68 CommandLine(int argc, char * argv[]);
69 CommandLine(const std::vector<std::string> & args);
70 virtual ~CommandLine();
71
75 void addArguments(int argc, char * argv[]);
79 void addArgument(const std::string & arg);
83 void addArguments(const std::vector<std::string> & args);
84
88 bool hasArgument(const std::string & arg) const;
89
93 void removeArgument(const std::string & arg);
94
100 void parse();
101
105 bool hasParsed() const { return _has_parsed; }
106
122 std::unique_ptr<CommandLine>
123 initSubAppCommandLine(const std::string & multiapp_name,
124 const std::string & subapp_name,
125 const std::vector<std::string> & input_cli_args,
126 const std::set<std::string> & exclude_params = {});
127
133 std::vector<std::string> buildHitParams();
134
138 const std::vector<std::string> & getArguments() { return _argv; }
139
147
151 auto begin() const { return _entries.begin(); }
155 auto end() const { return _entries.end(); }
156
160 const std::list<Entry> & getEntries() const;
161
165 std::string getExecutableName() const;
166
170 std::string getExecutableNameBase() const;
171
175 void printUsage() const;
176
186 std::vector<std::string> unusedHitParams(const Parallel::Communicator & comm) const;
187
192 std::list<Entry>::const_iterator findCommandLineParam(const std::string & name) const;
193
197 std::string formatEntry(const Entry & entry) const;
198
199private:
203 std::list<Entry> & getEntries();
204
216 template <typename T>
217 void setCommandLineParam(std::list<Entry>::iterator entry_it,
218 const CommandLineParam & param,
219 const std::string & cli_switch,
220 T & value);
221
226 std::list<Entry>::iterator findCommandLineParam(const std::string & name);
227
229 std::vector<std::string> _argv;
230
233 std::list<Entry> _entries;
234
236 std::map<std::string, CommandLineParam> _command_line_params;
237
239 bool _has_parsed = false;
243 bool _hit_params_built = false;
244};
245
246template <typename T>
247void
248CommandLine::setCommandLineParam(std::list<CommandLine::Entry>::iterator entry_it,
249 const CommandLineParam & param,
250 const std::string & cli_switch,
251 T & value)
252{
253 auto & entry = *entry_it;
254 const auto required = param.metadata.argument_type == ArgumentType::REQUIRED;
255
256 // Mark this entry as used
257 entry.used = true;
258
259 // Option doesn't have any arguments (boolean)
260 if constexpr (std::is_same_v<bool, T>)
261 {
262 mooseAssert(param.metadata.argument_type == ArgumentType::NONE, "Incorrect argument type");
263
264 if (entry.value)
265 mooseError("The command line option '",
266 cli_switch,
267 "' is a boolean and does not support a value but the value '",
268 *entry.value,
269 "' was provided.\nDoc string: ",
270 param.description);
271 value = true;
272 }
273 // Option has arguments
274 else
275 {
276 mooseAssert(param.metadata.argument_type != ArgumentType::NONE, "Incorrect argument type");
277
278 // Helper for setting a value depending on its type and also throwing a useful
279 // error when the conversion fails
280 const auto set_value = [&cli_switch](const std::string & from, auto & value)
281 {
282 using type = typename std::remove_reference<decltype(value)>::type;
283
284 // Keep track of and change the throw on error characteristics so that
285 // we can catch parsing errors for the argument
286 const auto throw_on_error_orig = Moose::_throw_on_error;
288
289 try
290 {
291 if constexpr (std::is_same_v<type, std::string> || std::is_same_v<type, MooseEnum>)
292 value = from;
293 else
294 value = MooseUtils::convert<type>(from, true);
295 }
296 catch (std::exception & e)
297 {
298 Moose::_throw_on_error = throw_on_error_orig;
299 mooseError("While parsing command line option '",
300 cli_switch,
301 "' with value '",
302 from,
303 "':\n\n",
304 e.what());
305 }
306
307 Moose::_throw_on_error = throw_on_error_orig;
308 };
309
310 // If a value doesn't exist, check the next argument to see if it
311 // would work. This is needed for when we have argument values that
312 // have = signs that get split. For example:
313 // "--required-capabilities 'petsc>=3.11'" would get split into:
314 // - "--required-capabilities" with no value
315 // - "petsc>" with value "3.11"
316 // which we want to re-combine into
317 // - "--required-capabilities" with value "petsc>=3.11"
318 if (!entry.value)
319 {
320 auto next_entry_it = std::next(entry_it);
321 if (next_entry_it != _entries.end())
322 {
323 const auto & next_entry = *next_entry_it;
324 if (!next_entry.used && // isn't already used
325 (required || !next_entry.hit_param) && // if required, get the last value. if not, get
326 // it if it's not a hit param
327 !MooseUtils::beginsWith(next_entry.name, "-") && // doesn't start with a -
328 next_entry.value_separator && // has a separator
329 *next_entry.value_separator == "=" && // that separator is =
330 next_entry.value) // and has a value after the =
331 {
332 const auto & next_entry = *next_entry_it;
333 // Merge with the next Entry object and remove said next object
334 entry.value = next_entry.name + *next_entry.value_separator + *next_entry.value;
335 entry.value_separator = " ";
336 entry.raw_args.insert(
337 entry.raw_args.end(), next_entry.raw_args.begin(), next_entry.raw_args.end());
338 _entries.erase(next_entry_it);
339 }
340 }
341 }
342
343 // If we have a value, set the parameter to it
344 if (entry.value)
345 {
346 // For vector<string>, we need to unpack the values
347 if constexpr (std::is_same_v<T, std::vector<std::string>>)
348 {
349 std::vector<std::string> split_values;
350 MooseUtils::tokenize(*entry.value, split_values, 1, " ");
351 value.resize(split_values.size());
352 for (const auto i : index_range(split_values))
353 set_value(split_values[i], value[i]);
354 }
355 // For everything else, we can set them directly
356 else
357 set_value(*entry.value, value);
358 }
359 // No value, but one is required
360 else if (param.metadata.argument_type == ArgumentType::REQUIRED)
361 mooseError("The command line option '",
362 cli_switch,
363 "' requires a value and one was not provided.\nDoc string: ",
364 param.description);
365 }
366}
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
This class wraps provides and tracks access to command line parameters.
Definition CommandLine.h:30
void setCommandLineParam(std::list< Entry >::iterator entry_it, const CommandLineParam &param, const std::string &cli_switch, T &value)
Sets an InputParameters command line option at value.
bool hasParsed() const
bool _hit_params_built
Whether or not the HIT parameters have been built (set as used)
bool _command_line_params_populated
Whether or not command line parameters have been populated.
std::list< Entry > _entries
The parsed command line entries (arguments split into name value pairs) This is a list because it is ...
const std::vector< std::string > & getArguments()
void removeArgument(const std::string &arg)
Removes an argument that must exist.
Definition CommandLine.C:59
std::unique_ptr< CommandLine > initSubAppCommandLine(const std::string &multiapp_name, const std::string &subapp_name, const std::vector< std::string > &input_cli_args, const std::set< std::string > &exclude_params={})
Initializes a new CommandLine for a subapp with a MultiApp named multiapp_name and a subapp named sub...
const std::list< Entry > & getEntries() const
std::string getExecutableName() const
void populateCommandLineParams(InputParameters &params)
Populates the command line input parameters from params.
void addArguments(int argc, char *argv[])
Adds arguments from raw argc and argv.
Definition CommandLine.C:32
bool _has_parsed
Whether or not the Parser has parsed yet.
void addArgument(const std::string &arg)
Adds a single argument.
Definition CommandLine.C:39
std::string getExecutableNameBase() const
std::list< Entry >::const_iterator findCommandLineParam(const std::string &name) const
std::string formatEntry(const Entry &entry) const
std::vector< std::string > _argv
Storage for the raw argv.
bool hasArgument(const std::string &arg) const
Definition CommandLine.C:53
virtual ~CommandLine()
auto begin() const
void parse()
Performs the parsing, which is the combining of arguments into [name, value] pairs.
Definition CommandLine.C:69
void printUsage() const
Print the usage info for this command line.
auto end() const
std::vector< std::string > buildHitParams()
std::map< std::string, CommandLineParam > _command_line_params
The command line parameters, added by populateCommandLineParams()
std::vector< std::string > unusedHitParams(const Parallel::Communicator &comm) const
Returns the HIT command line arguments that are not used.
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
void tokenize(const std::string &str, std::vector< T > &elements, unsigned int min_len=1, const std::string &delims="/")
This function will split the passed in string on a set of delimiters appending the substrings to the ...
bool beginsWith(const std::string &value, const std::string &begin_value)
Definition MooseUtils.C:966
bool _throw_on_error
Variable to turn on exceptions during mooseError(), should only be used within MOOSE unit tests or wh...
Definition Moose.C:896
Stores information pertaining to a command line InputParameter.
Definition CommandLine.h:60
std::string description
The description (doc string) for the parameter.
Definition CommandLine.h:62
InputParameters::CommandLineMetadata metadata
The command line metadata for the parameter.
Definition CommandLine.h:64
Stores name/value pairs for each command line argument.
Definition CommandLine.h:37
std::optional< std::string > value
The value, i.e. ["-foo=bar"] -> "bar" or ["-foo"] -> empty, if any.
Definition CommandLine.h:43
std::optional< std::string > subapp_name
The name of the subapp, if any (with subapp:something=value syntax)
Definition CommandLine.h:41
std::optional< std::string > value_separator
The string that separates the value, if a value exists (space or =)
Definition CommandLine.h:45
std::vector< std::string > raw_args
The raw arguments that represent these split values.
Definition CommandLine.h:47
bool hit_param
Whether or not this parameter is recognized as a HIT parameter.
Definition CommandLine.h:53
bool used
Whether or not this set of arguments was used.
Definition CommandLine.h:49
bool global
Whether or not this parameter is global (passed to MultiApps)
Definition CommandLine.h:51
std::string name
The name, i.e, ["-foo=bar"] -> "-foo" or ["--foo", "bar"] -> "--foo".
Definition CommandLine.h:39
Structure for storing information about a command line parameter.
ArgumentType argument_type
The type of argument.