Merge lp:~thomas-voss/biometryd/restructure-cli into lp:biometryd
- restructure-cli
- Merge into trunk
Proposed by
Thomas Voß
Status: | Merged |
---|---|
Approved by: | Thomas Voß |
Approved revision: | 10 |
Merged at revision: | 10 |
Proposed branch: | lp:~thomas-voss/biometryd/restructure-cli |
Merge into: | lp:biometryd |
Diff against target: |
1263 lines (+554/-432) 19 files modified
src/biometry/CMakeLists.txt (+0/-2) src/biometry/cmds/enroll.cpp (+8/-16) src/biometry/cmds/enroll.h (+1/-1) src/biometry/cmds/help.cpp (+0/-40) src/biometry/cmds/help.h (+0/-47) src/biometry/cmds/identify.cpp (+7/-7) src/biometry/cmds/identify.h (+1/-1) src/biometry/cmds/list_devices.cpp (+8/-7) src/biometry/cmds/list_devices.h (+1/-1) src/biometry/cmds/run.cpp (+4/-6) src/biometry/cmds/run.h (+1/-1) src/biometry/cmds/version.cpp (+8/-7) src/biometry/cmds/version.h (+1/-1) src/biometry/daemon.cpp (+10/-99) src/biometry/daemon.h (+1/-4) src/biometry/daemon_main.cpp (+5/-4) src/biometry/util/cli.cpp (+240/-25) src/biometry/util/cli.h (+251/-156) tests/test_daemon.cpp (+7/-7) |
To merge this branch: | bzr merge lp:~thomas-voss/biometryd/restructure-cli |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Phablet Team | Pending | ||
Review via email:
|
Commit message
Alter cli::* interface and provide a cli::Command:
Restructure setup of default help options and commands.
Description of the change
Alter cli::* interface and provide a cli::Command:
Restructure setup of default help options and commands.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'src/biometry/CMakeLists.txt' |
2 | --- src/biometry/CMakeLists.txt 2016-05-09 14:37:52 +0000 |
3 | +++ src/biometry/CMakeLists.txt 2016-05-10 11:29:00 +0000 |
4 | @@ -37,8 +37,6 @@ |
5 | cmds/identify.cpp |
6 | cmds/list_devices.h |
7 | cmds/list_devices.cpp |
8 | - cmds/help.h |
9 | - cmds/help.cpp |
10 | cmds/run.h |
11 | cmds/run.cpp |
12 | cmds/version.h |
13 | |
14 | === modified file 'src/biometry/cmds/enroll.cpp' |
15 | --- src/biometry/cmds/enroll.cpp 2016-05-09 14:37:52 +0000 |
16 | +++ src/biometry/cmds/enroll.cpp 2016-05-10 11:29:00 +0000 |
17 | @@ -35,26 +35,18 @@ |
18 | namespace cli = biometry::util::cli; |
19 | |
20 | biometry::cmds::Enroll::Enroll() |
21 | - : Command |
22 | - { |
23 | - { |
24 | - Name{"enroll"}, |
25 | - Usage{"enroll"}, |
26 | - Description{"enrolls a new template to a device"}, |
27 | - {} |
28 | - } |
29 | - }, |
30 | + : CommandWithFlagsAndAction{cli::Name{"enroll"}, cli::Usage{"enroll"}, cli::Description{"enrolls a new template to a device"}}, |
31 | user(biometry::User::current()) |
32 | { |
33 | - mutable_info().flags.push_back(cli::make_flag(Name{"device"}, Description{"The device to enroll to"}, device)); |
34 | - mutable_info().flags.push_back(cli::make_flag(Name{"device"}, Description{"The device to enroll to"}, device)); |
35 | - mutable_info().flags.push_back(cli::make_flag(Name{"user"}, Description{"The user to enroll for"}, device)); |
36 | + flag(cli::make_flag(cli::Name{"device"}, cli::Description{"The device to enroll to"}, device)); |
37 | + flag(cli::make_flag(cli::Name{"device"}, cli::Description{"The device to enroll to"}, device)); |
38 | + flag(cli::make_flag(cli::Name{"user"}, cli::Description{"The user to enroll for"}, device)); |
39 | |
40 | - mutable_run() = [this]() |
41 | + action([this](const cli::Command::Context& ctxt) |
42 | { |
43 | if (device.empty()) |
44 | { |
45 | - std::cout << "You must specify a device for enrolling a template" << std::endl; |
46 | + ctxt.cout << "You must specify a device for enrolling a template" << std::endl; |
47 | return EXIT_FAILURE; |
48 | } |
49 | |
50 | @@ -71,10 +63,10 @@ |
51 | |
52 | auto op = device->template_store().enroll(biometry::Application::system(), user); |
53 | |
54 | - std::cout << "Starting template enrollment for " << user << " to " << descriptor->name() << std::endl; |
55 | + ctxt.cout << "Starting template enrollment for " << user << " to " << descriptor->name() << std::endl; |
56 | |
57 | op->start_with_observer(std::make_shared<TracingObserver<biometry::TemplateStore::Enrollment>>()); |
58 | |
59 | return 0; |
60 | - }; |
61 | + }); |
62 | } |
63 | |
64 | === modified file 'src/biometry/cmds/enroll.h' |
65 | --- src/biometry/cmds/enroll.h 2016-05-09 14:37:52 +0000 |
66 | +++ src/biometry/cmds/enroll.h 2016-05-10 11:29:00 +0000 |
67 | @@ -36,7 +36,7 @@ |
68 | namespace cmds |
69 | { |
70 | /// @brief Enroll requests enrollment of a new template to a biometric device. |
71 | -class Enroll : public util::cli::Command |
72 | +class Enroll : public util::cli::CommandWithFlagsAndAction |
73 | { |
74 | public: |
75 | /// @brief Enroll creates a new instance, initializing flags to default values. |
76 | |
77 | === removed file 'src/biometry/cmds/help.cpp' |
78 | --- src/biometry/cmds/help.cpp 2016-05-09 14:37:52 +0000 |
79 | +++ src/biometry/cmds/help.cpp 1970-01-01 00:00:00 +0000 |
80 | @@ -1,40 +0,0 @@ |
81 | -/* |
82 | - * Copyright (C) 2016 Canonical, Ltd. |
83 | - * |
84 | - * This program is free software; you can redistribute it and/or modify |
85 | - * it under the terms of the GNU Lesser General Public License as published by |
86 | - * the Free Software Foundation; version 3. |
87 | - * |
88 | - * This program is distributed in the hope that it will be useful, |
89 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
90 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
91 | - * GNU Lesser General Public License for more details. |
92 | - * |
93 | - * You should have received a copy of the GNU Lesser General Public License |
94 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
95 | - * |
96 | - * Authored by: Thomas Voß <thomas.voss@canonical.com> |
97 | - * |
98 | - */ |
99 | - |
100 | -#include <biometry/cmds/help.h> |
101 | - |
102 | -namespace cli = biometry::util::cli; |
103 | - |
104 | -biometry::cmds::Help::Help(const CommandEnumerator& enumerator) |
105 | - : Command{{Name{"help"}, Usage{"help"}, Description{"print a help message and exit"}, {}}, [this]() |
106 | - { |
107 | - std::cout << "Usage: biometryd [COMMAND] \n" |
108 | - "\n" |
109 | - "biometryd mediates access to biometric devices. \n" |
110 | - "\n" |
111 | - "Commands:\n"; |
112 | - Help::enumerator([](const Command::Ptr& command) |
113 | - { |
114 | - std::cout << " " << command->info().name << " " << command->info().description << std::endl; |
115 | - }); |
116 | - return EXIT_FAILURE; |
117 | - }}, |
118 | - enumerator{enumerator} |
119 | -{ |
120 | -} |
121 | |
122 | === removed file 'src/biometry/cmds/help.h' |
123 | --- src/biometry/cmds/help.h 2016-05-09 14:37:52 +0000 |
124 | +++ src/biometry/cmds/help.h 1970-01-01 00:00:00 +0000 |
125 | @@ -1,47 +0,0 @@ |
126 | -/* |
127 | - * Copyright (C) 2016 Canonical, Ltd. |
128 | - * |
129 | - * This program is free software; you can redistribute it and/or modify |
130 | - * it under the terms of the GNU Lesser General Public License as published by |
131 | - * the Free Software Foundation; version 3. |
132 | - * |
133 | - * This program is distributed in the hope that it will be useful, |
134 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
135 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
136 | - * GNU Lesser General Public License for more details. |
137 | - * |
138 | - * You should have received a copy of the GNU Lesser General Public License |
139 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
140 | - * |
141 | - * Authored by: Thomas Voß <thomas.voss@canonical.com> |
142 | - * |
143 | - */ |
144 | - |
145 | -#ifndef BIOMETRYD_CMDS_HELP_H_ |
146 | -#define BIOMETRYD_CMDS_HELP_H_ |
147 | - |
148 | -#include <biometry/util/cli.h> |
149 | - |
150 | -#include <functional> |
151 | -#include <iostream> |
152 | -#include <memory> |
153 | - |
154 | -namespace biometry |
155 | -{ |
156 | -namespace cmds |
157 | -{ |
158 | -class Help : public util::cli::Command |
159 | -{ |
160 | -public: |
161 | - typedef std::function<void(const Command::Ptr&)> Enumerator; |
162 | - typedef std::function<void(const Enumerator&)> CommandEnumerator; |
163 | - |
164 | - Help(const CommandEnumerator& enumerator); |
165 | - |
166 | -private: |
167 | - CommandEnumerator enumerator; |
168 | -}; |
169 | -} |
170 | -} |
171 | - |
172 | -#endif // BIOMETRYD_CMDS_HELP_H_ |
173 | |
174 | === modified file 'src/biometry/cmds/identify.cpp' |
175 | --- src/biometry/cmds/identify.cpp 2016-05-09 14:37:52 +0000 |
176 | +++ src/biometry/cmds/identify.cpp 2016-05-10 11:29:00 +0000 |
177 | @@ -37,15 +37,15 @@ |
178 | namespace cli = biometry::util::cli; |
179 | |
180 | biometry::cmds::Identify::Identify() |
181 | - : Command{{Name{"identify"}, Usage{"identify"}, Description{"tries to identify the user holding the device"}, {}}} |
182 | + : CommandWithFlagsAndAction{cli::Name{"identify"}, cli::Usage{"identify"}, cli::Description{"tries to identify the user holding the device"}} |
183 | { |
184 | - mutable_info().flags.push_back(cli::make_flag(Name{"device"}, Description{"The device to enroll to"}, device)); |
185 | - mutable_info().flags.push_back(cli::make_flag(Command::Name{"config"}, Command::Description{"The daemon configuration"}, config)); |
186 | - mutable_run() = [this]() |
187 | + flag(cli::make_flag(cli::Name{"device"}, cli::Description{"The device to enroll to"}, device)); |
188 | + flag(cli::make_flag(cli::Name{"config"}, cli::Description{"The daemon configuration"}, config)); |
189 | + action([this](const cli::Command::Context& ctxt) |
190 | { |
191 | if (device.empty()) |
192 | { |
193 | - std::cout << "You must specify a device for identification" << std::endl; |
194 | + ctxt.cout << "You must specify a device for identification" << std::endl; |
195 | return EXIT_FAILURE; |
196 | } |
197 | |
198 | @@ -62,10 +62,10 @@ |
199 | |
200 | auto op = device->identifier().identify_user(biometry::Application::system(), biometry::Reason{"requested by cli"}); |
201 | |
202 | - std::cout << "Starting identification using device " << descriptor->name() << std::endl; |
203 | + ctxt.cout << "Starting identification using device " << descriptor->name() << std::endl; |
204 | |
205 | op->start_with_observer(std::make_shared<TracingObserver<biometry::Identification>>()); |
206 | |
207 | return 0; |
208 | - }; |
209 | + }); |
210 | } |
211 | |
212 | === modified file 'src/biometry/cmds/identify.h' |
213 | --- src/biometry/cmds/identify.h 2016-05-09 14:37:52 +0000 |
214 | +++ src/biometry/cmds/identify.h 2016-05-10 11:29:00 +0000 |
215 | @@ -36,7 +36,7 @@ |
216 | namespace cmds |
217 | { |
218 | /// @brief Identify requests identification of the user. |
219 | -class Identify : public util::cli::Command |
220 | +class Identify : public util::cli::CommandWithFlagsAndAction |
221 | { |
222 | public: |
223 | /// @brief Enroll creates a new instance, initializing flags to default values. |
224 | |
225 | === modified file 'src/biometry/cmds/list_devices.cpp' |
226 | --- src/biometry/cmds/list_devices.cpp 2016-05-09 14:37:52 +0000 |
227 | +++ src/biometry/cmds/list_devices.cpp 2016-05-10 11:29:00 +0000 |
228 | @@ -25,12 +25,13 @@ |
229 | namespace cli = biometry::util::cli; |
230 | |
231 | biometry::cmds::ListDevices::ListDevices() |
232 | - : Command{{Name{"list-devices"}, Usage{"list-devices"}, Description{"lists all known devices"}, {}}, []() |
233 | - { |
234 | - std::cout << "Known devices:" << std::endl; |
235 | - for (const auto& pair : biometry::device_registry()) |
236 | - std::cout << " - " << pair.first << "\t" << pair.second->description() << std::endl; |
237 | - return 0; |
238 | - }} |
239 | + : CommandWithFlagsAndAction{cli::Name{"list-devices"}, cli::Usage{"list-devices"}, cli::Description{"lists all known devices"}} |
240 | { |
241 | + action([](const cli::Command::Context& ctxt) |
242 | + { |
243 | + ctxt.cout << "Known devices:" << std::endl; |
244 | + for (const auto& pair : biometry::device_registry()) |
245 | + ctxt.cout << " - " << pair.first << "\t" << pair.second->description() << std::endl; |
246 | + return 0; |
247 | + }); |
248 | } |
249 | |
250 | === modified file 'src/biometry/cmds/list_devices.h' |
251 | --- src/biometry/cmds/list_devices.h 2016-05-09 14:37:52 +0000 |
252 | +++ src/biometry/cmds/list_devices.h 2016-05-10 11:29:00 +0000 |
253 | @@ -26,7 +26,7 @@ |
254 | { |
255 | namespace cmds |
256 | { |
257 | -class ListDevices : public util::cli::Command |
258 | +class ListDevices : public util::cli::CommandWithFlagsAndAction |
259 | { |
260 | public: |
261 | ListDevices(); |
262 | |
263 | === modified file 'src/biometry/cmds/run.cpp' |
264 | --- src/biometry/cmds/run.cpp 2016-05-09 14:37:52 +0000 |
265 | +++ src/biometry/cmds/run.cpp 2016-05-10 11:29:00 +0000 |
266 | @@ -47,11 +47,11 @@ |
267 | |
268 | |
269 | biometry::cmds::Run::Run(const BusFactory& bus_factory) |
270 | - : Command{{Name{"run"}, Usage{"run"}, Description{"run the daemon"}, {}}}, |
271 | + : CommandWithFlagsAndAction{cli::Name{"run"}, cli::Usage{"run"}, cli::Description{"run the daemon"}}, |
272 | bus_factory{bus_factory} |
273 | { |
274 | - mutable_info().flags.push_back(cli::make_flag(Command::Name{"config"}, Command::Description{"The daemon configuration"}, config)); |
275 | - mutable_run() = [this]() |
276 | + flag(cli::make_flag(cli::Name{"config"}, cli::Description{"The daemon configuration"}, config)); |
277 | + action([this](const cli::Command::Context&) |
278 | { |
279 | auto trap = core::posix::trap_signals_for_all_subsequent_threads({core::posix::Signal::sig_term}); |
280 | trap->signal_raised().connect([trap](const core::posix::Signal&) |
281 | @@ -59,8 +59,6 @@ |
282 | trap->stop(); |
283 | }); |
284 | |
285 | - std::cout << "here " << config.get() << std::endl; |
286 | - |
287 | using StreamingJsonConfigurationBuilder = util::StreamingConfigurationBuilder<util::JsonConfigurationBuilder>; |
288 | StreamingJsonConfigurationBuilder builder |
289 | { |
290 | @@ -92,5 +90,5 @@ |
291 | runtime->stop(); |
292 | |
293 | return EXIT_SUCCESS; |
294 | - }; |
295 | + }); |
296 | } |
297 | |
298 | === modified file 'src/biometry/cmds/run.h' |
299 | --- src/biometry/cmds/run.h 2016-05-09 14:37:52 +0000 |
300 | +++ src/biometry/cmds/run.h 2016-05-10 11:29:00 +0000 |
301 | @@ -36,7 +36,7 @@ |
302 | { |
303 | namespace cmds |
304 | { |
305 | -class Run : public util::cli::Command |
306 | +class Run : public util::cli::CommandWithFlagsAndAction |
307 | { |
308 | public: |
309 | /// @brief BusFactory models creation of bus instances. |
310 | |
311 | === modified file 'src/biometry/cmds/version.cpp' |
312 | --- src/biometry/cmds/version.cpp 2016-05-09 14:37:52 +0000 |
313 | +++ src/biometry/cmds/version.cpp 2016-05-10 11:29:00 +0000 |
314 | @@ -23,12 +23,13 @@ |
315 | namespace cli = biometry::util::cli; |
316 | |
317 | biometry::cmds::Version::Version() |
318 | - : Command{{Name{"version"}, Usage{"version"}, Description{"print the version of the daemon"}, {}}, []() |
319 | - { |
320 | - std::uint32_t major, minor, patch; |
321 | - biometry::version(major, minor, patch); |
322 | - std::cout << "biometryd " << major << "." << minor << "." << patch << std::endl; |
323 | - return 0; |
324 | - }} |
325 | + : CommandWithFlagsAndAction{cli::Name{"version"}, cli::Usage{"version"}, cli::Description{"print the version of the daemon"}} |
326 | { |
327 | + action([](const cli::Command::Context& ctxt) |
328 | + { |
329 | + std::uint32_t major, minor, patch; |
330 | + biometry::version(major, minor, patch); |
331 | + ctxt.cout << "biometryd " << major << "." << minor << "." << patch << std::endl; |
332 | + return 0; |
333 | + }); |
334 | } |
335 | |
336 | === modified file 'src/biometry/cmds/version.h' |
337 | --- src/biometry/cmds/version.h 2016-05-09 14:37:52 +0000 |
338 | +++ src/biometry/cmds/version.h 2016-05-10 11:29:00 +0000 |
339 | @@ -30,7 +30,7 @@ |
340 | { |
341 | namespace cmds |
342 | { |
343 | -class Version : public util::cli::Command |
344 | +class Version : public util::cli::CommandWithFlagsAndAction |
345 | { |
346 | public: |
347 | Version(); |
348 | |
349 | === modified file 'src/biometry/daemon.cpp' |
350 | --- src/biometry/daemon.cpp 2016-05-09 14:37:52 +0000 |
351 | +++ src/biometry/daemon.cpp 2016-05-10 11:29:00 +0000 |
352 | @@ -22,7 +22,6 @@ |
353 | #include <biometry/devices/plugin/enumerator.h> |
354 | |
355 | #include <biometry/cmds/enroll.h> |
356 | -#include <biometry/cmds/help.h> |
357 | #include <biometry/cmds/identify.h> |
358 | #include <biometry/cmds/list_devices.h> |
359 | #include <biometry/cmds/run.h> |
360 | @@ -37,106 +36,18 @@ |
361 | namespace cli = biometry::util::cli; |
362 | namespace po = boost::program_options; |
363 | |
364 | -namespace |
365 | -{ |
366 | -std::multimap<cli::Command::Name, std::function<void(const std::string&)>>& notifiers() |
367 | -{ |
368 | - static std::multimap<cli::Command::Name, std::function<void(const std::string&)>> instance; |
369 | - return instance; |
370 | -} |
371 | -} |
372 | - |
373 | -cli::Command::Flag::Flag(const Name& name, const Description& description) |
374 | - : name_{name}, |
375 | - description_{description} |
376 | -{ |
377 | -} |
378 | - |
379 | -const cli::Command::Name& cli::Command::Flag::name() const |
380 | -{ |
381 | - return name_; |
382 | -} |
383 | - |
384 | -const cli::Command::Description& cli::Command::Flag::description() const |
385 | -{ |
386 | - return description_; |
387 | -} |
388 | - |
389 | -biometry::Daemon::Daemon() : device_registrar{biometry::devices::plugin::DirectoryEnumerator{Configuration::default_plugin_directory()}} |
390 | -{ |
391 | - install_command(std::make_shared<cmds::Enroll>()); |
392 | - install_command(std::make_shared<cmds::Identify>()); |
393 | - install_command(std::make_shared<cmds::ListDevices>()); |
394 | - install_command(std::make_shared<cmds::Run>()); |
395 | - install_command(std::make_shared<cmds::Version>()); |
396 | - |
397 | - help = std::make_shared<cmds::Help>([this](const cmds::Help::Enumerator& enumerator) |
398 | - { |
399 | - for (const auto& pair : cmds) |
400 | - enumerator(pair.second); |
401 | - }); |
402 | +biometry::Daemon::Daemon() |
403 | + : device_registrar{biometry::devices::plugin::DirectoryEnumerator{Configuration::default_plugin_directory()}}, |
404 | + cmd{cli::Name{"biometryd"}, cli::Usage{"biometryd"}, cli::Description{"biometryd"}} |
405 | +{ |
406 | + cmd.command(std::make_shared<cmds::Enroll>()) |
407 | + .command(std::make_shared<cmds::Identify>()) |
408 | + .command(std::make_shared<cmds::ListDevices>()) |
409 | + .command(std::make_shared<cmds::Run>()) |
410 | + .command(std::make_shared<cmds::Version>()); |
411 | } |
412 | |
413 | int biometry::Daemon::run(const std::vector<std::string>& args) |
414 | { |
415 | - po::positional_options_description pdesc; |
416 | - pdesc.add("command", 1); |
417 | - |
418 | - po::options_description desc("Options"); |
419 | - desc.add_options() |
420 | - ("command", po::value<std::string>()->default_value(help->info().name), "the command to be executed"); |
421 | - |
422 | - for (const auto& pair : cmds) |
423 | - { |
424 | - po::options_description cd(pair.first); |
425 | - for (auto flag : pair.second->info().flags) |
426 | - { |
427 | - // Depending on the name of the flag, we only ever install it once |
428 | - // to the options_description to avoid triggering an issue caused |
429 | - // by ambigious options. Instead, we relay the notify method to inform multiple |
430 | - // flags of the same name that a new value is available. |
431 | - if (notifiers().count(flag->name()) == 0) |
432 | - { |
433 | - auto v = po::value<std::string>()->notifier([flag](const std::string& s) |
434 | - { |
435 | - // Iterate over all known identifiers. |
436 | - auto range = notifiers().equal_range(flag->name()); |
437 | - while (range.first != range.second) |
438 | - { |
439 | - (range.first->second)(s); |
440 | - ++range.first; |
441 | - } |
442 | - }); |
443 | - |
444 | - cd.add_options()(flag->name().as_string().c_str(), v, flag->description().as_string().c_str()); |
445 | - } |
446 | - |
447 | - notifiers().insert(std::make_pair(flag->name(), [flag](const std::string& s) { flag->notify(s); })); |
448 | - } |
449 | - desc.add(cd); |
450 | - } |
451 | - |
452 | - try |
453 | - { |
454 | - po::variables_map vm; |
455 | - po::store(po::command_line_parser(args).options(desc).positional(pdesc).run(), vm); |
456 | - po::notify(vm); |
457 | - |
458 | - auto command = vm["command"].as<std::string>(); |
459 | - |
460 | - if (command == "help") |
461 | - return help->run(); |
462 | - |
463 | - return cmds[command]->run(); |
464 | - } |
465 | - catch (const std::exception& e) |
466 | - { |
467 | - std::cout << e.what() << std::endl; |
468 | - return help->run(); |
469 | - } |
470 | -} |
471 | - |
472 | -void biometry::Daemon::install_command(const cli::Command::Ptr& command) |
473 | -{ |
474 | - cmds[command->info().name] = command; |
475 | + return cmd.run({std::cin, std::cout, args}); |
476 | } |
477 | |
478 | === modified file 'src/biometry/daemon.h' |
479 | --- src/biometry/daemon.h 2016-05-09 14:37:52 +0000 |
480 | +++ src/biometry/daemon.h 2016-05-10 11:29:00 +0000 |
481 | @@ -54,11 +54,8 @@ |
482 | int run(const std::vector<std::string>& args); |
483 | |
484 | private: |
485 | - void install_command(const util::cli::Command::Ptr& command); |
486 | - |
487 | DeviceRegistrar device_registrar; |
488 | - std::unordered_map<std::string, util::cli::Command::Ptr> cmds; |
489 | - util::cli::Command::Ptr help; |
490 | + util::cli::CommandWithSubcommands cmd; |
491 | }; |
492 | |
493 | |
494 | |
495 | === modified file 'src/biometry/daemon_main.cpp' |
496 | --- src/biometry/daemon_main.cpp 2016-05-04 12:17:44 +0000 |
497 | +++ src/biometry/daemon_main.cpp 2016-05-10 11:29:00 +0000 |
498 | @@ -19,11 +19,12 @@ |
499 | |
500 | #include <biometry/daemon.h> |
501 | |
502 | +#include <biometry/util/cli.h> |
503 | + |
504 | +namespace cli = biometry::util::cli; |
505 | + |
506 | int main(int argc, char** argv) |
507 | { |
508 | - std::vector<std::string> args; |
509 | - for (int i = 1; i < argc; i++) args.emplace_back(argv[i]); |
510 | - |
511 | biometry::Daemon biometryd; |
512 | - return biometryd.run(args); |
513 | + return biometryd.run(cli::args(argc, argv)); |
514 | } |
515 | |
516 | === modified file 'src/biometry/util/cli.cpp' |
517 | --- src/biometry/util/cli.cpp 2016-05-09 14:37:52 +0000 |
518 | +++ src/biometry/util/cli.cpp 2016-05-10 11:29:00 +0000 |
519 | @@ -19,30 +19,245 @@ |
520 | |
521 | #include <biometry/util/cli.h> |
522 | |
523 | +#include <boost/format.hpp> |
524 | +#include <boost/program_options.hpp> |
525 | + |
526 | namespace cli = biometry::util::cli; |
527 | - |
528 | -cli::Command::Info cli::Command::info() const |
529 | -{ |
530 | - return info_; |
531 | -} |
532 | - |
533 | -int cli::Command::run() |
534 | -{ |
535 | - return run_(); |
536 | -} |
537 | - |
538 | -cli::Command::Command(const cli::Command::Info& info, const std::function<int()>& run) |
539 | - : info_(info), |
540 | - run_{run} |
541 | -{ |
542 | -} |
543 | - |
544 | -cli::Command::Info& cli::Command::mutable_info() |
545 | -{ |
546 | - return info_; |
547 | -} |
548 | - |
549 | -std::function<int()>& cli::Command::mutable_run() |
550 | -{ |
551 | - return run_; |
552 | +namespace po = boost::program_options; |
553 | + |
554 | +namespace |
555 | +{ |
556 | +namespace pattern |
557 | +{ |
558 | +static constexpr const char* help_for_command_with_subcommands = |
559 | +"NAME:\n" |
560 | +" %1% - %2%\n" |
561 | +"\n" |
562 | +"USAGE:\n" |
563 | +" %3% [command options] [arguments...]"; |
564 | + |
565 | +static constexpr const char* commands = "COMMANDS:"; |
566 | +static constexpr const char* command = " %1% %2%"; |
567 | + |
568 | +static constexpr const char* options = "OPTIONS:"; |
569 | +static constexpr const char* option = " --%1% %2%"; |
570 | +} |
571 | + |
572 | +void add_to_desc_for_flags(po::options_description& desc, const std::set<cli::Flag::Ptr>& flags) |
573 | +{ |
574 | + for (auto flag : flags) |
575 | + { |
576 | + auto v = po::value<std::string>()->notifier([flag](const std::string& s) |
577 | + { |
578 | + flag->notify(s); |
579 | + }); |
580 | + desc.add_options()(flag->name().as_string().c_str(), v, flag->description().as_string().c_str()); |
581 | + } |
582 | +} |
583 | +} |
584 | + |
585 | +std::vector<std::string> cli::args(int argc, char **argv) |
586 | +{ |
587 | + std::vector<std::string> result; |
588 | + for (int i = 1; i < argc; i++) result.push_back(argv[i]); |
589 | + return result; |
590 | +} |
591 | + |
592 | +const cli::Name& cli::Flag::name() const |
593 | +{ |
594 | + return name_; |
595 | +} |
596 | + |
597 | +const cli::Description& cli::Flag::description() const |
598 | +{ |
599 | + return description_; |
600 | +} |
601 | + |
602 | +cli::Flag::Flag(const Name& name, const Description& description) |
603 | + : name_{name}, |
604 | + description_{description} |
605 | +{ |
606 | +} |
607 | + |
608 | +cli::Name cli::Command::name() const |
609 | +{ |
610 | + return name_; |
611 | +} |
612 | + |
613 | +cli::Usage cli::Command::usage() const |
614 | +{ |
615 | + return usage_; |
616 | +} |
617 | + |
618 | +cli::Description cli::Command::description() const |
619 | +{ |
620 | + return description_; |
621 | +} |
622 | + |
623 | +cli::Command::Command(const cli::Name& name, const cli::Usage& usage, const cli::Description& description) |
624 | + : name_(name), |
625 | + usage_(usage), |
626 | + description_(description) |
627 | +{ |
628 | +} |
629 | + |
630 | +cli::CommandWithSubcommands::CommandWithSubcommands(const Name& name, const Usage& usage, const Description& description) |
631 | + : Command{name, usage, description} |
632 | +{ |
633 | + command(std::make_shared<cmd::Help>(*this)); |
634 | +} |
635 | + |
636 | +cli::CommandWithSubcommands& cli::CommandWithSubcommands::command(const Command::Ptr& command) |
637 | +{ |
638 | + commands_[command->name().as_string()] = command; |
639 | + return *this; |
640 | +} |
641 | + |
642 | +cli::CommandWithSubcommands& cli::CommandWithSubcommands::flag(const Flag::Ptr& flag) |
643 | +{ |
644 | + flags_.insert(flag); |
645 | + return *this; |
646 | +} |
647 | + |
648 | +void cli::CommandWithSubcommands::help(std::ostream& out) |
649 | +{ |
650 | + out << boost::format(pattern::help_for_command_with_subcommands) |
651 | + % name().as_string() % usage().as_string() |
652 | + % name().as_string() << std::endl; |
653 | + |
654 | + if (flags_.size() > 0) |
655 | + { |
656 | + out << std::endl << pattern::options << std::endl; |
657 | + for (const auto& flag : flags_) |
658 | + out << boost::format(pattern::option) % flag->name() % flag->description() << std::endl; |
659 | + } |
660 | + |
661 | + if (commands_.size() > 0) |
662 | + { |
663 | + out << std::endl << pattern::commands << std::endl; |
664 | + for (const auto& cmd : commands_) |
665 | + out << boost::format(pattern::command) % cmd.second->name() % cmd.second->description() << std::endl; |
666 | + } |
667 | +} |
668 | + |
669 | +int cli::CommandWithSubcommands::run(const cli::Command::Context& ctxt) |
670 | +{ |
671 | + po::positional_options_description pdesc; |
672 | + pdesc.add("command", 1); |
673 | + |
674 | + po::options_description desc("Options"); |
675 | + desc.add_options()("command", po::value<std::string>()->required(), "the command to be executed"); |
676 | + |
677 | + add_to_desc_for_flags(desc, flags_); |
678 | + |
679 | + try |
680 | + { |
681 | + po::variables_map vm; |
682 | + auto parsed = po::command_line_parser(ctxt.args).options(desc).positional(pdesc).allow_unregistered().run(); |
683 | + po::store(parsed, vm); |
684 | + po::notify(vm); |
685 | + |
686 | + return commands_[vm["command"].as<std::string>()]->run(cli::Command::Context |
687 | + { |
688 | + ctxt.cin, |
689 | + ctxt.cout, |
690 | + po::collect_unrecognized(parsed.options, po::include_positional) |
691 | + }); |
692 | + } |
693 | + catch (const po::error& e) |
694 | + { |
695 | + ctxt.cout << e.what() << std::endl; |
696 | + help(ctxt.cout); |
697 | + return EXIT_FAILURE; |
698 | + } |
699 | + |
700 | + return EXIT_FAILURE; |
701 | +} |
702 | + |
703 | +cli::CommandWithFlagsAndAction::CommandWithFlagsAndAction(const Name& name, const Usage& usage, const Description& description) |
704 | + : Command{name, usage, description} |
705 | +{ |
706 | +} |
707 | + |
708 | +cli::CommandWithFlagsAndAction& cli::CommandWithFlagsAndAction::flag(const Flag::Ptr& flag) |
709 | +{ |
710 | + flags_.insert(flag); |
711 | + return *this; |
712 | +} |
713 | + |
714 | +cli::CommandWithFlagsAndAction& cli::CommandWithFlagsAndAction::action(const Action& action) |
715 | +{ |
716 | + action_ = action; |
717 | + return *this; |
718 | +} |
719 | + |
720 | +int cli::CommandWithFlagsAndAction::run(const Context& ctxt) |
721 | +{ |
722 | + po::options_description cd(name().as_string()); |
723 | + |
724 | + bool help_requested{false}; |
725 | + cd.add_options()("help", po::bool_switch(&help_requested), "produces a help message"); |
726 | + |
727 | + add_to_desc_for_flags(cd, flags_); |
728 | + |
729 | + try |
730 | + { |
731 | + po::variables_map vm; |
732 | + auto parsed = po::command_line_parser(ctxt.args).options(cd).allow_unregistered().run(); |
733 | + po::store(parsed, vm); |
734 | + po::notify(vm); |
735 | + |
736 | + if (help_requested) |
737 | + { |
738 | + help(ctxt.cout); |
739 | + return EXIT_SUCCESS; |
740 | + } |
741 | + |
742 | + return action_(cli::Command::Context |
743 | + { |
744 | + ctxt.cin, |
745 | + ctxt.cout, |
746 | + po::collect_unrecognized(parsed.options, po::include_positional) |
747 | + }); |
748 | + } |
749 | + catch (const po::error& e) |
750 | + { |
751 | + ctxt.cout << e.what() << std::endl; |
752 | + help(ctxt.cout); |
753 | + return EXIT_FAILURE; |
754 | + } |
755 | + |
756 | + return EXIT_FAILURE; |
757 | +} |
758 | + |
759 | +void cli::CommandWithFlagsAndAction::help(std::ostream& out) |
760 | +{ |
761 | + out << boost::format(pattern::help_for_command_with_subcommands) |
762 | + % name().as_string() % description().as_string() |
763 | + % name().as_string() << std::endl; |
764 | + |
765 | + if (flags_.size() > 0) |
766 | + { |
767 | + out << std::endl << boost::format(pattern::options) << std::endl; |
768 | + for (const auto& flag : flags_) |
769 | + out << boost::format(pattern::option) % flag->name() % flag->description() << std::endl; |
770 | + } |
771 | +} |
772 | + |
773 | +cli::cmd::Help::Help(Command& cmd) |
774 | + : Command{cli::Name{"help"}, cli::Usage{"prints a short help message"}, cli::Description{"prints a short help message"}}, |
775 | + command{cmd} |
776 | +{ |
777 | +} |
778 | + |
779 | +// From Command |
780 | +int cli::cmd::Help::run(const Context &context) |
781 | +{ |
782 | + command.help(context.cout); |
783 | + return EXIT_FAILURE; |
784 | +} |
785 | + |
786 | +void cli::cmd::Help::help(std::ostream &out) |
787 | +{ |
788 | + command.help(out); |
789 | } |
790 | |
791 | === modified file 'src/biometry/util/cli.h' |
792 | --- src/biometry/util/cli.h 2016-05-09 14:37:52 +0000 |
793 | +++ src/biometry/util/cli.h 2016-05-10 11:29:00 +0000 |
794 | @@ -26,9 +26,11 @@ |
795 | #include <iomanip> |
796 | #include <iostream> |
797 | #include <memory> |
798 | +#include <set> |
799 | #include <sstream> |
800 | #include <stdexcept> |
801 | #include <string> |
802 | +#include <unordered_map> |
803 | |
804 | namespace biometry |
805 | { |
806 | @@ -78,170 +80,263 @@ |
807 | return out << std::setw(max) << std::left << scs.as_string(); |
808 | } |
809 | |
810 | +// We are imposing size constraints to ensure a consistent CLI layout. |
811 | +typedef SizeConstrainedString<15> Name; |
812 | +typedef SizeConstrainedString<60> Usage; |
813 | +typedef SizeConstrainedString<60> Description; |
814 | + |
815 | +/// @brief Flag models an input parameter to a command. |
816 | +class BIOMETRY_DLL_PUBLIC Flag : public DoNotCopyOrMove |
817 | +{ |
818 | +public: |
819 | + // Safe us some typing. |
820 | + typedef std::shared_ptr<Flag> Ptr; |
821 | + |
822 | + /// @brief notify announces a new value to the flag. |
823 | + virtual void notify(const std::string& value) = 0; |
824 | + /// @brief name returns the name of the Flag. |
825 | + const Name& name() const; |
826 | + /// @brief description returns a human-readable description of the flag. |
827 | + const Description& description() const; |
828 | + |
829 | +protected: |
830 | + /// @brief Flag creates a new instance, initializing name and description |
831 | + /// from the given values. |
832 | + Flag(const Name& name, const Description& description); |
833 | + |
834 | +private: |
835 | + Name name_; |
836 | + Description description_; |
837 | +}; |
838 | + |
839 | +/// @brief TypedFlag implements Flag relying on operator<< and operator>> to read/write values to/from strings. |
840 | +template<typename T> |
841 | +class BIOMETRY_DLL_PUBLIC TypedFlag : public Flag |
842 | +{ |
843 | +public: |
844 | + typedef std::shared_ptr<TypedFlag<T>> Ptr; |
845 | + |
846 | + TypedFlag(const Name& name, const Description& description) : Flag{name, description} |
847 | + { |
848 | + } |
849 | + |
850 | + /// @brief value installs the given value in the flag. |
851 | + TypedFlag& value(const T& value) |
852 | + { |
853 | + value_ = value; |
854 | + return *this; |
855 | + } |
856 | + |
857 | + /// @brief value returns the optional value associated with the flag. |
858 | + const Optional<T>& value() const |
859 | + { |
860 | + return value_; |
861 | + } |
862 | + |
863 | + /// @brief notify tries to unwrap a value of type T from value. |
864 | + void notify(const std::string& s) override |
865 | + { |
866 | + std::stringstream ss{s}; |
867 | + T value; ss >> value; |
868 | + value_ = value; |
869 | + } |
870 | + |
871 | +private: |
872 | + Optional<T> value_; |
873 | +}; |
874 | + |
875 | +/// @brief TypedReferenceFlag implements Flag, relying on operator<</>> to convert to/from string representations, |
876 | +/// updating the given mutable reference to a value of type T. |
877 | +template<typename T> |
878 | +class BIOMETRY_DLL_PUBLIC TypedReferenceFlag : public Flag |
879 | +{ |
880 | +public: |
881 | + // Safe us some typing. |
882 | + typedef std::shared_ptr<TypedReferenceFlag<T>> Ptr; |
883 | + |
884 | + /// @brief TypedReferenceFlag initializes a new instance with name, description and value. |
885 | + TypedReferenceFlag(const Name& name, const Description& description, T& value) |
886 | + : Flag{name, description}, |
887 | + value_{value} |
888 | + { |
889 | + } |
890 | + |
891 | + /// @brief notify tries to unwrap a value of type T from value, |
892 | + /// relying on operator>> to read from given string s. |
893 | + void notify(const std::string& s) override |
894 | + { |
895 | + std::stringstream ss{s}; |
896 | + ss >> value_.get(); |
897 | + } |
898 | + |
899 | +private: |
900 | + std::reference_wrapper<T> value_; |
901 | +}; |
902 | + |
903 | +/// @brief OptionalTypedReferenceFlag handles Optional<T> references, making sure that |
904 | +/// a value is always read on notify, even if the Optional<T> wasn't initialized previously. |
905 | +template<typename T> |
906 | +class BIOMETRY_DLL_PUBLIC OptionalTypedReferenceFlag : public Flag |
907 | +{ |
908 | +public: |
909 | + typedef std::shared_ptr<OptionalTypedReferenceFlag<T>> Ptr; |
910 | + |
911 | + OptionalTypedReferenceFlag(const Name& name, const Description& description, Optional<T>& value) |
912 | + : Flag{name, description}, |
913 | + value_{value} |
914 | + { |
915 | + } |
916 | + |
917 | + /// @brief notify tries to unwrap a value of type T from value. |
918 | + void notify(const std::string& s) override |
919 | + { |
920 | + std::stringstream ss{s}; T value; ss >> value; |
921 | + value_.get() = value; |
922 | + } |
923 | + |
924 | +private: |
925 | + std::reference_wrapper<Optional<T>> value_; |
926 | +}; |
927 | + |
928 | /// @brief Command abstracts an individual command available from the daemon. |
929 | class BIOMETRY_DLL_PUBLIC Command : public DoNotCopyOrMove |
930 | { |
931 | public: |
932 | // Safe us some typing |
933 | - typedef std::shared_ptr<Command> Ptr; |
934 | - |
935 | - // We are imposing size constraints to ensure a consistent CLI layout. |
936 | - typedef SizeConstrainedString<15> Name; |
937 | - typedef SizeConstrainedString<60> Usage; |
938 | - typedef SizeConstrainedString<60> Description; |
939 | - |
940 | - /// @brief Flag models an input parameter to a command. |
941 | - class Flag : public DoNotCopyOrMove |
942 | - { |
943 | - public: |
944 | - // Safe us some typing. |
945 | - typedef std::shared_ptr<Flag> Ptr; |
946 | - |
947 | - /// @brief notify announces a new value to the flag. |
948 | - virtual void notify(const std::string& value) = 0; |
949 | - /// @brief name returns the name of the Flag. |
950 | - const Name& name() const; |
951 | - /// @brief description returns a human-readable description of the flag. |
952 | - const Description& description() const; |
953 | - |
954 | - protected: |
955 | - /// @brief Flag creates a new instance, initializing name and description |
956 | - /// from the given values. |
957 | - Flag(const Name& name, const Description& description); |
958 | - |
959 | - private: |
960 | - Name name_; |
961 | - Description description_; |
962 | - }; |
963 | - |
964 | - /// @brief Info bundles details about a command. |
965 | - struct Info |
966 | - { |
967 | - Name name; ///< The name of the command. |
968 | - Usage usage; ///< Short usage description of the command. |
969 | - Description description; /// More detailed description of the command. |
970 | - std::vector<Flag::Ptr> flags; /// Flags known to the command. |
971 | - }; |
972 | - |
973 | - template<typename T> |
974 | - class TypedFlag : public Flag |
975 | - { |
976 | - public: |
977 | - typedef std::shared_ptr<TypedFlag<T>> Ptr; |
978 | - |
979 | - TypedFlag(const Name& name, const Description& description) : Flag{name, description} |
980 | - { |
981 | - } |
982 | - |
983 | - /// @brief value installs the given value in the flag. |
984 | - TypedFlag& value(const T& value) |
985 | - { |
986 | - value_ = value; |
987 | - return *this; |
988 | - } |
989 | - |
990 | - /// @brief value returns the optional value associated with the flag. |
991 | - const Optional<T>& value() const |
992 | - { |
993 | - return value_; |
994 | - } |
995 | - |
996 | - /// @brief notify tries to unwrap a value of type T from value. |
997 | - void notify(const std::string& s) override |
998 | - { |
999 | - std::stringstream ss{s}; |
1000 | - T value; ss >> value; |
1001 | - value_ = value; |
1002 | - } |
1003 | - |
1004 | - private: |
1005 | - Optional<T> value_; |
1006 | - }; |
1007 | - |
1008 | - template<typename T> |
1009 | - class TypedReferenceFlag : public Flag |
1010 | - { |
1011 | - public: |
1012 | - typedef std::shared_ptr<TypedReferenceFlag<T>> Ptr; |
1013 | - |
1014 | - TypedReferenceFlag(const Name& name, const Description& description, T& value) |
1015 | - : Flag{name, description}, |
1016 | - value_{value} |
1017 | - { |
1018 | - } |
1019 | - |
1020 | - /// @brief notify tries to unwrap a value of type T from value. |
1021 | - void notify(const std::string& s) override |
1022 | - { |
1023 | - std::stringstream ss{s}; |
1024 | - ss >> value_.get(); |
1025 | - } |
1026 | - |
1027 | - private: |
1028 | - std::reference_wrapper<T> value_; |
1029 | - }; |
1030 | - |
1031 | - /// @brief OptionalTypedReferenceFlag handles Optional<T> references, making sure that |
1032 | - /// a value is always read on notify, even if the Optional<T> wasn't initialized previously. |
1033 | - template<typename T> |
1034 | - class OptionalTypedReferenceFlag : public Flag |
1035 | - { |
1036 | - public: |
1037 | - typedef std::shared_ptr<OptionalTypedReferenceFlag<T>> Ptr; |
1038 | - |
1039 | - OptionalTypedReferenceFlag(const Name& name, const Description& description, Optional<T>& value) |
1040 | - : Flag{name, description}, |
1041 | - value_{value} |
1042 | - { |
1043 | - } |
1044 | - |
1045 | - /// @brief notify tries to unwrap a value of type T from value. |
1046 | - void notify(const std::string& s) override |
1047 | - { |
1048 | - std::stringstream ss{s}; T value; ss >> value; |
1049 | - value_.get() = value; |
1050 | - } |
1051 | - |
1052 | - private: |
1053 | - std::reference_wrapper<Optional<T>> value_; |
1054 | - }; |
1055 | - |
1056 | - /// @brief info returns Info about a command. |
1057 | - virtual Info info() const; |
1058 | + typedef std::shared_ptr<Command> Ptr; |
1059 | + |
1060 | + /// @brief Context bundles information passed to Command::run invocations. |
1061 | + struct Context |
1062 | + { |
1063 | + std::istream& cin; ///< The std::istream that should be used for reading. |
1064 | + std::ostream& cout; ///< The std::ostream that should be used for writing. |
1065 | + std::vector<std::string> args; ///< The command line args. |
1066 | + }; |
1067 | + |
1068 | + /// @brief name returns the Name of the command. |
1069 | + virtual Name name() const; |
1070 | + |
1071 | + /// @brief usage returns a short usage string for the command. |
1072 | + virtual Usage usage() const; |
1073 | + |
1074 | + /// @brief description returns a longer string explaining the command. |
1075 | + virtual Description description() const; |
1076 | + |
1077 | /// @brief run puts the command to execution. |
1078 | - virtual int run(); |
1079 | + virtual int run(const Context& context) = 0; |
1080 | + |
1081 | + /// @brief help prints information about a command to out. |
1082 | + virtual void help(std::ostream& out) = 0; |
1083 | |
1084 | protected: |
1085 | - /// @brief Command initializes a new instance with the given info and functor. |
1086 | - Command(const Info& info, const std::function<int()>& run = std::function<int()>()); |
1087 | - |
1088 | - /// @brief info returns a mutable reference to info_. |
1089 | - Info& mutable_info(); |
1090 | - |
1091 | - /// @brief run returns a mutable reference to run_. |
1092 | - std::function<int()>& mutable_run(); |
1093 | - |
1094 | -private: |
1095 | - Info info_; |
1096 | - std::function<int()> run_; |
1097 | -}; |
1098 | - |
1099 | -template<typename T> |
1100 | -BIOMETRY_DLL_PUBLIC typename Command::TypedFlag<T>::Ptr make_flag(const Command::Name& name, const Command::Description& desc) |
1101 | -{ |
1102 | - return std::make_shared<Command::TypedFlag<T>>(name, desc); |
1103 | -} |
1104 | - |
1105 | -template<typename T> |
1106 | -BIOMETRY_DLL_PUBLIC typename Command::TypedReferenceFlag<T>::Ptr make_flag(const Command::Name& name, const Command::Description& desc, T& value) |
1107 | -{ |
1108 | - return std::make_shared<Command::TypedReferenceFlag<T>>(name, desc, value); |
1109 | -} |
1110 | - |
1111 | -template<typename T> |
1112 | -BIOMETRY_DLL_PUBLIC typename Command::OptionalTypedReferenceFlag<T>::Ptr make_flag(const Command::Name& name, const Command::Description& desc, Optional<T>& value) |
1113 | -{ |
1114 | - return std::make_shared<Command::OptionalTypedReferenceFlag<T>>(name, desc, value); |
1115 | + /// @brief Command initializes a new instance with the given name, usage and description. |
1116 | + Command(const Name& name, const Usage& usage, const Description& description); |
1117 | + |
1118 | + /// @brief name adjusts the name of the command to n. |
1119 | + // virtual void name(const Name& n); |
1120 | + /// @brief usage adjusts the usage string of the comand to u. |
1121 | + // virtual void usage(const Usage& u); |
1122 | + /// @brief description adjusts the description string of the command to d. |
1123 | + // virtual void description(const Description& d); |
1124 | + |
1125 | +private: |
1126 | + Name name_; |
1127 | + Usage usage_; |
1128 | + Description description_; |
1129 | +}; |
1130 | + |
1131 | +/// @brief CommandWithSubcommands implements Command, selecting one of a set of actions. |
1132 | +class BIOMETRY_DLL_PUBLIC CommandWithSubcommands : public Command |
1133 | +{ |
1134 | +public: |
1135 | + typedef std::shared_ptr<CommandWithSubcommands> Ptr; |
1136 | + typedef std::function<int(const Context&)> Action; |
1137 | + |
1138 | + /// @brief CommandWithSubcommands initializes a new instance with the given name, usage and description |
1139 | + CommandWithSubcommands(const Name& name, const Usage& usage, const Description& description); |
1140 | + |
1141 | + /// @brief command adds the given command to the set of known commands. |
1142 | + CommandWithSubcommands& command(const Command::Ptr& command); |
1143 | + |
1144 | + /// @brief flag adds the given flag to the set of known flags. |
1145 | + CommandWithSubcommands& flag(const Flag::Ptr& flag); |
1146 | + |
1147 | + // From Command |
1148 | + int run(const Context& context) override; |
1149 | + void help(std::ostream &out) override; |
1150 | + |
1151 | +private: |
1152 | + std::unordered_map<std::string, Command::Ptr> commands_; |
1153 | + std::set<Flag::Ptr> flags_; |
1154 | +}; |
1155 | + |
1156 | +/// @brief CommandWithFlagsAction implements Command, executing an Action after handling |
1157 | +class BIOMETRY_DLL_PUBLIC CommandWithFlagsAndAction : public Command |
1158 | +{ |
1159 | +public: |
1160 | + typedef std::shared_ptr<CommandWithFlagsAndAction> Ptr; |
1161 | + typedef std::function<int(const Context&)> Action; |
1162 | + |
1163 | + /// @brief CommandWithFlagsAndAction initializes a new instance with the given name, usage and description |
1164 | + CommandWithFlagsAndAction(const Name& name, const Usage& usage, const Description& description); |
1165 | + |
1166 | + /// @brief flag adds the given flag to the set of known flags. |
1167 | + CommandWithFlagsAndAction& flag(const Flag::Ptr& flag); |
1168 | + |
1169 | + /// @brief action installs the given action. |
1170 | + CommandWithFlagsAndAction& action(const Action& action); |
1171 | + |
1172 | + // From Command |
1173 | + int run(const Context& context) override; |
1174 | + void help(std::ostream &out) override; |
1175 | + |
1176 | +private: |
1177 | + std::set<Flag::Ptr> flags_; |
1178 | + Action action_; |
1179 | +}; |
1180 | + |
1181 | +namespace cmd |
1182 | +{ |
1183 | +/// @brief HelpFor prints a help message for the given command on execution. |
1184 | +class Help : public Command |
1185 | +{ |
1186 | +public: |
1187 | + /// @brief HelpFor initializes a new instance with the given reference to a cmd. |
1188 | + explicit Help(Command& cmd); |
1189 | + |
1190 | + // From Command |
1191 | + int run(const Context &context) override; |
1192 | + void help(std::ostream &out) override; |
1193 | + |
1194 | +private: |
1195 | + /// @cond |
1196 | + Command& command; |
1197 | + /// @endcond |
1198 | +}; |
1199 | +} |
1200 | + |
1201 | +/// @brief args returns a vector of strings assembled from argc and argv. |
1202 | +BIOMETRY_DLL_PUBLIC std::vector<std::string> args(int argc, char** argv); |
1203 | + |
1204 | +/// @brief make_flag returns a flag with the given name and description. |
1205 | +template<typename T> |
1206 | +BIOMETRY_DLL_PUBLIC typename TypedFlag<T>::Ptr make_flag(const Name& name, const Description& description) |
1207 | +{ |
1208 | + return std::make_shared<TypedFlag<T>>(name, description); |
1209 | +} |
1210 | + |
1211 | +/// @brief make_flag returns a flag with the given name and description, notifying updates to value. |
1212 | +template<typename T> |
1213 | +BIOMETRY_DLL_PUBLIC typename TypedReferenceFlag<T>::Ptr make_flag(const Name& name, const Description& desc, T& value) |
1214 | +{ |
1215 | + return std::make_shared<TypedReferenceFlag<T>>(name, desc, value); |
1216 | +} |
1217 | + |
1218 | +/// @brief make_flag returns a flag with the given name and description, updating the given optional value. |
1219 | +template<typename T> |
1220 | +BIOMETRY_DLL_PUBLIC typename OptionalTypedReferenceFlag<T>::Ptr make_flag(const Name& name, const Description& desc, Optional<T>& value) |
1221 | +{ |
1222 | + return std::make_shared<OptionalTypedReferenceFlag<T>>(name, desc, value); |
1223 | } |
1224 | } |
1225 | } |
1226 | |
1227 | === modified file 'tests/test_daemon.cpp' |
1228 | --- tests/test_daemon.cpp 2016-05-09 14:37:52 +0000 |
1229 | +++ tests/test_daemon.cpp 2016-05-10 11:29:00 +0000 |
1230 | @@ -65,18 +65,18 @@ |
1231 | |
1232 | TEST(TypedFlag, stores_name_and_desc_passed_on_construction) |
1233 | { |
1234 | - cli::Command::Name name{"42"}; |
1235 | - cli::Command::Description desc{"43"}; |
1236 | - cli::Command::TypedFlag<int> flag{name, desc}; |
1237 | + cli::Name name{"42"}; |
1238 | + cli::Description desc{"43"}; |
1239 | + cli::TypedFlag<int> flag{name, desc}; |
1240 | EXPECT_EQ(name, flag.name()); |
1241 | EXPECT_EQ(desc, flag.description()); |
1242 | } |
1243 | |
1244 | TEST(TypedFlag, parses_string_on_notify_and_sets_value) |
1245 | { |
1246 | - cli::Command::Name name{"42"}; |
1247 | - cli::Command::Description desc{"43"}; |
1248 | - cli::Command::TypedFlag<int> flag{name, desc}; |
1249 | + cli::Name name{"42"}; |
1250 | + cli::Description desc{"43"}; |
1251 | + cli::TypedFlag<int> flag{name, desc}; |
1252 | EXPECT_FALSE(flag.value().is_initialized()); |
1253 | flag.notify("42"); |
1254 | EXPECT_TRUE(flag.value().is_initialized()); |
1255 | @@ -153,7 +153,7 @@ |
1256 | biometry::Daemon daemon; |
1257 | auto rc = daemon.run( |
1258 | { |
1259 | - "run", "--config", "test.json" |
1260 | + "run", "--config=test.json" |
1261 | }); |
1262 | |
1263 | return rc == EXIT_SUCCESS ? core::posix::exit::Status::success : core::posix::exit::Status::failure; |