Line data Source code
1 : /*!
2 : * \file esys/repo/cli/cmd_cli.cpp
3 : * \brief
4 : *
5 : * \cond
6 : * __legal_b__
7 : *
8 : * Copyright (c) 2020-2023 Michel Gillet
9 : * Distributed under the MIT License.
10 : * (See accompanying file LICENSE.txt or
11 : * copy at https://opensource.org/licenses/MIT)
12 : *
13 : * __legal_e__
14 : * \endcond
15 : *
16 : */
17 :
18 : #include "esys/repo/esysrepo_prec.h"
19 : #include "esys/repo/cli/cmd.h"
20 : #include "esys/repo/cli/appbase.h"
21 :
22 : #include <boost/program_options/parsers.hpp>
23 : #include <boost/tokenizer.hpp>
24 :
25 : #include <cassert>
26 :
27 : namespace esys::repo::cli
28 : {
29 :
30 171 : Cmd::Cmd(AppBase *app, const std::string &name, const std::string &description)
31 : : esys::log::User()
32 171 : , m_name(name)
33 171 : , m_description(description)
34 342 : , m_app(app)
35 : {
36 171 : m_positional.add("command", 1).add("subargs", -1);
37 :
38 171 : if (app != nullptr) app->register_cmd(this);
39 171 : }
40 :
41 434 : Cmd::~Cmd() = default;
42 :
43 0 : void Cmd::set_name(const std::string &name)
44 : {
45 0 : m_name = name;
46 0 : }
47 :
48 348 : const std::string &Cmd::get_name() const
49 : {
50 348 : return m_name;
51 : }
52 :
53 0 : void Cmd::set_description(const std::string &description)
54 : {
55 0 : m_description = description;
56 0 : }
57 :
58 31 : const std::string &Cmd::get_description() const
59 : {
60 31 : return m_description;
61 : }
62 :
63 0 : void Cmd::set_app(AppBase *app)
64 : {
65 0 : m_app = app;
66 0 : }
67 :
68 0 : AppBase *Cmd::get_app()
69 : {
70 0 : return m_app;
71 : }
72 :
73 27 : std::shared_ptr<po::options_description> Cmd::get_common_desc()
74 : {
75 27 : if (m_common_desc != nullptr) return m_common_desc;
76 :
77 27 : m_common_desc = std::make_shared<po::options_description>("Common options");
78 : // clang-format off
79 27 : m_common_desc->add_options()
80 27 : ("help,h", "Produce help message")
81 27 : ("command", po::value<std::string>()->required(), "Command to execute")
82 27 : ("subargs", po::value<std::vector<std::string>>(), "Arguments for command")
83 27 : ("time", po::value<bool>()->default_value(false)->implicit_value(true), "Display timestamp")
84 27 : ("delta-time", po::value<bool>()->default_value(false)->implicit_value(true), "Display delta timestamp")
85 27 : ("public", po::value<bool>()->default_value(false)->implicit_value(true), "Only use https when possible")
86 27 : ("log", po::value<std::vector<std::string>>(), "Log execution to a file")
87 27 : ("verbose", po::value<int>()->default_value(0)->implicit_value(1), "Set verbose level")
88 27 : ("debug", po::value<bool>()->default_value(false)->implicit_value(true), "Set debug mode")
89 27 : ("workspace,w", po::value<std::string>(), "the path to the workspade to use")
90 27 : ("folder,f", po::value<std::string>(), "the folder to work with")
91 27 : ("trace", "enable execution trace to a file and to the console")
92 27 : ("trace-file", "enable execution trace to a file")
93 27 : ("trace-cons", "enable execution trace to the console")
94 : ;
95 : // clang-format on
96 27 : return m_common_desc;
97 : }
98 :
99 21 : std::shared_ptr<po::options_description> Cmd::get_desc()
100 : {
101 21 : return m_desc;
102 : }
103 :
104 0 : void Cmd::set_desc_all(std::shared_ptr<po::options_description> desc_all)
105 : {
106 0 : m_desc_all = desc_all;
107 0 : }
108 :
109 50 : std::shared_ptr<po::options_description> Cmd::get_desc_all()
110 : {
111 50 : if (m_desc_all != nullptr) return m_desc_all;
112 :
113 27 : m_desc_all = std::make_shared<po::options_description>();
114 27 : auto desc = get_desc();
115 27 : if (desc != nullptr) m_desc_all->add(*desc);
116 :
117 27 : m_desc_all->add(*get_common_desc());
118 :
119 54 : return m_desc_all;
120 50 : }
121 :
122 34 : void Cmd::set_args(const std::vector<std::string> &args)
123 : {
124 34 : m_args = args;
125 34 : }
126 :
127 50 : std::vector<std::string> &Cmd::get_args()
128 : {
129 50 : return m_args;
130 : }
131 :
132 0 : const std::vector<std::string> &Cmd::get_args() const
133 : {
134 0 : return m_args;
135 : }
136 :
137 50 : int Cmd::parse(bool strict)
138 : {
139 50 : bool parse_error = false;
140 :
141 50 : m_to_parse_further.clear();
142 50 : m_vm.clear();
143 :
144 50 : try
145 : {
146 50 : if (strict == false)
147 : {
148 0 : po::parsed_options parsed = po::command_line_parser(get_args())
149 0 : .options(*get_desc_all())
150 0 : .positional(m_positional)
151 0 : .allow_unregistered()
152 0 : .run();
153 0 : m_to_parse_further = po::collect_unrecognized(parsed.options, po::include_positional);
154 0 : po::store(parsed, m_vm);
155 0 : }
156 : else
157 : {
158 50 : po::parsed_options parsed =
159 100 : po::command_line_parser(get_args()).options(*get_desc_all()).positional(m_positional).run();
160 50 : m_to_parse_further = po::collect_unrecognized(parsed.options, po::include_positional);
161 50 : po::store(parsed, m_vm);
162 50 : }
163 50 : po::notify(m_vm);
164 : }
165 2 : catch (po::error &e)
166 : {
167 2 : parse_error = true;
168 2 : error(e.what());
169 0 : }
170 :
171 2 : if (parse_error) return -1;
172 : return 0;
173 : }
174 :
175 48 : int Cmd::configure_cmd(exe::Cmd &cmd)
176 : {
177 48 : cmd.set_workspace_path(get_workspace());
178 48 : cmd.set_folder(get_folder());
179 48 : cmd.set_debug(get_debug());
180 48 : cmd.set_sub_args(get_sub_args());
181 48 : cmd.set_time(get_time());
182 48 : cmd.set_delta_time(get_delta_time());
183 : // \TODO add all missing data
184 48 : return 0;
185 : }
186 :
187 0 : int Cmd::print_doc(std::ostream &os)
188 : {
189 0 : return -1;
190 : }
191 :
192 0 : int Cmd::print_help(std::ostream &os)
193 : {
194 0 : std::ostringstream oss;
195 :
196 0 : oss << "Usage: esysrepo " << get_name() << " [" << get_name() << "_options] [common_options]" << std::endl;
197 :
198 0 : auto desc_all = get_desc_all();
199 0 : if (desc_all == nullptr) return -1;
200 0 : oss << *desc_all;
201 0 : os << oss.str();
202 0 : return 0;
203 0 : }
204 :
205 16 : void Cmd::set_console_os(std::ostream *console_os)
206 : {
207 16 : m_console_os = console_os;
208 16 : }
209 :
210 16 : std::ostream *Cmd::get_console_os()
211 : {
212 16 : return m_console_os;
213 : }
214 :
215 0 : bool Cmd::is_help()
216 : {
217 0 : return is_present("help");
218 : }
219 :
220 0 : std::string Cmd::get_command()
221 : {
222 0 : return get_string("command");
223 : }
224 :
225 48 : bool Cmd::get_time()
226 : {
227 48 : return get_bool("time");
228 : }
229 :
230 48 : bool Cmd::get_delta_time()
231 : {
232 48 : return get_bool("delta-time");
233 : }
234 :
235 0 : bool Cmd::get_public()
236 : {
237 0 : return get_bool("public");
238 : }
239 :
240 0 : int Cmd::get_verbose()
241 : {
242 0 : return get_int("verbose", 0);
243 : }
244 :
245 48 : bool Cmd::get_debug()
246 : {
247 48 : return get_bool("debug");
248 : }
249 :
250 48 : std::string Cmd::get_workspace()
251 : {
252 96 : return get_string("workspace");
253 : }
254 :
255 48 : std::string Cmd::get_folder()
256 : {
257 96 : return get_string("folder");
258 : }
259 :
260 54 : std::vector<std::string> Cmd::get_sub_args()
261 : {
262 110 : if (m_vm.count("subargs") == 0) return std::vector<std::string>();
263 :
264 6 : return m_vm["subargs"].as<std::vector<std::string>>();
265 : }
266 :
267 0 : std::shared_ptr<UserFolder> Cmd::get_user_folder() const
268 : {
269 0 : return m_user_folder;
270 : }
271 :
272 17 : void Cmd::set_user_folder(std::shared_ptr<UserFolder> user_folder)
273 : {
274 17 : m_user_folder = user_folder;
275 17 : }
276 :
277 21 : void Cmd::set_desc(std::shared_ptr<po::options_description> desc)
278 : {
279 21 : m_desc = desc;
280 21 : }
281 :
282 96 : std::string Cmd::get_string(const std::string &name)
283 : {
284 96 : if (m_vm.count(name)) return m_vm[name].as<std::string>();
285 72 : return "";
286 : }
287 :
288 0 : bool Cmd::is_present(const std::string &name)
289 : {
290 0 : return m_vm.count(name) > 0;
291 : }
292 :
293 144 : bool Cmd::get_bool(const std::string &name)
294 : {
295 144 : if (m_vm.count(name)) return m_vm[name].as<bool>();
296 : return false;
297 : }
298 :
299 0 : int Cmd::get_int(const std::string &name, int dflt)
300 : {
301 0 : if (m_vm.count(name)) return m_vm[name].as<int>();
302 : return dflt;
303 : }
304 :
305 328 : po::variables_map &Cmd::get_vm()
306 : {
307 328 : return m_vm;
308 : }
309 :
310 0 : const po::variables_map &Cmd::get_vm() const
311 : {
312 0 : return m_vm;
313 : }
314 :
315 0 : int Cmd::groups_str_to_groups(const std::string &groups_str, std::vector<std::string> &groups)
316 : {
317 0 : typedef boost::tokenizer<boost::char_separator<char>> tokenizer;
318 0 : boost::char_separator<char> sep(", ");
319 0 : tokenizer tokens(groups_str, sep);
320 :
321 0 : groups.clear();
322 :
323 0 : for (tokenizer::iterator it = tokens.begin(); it != tokens.end(); ++it) groups.push_back(*it);
324 :
325 0 : return 0;
326 0 : }
327 :
328 : } // namespace esys::repo::cli
|