blob: 2d69e633da1606a62fd57d493e0e7e03662572a8 [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át812ee282018-08-30 17:10:03 +020017void Interpreter::operator()(const commit_&) const
18{
19 m_datastore.commitChanges();
20}
21
Václav Kubernát6d791432018-10-25 16:00:35 +020022void Interpreter::operator()(const discard_&) const
23{
24 m_datastore.discardChanges();
25}
26
Václav Kubernát07204242018-06-04 18:12:09 +020027void Interpreter::operator()(const set_& set) const
28{
Václav Kubernáteeb38842019-03-20 19:46:05 +010029 auto data = set.m_data;
30
31 // If the user didn't supply a module prefix for identityref, we need to add it ourselves
32 if (data.type() == typeid(identityRef_)) {
33 auto identityRef = boost::get<identityRef_>(data);
34 if (!identityRef.m_prefix) {
35 identityRef.m_prefix = set.m_path.m_nodes.front().m_prefix.value();
36 data = identityRef;
37 }
38 }
39 m_datastore.setLeaf(absolutePathFromCommand(set), data);
Václav Kubernát07204242018-06-04 18:12:09 +020040}
41
Václav Kubernátb6ff0b62018-08-30 16:14:53 +020042void Interpreter::operator()(const get_& get) const
43{
44 auto items = m_datastore.getItems(absolutePathFromCommand(get));
Václav Kubernát5b8a8f32020-05-20 00:57:22 +020045 for (auto it = items.begin(); it != items.end(); it++) {
46 auto [path, value] = *it;
47 if (value.type() == typeid(special_) && boost::get<special_>(value).m_value == SpecialValue::LeafList) {
48 auto leafListPrefix = path;
49 std::cout << path << " = " << leafDataToString(value) << std::endl;
50 ++it;
51 while (boost::starts_with(it->first, leafListPrefix)) {
52 std::cout << stripLeafListValueFromPath(it->first) << " = " << leafDataToString(it->second) << std::endl;
53 ++it;
54 }
55 } else {
56 std::cout << path << " = " << leafDataToString(value) << std::endl;
57 }
Václav Kubernátb6ff0b62018-08-30 16:14:53 +020058 }
59}
60
Václav Kubernát96344a12018-05-28 16:33:39 +020061void Interpreter::operator()(const cd_& cd) const
62{
63 m_parser.changeNode(cd.m_path);
64}
65
Václav Kubernátb61336d2018-05-28 17:35:03 +020066void Interpreter::operator()(const create_& create) const
67{
Václav Kubernátb5ca1542020-05-27 01:03:54 +020068 if (std::holds_alternative<listElement_>(create.m_path.m_nodes.back().m_suffix))
Václav Kubernátbe228622019-05-23 14:44:12 +020069 m_datastore.createListInstance(absolutePathFromCommand(create));
Václav Kubernátb5ca1542020-05-27 01:03:54 +020070 else if (std::holds_alternative<leafListElement_>(create.m_path.m_nodes.back().m_suffix))
Václav Kubernát5b8a8f32020-05-20 00:57:22 +020071 m_datastore.createLeafListInstance(absolutePathFromCommand(create));
Václav Kubernátbe228622019-05-23 14:44:12 +020072 else
73 m_datastore.createPresenceContainer(absolutePathFromCommand(create));
Václav Kubernátb61336d2018-05-28 17:35:03 +020074}
75
76void Interpreter::operator()(const delete_& delet) const
77{
Václav Kubernátb5ca1542020-05-27 01:03:54 +020078 if (std::holds_alternative<container_>(delet.m_path.m_nodes.back().m_suffix))
Václav Kubernátf5f64f02019-03-19 17:15:47 +010079 m_datastore.deletePresenceContainer(absolutePathFromCommand(delet));
Václav Kubernátb5ca1542020-05-27 01:03:54 +020080 else if (std::holds_alternative<leafListElement_>(delet.m_path.m_nodes.back().m_suffix))
Václav Kubernát5b8a8f32020-05-20 00:57:22 +020081 m_datastore.deleteLeafListInstance(absolutePathFromCommand(delet));
Václav Kubernátf5f64f02019-03-19 17:15:47 +010082 else
83 m_datastore.deleteListInstance(absolutePathFromCommand(delet));
Václav Kubernátb61336d2018-05-28 17:35:03 +020084}
85
Václav Kubernát11afac72018-07-18 14:59:53 +020086void Interpreter::operator()(const ls_& ls) const
87{
88 std::cout << "Possible nodes:" << std::endl;
Václav Kubernáte7d4aea2018-09-11 18:15:48 +020089 auto recursion{Recursion::NonRecursive};
90 for (auto it : ls.m_options) {
91 if (it == LsOption::Recursive)
92 recursion = Recursion::Recursive;
93 }
Václav Kubernát11afac72018-07-18 14:59:53 +020094
Václav Kubernát95b08872020-04-28 01:04:17 +020095 std::set<ModuleNodePair> toPrint;
Václav Kubernát82086872020-04-29 01:09:50 +020096
97 auto pathArg = dataPathToSchemaPath(m_parser.currentPath());
98 if (ls.m_path) {
99 if (ls.m_path->type() == typeid(module_)) {
100 toPrint = m_datastore.schema()->availableNodes(*ls.m_path, recursion);
101 } else {
102 auto schemaPath = anyPathToSchemaPath(*ls.m_path);
103 if (schemaPath.m_scope == Scope::Absolute) {
104 pathArg = schemaPath;
105 } else {
106 pathArg.m_nodes.insert(pathArg.m_nodes.end(), schemaPath.m_nodes.begin(), schemaPath.m_nodes.end());
107 }
108 toPrint = m_datastore.schema()->availableNodes(pathArg, recursion);
109 }
110 } else {
111 toPrint = m_datastore.schema()->availableNodes(pathArg, recursion);
112 }
113
Václav Kubernát95b08872020-04-28 01:04:17 +0200114 for (const auto& it : toPrint) {
115 std::cout << (it.first ? *it.first + ":" : "" ) + it.second << std::endl;
116 }
Václav Kubernát11afac72018-07-18 14:59:53 +0200117}
118
Václav Kubernát7160a132020-04-03 02:11:01 +0200119void Interpreter::operator()(const copy_& copy) const
120{
121 m_datastore.copyConfig(copy.m_source, copy.m_destination);
122}
123
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100124std::string Interpreter::buildTypeInfo(const std::string& path) const
125{
126 std::ostringstream ss;
127 switch (m_datastore.schema()->nodeType(path)) {
128 case yang::NodeTypes::Container:
129 ss << "container";
130 break;
131 case yang::NodeTypes::PresenceContainer:
132 ss << "presence container";
133 break;
134 case yang::NodeTypes::Leaf:
135 {
136 auto leafType = m_datastore.schema()->leafType(path);
137 auto typedefName = m_datastore.schema()->leafTypeName(path);
138 std::string baseTypeStr;
Václav Kubernát13b23d72020-04-16 21:49:51 +0200139 if (std::holds_alternative<yang::LeafRef>(leafType.m_type)) {
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100140 ss << "-> ";
141 ss << m_datastore.schema()->leafrefPath(path) << " ";
Václav Kubernát13b23d72020-04-16 21:49:51 +0200142 baseTypeStr = leafDataTypeToString(std::get<yang::LeafRef>(leafType.m_type).m_targetType->m_type);
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100143 } else {
Václav Kubernát13b23d72020-04-16 21:49:51 +0200144 baseTypeStr = leafDataTypeToString(leafType.m_type);
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100145 }
146
147 if (typedefName) {
148 ss << *typedefName << " (" << baseTypeStr << ")";
149 } else {
150 ss << baseTypeStr;
151 }
152
Václav Kubernát13b23d72020-04-16 21:49:51 +0200153 if (leafType.m_units) {
154 ss << " [" + *leafType.m_units + "]";
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100155 }
156
157 if (m_datastore.schema()->leafIsKey(path)) {
158 ss << " (key)";
159 }
Václav Kubernátb1a75c62020-04-21 15:20:16 +0200160
161 if (auto defaultValue = m_datastore.schema()->defaultValue(path)) {
162 ss << " default: " << leafDataToString(*defaultValue);
163 }
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100164 break;
165 }
166 case yang::NodeTypes::List:
167 ss << "list";
168 break;
Václav Kubernátaaafeae2020-05-05 15:41:45 +0200169 case yang::NodeTypes::Action:
170 case yang::NodeTypes::AnyXml:
171 case yang::NodeTypes::LeafList:
172 case yang::NodeTypes::Notification:
173 case yang::NodeTypes::Rpc:
174 throw std::logic_error("describe got an rpc or an action: this should never happen, because their paths cannot be parsed");
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100175 }
Václav Kubernát0599e9f2020-04-21 09:51:33 +0200176
177 if (!m_datastore.schema()->isConfig(path)) {
178 ss << " (ro)";
179 }
180
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100181 return ss.str();
182}
183
184void Interpreter::operator()(const describe_& describe) const
185{
186 auto path = absolutePathFromCommand(describe);
Václav Kubernáta1c4c9e2020-04-22 00:37:52 +0200187 auto status = m_datastore.schema()->status(path);
188 auto statusStr = status == yang::Status::Deprecated ? " (deprecated)" :
189 status == yang::Status::Obsolete ? " (obsolete)" :
190 "";
191
192 std::cout << path << ": " << buildTypeInfo(path) << statusStr << std::endl;
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100193 if (auto description = m_datastore.schema()->description(path)) {
194 std::cout << std::endl << *description << std::endl;
195 }
196}
197
Václav Kubernát054cc992019-02-21 14:23:52 +0100198struct commandLongHelpVisitor : boost::static_visitor<const char*> {
199 template <typename T>
200 auto constexpr operator()(boost::type<T>) const
201 {
202 return T::longHelp;
203 }
204};
205
206struct commandShortHelpVisitor : boost::static_visitor<const char*> {
207 template <typename T>
208 auto constexpr operator()(boost::type<T>) const
209 {
210 return T::shortHelp;
211 }
212};
213
214void Interpreter::operator()(const help_& help) const
215{
216 if (help.m_cmd)
217 std::cout << boost::apply_visitor(commandLongHelpVisitor(), help.m_cmd.get()) << std::endl;
218 else
219 boost::mpl::for_each<CommandTypes, boost::type<boost::mpl::_>>([](auto cmd) {
220 std::cout << commandShortHelpVisitor()(cmd) << std::endl;
221 });
222}
223
Václav Kubernát6415b822018-08-22 17:40:01 +0200224template <typename T>
225std::string Interpreter::absolutePathFromCommand(const T& command) const
226{
Václav Kubernát37171a12018-08-31 17:01:48 +0200227 if (command.m_path.m_scope == Scope::Absolute)
Václav Kubernátefcac932020-01-10 15:26:32 +0100228 return pathToDataString(command.m_path, Prefixes::WhenNeeded);
Václav Kubernát37171a12018-08-31 17:01:48 +0200229 else
Václav Kubernátefcac932020-01-10 15:26:32 +0100230 return joinPaths(m_parser.currentNode(), pathToDataString(command.m_path, Prefixes::WhenNeeded));
Václav Kubernát6415b822018-08-22 17:40:01 +0200231}
232
Václav Kubernát5c75b252018-10-10 18:33:47 +0200233struct pathToStringVisitor : boost::static_visitor<std::string> {
Václav Kubernátd6247992020-05-27 00:17:56 +0200234 std::string operator()(const module_& path) const
235 {
236 using namespace std::string_literals;
237 return "/"s + boost::get<module_>(path).m_name + ":*";
238 }
Václav Kubernát5c75b252018-10-10 18:33:47 +0200239 std::string operator()(const schemaPath_& path) const
240 {
Václav Kubernátefcac932020-01-10 15:26:32 +0100241 return pathToSchemaString(path, Prefixes::WhenNeeded);
Václav Kubernát5c75b252018-10-10 18:33:47 +0200242 }
243 std::string operator()(const dataPath_& path) const
244 {
Václav Kubernátefcac932020-01-10 15:26:32 +0100245 return pathToDataString(path, Prefixes::WhenNeeded);
Václav Kubernát5c75b252018-10-10 18:33:47 +0200246 }
247};
248
249struct getPathScopeVisitor : boost::static_visitor<Scope> {
Václav Kubernátd6247992020-05-27 00:17:56 +0200250 Scope operator()(const module_&) const
251 {
252 throw std::logic_error("Interpreter: a top-level module has no scope.");
253 }
254
Václav Kubernát5c75b252018-10-10 18:33:47 +0200255 template <typename T>
256 Scope operator()(const T& path) const
257 {
258 return path.m_scope;
259 }
260};
261
Václav Kubernátb6ff0b62018-08-30 16:14:53 +0200262std::string Interpreter::absolutePathFromCommand(const get_& get) const
263{
Václav Kubernát9456b5c2019-10-02 21:14:52 +0200264 using namespace std::string_literals;
Václav Kubernátb6ff0b62018-08-30 16:14:53 +0200265 if (!get.m_path) {
266 return m_parser.currentNode();
Václav Kubernát5c75b252018-10-10 18:33:47 +0200267 }
268
269 const auto path = *get.m_path;
Václav Kubernát9456b5c2019-10-02 21:14:52 +0200270 if (path.type() == typeid(module_)) {
Václav Kubernátd6247992020-05-27 00:17:56 +0200271 return boost::apply_visitor(pathToStringVisitor(), path);
Václav Kubernátb6ff0b62018-08-30 16:14:53 +0200272 } else {
Václav Kubernátd6247992020-05-27 00:17:56 +0200273 std::string pathString = boost::apply_visitor(pathToStringVisitor(), path);
274 auto pathScope{boost::apply_visitor(getPathScopeVisitor(), path)};
Václav Kubernát9456b5c2019-10-02 21:14:52 +0200275
276 if (pathScope == Scope::Absolute) {
Václav Kubernát82684cf2020-01-06 13:30:37 +0100277 return pathString;
Václav Kubernát9456b5c2019-10-02 21:14:52 +0200278 } else {
279 return joinPaths(m_parser.currentNode(), pathString);
280 }
Václav Kubernátb6ff0b62018-08-30 16:14:53 +0200281 }
282}
283
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100284std::string Interpreter::absolutePathFromCommand(const describe_& describe) const
285{
286 auto pathStr = boost::apply_visitor(pathToStringVisitor(), describe.m_path);
287 if (boost::apply_visitor(getPathScopeVisitor(), describe.m_path) == Scope::Absolute)
288 return pathStr;
289 else
290 return joinPaths(m_parser.currentNode(), pathStr);
291}
292
Václav Kubernát6415b822018-08-22 17:40:01 +0200293Interpreter::Interpreter(Parser& parser, DatastoreAccess& datastore)
Václav Kubernát812ee282018-08-30 17:10:03 +0200294 : m_parser(parser)
295 , m_datastore(datastore)
Václav Kubernát96344a12018-05-28 16:33:39 +0200296{
297}