helics  3.6.1
helicsCLI11.hpp
1 /*
2 Copyright (c) 2017-2025,
3 Battelle Memorial Institute; Lawrence Livermore National Security, LLC; Alliance for Sustainable
4 Energy, LLC. See the top-level NOTICE for additional details. All rights reserved.
5 SPDX-License-Identifier: BSD-3-Clause
6 */
7 
8 #pragma once
9 
10 #define CLI11_EXPERIMENTAL_OPTIONAL 0
11 #define CLI11_HAS_FILESYSTEM 1
12 #include "helics/external/CLI11/CLI11.hpp"
13 #undef CLI11_EXPERIMENTAL_OPTIONAL
14 
15 #include "CoreTypes.hpp"
16 #include "helicsTime.hpp"
17 
18 #include <filesystem>
19 #include <iostream>
20 #include <set>
21 #include <string>
22 #include <utility>
23 #include <vector>
24 
25 #if defined HELICS_SHARED_LIBRARY || !defined HELICS_STATIC_CORE_LIBRARY
26 # include "../application_api/timeOperations.hpp"
27 # include "../application_api/typeOperations.hpp"
28 
31 using helics::systemInfo;
32 using helics::to_string;
33 
34 #else
35 # include "../utilities/timeStringOps.hpp"
36 # include "coreTypeOperations.hpp"
37 
38 using helics::core::coreTypeFromString;
40 using helics::core::to_string;
42 inline helics::Time loadTimeFromString(std::string_view str, time_units defUnit)
43 {
44  return gmlc::utilities::loadTimeFromString<helics::Time>(str, defUnit);
45 }
46 
47 #endif
48 #include "helicsVersion.hpp"
49 namespace helics {
50 class helicsCLI11App: public CLI::App {
51  public:
52  explicit helicsCLI11App(std::string app_description = "", const std::string& app_name = ""):
53  CLI::App(std::move(app_description), app_name, nullptr)
54  {
55  set_help_flag("-h,-?,--help", "Print this help message and exit");
56  set_config("--config-file,--config",
57  "helics_config.toml",
58  "specify base configuration file");
59  set_version_flag("--version", helics::versionString);
60  add_option_group("quiet")->immediate_callback()->add_flag("--quiet",
61  quiet,
62  "silence most print output");
63  }
64 
65  enum class ParseOutput : int {
66  PARSE_ERROR = -4,
67  OK = 0,
68  HELP_CALL = 1,
69  HELP_ALL_CALL = 2,
70  VERSION_CALL = 4,
71  SUCCESS_TERMINATION = 7
72 
73  };
74  bool quiet{false};
75  bool passConfig{true};
76  ParseOutput last_output{ParseOutput::OK};
77 
78  template<typename... Args>
79  ParseOutput helics_parse(Args&&... args) noexcept
80  {
81  try {
82  parse(std::forward<Args>(args)...);
83  last_output = ParseOutput::OK;
84  remArgs = remaining_for_passthrough();
85  if (passConfig) {
86  auto* opt = get_option_no_throw("--config");
87  if (opt != nullptr && opt->count() > 0) {
88  remArgs.push_back(opt->as<std::string>());
89  remArgs.emplace_back("--config");
90  }
91  }
92  }
93  catch (const CLI::CallForHelp& ch) {
94  if (!quiet) {
95  exit(ch);
96  }
97  last_output = ParseOutput::HELP_CALL;
98  }
99  catch (const CLI::CallForAllHelp& ca) {
100  if (!quiet) {
101  exit(ca);
102  }
103  last_output = ParseOutput::HELP_ALL_CALL;
104  }
105  catch (const CLI::CallForVersion& cv) {
106  if (!quiet) {
107  exit(cv);
108  }
109  last_output = ParseOutput::VERSION_CALL;
110  }
111  catch (const CLI::Success& /*sc*/) {
112  last_output = ParseOutput::SUCCESS_TERMINATION;
113  }
114  catch (const CLI::Error& ce) {
115  CLI::App::exit(ce);
116  last_output = ParseOutput::PARSE_ERROR;
117  }
118  catch (...) {
119  last_output = ParseOutput::PARSE_ERROR;
120  }
121  return last_output;
122  }
123  std::vector<std::string>& remainArgs() { return remArgs; }
124  void remove_helics_specifics()
125  {
126  set_help_flag();
127  set_config();
128  try {
129  remove_option(get_option_no_throw("-v"));
130  remove_subcommand(get_option_group("quiet"));
131  }
132  catch (const CLI::Error&) {
133  // must have been removed earlier
134  }
135  }
137  void add_callback(std::function<void()> cback)
138  {
139  if (cbacks.empty()) {
140  callback([this]() {
141  for (auto& cb : cbacks) {
142  cb();
143  }
144  });
145  }
146  cbacks.push_back(std::move(cback));
147  }
148  void addSystemInfoCall()
149  {
150  add_flag_callback(
151  "--system",
152  []() {
153  std::cout << systemInfo() << std::endl;
154  throw CLI::Success{};
155  },
156  "display system information details");
157  }
158  void add_config_validation()
159  {
160  auto* opt = get_option("--config");
161  if (opt != nullptr) {
162  validate_positionals();
163  opt->check([](const std::string& fname) {
164  static const std::set<std::string> validExt = {
165  ".ini", ".toml", ".json", ".INI", ".JSON", ".TOML"};
166  auto ext = std::filesystem::path(fname).extension().string();
167  if (validExt.find(ext) == validExt.end()) {
168  return fname + " does not have a valid extension";
169  }
170  return std::string{};
171  });
172  }
173  }
174  void addTypeOption(bool includeEnvironmentVariable = true)
175  {
176  auto* og = add_option_group("network type")->immediate_callback();
177  auto* typeOption =
178  og->add_option_function<std::string>(
179  "--coretype,-t",
180  [this](const std::string& val) {
181  coreType = coreTypeFromString(val);
182  if (coreType == CoreType::UNRECOGNIZED) {
183  throw CLI::ValidationError(val + " is NOT a recognized core type");
184  }
185  },
186  "type of the core to connect to")
187  ->default_str("(" + to_string(coreType) + ")")
188  ->ignore_case()
189  ->ignore_underscore();
190  if (includeEnvironmentVariable) {
191  typeOption->envname("HELICS_CORE_TYPE");
192  }
193  }
194  CoreType getCoreType() const { return coreType; }
196  void setDefaultCoreType(CoreType type) { coreType = type; }
197 
198  private:
199  std::vector<std::function<void()>> cbacks;
200  std::vector<std::string> remArgs;
201  CoreType coreType{CoreType::DEFAULT};
202 };
203 } // namespace helics
204 
205 // use the CLI lexical cast function overload to convert a string into a time
206 namespace CLI::detail {
207 template<>
208 inline bool lexical_cast<helics::Time>(const std::string& input, helics::Time& output)
209 {
210  try {
211  output = loadTimeFromString(input, time_units::ms);
212  }
213  catch (std::invalid_argument&) {
214  return false;
215  }
216  return true;
217 }
218 
219 template<>
220 constexpr const char* type_name<helics::Time>()
221 {
222  return "TIME";
223 }
224 } // namespace CLI::detail
Definition: helicsCLI11.hpp:50
void add_callback(std::function< void()> cback)
Definition: helicsCLI11.hpp:137
void setDefaultCoreType(CoreType type)
Definition: helicsCLI11.hpp:196
std::string systemInfo()
Definition: helicsVersion.cpp:196
the main namespace for the helics co-simulation library User functions will be in the helics namespac...
Definition: AsyncFedCallInfo.hpp:14
CoreType
Definition: CoreTypes.hpp:46
@ DEFAULT
ZMQ if available or UDP.
@ UNRECOGNIZED
unknown
CoreType coreTypeFromString(std::string_view type) noexcept
Definition: typeOperations.cpp:20
std::string to_string(CoreType type)
Definition: typeOperations.cpp:15
Time loadTimeFromString(std::string_view timeString)
Definition: timeOperations.cpp:21
constexpr auto versionString
Definition: helicsVersion.hpp:18
TimeRepresentation< count_time< 9 > > Time
Definition: helicsTime.hpp:27
std::string systemInfo()
Definition: typeOperations.cpp:30