blob: f1682bfd68ba649025da1c74b089bebe483a20de [file] [log] [blame]
Václav Kubernát96344a12018-05-28 16:33:39 +02001/*
2 * Copyright (C) 2018 CESNET, https://photonics.cesnet.cz/
3 * Copyright (C) 2018 FIT CVUT, https://fit.cvut.cz/
4 *
5 * Written by Václav Kubernát <kubervac@fit.cvut.cz>
6 *
7*/
8
Václav Kubernát5b8a8f32020-05-20 00:57:22 +02009#include <boost/algorithm/string/predicate.hpp>
Václav Kubernát509ce652019-05-29 19:46:44 +020010#include <boost/mpl/for_each.hpp>
Václav Kubernátb61336d2018-05-28 17:35:03 +020011#include <iostream>
Václav Kubernát9cfcd872020-02-18 12:34:02 +010012#include <sstream>
Václav Kubernát6415b822018-08-22 17:40:01 +020013#include "datastore_access.hpp"
Václav Kubernát96344a12018-05-28 16:33:39 +020014#include "interpreter.hpp"
Václav Kubernát509ce652019-05-29 19:46:44 +020015#include "utils.hpp"
Václav Kubernát96344a12018-05-28 16:33:39 +020016
Václav Kubernát4c3d22f2020-06-12 16:05:01 +020017struct pathToStringVisitor : boost::static_visitor<std::string> {
18 std::string operator()(const module_& path) const
19 {
20 using namespace std::string_literals;
21 return "/"s + boost::get<module_>(path).m_name + ":*";
22 }
23 std::string operator()(const schemaPath_& path) const
24 {
25 return pathToSchemaString(path, Prefixes::WhenNeeded);
26 }
27 std::string operator()(const dataPath_& path) const
28 {
29 return pathToDataString(path, Prefixes::WhenNeeded);
30 }
31};
32
Václav Kubernáte7248b22020-06-26 15:38:59 +020033namespace {
34void printTree(const DatastoreAccess::Tree tree)
35{
36 for (auto it = tree.begin(); it != tree.end(); it++) {
37 auto [path, value] = *it;
38 if (value.type() == typeid(special_) && boost::get<special_>(value).m_value == SpecialValue::LeafList) {
39 auto leafListPrefix = path;
40 std::cout << path << " = " << leafDataToString(value) << std::endl;
41
42 while (it + 1 != tree.end() && boost::starts_with((it + 1)->first, leafListPrefix)) {
43 ++it;
44 std::cout << stripLeafListValueFromPath(it->first) << " = " << leafDataToString(it->second) << std::endl;
45 }
46 } else {
47 std::cout << path << " = " << leafDataToString(value) << std::endl;
48 }
49 }
50}
51}
52
Václav Kubernát4c3d22f2020-06-12 16:05:01 +020053template <typename PathType>
54std::string pathToString(const PathType& path)
55{
56 return boost::apply_visitor(pathToStringVisitor(), path);
57}
58
Václav Kubernát812ee282018-08-30 17:10:03 +020059void Interpreter::operator()(const commit_&) const
60{
61 m_datastore.commitChanges();
62}
63
Václav Kubernát6d791432018-10-25 16:00:35 +020064void Interpreter::operator()(const discard_&) const
65{
66 m_datastore.discardChanges();
67}
68
Václav Kubernát07204242018-06-04 18:12:09 +020069void Interpreter::operator()(const set_& set) const
70{
Václav Kubernáteeb38842019-03-20 19:46:05 +010071 auto data = set.m_data;
72
73 // If the user didn't supply a module prefix for identityref, we need to add it ourselves
74 if (data.type() == typeid(identityRef_)) {
75 auto identityRef = boost::get<identityRef_>(data);
76 if (!identityRef.m_prefix) {
77 identityRef.m_prefix = set.m_path.m_nodes.front().m_prefix.value();
78 data = identityRef;
79 }
80 }
Václav Kubernát4c3d22f2020-06-12 16:05:01 +020081 m_datastore.setLeaf(pathToString(toCanonicalPath(set.m_path)), data);
Václav Kubernát07204242018-06-04 18:12:09 +020082}
83
Václav Kubernátb6ff0b62018-08-30 16:14:53 +020084void Interpreter::operator()(const get_& get) const
85{
Václav Kubernát4c3d22f2020-06-12 16:05:01 +020086 auto items = m_datastore.getItems(pathToString(toCanonicalPath(get.m_path)));
Václav Kubernáte7248b22020-06-26 15:38:59 +020087 printTree(items);
Václav Kubernátb6ff0b62018-08-30 16:14:53 +020088}
89
Václav Kubernát96344a12018-05-28 16:33:39 +020090void Interpreter::operator()(const cd_& cd) const
91{
92 m_parser.changeNode(cd.m_path);
93}
94
Václav Kubernátb61336d2018-05-28 17:35:03 +020095void Interpreter::operator()(const create_& create) const
96{
Jan Kundrátcbf288b2020-06-18 20:44:39 +020097 m_datastore.createItem(pathToString(toCanonicalPath(create.m_path)));
Václav Kubernátb61336d2018-05-28 17:35:03 +020098}
99
100void Interpreter::operator()(const delete_& delet) const
101{
Jan Kundrátcbf288b2020-06-18 20:44:39 +0200102 m_datastore.deleteItem(pathToString(toCanonicalPath(delet.m_path)));
Václav Kubernátb61336d2018-05-28 17:35:03 +0200103}
104
Václav Kubernát11afac72018-07-18 14:59:53 +0200105void Interpreter::operator()(const ls_& ls) const
106{
107 std::cout << "Possible nodes:" << std::endl;
Václav Kubernáte7d4aea2018-09-11 18:15:48 +0200108 auto recursion{Recursion::NonRecursive};
109 for (auto it : ls.m_options) {
Václav Kubernát3a433232020-07-08 17:52:50 +0200110 if (it == LsOption::Recursive) {
Václav Kubernáte7d4aea2018-09-11 18:15:48 +0200111 recursion = Recursion::Recursive;
Václav Kubernát3a433232020-07-08 17:52:50 +0200112 }
Václav Kubernáte7d4aea2018-09-11 18:15:48 +0200113 }
Václav Kubernát11afac72018-07-18 14:59:53 +0200114
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200115 auto toPrint = m_datastore.schema()->availableNodes(toCanonicalPath(ls.m_path), recursion);
Václav Kubernát82086872020-04-29 01:09:50 +0200116
Václav Kubernát95b08872020-04-28 01:04:17 +0200117 for (const auto& it : toPrint) {
Václav Kubernátb4e5b182020-11-16 19:55:09 +0100118 std::cout << (it.first ? *it.first + ":" : "") + it.second << std::endl;
Václav Kubernát95b08872020-04-28 01:04:17 +0200119 }
Václav Kubernát11afac72018-07-18 14:59:53 +0200120}
121
Václav Kubernát7160a132020-04-03 02:11:01 +0200122void Interpreter::operator()(const copy_& copy) const
123{
124 m_datastore.copyConfig(copy.m_source, copy.m_destination);
125}
126
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100127std::string Interpreter::buildTypeInfo(const std::string& path) const
128{
129 std::ostringstream ss;
130 switch (m_datastore.schema()->nodeType(path)) {
131 case yang::NodeTypes::Container:
132 ss << "container";
133 break;
134 case yang::NodeTypes::PresenceContainer:
135 ss << "presence container";
136 break;
Václav Kubernátb4e5b182020-11-16 19:55:09 +0100137 case yang::NodeTypes::Leaf: {
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100138 auto leafType = m_datastore.schema()->leafType(path);
139 auto typedefName = m_datastore.schema()->leafTypeName(path);
140 std::string baseTypeStr;
Václav Kubernát13b23d72020-04-16 21:49:51 +0200141 if (std::holds_alternative<yang::LeafRef>(leafType.m_type)) {
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100142 ss << "-> ";
143 ss << m_datastore.schema()->leafrefPath(path) << " ";
Václav Kubernát13b23d72020-04-16 21:49:51 +0200144 baseTypeStr = leafDataTypeToString(std::get<yang::LeafRef>(leafType.m_type).m_targetType->m_type);
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100145 } else {
Václav Kubernát13b23d72020-04-16 21:49:51 +0200146 baseTypeStr = leafDataTypeToString(leafType.m_type);
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100147 }
148
149 if (typedefName) {
150 ss << *typedefName << " (" << baseTypeStr << ")";
151 } else {
152 ss << baseTypeStr;
153 }
154
Václav Kubernát13b23d72020-04-16 21:49:51 +0200155 if (leafType.m_units) {
156 ss << " [" + *leafType.m_units + "]";
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100157 }
158
159 if (m_datastore.schema()->leafIsKey(path)) {
160 ss << " (key)";
161 }
Václav Kubernátb1a75c62020-04-21 15:20:16 +0200162
163 if (auto defaultValue = m_datastore.schema()->defaultValue(path)) {
164 ss << " default: " << leafDataToString(*defaultValue);
165 }
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100166 break;
167 }
168 case yang::NodeTypes::List:
169 ss << "list";
170 break;
Václav Kubernáte7248b22020-06-26 15:38:59 +0200171 case yang::NodeTypes::Rpc:
172 ss << "RPC";
173 break;
Václav Kubernátaaafeae2020-05-05 15:41:45 +0200174 case yang::NodeTypes::LeafList:
Václav Kubernát160e5a22020-12-01 01:11:28 +0100175 ss << "leaf-list";
176 break;
177 case yang::NodeTypes::Action:
178 ss << "action";
179 break;
180 case yang::NodeTypes::AnyXml:
181 throw std::logic_error("Sorry, anyxml isn't supported yet.");
Václav Kubernátaaafeae2020-05-05 15:41:45 +0200182 case yang::NodeTypes::Notification:
Václav Kubernát160e5a22020-12-01 01:11:28 +0100183 throw std::logic_error("Sorry, notifications aren't supported yet.");
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100184 }
Václav Kubernát0599e9f2020-04-21 09:51:33 +0200185
186 if (!m_datastore.schema()->isConfig(path)) {
187 ss << " (ro)";
188 }
189
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100190 return ss.str();
191}
192
193void Interpreter::operator()(const describe_& describe) const
194{
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200195 auto path = pathToString(toCanonicalPath(describe.m_path));
Václav Kubernáta1c4c9e2020-04-22 00:37:52 +0200196 auto status = m_datastore.schema()->status(path);
197 auto statusStr = status == yang::Status::Deprecated ? " (deprecated)" :
198 status == yang::Status::Obsolete ? " (obsolete)" :
199 "";
200
201 std::cout << path << ": " << buildTypeInfo(path) << statusStr << std::endl;
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100202 if (auto description = m_datastore.schema()->description(path)) {
203 std::cout << std::endl << *description << std::endl;
204 }
205}
206
Václav Kubernátbf65dd72020-05-28 02:32:31 +0200207void Interpreter::operator()(const move_& move) const
208{
209 m_datastore.moveItem(pathToDataString(move.m_source, Prefixes::WhenNeeded), move.m_destination);
210}
211
Václav Kubernát70d7f7a2020-06-23 14:40:40 +0200212void Interpreter::operator()(const dump_& dump) const
213{
214 std::cout << m_datastore.dump(dump.m_format) << "\n";
215}
216
Václav Kubernátaa4250a2020-07-22 00:02:23 +0200217void Interpreter::operator()(const prepare_& prepare) const
Václav Kubernáte7248b22020-06-26 15:38:59 +0200218{
Václav Kubernátaa4250a2020-07-22 00:02:23 +0200219 if (std::holds_alternative<rpcNode_>(prepare.m_path.m_nodes.back().m_suffix)) {
220 m_datastore.initiateRpc(pathToString(toCanonicalPath(prepare.m_path)));
221 } else {
222 m_datastore.initiateAction(pathToString(toCanonicalPath(prepare.m_path)));
223 }
224 m_parser.changeNode(prepare.m_path);
Václav Kubernáte7248b22020-06-26 15:38:59 +0200225}
226
227void Interpreter::operator()(const exec_&) const
228{
229 m_parser.changeNode({Scope::Absolute, {}});
Václav Kubernátaa4250a2020-07-22 00:02:23 +0200230 auto output = m_datastore.execute();
231 std::cout << "RPC/action output:\n";
Václav Kubernáte7248b22020-06-26 15:38:59 +0200232 printTree(output);
233}
234
235void Interpreter::operator()(const cancel_&) const
236{
237 m_parser.changeNode({Scope::Absolute, {}});
Václav Kubernátaa4250a2020-07-22 00:02:23 +0200238 m_datastore.cancel();
Václav Kubernáte7248b22020-06-26 15:38:59 +0200239}
240
Václav Kubernát054cc992019-02-21 14:23:52 +0100241struct commandLongHelpVisitor : boost::static_visitor<const char*> {
242 template <typename T>
243 auto constexpr operator()(boost::type<T>) const
244 {
245 return T::longHelp;
246 }
247};
248
249struct commandShortHelpVisitor : boost::static_visitor<const char*> {
250 template <typename T>
251 auto constexpr operator()(boost::type<T>) const
252 {
253 return T::shortHelp;
254 }
255};
256
257void Interpreter::operator()(const help_& help) const
258{
Václav Kubernát3a433232020-07-08 17:52:50 +0200259 if (help.m_cmd) {
Václav Kubernát054cc992019-02-21 14:23:52 +0100260 std::cout << boost::apply_visitor(commandLongHelpVisitor(), help.m_cmd.get()) << std::endl;
Václav Kubernát3a433232020-07-08 17:52:50 +0200261 } else {
Václav Kubernát054cc992019-02-21 14:23:52 +0100262 boost::mpl::for_each<CommandTypes, boost::type<boost::mpl::_>>([](auto cmd) {
263 std::cout << commandShortHelpVisitor()(cmd) << std::endl;
264 });
Václav Kubernát3a433232020-07-08 17:52:50 +0200265 }
Václav Kubernát054cc992019-02-21 14:23:52 +0100266}
267
Václav Kubernát7e167692020-06-12 09:53:01 +0200268template <typename PathType>
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200269boost::variant<dataPath_, schemaPath_, module_> Interpreter::toCanonicalPath(const boost::optional<PathType>& optPath) const
Václav Kubernát6415b822018-08-22 17:40:01 +0200270{
Václav Kubernát7e167692020-06-12 09:53:01 +0200271 if (!optPath) {
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200272 return m_parser.currentPath();
Václav Kubernát7e167692020-06-12 09:53:01 +0200273 }
274 return toCanonicalPath(*optPath);
Václav Kubernát6415b822018-08-22 17:40:01 +0200275}
276
Václav Kubernát7e167692020-06-12 09:53:01 +0200277struct impl_toCanonicalPath {
278 const dataPath_& m_parserPath;
279
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200280 using ReturnType = boost::variant<dataPath_, schemaPath_, module_>;
281
Václav Kubernát7e167692020-06-12 09:53:01 +0200282 impl_toCanonicalPath(const dataPath_& parserPath)
283 : m_parserPath(parserPath)
284 {
285 }
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200286 ReturnType operator()(const module_& path) const
Václav Kubernátd6247992020-05-27 00:17:56 +0200287 {
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200288 return path;
Václav Kubernátd6247992020-05-27 00:17:56 +0200289 }
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200290 ReturnType operator()(const schemaPath_& path) const
Václav Kubernát5c75b252018-10-10 18:33:47 +0200291 {
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200292 return impl(path);
Václav Kubernát5c75b252018-10-10 18:33:47 +0200293 }
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200294 ReturnType operator()(const dataPath_& path) const
Václav Kubernát5c75b252018-10-10 18:33:47 +0200295 {
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200296 return impl(path);
Václav Kubernát5c75b252018-10-10 18:33:47 +0200297 }
Václav Kubernát5c75b252018-10-10 18:33:47 +0200298
Václav Kubernát7e167692020-06-12 09:53:01 +0200299private:
300 template <typename PathType>
Václav Kubernát59e4ee42020-07-08 17:32:45 +0200301 [[nodiscard]] ReturnType impl(const PathType& suffix) const
Václav Kubernátd6247992020-05-27 00:17:56 +0200302 {
Václav Kubernát7e167692020-06-12 09:53:01 +0200303 PathType res = [this] {
304 if constexpr (std::is_same<PathType, schemaPath_>()) {
305 return dataPathToSchemaPath(m_parserPath);
306 } else {
307 return m_parserPath;
308 }
309 }();
Václav Kubernátd6247992020-05-27 00:17:56 +0200310
Václav Kubernát7e167692020-06-12 09:53:01 +0200311 if (suffix.m_scope == Scope::Absolute) {
Václav Kubernát59be0de2020-06-15 13:58:45 +0200312 res = {Scope::Absolute, {}};
Václav Kubernát9456b5c2019-10-02 21:14:52 +0200313 }
Václav Kubernátb6ff0b62018-08-30 16:14:53 +0200314
Václav Kubernát7e167692020-06-12 09:53:01 +0200315 for (const auto& fragment : suffix.m_nodes) {
Václav Kubernáte781b902020-06-15 14:35:11 +0200316 res.pushFragment(fragment);
Václav Kubernát7e167692020-06-12 09:53:01 +0200317 }
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200318
Václav Kubernát7e167692020-06-12 09:53:01 +0200319 return res;
320 }
321};
322
323template <typename PathType>
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200324boost::variant<dataPath_, schemaPath_, module_> Interpreter::toCanonicalPath(const PathType& path) const
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100325{
Václav Kubernát7e167692020-06-12 09:53:01 +0200326 if constexpr (std::is_same<PathType, dataPath_>()) {
327 return impl_toCanonicalPath(m_parser.currentPath())(path);
328 } else {
329 return boost::apply_visitor(impl_toCanonicalPath(m_parser.currentPath()), path);
330 }
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100331}
332
Václav Kubernát48e9dfa2020-07-08 10:55:12 +0200333Interpreter::Interpreter(Parser& parser, ProxyDatastore& datastore)
Václav Kubernát812ee282018-08-30 17:10:03 +0200334 : m_parser(parser)
335 , m_datastore(datastore)
Václav Kubernát96344a12018-05-28 16:33:39 +0200336{
337}