blob: f2c0869e730aa7a336fbfa8092490ccdea1dd9dc [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
33template <typename PathType>
34std::string pathToString(const PathType& path)
35{
36 return boost::apply_visitor(pathToStringVisitor(), path);
37}
38
Václav Kubernát812ee282018-08-30 17:10:03 +020039void Interpreter::operator()(const commit_&) const
40{
41 m_datastore.commitChanges();
42}
43
Václav Kubernát6d791432018-10-25 16:00:35 +020044void Interpreter::operator()(const discard_&) const
45{
46 m_datastore.discardChanges();
47}
48
Václav Kubernát07204242018-06-04 18:12:09 +020049void Interpreter::operator()(const set_& set) const
50{
Václav Kubernáteeb38842019-03-20 19:46:05 +010051 auto data = set.m_data;
52
53 // If the user didn't supply a module prefix for identityref, we need to add it ourselves
54 if (data.type() == typeid(identityRef_)) {
55 auto identityRef = boost::get<identityRef_>(data);
56 if (!identityRef.m_prefix) {
57 identityRef.m_prefix = set.m_path.m_nodes.front().m_prefix.value();
58 data = identityRef;
59 }
60 }
Václav Kubernát4c3d22f2020-06-12 16:05:01 +020061 m_datastore.setLeaf(pathToString(toCanonicalPath(set.m_path)), data);
Václav Kubernát07204242018-06-04 18:12:09 +020062}
63
Václav Kubernátb6ff0b62018-08-30 16:14:53 +020064void Interpreter::operator()(const get_& get) const
65{
Václav Kubernát4c3d22f2020-06-12 16:05:01 +020066 auto items = m_datastore.getItems(pathToString(toCanonicalPath(get.m_path)));
Václav Kubernát5b8a8f32020-05-20 00:57:22 +020067 for (auto it = items.begin(); it != items.end(); it++) {
68 auto [path, value] = *it;
69 if (value.type() == typeid(special_) && boost::get<special_>(value).m_value == SpecialValue::LeafList) {
70 auto leafListPrefix = path;
71 std::cout << path << " = " << leafDataToString(value) << std::endl;
Václav Kubernátfb4bda62020-06-09 12:54:41 +020072
73 while (it + 1 != items.end() && boost::starts_with((it + 1) ->first, leafListPrefix)) {
Václav Kubernát5b8a8f32020-05-20 00:57:22 +020074 ++it;
Václav Kubernátfb4bda62020-06-09 12:54:41 +020075 std::cout << stripLeafListValueFromPath(it->first) << " = " << leafDataToString(it->second) << std::endl;
Václav Kubernát5b8a8f32020-05-20 00:57:22 +020076 }
77 } else {
78 std::cout << path << " = " << leafDataToString(value) << std::endl;
79 }
Václav Kubernátb6ff0b62018-08-30 16:14:53 +020080 }
81}
82
Václav Kubernát96344a12018-05-28 16:33:39 +020083void Interpreter::operator()(const cd_& cd) const
84{
85 m_parser.changeNode(cd.m_path);
86}
87
Václav Kubernátb61336d2018-05-28 17:35:03 +020088void Interpreter::operator()(const create_& create) const
89{
Václav Kubernátb5ca1542020-05-27 01:03:54 +020090 if (std::holds_alternative<listElement_>(create.m_path.m_nodes.back().m_suffix))
Václav Kubernát4c3d22f2020-06-12 16:05:01 +020091 m_datastore.createListInstance(pathToString(toCanonicalPath(create.m_path)));
Václav Kubernátb5ca1542020-05-27 01:03:54 +020092 else if (std::holds_alternative<leafListElement_>(create.m_path.m_nodes.back().m_suffix))
Václav Kubernát4c3d22f2020-06-12 16:05:01 +020093 m_datastore.createLeafListInstance(pathToString(toCanonicalPath(create.m_path)));
Václav Kubernátbe228622019-05-23 14:44:12 +020094 else
Václav Kubernát4c3d22f2020-06-12 16:05:01 +020095 m_datastore.createPresenceContainer(pathToString(toCanonicalPath(create.m_path)));
Václav Kubernátb61336d2018-05-28 17:35:03 +020096}
97
98void Interpreter::operator()(const delete_& delet) const
99{
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200100 if (std::holds_alternative<container_>(delet.m_path.m_nodes.back().m_suffix))
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200101 m_datastore.deletePresenceContainer(pathToString(toCanonicalPath(delet.m_path)));
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200102 else if (std::holds_alternative<leafListElement_>(delet.m_path.m_nodes.back().m_suffix))
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200103 m_datastore.deleteLeafListInstance(pathToString(toCanonicalPath(delet.m_path)));
Václav Kubernátf5f64f02019-03-19 17:15:47 +0100104 else
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200105 m_datastore.deleteListInstance(pathToString(toCanonicalPath(delet.m_path)));
Václav Kubernátb61336d2018-05-28 17:35:03 +0200106}
107
Václav Kubernát11afac72018-07-18 14:59:53 +0200108void Interpreter::operator()(const ls_& ls) const
109{
110 std::cout << "Possible nodes:" << std::endl;
Václav Kubernáte7d4aea2018-09-11 18:15:48 +0200111 auto recursion{Recursion::NonRecursive};
112 for (auto it : ls.m_options) {
113 if (it == LsOption::Recursive)
114 recursion = Recursion::Recursive;
115 }
Václav Kubernát11afac72018-07-18 14:59:53 +0200116
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200117 auto toPrint = m_datastore.schema()->availableNodes(toCanonicalPath(ls.m_path), recursion);
Václav Kubernát82086872020-04-29 01:09:50 +0200118
Václav Kubernát95b08872020-04-28 01:04:17 +0200119 for (const auto& it : toPrint) {
120 std::cout << (it.first ? *it.first + ":" : "" ) + it.second << std::endl;
121 }
Václav Kubernát11afac72018-07-18 14:59:53 +0200122}
123
Václav Kubernát7160a132020-04-03 02:11:01 +0200124void Interpreter::operator()(const copy_& copy) const
125{
126 m_datastore.copyConfig(copy.m_source, copy.m_destination);
127}
128
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100129std::string Interpreter::buildTypeInfo(const std::string& path) const
130{
131 std::ostringstream ss;
132 switch (m_datastore.schema()->nodeType(path)) {
133 case yang::NodeTypes::Container:
134 ss << "container";
135 break;
136 case yang::NodeTypes::PresenceContainer:
137 ss << "presence container";
138 break;
139 case yang::NodeTypes::Leaf:
140 {
141 auto leafType = m_datastore.schema()->leafType(path);
142 auto typedefName = m_datastore.schema()->leafTypeName(path);
143 std::string baseTypeStr;
Václav Kubernát13b23d72020-04-16 21:49:51 +0200144 if (std::holds_alternative<yang::LeafRef>(leafType.m_type)) {
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100145 ss << "-> ";
146 ss << m_datastore.schema()->leafrefPath(path) << " ";
Václav Kubernát13b23d72020-04-16 21:49:51 +0200147 baseTypeStr = leafDataTypeToString(std::get<yang::LeafRef>(leafType.m_type).m_targetType->m_type);
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100148 } else {
Václav Kubernát13b23d72020-04-16 21:49:51 +0200149 baseTypeStr = leafDataTypeToString(leafType.m_type);
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100150 }
151
152 if (typedefName) {
153 ss << *typedefName << " (" << baseTypeStr << ")";
154 } else {
155 ss << baseTypeStr;
156 }
157
Václav Kubernát13b23d72020-04-16 21:49:51 +0200158 if (leafType.m_units) {
159 ss << " [" + *leafType.m_units + "]";
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100160 }
161
162 if (m_datastore.schema()->leafIsKey(path)) {
163 ss << " (key)";
164 }
Václav Kubernátb1a75c62020-04-21 15:20:16 +0200165
166 if (auto defaultValue = m_datastore.schema()->defaultValue(path)) {
167 ss << " default: " << leafDataToString(*defaultValue);
168 }
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100169 break;
170 }
171 case yang::NodeTypes::List:
172 ss << "list";
173 break;
Václav Kubernátaaafeae2020-05-05 15:41:45 +0200174 case yang::NodeTypes::Action:
175 case yang::NodeTypes::AnyXml:
176 case yang::NodeTypes::LeafList:
177 case yang::NodeTypes::Notification:
178 case yang::NodeTypes::Rpc:
179 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 +0100180 }
Václav Kubernát0599e9f2020-04-21 09:51:33 +0200181
182 if (!m_datastore.schema()->isConfig(path)) {
183 ss << " (ro)";
184 }
185
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100186 return ss.str();
187}
188
189void Interpreter::operator()(const describe_& describe) const
190{
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200191 auto path = pathToString(toCanonicalPath(describe.m_path));
Václav Kubernáta1c4c9e2020-04-22 00:37:52 +0200192 auto status = m_datastore.schema()->status(path);
193 auto statusStr = status == yang::Status::Deprecated ? " (deprecated)" :
194 status == yang::Status::Obsolete ? " (obsolete)" :
195 "";
196
197 std::cout << path << ": " << buildTypeInfo(path) << statusStr << std::endl;
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100198 if (auto description = m_datastore.schema()->description(path)) {
199 std::cout << std::endl << *description << std::endl;
200 }
201}
202
Václav Kubernátbf65dd72020-05-28 02:32:31 +0200203void Interpreter::operator()(const move_& move) const
204{
205 m_datastore.moveItem(pathToDataString(move.m_source, Prefixes::WhenNeeded), move.m_destination);
206}
207
Václav Kubernát054cc992019-02-21 14:23:52 +0100208struct commandLongHelpVisitor : boost::static_visitor<const char*> {
209 template <typename T>
210 auto constexpr operator()(boost::type<T>) const
211 {
212 return T::longHelp;
213 }
214};
215
216struct commandShortHelpVisitor : boost::static_visitor<const char*> {
217 template <typename T>
218 auto constexpr operator()(boost::type<T>) const
219 {
220 return T::shortHelp;
221 }
222};
223
224void Interpreter::operator()(const help_& help) const
225{
226 if (help.m_cmd)
227 std::cout << boost::apply_visitor(commandLongHelpVisitor(), help.m_cmd.get()) << std::endl;
228 else
229 boost::mpl::for_each<CommandTypes, boost::type<boost::mpl::_>>([](auto cmd) {
230 std::cout << commandShortHelpVisitor()(cmd) << std::endl;
231 });
232}
233
Václav Kubernát7e167692020-06-12 09:53:01 +0200234template <typename PathType>
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200235boost::variant<dataPath_, schemaPath_, module_> Interpreter::toCanonicalPath(const boost::optional<PathType>& optPath) const
Václav Kubernát6415b822018-08-22 17:40:01 +0200236{
Václav Kubernát7e167692020-06-12 09:53:01 +0200237 if (!optPath) {
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200238 return m_parser.currentPath();
Václav Kubernát7e167692020-06-12 09:53:01 +0200239 }
240 return toCanonicalPath(*optPath);
Václav Kubernát6415b822018-08-22 17:40:01 +0200241}
242
Václav Kubernát7e167692020-06-12 09:53:01 +0200243struct impl_toCanonicalPath {
244 const dataPath_& m_parserPath;
245
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200246 using ReturnType = boost::variant<dataPath_, schemaPath_, module_>;
247
Václav Kubernát7e167692020-06-12 09:53:01 +0200248 impl_toCanonicalPath(const dataPath_& parserPath)
249 : m_parserPath(parserPath)
250 {
251 }
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200252 ReturnType operator()(const module_& path) const
Václav Kubernátd6247992020-05-27 00:17:56 +0200253 {
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200254 return path;
Václav Kubernátd6247992020-05-27 00:17:56 +0200255 }
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200256 ReturnType operator()(const schemaPath_& path) const
Václav Kubernát5c75b252018-10-10 18:33:47 +0200257 {
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200258 return impl(path);
Václav Kubernát5c75b252018-10-10 18:33:47 +0200259 }
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200260 ReturnType operator()(const dataPath_& path) const
Václav Kubernát5c75b252018-10-10 18:33:47 +0200261 {
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200262 return impl(path);
Václav Kubernát5c75b252018-10-10 18:33:47 +0200263 }
Václav Kubernát5c75b252018-10-10 18:33:47 +0200264
Václav Kubernát7e167692020-06-12 09:53:01 +0200265private:
266 template <typename PathType>
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200267 ReturnType impl(const PathType& suffix) const
Václav Kubernátd6247992020-05-27 00:17:56 +0200268 {
Václav Kubernát7e167692020-06-12 09:53:01 +0200269 PathType res = [this] {
270 if constexpr (std::is_same<PathType, schemaPath_>()) {
271 return dataPathToSchemaPath(m_parserPath);
272 } else {
273 return m_parserPath;
274 }
275 }();
Václav Kubernátd6247992020-05-27 00:17:56 +0200276
Václav Kubernát7e167692020-06-12 09:53:01 +0200277 if (suffix.m_scope == Scope::Absolute) {
278 return suffix;
Václav Kubernát9456b5c2019-10-02 21:14:52 +0200279 }
Václav Kubernátb6ff0b62018-08-30 16:14:53 +0200280
Václav Kubernát7e167692020-06-12 09:53:01 +0200281 for (const auto& fragment : suffix.m_nodes) {
282 if (std::holds_alternative<nodeup_>(fragment.m_suffix)) {
283 res.m_nodes.pop_back();
284 } else {
285 res.m_nodes.push_back(fragment);
286 }
287 }
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200288
Václav Kubernát7e167692020-06-12 09:53:01 +0200289 return res;
290 }
291};
292
293template <typename PathType>
Václav Kubernát4c3d22f2020-06-12 16:05:01 +0200294boost::variant<dataPath_, schemaPath_, module_> Interpreter::toCanonicalPath(const PathType& path) const
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100295{
Václav Kubernát7e167692020-06-12 09:53:01 +0200296 if constexpr (std::is_same<PathType, dataPath_>()) {
297 return impl_toCanonicalPath(m_parser.currentPath())(path);
298 } else {
299 return boost::apply_visitor(impl_toCanonicalPath(m_parser.currentPath()), path);
300 }
Václav Kubernát9cfcd872020-02-18 12:34:02 +0100301}
302
Václav Kubernát6415b822018-08-22 17:40:01 +0200303Interpreter::Interpreter(Parser& parser, DatastoreAccess& datastore)
Václav Kubernát812ee282018-08-30 17:10:03 +0200304 : m_parser(parser)
305 , m_datastore(datastore)
Václav Kubernát96344a12018-05-28 16:33:39 +0200306{
307}