https://mooseframework.inl.gov
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 {
31 public:
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 
60  {
62  std::string description;
65  };
66 
67  CommandLine();
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 
117  std::unique_ptr<CommandLine>
118  initSubAppCommandLine(const std::string & multiapp_name,
119  const std::string & subapp_name,
120  const std::vector<std::string> & input_cli_args);
121 
127  std::string buildHitParams();
128 
132  const std::vector<std::string> & getArguments() { return _argv; }
133 
141 
145  auto begin() const { return _entries.begin(); }
149  auto end() const { return _entries.end(); }
150 
154  const std::list<Entry> & getEntries() const;
155 
159  std::string getExecutableName() const;
160 
164  std::string getExecutableNameBase() const;
165 
169  void printUsage() const;
170 
180  std::vector<std::string> unusedHitParams(const Parallel::Communicator & comm) const;
181 
186  std::list<Entry>::const_iterator findCommandLineParam(const std::string & name) const;
187 
191  std::string formatEntry(const Entry & entry) const;
192 
193 private:
197  std::list<Entry> & getEntries();
198 
210  template <typename T>
211  void setCommandLineParam(std::list<Entry>::iterator entry_it,
212  const CommandLineParam & param,
213  const std::string & cli_switch,
214  T & value);
215 
220  std::list<Entry>::iterator findCommandLineParam(const std::string & name);
221 
223  std::vector<std::string> _argv;
224 
227  std::list<Entry> _entries;
228 
230  std::map<std::string, CommandLineParam> _command_line_params;
231 
233  bool _has_parsed = false;
236 };
237 
238 template <typename T>
239 void
240 CommandLine::setCommandLineParam(std::list<CommandLine::Entry>::iterator entry_it,
241  const CommandLineParam & param,
242  const std::string & cli_switch,
243  T & value)
244 {
245  auto & entry = *entry_it;
246  const auto required = param.metadata.argument_type == ArgumentType::REQUIRED;
247 
248  // Mark this entry as used
249  entry.used = true;
250 
251  // Option doesn't have any arguments (boolean)
252  if constexpr (std::is_same_v<bool, T>)
253  {
254  mooseAssert(param.metadata.argument_type == ArgumentType::NONE, "Incorrect argument type");
255 
256  if (entry.value)
257  mooseError("The command line option '",
258  cli_switch,
259  "' is a boolean and does not support a value but the value '",
260  *entry.value,
261  "' was provided.\nDoc string: ",
262  param.description);
263  value = true;
264  }
265  // Option has arguments
266  else
267  {
268  mooseAssert(param.metadata.argument_type != ArgumentType::NONE, "Incorrect argument type");
269 
270  // Helper for setting a value depending on its type and also throwing a useful
271  // error when the conversion fails
272  const auto set_value = [&cli_switch](const std::string & from, auto & value)
273  {
274  using type = typename std::remove_reference<decltype(value)>::type;
275 
276  // Keep track of and change the throw on error characteristics so that
277  // we can catch parsing errors for the argument
278  const auto throw_on_error_orig = Moose::_throw_on_error;
279  Moose::_throw_on_error = true;
280 
281  try
282  {
283  if constexpr (std::is_same_v<type, std::string> || std::is_same_v<type, MooseEnum>)
284  value = from;
285  else
286  value = MooseUtils::convert<type>(from, true);
287  }
288  catch (std::exception & e)
289  {
290  Moose::_throw_on_error = throw_on_error_orig;
291  mooseError("While parsing command line option '",
292  cli_switch,
293  "' with value '",
294  from,
295  "':\n\n",
296  e.what());
297  }
298 
299  Moose::_throw_on_error = throw_on_error_orig;
300  };
301 
302  // If a value doesn't exist, check the next argument to see if it
303  // would work. This is needed for when we have argument values that
304  // have = signs that get split. For example:
305  // "--required-capabilities 'petsc>=3.11'" would get split into:
306  // - "--required-capabilities" with no value
307  // - "petsc>" with value "3.11"
308  // which we want to re-combine into
309  // - "--required-capabilities" with value "petsc>=3.11"
310  if (!entry.value)
311  {
312  auto next_entry_it = std::next(entry_it);
313  if (next_entry_it != _entries.end())
314  {
315  const auto & next_entry = *next_entry_it;
316  if (!next_entry.used && // isn't already used
317  (required || !next_entry.hit_param) && // if required, get the last value. if not, get
318  // it if it's not a hit param
319  !MooseUtils::beginsWith(next_entry.name, "-") && // doesn't start with a -
320  next_entry.value_separator && // has a separator
321  *next_entry.value_separator == "=" && // that separator is =
322  next_entry.value) // and has a value after the =
323  {
324  const auto & next_entry = *next_entry_it;
325  // Merge with the next Entry object and remove said next object
326  entry.value = next_entry.name + *next_entry.value_separator + *next_entry.value;
327  entry.raw_args.insert(
328  entry.raw_args.end(), next_entry.raw_args.begin(), next_entry.raw_args.end());
329  _entries.erase(next_entry_it);
330  }
331  }
332  }
333 
334  // If we have a value, set the parameter to it
335  if (entry.value)
336  {
337  // For vector<string>, we need to unpack the values
338  if constexpr (std::is_same_v<T, std::vector<std::string>>)
339  {
340  std::vector<std::string> split_values;
341  MooseUtils::tokenize(*entry.value, split_values, 1, " ");
342  value.resize(split_values.size());
343  for (const auto i : index_range(split_values))
344  set_value(split_values[i], value[i]);
345  }
346  // For everything else, we can set them directly
347  else
348  set_value(*entry.value, value);
349  }
350  // No value, but one is required
351  else if (param.metadata.argument_type == ArgumentType::REQUIRED)
352  mooseError("The command line option '",
353  cli_switch,
354  "' requires a value and one was not provided.\nDoc string: ",
355  param.description);
356  }
357 }
bool _has_parsed
Whether or not the Parser has parsed yet.
Definition: CommandLine.h:233
std::string getExecutableName() const
Definition: CommandLine.C:384
std::optional< std::string > value_separator
The string that separates the value, if a value exists (space or =)
Definition: CommandLine.h:45
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:1061
std::list< Entry >::const_iterator findCommandLineParam(const std::string &name) const
Definition: CommandLine.C:463
std::string formatEntry(const Entry &entry) const
Definition: CommandLine.C:490
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:302
Stores name/value pairs for each command line argument.
Definition: CommandLine.h:36
void printUsage() const
Print the usage info for this command line.
Definition: CommandLine.C:404
ArgumentType argument_type
The type of argument.
std::string name
The name, i.e, ["-foo=bar"] -> "-foo" or ["--foo", "bar"] -> "--foo".
Definition: CommandLine.h:39
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
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.
void addArgument(const std::string &arg)
Adds a single argument.
Definition: CommandLine.C:39
This class wraps provides and tracks access to command line parameters.
Definition: CommandLine.h:29
auto end() const
Definition: CommandLine.h:149
Structure for storing information about a command line parameter.
std::list< Entry > _entries
The parsed command line entries (arguments split into name value pairs) This is a list because it is ...
Definition: CommandLine.h:227
std::vector< std::string > raw_args
The raw arguments that represent these split values.
Definition: CommandLine.h:47
bool _command_line_params_populated
Whether or not command line parameters have been populated.
Definition: CommandLine.h:235
auto begin() const
Definition: CommandLine.h:145
void populateCommandLineParams(InputParameters &params)
Populates the command line input parameters from params.
Definition: CommandLine.C:294
Real value(unsigned n, unsigned alpha, unsigned beta, Real x)
Stores information pertaining to a command line InputParameter.
Definition: CommandLine.h:59
std::map< std::string, CommandLineParam > _command_line_params
The command line parameters, added by populateCommandLineParams()
Definition: CommandLine.h:230
std::vector< std::string > _argv
Storage for the raw argv.
Definition: CommandLine.h:223
const std::list< Entry > & getEntries() const
Definition: CommandLine.C:186
virtual ~CommandLine()
Definition: CommandLine.C:199
std::string description
The description (doc string) for the parameter.
Definition: CommandLine.h:62
bool hasArgument(const std::string &arg) const
Definition: CommandLine.C:53
InputParameters::CommandLineMetadata metadata
The command line metadata for the parameter.
Definition: CommandLine.h:64
bool used
Whether or not this set of arguments was used.
Definition: CommandLine.h:49
void removeArgument(const std::string &arg)
Removes an argument that must exist.
Definition: CommandLine.C:59
bool hit_param
Whether or not this parameter is recognized as a HIT parameter.
Definition: CommandLine.h:53
std::optional< std::string > subapp_name
The name of the subapp, if any (with subapp:something=value syntax)
Definition: CommandLine.h:41
void parse()
Performs the parsing, which is the combining of arguments into [name, value] pairs.
Definition: CommandLine.C:69
std::unique_ptr< CommandLine > initSubAppCommandLine(const std::string &multiapp_name, const std::string &subapp_name, const std::vector< std::string > &input_cli_args)
Initializes a new CommandLine for a subapp with a MultiApp named multiapp_name and a subapp named sub...
Definition: CommandLine.C:202
bool global
Whether or not this parameter is global (passed to MultiApps)
Definition: CommandLine.h:51
bool hasParsed() const
Definition: CommandLine.h:105
std::vector< std::string > unusedHitParams(const Parallel::Communicator &comm) const
Returns the HIT command line arguments that are not used.
Definition: CommandLine.C:439
bool _throw_on_error
Variable to turn on exceptions during mooseError(), should only be used within MOOSE unit tests or wh...
Definition: Moose.C:758
std::optional< std::string > value
The value, i.e. ["-foo=bar"] -> "bar" or ["-foo"] -> empty, if any.
Definition: CommandLine.h:43
auto index_range(const T &sizable)
const std::vector< std::string > & getArguments()
Definition: CommandLine.h:132
std::string getExecutableNameBase() const
Definition: CommandLine.C:394
void addArguments(int argc, char *argv[])
Adds arguments from raw argc and argv.
Definition: CommandLine.C:32
std::string buildHitParams()
Definition: CommandLine.C:240