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