| /* |
| * Copyright (C) 2018 CESNET, https://photonics.cesnet.cz/ |
| * Copyright (C) 2018 FIT CVUT, https://fit.cvut.cz/ |
| * |
| * Written by Václav Kubernát <kubervac@fit.cvut.cz> |
| * |
| */ |
| |
| #include <boost/mpl/for_each.hpp> |
| #include <iostream> |
| #include <sstream> |
| #include "datastore_access.hpp" |
| #include "interpreter.hpp" |
| #include "utils.hpp" |
| |
| void Interpreter::operator()(const commit_&) const |
| { |
| m_datastore.commitChanges(); |
| } |
| |
| void Interpreter::operator()(const discard_&) const |
| { |
| m_datastore.discardChanges(); |
| } |
| |
| void Interpreter::operator()(const set_& set) const |
| { |
| auto data = set.m_data; |
| |
| // If the user didn't supply a module prefix for identityref, we need to add it ourselves |
| if (data.type() == typeid(identityRef_)) { |
| auto identityRef = boost::get<identityRef_>(data); |
| if (!identityRef.m_prefix) { |
| identityRef.m_prefix = set.m_path.m_nodes.front().m_prefix.value(); |
| data = identityRef; |
| } |
| } |
| m_datastore.setLeaf(absolutePathFromCommand(set), data); |
| } |
| |
| void Interpreter::operator()(const get_& get) const |
| { |
| auto items = m_datastore.getItems(absolutePathFromCommand(get)); |
| for (auto it : items) { |
| std::cout << it.first << " = " << leafDataToString(it.second) << std::endl; |
| } |
| } |
| |
| void Interpreter::operator()(const cd_& cd) const |
| { |
| m_parser.changeNode(cd.m_path); |
| } |
| |
| void Interpreter::operator()(const create_& create) const |
| { |
| if (create.m_path.m_nodes.back().m_suffix.type() == typeid(listElement_)) |
| m_datastore.createListInstance(absolutePathFromCommand(create)); |
| else |
| m_datastore.createPresenceContainer(absolutePathFromCommand(create)); |
| } |
| |
| void Interpreter::operator()(const delete_& delet) const |
| { |
| if (delet.m_path.m_nodes.back().m_suffix.type() == typeid(container_)) |
| m_datastore.deletePresenceContainer(absolutePathFromCommand(delet)); |
| else |
| m_datastore.deleteListInstance(absolutePathFromCommand(delet)); |
| } |
| |
| void Interpreter::operator()(const ls_& ls) const |
| { |
| std::cout << "Possible nodes:" << std::endl; |
| auto recursion{Recursion::NonRecursive}; |
| for (auto it : ls.m_options) { |
| if (it == LsOption::Recursive) |
| recursion = Recursion::Recursive; |
| } |
| |
| std::set<ModuleNodePair> toPrint; |
| |
| auto pathArg = dataPathToSchemaPath(m_parser.currentPath()); |
| if (ls.m_path) { |
| if (ls.m_path->type() == typeid(module_)) { |
| toPrint = m_datastore.schema()->availableNodes(*ls.m_path, recursion); |
| } else { |
| auto schemaPath = anyPathToSchemaPath(*ls.m_path); |
| if (schemaPath.m_scope == Scope::Absolute) { |
| pathArg = schemaPath; |
| } else { |
| pathArg.m_nodes.insert(pathArg.m_nodes.end(), schemaPath.m_nodes.begin(), schemaPath.m_nodes.end()); |
| } |
| toPrint = m_datastore.schema()->availableNodes(pathArg, recursion); |
| } |
| } else { |
| toPrint = m_datastore.schema()->availableNodes(pathArg, recursion); |
| } |
| |
| for (const auto& it : toPrint) { |
| std::cout << (it.first ? *it.first + ":" : "" ) + it.second << std::endl; |
| } |
| } |
| |
| void Interpreter::operator()(const copy_& copy) const |
| { |
| m_datastore.copyConfig(copy.m_source, copy.m_destination); |
| } |
| |
| std::string Interpreter::buildTypeInfo(const std::string& path) const |
| { |
| std::ostringstream ss; |
| switch (m_datastore.schema()->nodeType(path)) { |
| case yang::NodeTypes::Container: |
| ss << "container"; |
| break; |
| case yang::NodeTypes::PresenceContainer: |
| ss << "presence container"; |
| break; |
| case yang::NodeTypes::Leaf: |
| { |
| auto leafType = m_datastore.schema()->leafType(path); |
| auto typedefName = m_datastore.schema()->leafTypeName(path); |
| std::string baseTypeStr; |
| if (std::holds_alternative<yang::LeafRef>(leafType.m_type)) { |
| ss << "-> "; |
| ss << m_datastore.schema()->leafrefPath(path) << " "; |
| baseTypeStr = leafDataTypeToString(std::get<yang::LeafRef>(leafType.m_type).m_targetType->m_type); |
| } else { |
| baseTypeStr = leafDataTypeToString(leafType.m_type); |
| } |
| |
| if (typedefName) { |
| ss << *typedefName << " (" << baseTypeStr << ")"; |
| } else { |
| ss << baseTypeStr; |
| } |
| |
| if (leafType.m_units) { |
| ss << " [" + *leafType.m_units + "]"; |
| } |
| |
| if (m_datastore.schema()->leafIsKey(path)) { |
| ss << " (key)"; |
| } |
| |
| if (auto defaultValue = m_datastore.schema()->defaultValue(path)) { |
| ss << " default: " << leafDataToString(*defaultValue); |
| } |
| break; |
| } |
| case yang::NodeTypes::List: |
| ss << "list"; |
| break; |
| case yang::NodeTypes::Action: |
| case yang::NodeTypes::AnyXml: |
| case yang::NodeTypes::LeafList: |
| case yang::NodeTypes::Notification: |
| case yang::NodeTypes::Rpc: |
| throw std::logic_error("describe got an rpc or an action: this should never happen, because their paths cannot be parsed"); |
| } |
| |
| if (!m_datastore.schema()->isConfig(path)) { |
| ss << " (ro)"; |
| } |
| |
| return ss.str(); |
| } |
| |
| void Interpreter::operator()(const describe_& describe) const |
| { |
| auto path = absolutePathFromCommand(describe); |
| auto status = m_datastore.schema()->status(path); |
| auto statusStr = status == yang::Status::Deprecated ? " (deprecated)" : |
| status == yang::Status::Obsolete ? " (obsolete)" : |
| ""; |
| |
| std::cout << path << ": " << buildTypeInfo(path) << statusStr << std::endl; |
| if (auto description = m_datastore.schema()->description(path)) { |
| std::cout << std::endl << *description << std::endl; |
| } |
| } |
| |
| struct commandLongHelpVisitor : boost::static_visitor<const char*> { |
| template <typename T> |
| auto constexpr operator()(boost::type<T>) const |
| { |
| return T::longHelp; |
| } |
| }; |
| |
| struct commandShortHelpVisitor : boost::static_visitor<const char*> { |
| template <typename T> |
| auto constexpr operator()(boost::type<T>) const |
| { |
| return T::shortHelp; |
| } |
| }; |
| |
| void Interpreter::operator()(const help_& help) const |
| { |
| if (help.m_cmd) |
| std::cout << boost::apply_visitor(commandLongHelpVisitor(), help.m_cmd.get()) << std::endl; |
| else |
| boost::mpl::for_each<CommandTypes, boost::type<boost::mpl::_>>([](auto cmd) { |
| std::cout << commandShortHelpVisitor()(cmd) << std::endl; |
| }); |
| } |
| |
| template <typename T> |
| std::string Interpreter::absolutePathFromCommand(const T& command) const |
| { |
| if (command.m_path.m_scope == Scope::Absolute) |
| return pathToDataString(command.m_path, Prefixes::WhenNeeded); |
| else |
| return joinPaths(m_parser.currentNode(), pathToDataString(command.m_path, Prefixes::WhenNeeded)); |
| } |
| |
| struct pathToStringVisitor : boost::static_visitor<std::string> { |
| std::string operator()(const schemaPath_& path) const |
| { |
| return pathToSchemaString(path, Prefixes::WhenNeeded); |
| } |
| std::string operator()(const dataPath_& path) const |
| { |
| return pathToDataString(path, Prefixes::WhenNeeded); |
| } |
| }; |
| |
| struct getPathScopeVisitor : boost::static_visitor<Scope> { |
| template <typename T> |
| Scope operator()(const T& path) const |
| { |
| return path.m_scope; |
| } |
| }; |
| |
| std::string Interpreter::absolutePathFromCommand(const get_& get) const |
| { |
| using namespace std::string_literals; |
| if (!get.m_path) { |
| return m_parser.currentNode(); |
| } |
| |
| const auto path = *get.m_path; |
| if (path.type() == typeid(module_)) { |
| return "/"s + boost::get<module_>(path).m_name + ":*"; |
| } else { |
| auto actualPath = boost::get<boost::variant<dataPath_, schemaPath_>>(path); |
| std::string pathString = boost::apply_visitor(pathToStringVisitor(), actualPath); |
| auto pathScope{boost::apply_visitor(getPathScopeVisitor(), actualPath)}; |
| |
| if (pathScope == Scope::Absolute) { |
| return pathString; |
| } else { |
| return joinPaths(m_parser.currentNode(), pathString); |
| } |
| } |
| } |
| |
| std::string Interpreter::absolutePathFromCommand(const describe_& describe) const |
| { |
| auto pathStr = boost::apply_visitor(pathToStringVisitor(), describe.m_path); |
| if (boost::apply_visitor(getPathScopeVisitor(), describe.m_path) == Scope::Absolute) |
| return pathStr; |
| else |
| return joinPaths(m_parser.currentNode(), pathStr); |
| } |
| |
| Interpreter::Interpreter(Parser& parser, DatastoreAccess& datastore) |
| : m_parser(parser) |
| , m_datastore(datastore) |
| { |
| } |