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 236 : Cmd::Cmd(AppBase *app, const std::string &name, const std::string &description)
31 : : esys::log::User()
32 236 : , m_name(name)
33 236 : , m_description(description)
34 472 : , m_app(app)
35 : {
36 236 : m_positional.add("command", 1).add("subargs", -1);
37 :
38 236 : if (app != nullptr) app->register_cmd(this);
39 236 : }
40 :
41 615 : Cmd::~Cmd() = default;
42 :
43 0 : void Cmd::set_name(const std::string &name)
44 : {
45 0 : m_name = name;
46 0 : }
47 :
48 464 : const std::string &Cmd::get_name() const
49 : {
50 464 : 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 40 : const std::string &Cmd::get_description() const
59 : {
60 40 : 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 44 : std::shared_ptr<po::options_description> Cmd::get_common_desc()
74 : {
75 44 : if (m_common_desc != nullptr) return m_common_desc;
76 :
77 44 : m_common_desc = std::make_shared<po::options_description>("Common options");
78 : // clang-format off
79 44 : m_common_desc->add_options()
80 44 : ("help,h", "Produce help message")
81 44 : ("command", po::value<std::string>()->required(), "Command to execute")
82 44 : ("subargs", po::value<std::vector<std::string>>(), "Arguments for command")
83 44 : ("time", po::value<bool>()->default_value(false)->implicit_value(true), "Display timestamp")
84 44 : ("delta-time", po::value<bool>()->default_value(false)->implicit_value(true), "Display delta timestamp")
85 44 : ("public", po::value<bool>()->default_value(false)->implicit_value(true), "Only use https when possible")
86 44 : ("log", po::value<std::vector<std::string>>(), "Log execution to a file")
87 44 : ("verbose", po::value<int>()->default_value(0)->implicit_value(1), "Set verbose level")
88 44 : ("debug", po::value<bool>()->default_value(false)->implicit_value(true), "Set debug mode")
89 44 : ("workspace,w", po::value<std::string>(), "the path to the workspade to use")
90 44 : ("folder,f", po::value<std::string>(), "the folder to work with")
91 44 : ("trace", "enable execution trace to a file and to the console")
92 44 : ("trace-file", "enable execution trace to a file")
93 44 : ("trace-cons", "enable execution trace to the console")
94 : ;
95 : // clang-format on
96 44 : return m_common_desc;
97 : }
98 :
99 38 : std::shared_ptr<po::options_description> Cmd::get_desc()
100 : {
101 38 : 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 74 : std::shared_ptr<po::options_description> Cmd::get_desc_all()
110 : {
111 74 : if (m_desc_all != nullptr) return m_desc_all;
112 :
113 44 : m_desc_all = std::make_shared<po::options_description>();
114 44 : auto desc = get_desc();
115 44 : if (desc != nullptr) m_desc_all->add(*desc);
116 :
117 44 : m_desc_all->add(*get_common_desc());
118 :
119 88 : return m_desc_all;
120 74 : }
121 :
122 58 : void Cmd::set_args(const std::vector<std::string> &args)
123 : {
124 58 : m_args = args;
125 58 : }
126 :
127 74 : std::vector<std::string> &Cmd::get_args()
128 : {
129 74 : 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 74 : int Cmd::parse(bool strict)
138 : {
139 74 : bool parse_error = false;
140 :
141 74 : m_to_parse_further.clear();
142 74 : m_vm.clear();
143 :
144 74 : try
145 : {
146 74 : 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 74 : po::parsed_options parsed =
159 148 : po::command_line_parser(get_args()).options(*get_desc_all()).positional(m_positional).run();
160 73 : m_to_parse_further = po::collect_unrecognized(parsed.options, po::include_positional);
161 73 : po::store(parsed, m_vm);
162 73 : }
163 73 : po::notify(m_vm);
164 : }
165 3 : catch (po::error &e)
166 : {
167 3 : parse_error = true;
168 3 : error(e.what());
169 0 : }
170 :
171 3 : if (parse_error) return -1;
172 : return 0;
173 : }
174 :
175 71 : int Cmd::configure_cmd(exe::Cmd &cmd)
176 : {
177 71 : cmd.set_workspace_path(get_workspace());
178 71 : cmd.set_folder(get_folder());
179 71 : cmd.set_debug(get_debug());
180 71 : cmd.set_sub_args(get_sub_args());
181 71 : cmd.set_time(get_time());
182 71 : cmd.set_delta_time(get_delta_time());
183 : // \TODO add all missing data
184 71 : 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 71 : bool Cmd::get_time()
226 : {
227 71 : return get_bool("time");
228 : }
229 :
230 71 : bool Cmd::get_delta_time()
231 : {
232 71 : 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 71 : bool Cmd::get_debug()
246 : {
247 71 : return get_bool("debug");
248 : }
249 :
250 71 : std::string Cmd::get_workspace()
251 : {
252 142 : return get_string("workspace");
253 : }
254 :
255 71 : std::string Cmd::get_folder()
256 : {
257 142 : return get_string("folder");
258 : }
259 :
260 97 : std::vector<std::string> Cmd::get_sub_args()
261 : {
262 196 : 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 13 : const std::vector<std::string> &Cmd::get_unrecognized() const
268 : {
269 13 : return m_to_parse_further;
270 : }
271 :
272 0 : std::shared_ptr<UserFolder> Cmd::get_user_folder() const
273 : {
274 0 : return m_user_folder;
275 : }
276 :
277 17 : void Cmd::set_user_folder(std::shared_ptr<UserFolder> user_folder)
278 : {
279 17 : m_user_folder = user_folder;
280 17 : }
281 :
282 38 : void Cmd::set_desc(std::shared_ptr<po::options_description> desc)
283 : {
284 38 : m_desc = desc;
285 38 : }
286 :
287 142 : std::string Cmd::get_string(const std::string &name)
288 : {
289 142 : if (m_vm.count(name)) return m_vm[name].as<std::string>();
290 118 : return "";
291 : }
292 :
293 0 : bool Cmd::is_present(const std::string &name)
294 : {
295 0 : return m_vm.count(name) > 0;
296 : }
297 :
298 213 : bool Cmd::get_bool(const std::string &name)
299 : {
300 213 : if (m_vm.count(name)) return m_vm[name].as<bool>();
301 : return false;
302 : }
303 :
304 0 : int Cmd::get_int(const std::string &name, int dflt)
305 : {
306 0 : if (m_vm.count(name)) return m_vm[name].as<int>();
307 : return dflt;
308 : }
309 :
310 720 : po::variables_map &Cmd::get_vm()
311 : {
312 720 : return m_vm;
313 : }
314 :
315 0 : const po::variables_map &Cmd::get_vm() const
316 : {
317 0 : return m_vm;
318 : }
319 :
320 0 : int Cmd::groups_str_to_groups(const std::string &groups_str, std::vector<std::string> &groups)
321 : {
322 0 : typedef boost::tokenizer<boost::char_separator<char>> tokenizer;
323 0 : boost::char_separator<char> sep(", ");
324 0 : tokenizer tokens(groups_str, sep);
325 :
326 0 : groups.clear();
327 :
328 0 : for (tokenizer::iterator it = tokens.begin(); it != tokens.end(); ++it) groups.push_back(*it);
329 :
330 0 : return 0;
331 0 : }
332 :
333 : } // namespace esys::repo::cli
|