yang-cli: Allow editing ops data
Change-Id: Ica85cacac7fed0b052687b7262a76411a03e80f1
diff --git a/src/ast_handlers.hpp b/src/ast_handlers.hpp
index 54f3f95..4227097 100644
--- a/src/ast_handlers.hpp
+++ b/src/ast_handlers.hpp
@@ -224,33 +224,6 @@
}
};
-struct writable_leaf_path_class {
- template <typename T, typename Iterator, typename Context>
- void on_success(Iterator const&, Iterator const&, T&, Context const& context)
- {
- auto& parserContext = x3::get<parser_context_tag>(context);
- if (parserContext.currentSchemaPath().m_nodes.empty()) {
- parserContext.m_errorMsg = "This is not a path to leaf.";
- _pass(context) = false;
- return;
- }
-
- try {
- auto lastNode = parserContext.currentSchemaPath().m_nodes.back();
- auto leaf = std::get<leaf_>(lastNode.m_suffix);
- auto location = pathWithoutLastNode(parserContext.currentSchemaPath());
- ModuleNodePair node{lastNode.m_prefix.flat_map([](const auto& it) { return boost::optional<std::string>{it.m_name}; }), leaf.m_name};
-
- parserContext.m_tmpListKeyLeafPath.m_location = location;
- parserContext.m_tmpListKeyLeafPath.m_node = node;
-
- } catch (std::bad_variant_access&) {
- parserContext.m_errorMsg = "This is not a path to leaf.";
- _pass(context) = false;
- }
- }
-};
-
struct set_class {
template <typename Iterator, typename Exception, typename Context>
x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const& x, Context const& context)
diff --git a/src/ast_path.hpp b/src/ast_path.hpp
index 83727ff..e097a0c 100644
--- a/src/ast_path.hpp
+++ b/src/ast_path.hpp
@@ -135,6 +135,11 @@
void pushFragment(const dataNode_& fragment);
};
+enum class WritableOps {
+ Yes,
+ No
+};
+
std::string nodeToSchemaString(decltype(dataPath_::m_nodes)::value_type node);
std::string pathToDataString(const dataPath_& path, Prefixes prefixes);
diff --git a/src/cli.cpp b/src/cli.cpp
index 53670d0..63ef4c3 100644
--- a/src/cli.cpp
+++ b/src/cli.cpp
@@ -36,14 +36,15 @@
will be used to find a schema for that module.
Usage:
- yang-cli [-s <search_dir>] [-e enable_features]... [-i data_file]... <schema_file_or_module_name>...
+ yang-cli [--configonly] [-s <search_dir>] [-e enable_features]... [-i data_file]... <schema_file_or_module_name>...
yang-cli (-h | --help)
yang-cli --version
Options:
-s <search_dir> Set search for schema lookup
-e <enable_features> Feature to enable after modules are loaded. This option can be supplied more than once. Format: <module_name>:<feature>
- -i <data_file> File to import data from)";
+ -i <data_file> File to import data from
+ --configonly Disable editing of operational data)";
#else
#error "Unknown CLI backend"
#endif
@@ -57,6 +58,7 @@
true,
PROGRAM_NAME " " NETCONF_CLI_VERSION,
true);
+ WritableOps writableOps = WritableOps::No;
#if defined(SYSREPO_CLI)
auto datastoreType = Datastore::Running;
@@ -74,6 +76,12 @@
std::cout << "Connected to sysrepo [datastore: " << (datastoreType == Datastore::Startup ? "startup" : "running") << "]" << std::endl;
#elif defined(YANG_CLI)
YangAccess datastore;
+ if (args["--configonly"].asBool()) {
+ writableOps = WritableOps::No;
+ } else {
+ writableOps = WritableOps::Yes;
+ std::cout << "ops is writable" << std::endl;
+ }
if (const auto& search_dir = args["-s"]) {
datastore.addSchemaDir(search_dir.asString());
}
@@ -116,7 +124,7 @@
#endif
auto dataQuery = std::make_shared<DataQuery>(datastore);
- Parser parser(datastore.schema(), dataQuery);
+ Parser parser(datastore.schema(), writableOps, dataQuery);
using replxx::Replxx;
diff --git a/src/parser.cpp b/src/parser.cpp
index bf00a7e..b5878bf 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -14,10 +14,11 @@
InvalidCommandException::~InvalidCommandException() = default;
-Parser::Parser(const std::shared_ptr<const Schema> schema, const std::shared_ptr<const DataQuery> dataQuery)
+Parser::Parser(const std::shared_ptr<const Schema> schema, WritableOps writableOps, const std::shared_ptr<const DataQuery> dataQuery)
: m_schema(schema)
, m_dataquery(dataQuery)
, m_curDir({Scope::Absolute, {}})
+ , m_writableOps(writableOps)
{
}
@@ -36,7 +37,8 @@
auto grammar =
x3::with<parser_context_tag>(ctx)[
- x3::with<x3::error_handler_tag>(std::ref(errorHandler))[command]
+ x3::with<x3::error_handler_tag>(std::ref(errorHandler))[
+ x3::with<writableOps_tag>(m_writableOps)[command]]
];
bool result = x3::phrase_parse(it, line.end(), grammar, x3::space, parsedCommand);
@@ -58,7 +60,8 @@
auto grammar =
x3::with<parser_context_tag>(ctx)[
- x3::with<x3::error_handler_tag>(std::ref(errorHandler))[command]
+ x3::with<x3::error_handler_tag>(std::ref(errorHandler))[
+ x3::with<writableOps_tag>(m_writableOps)[command]]
];
x3::phrase_parse(it, line.end(), grammar, x3::space, parsedCommand);
diff --git a/src/parser.hpp b/src/parser.hpp
index 14daa9e..1e8cdbb 100644
--- a/src/parser.hpp
+++ b/src/parser.hpp
@@ -33,7 +33,7 @@
class Parser {
public:
- Parser(const std::shared_ptr<const Schema> schema, const std::shared_ptr<const DataQuery> dataQuery = nullptr);
+ Parser(const std::shared_ptr<const Schema> schema, WritableOps writableOps = WritableOps::No, const std::shared_ptr<const DataQuery> dataQuery = nullptr);
command_ parseCommand(const std::string& line, std::ostream& errorStream);
void changeNode(const dataPath_& name);
std::string currentNode() const;
@@ -44,4 +44,5 @@
const std::shared_ptr<const Schema> m_schema;
const std::shared_ptr<const DataQuery> m_dataquery;
dataPath_ m_curDir;
+ const WritableOps m_writableOps;
};
diff --git a/src/path_parser.hpp b/src/path_parser.hpp
index c89b9df..39e2797 100644
--- a/src/path_parser.hpp
+++ b/src/path_parser.hpp
@@ -14,7 +14,6 @@
namespace x3 = boost::spirit::x3;
-x3::rule<writable_leaf_path_class, dataPath_> const writableLeafPath = "writableLeafPath";
x3::rule<presenceContainerPath_class, dataPath_> const presenceContainerPath = "presenceContainerPath";
x3::rule<listInstancePath_class, dataPath_> const listInstancePath = "listInstancePath";
x3::rule<leafListElementPath_class, dataPath_> const leafListElementPath = "leafListElementPath";
@@ -389,6 +388,36 @@
return schema.isConfig(path);
};
+struct writableOps_tag;
+
+PathParser<PathParserMode::DataPath, CompletionMode::Data> const dataPathFilterConfigFalse{filterConfigFalse};
+
+struct WritableLeafPath : x3::parser<WritableLeafPath> {
+ using attribute_type = dataPath_;
+ template <typename It, typename Ctx, typename RCtx, typename Attr>
+ static bool parse(It& begin, It end, Ctx const& ctx, RCtx& rctx, Attr& attr)
+ {
+ bool res;
+ if (x3::get<writableOps_tag>(ctx) == WritableOps::Yes) {
+ res = dataPath.parse(begin, end, ctx, rctx, attr);
+ } else {
+ res = dataPathFilterConfigFalse.parse(begin, end, ctx, rctx, attr);
+ }
+ if (!res) {
+ return false;
+ }
+
+ if (attr.m_nodes.empty() || !std::holds_alternative<leaf_>(attr.m_nodes.back().m_suffix)) {
+ auto& parserContext = x3::get<parser_context_tag>(ctx);
+ parserContext.m_errorMsg = "This is not a path to leaf.";
+ return false;
+ }
+
+ return true;
+ }
+
+} writableLeafPath;
+
auto const writableLeafPath_def =
PathParser<PathParserMode::DataPath, CompletionMode::Data>{filterConfigFalse};
@@ -414,7 +443,6 @@
BOOST_SPIRIT_DEFINE(keyValue)
BOOST_SPIRIT_DEFINE(key_identifier)
BOOST_SPIRIT_DEFINE(listSuffix)
-BOOST_SPIRIT_DEFINE(writableLeafPath)
BOOST_SPIRIT_DEFINE(presenceContainerPath)
BOOST_SPIRIT_DEFINE(listInstancePath)
BOOST_SPIRIT_DEFINE(leafListElementPath)