Merge "Fix issue with printing longHelp"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7fef00c..77b8a96 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -141,12 +141,12 @@
 add_library(leaf_data_type STATIC
     src/leaf_data_type.cpp
     )
-target_link_libraries(leaf_data_type ast_values)
+target_link_libraries(leaf_data_type PUBLIC ast_values)
 
 add_library(utils STATIC
     src/utils.cpp
     )
-target_link_libraries(utils path ast_values)
+target_link_libraries(utils PUBLIC path ast_values)
 
 add_library(schemas STATIC
     src/static_schema.cpp
@@ -198,7 +198,7 @@
     src/ast_handlers.cpp
     src/completion.cpp
     )
-target_link_libraries(parser schemas utils ast_values yangutils)
+target_link_libraries(parser PUBLIC schemas utils ast_values yangutils)
 
 add_library(proxydatastore STATIC
     src/proxy_datastore.cpp
@@ -207,7 +207,7 @@
 
 # Links libraries, that aren't specific to a datastore type
 function(cli_link_required cli_target)
-    target_link_libraries(${cli_target} proxydatastore yangschema PkgConfig::DOCOPT parser replxx::replxx)
+    target_link_libraries(${cli_target} PRIVATE proxydatastore yangschema PkgConfig::DOCOPT parser replxx::replxx)
     add_dependencies(${cli_target} target-NETCONF_CLI_VERSION)
     target_include_directories(${cli_target} PRIVATE ${PROJECT_BINARY_DIR})
 endfunction()
@@ -217,7 +217,7 @@
         src/cli.cpp
         )
     target_compile_definitions(sysrepo-cli PRIVATE SYSREPO_CLI)
-    target_link_libraries(sysrepo-cli sysrepoaccess)
+    target_link_libraries(sysrepo-cli PUBLIC sysrepoaccess)
     cli_link_required(sysrepo-cli)
     list(APPEND cli_targets sysrepo-cli)
 endif()
@@ -227,12 +227,12 @@
     )
 target_compile_definitions(yang-cli PRIVATE YANG_CLI)
 cli_link_required(yang-cli)
-target_link_libraries(yang-cli yangaccess)
+target_link_libraries(yang-cli PRIVATE yangaccess)
 list(APPEND cli_targets yang-cli)
 if(CMAKE_CXX_FLAGS MATCHES "-stdlib=libc\\+\\+" AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0)
-    target_link_libraries(yang-cli c++experimental)
+    target_link_libraries(yang-cli PRIVATE c++experimental)
 elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.1)
-    target_link_libraries(yang-cli stdc++fs)
+    target_link_libraries(yang-cli PRIVATE stdc++fs)
 endif()
 
 add_executable(netconf-cli
@@ -241,7 +241,7 @@
     )
 target_compile_definitions(netconf-cli PRIVATE NETCONF_CLI)
 
-target_link_libraries(netconf-cli netconfaccess Threads::Threads Boost::filesystem)
+target_link_libraries(netconf-cli PRIVATE netconfaccess Threads::Threads Boost::filesystem)
 cli_link_required(netconf-cli)
 list(APPEND cli_targets netconf-cli)
 
@@ -256,7 +256,7 @@
         tests/wait-a-bit-longer.cpp
         )
     target_include_directories(DoctestIntegration PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/tests/ ${CMAKE_CURRENT_SOURCE_DIR}/src/)
-    target_link_libraries(DoctestIntegration doctest::doctest trompeloeil::trompeloeil)
+    target_link_libraries(DoctestIntegration PUBLIC doctest::doctest trompeloeil::trompeloeil)
     target_compile_definitions(DoctestIntegration PUBLIC DOCTEST_CONFIG_SUPER_FAST_ASSERTS)
 
     if(DO_ENABLE_NETCONF_TESTS)
@@ -282,7 +282,7 @@
                 tests/${name}.cpp
                 )
         endif()
-        target_link_libraries(test_${name} DoctestIntegration parser datastoreaccess)
+        target_link_libraries(test_${name} PRIVATE DoctestIntegration parser datastoreaccess)
         if(NOT CMAKE_CROSSCOMPILING)
             add_test(test_${name} test_${name})
         endif()
@@ -295,15 +295,15 @@
         cli_test(${name}_${backend} ${name}.cpp)
         target_include_directories(${TESTNAME} PRIVATE ${PROJECT_SOURCE_DIR}/tests/mock)
         if (${backend} STREQUAL "sysrepo")
-            target_link_libraries(${TESTNAME} sysrepoaccess)
+            target_link_libraries(${TESTNAME} PRIVATE sysrepoaccess)
         elseif (${backend} STREQUAL "netconf")
-            target_link_libraries(${TESTNAME} netconfaccess)
+            target_link_libraries(${TESTNAME} PRIVATE netconfaccess)
         elseif (${backend} STREQUAL "yang")
-            target_link_libraries(${TESTNAME} yangaccess)
+            target_link_libraries(${TESTNAME} PRIVATE yangaccess)
         else()
             message(FATAL_ERROR "Unknown backend ${backend}")
         endif()
-        target_link_libraries(${TESTNAME} yangschema sysreposubscription proxydatastore PkgConfig::SYSREPO)
+        target_link_libraries(${TESTNAME} PRIVATE yangschema sysreposubscription proxydatastore PkgConfig::SYSREPO)
 
         target_compile_definitions(${TESTNAME} PRIVATE ${backend}_BACKEND)
         set_tests_properties(${TESTNAME} PROPERTIES FIXTURES_REQUIRED ${TESTNAME}_setup)
@@ -331,20 +331,20 @@
     cli_test(ls)
     cli_test(presence_containers)
     cli_test(leaf_editing)
-    target_link_libraries(test_leaf_editing leaf_data_type)
+    target_link_libraries(test_leaf_editing PRIVATE leaf_data_type)
     cli_test(yang)
-    target_link_libraries(test_yang yangschema)
+    target_link_libraries(test_yang PRIVATE yangschema)
     cli_test(utils)
-    target_link_libraries(test_utils yangutils)
+    target_link_libraries(test_utils PRIVATE yangutils)
     cli_test(path_completion)
     cli_test(command_completion)
     cli_test(set_value_completion)
-    target_link_libraries(test_set_value_completion leaf_data_type)
+    target_link_libraries(test_set_value_completion PRIVATE leaf_data_type)
     cli_test(list_manipulation)
     cli_test(interpreter)
-    target_link_libraries(test_interpreter proxydatastore)
+    target_link_libraries(test_interpreter PRIVATE proxydatastore)
     cli_test(path_utils)
-    target_link_libraries(test_path_utils path)
+    target_link_libraries(test_path_utils PRIVATE path)
     cli_test(keyvalue_completion)
     cli_test(parser_rpc)
     cli_test(misc_commands)
diff --git a/src/ast_path.cpp b/src/ast_path.cpp
index e0348db..b34817b 100644
--- a/src/ast_path.cpp
+++ b/src/ast_path.cpp
@@ -359,3 +359,16 @@
     impl_pushFragment(m_nodes, fragment);
     validatePathNodes(m_nodes);
 }
+
+dataPath_ realPath(const dataPath_& cwd, const dataPath_& newPath)
+{
+    if (newPath.m_scope == Scope::Absolute) {
+        return newPath;
+    }
+
+    dataPath_ res = cwd;
+    for (const auto& it : newPath.m_nodes) {
+        res.pushFragment(it);
+    }
+    return res;
+}
diff --git a/src/ast_path.hpp b/src/ast_path.hpp
index e7df783..2da836f 100644
--- a/src/ast_path.hpp
+++ b/src/ast_path.hpp
@@ -154,6 +154,9 @@
 schemaPath_ dataPathToSchemaPath(const dataPath_& path);
 std::string escapeListKeyString(const std::string& what);
 
+// @brief Combining the current working directory with a new path, this function returns the resulting absolute path
+dataPath_ realPath(const dataPath_& cwd, const dataPath_& newPath);
+
 BOOST_FUSION_ADAPT_STRUCT(container_, m_name)
 BOOST_FUSION_ADAPT_STRUCT(listElement_, m_name, m_keys)
 BOOST_FUSION_ADAPT_STRUCT(leafListElement_, m_name, m_value)
diff --git a/src/interpreter.cpp b/src/interpreter.cpp
index d139e8b..73af6fc 100644
--- a/src/interpreter.cpp
+++ b/src/interpreter.cpp
@@ -57,6 +57,16 @@
     return boost::apply_visitor(pathToStringVisitor(), path);
 }
 
+void Interpreter::checkRpcPath(const dataPath_& commandPath) const
+{
+    if (auto inputPath = m_datastore.inputDatastorePath()) {
+        dataPath_ newPath = realPath(m_parser.currentPath(), commandPath);
+        if (!pathToDataString(newPath, Prefixes::WhenNeeded).starts_with(*inputPath)) {
+            throw std::runtime_error("Can't execute `cd` outside of the `prepare` context.");
+        }
+    }
+}
+
 void Interpreter::operator()(const commit_&) const
 {
     m_datastore.commitChanges();
@@ -98,9 +108,7 @@
 
 void Interpreter::operator()(const cd_& cd) const
 {
-    if (auto rpcInputPath = m_datastore.inputDatastorePath(); rpcInputPath && !pathToDataString(cd.m_path, Prefixes::WhenNeeded).starts_with(m_parser.currentNode())) {
-        throw std::runtime_error("Can't cd out of `prepare` context");
-    }
+    checkRpcPath(cd.m_path);
     m_parser.changeNode(cd.m_path);
 }
 
diff --git a/src/interpreter.hpp b/src/interpreter.hpp
index f2cfd11..3723432 100644
--- a/src/interpreter.hpp
+++ b/src/interpreter.hpp
@@ -36,6 +36,8 @@
     void operator()(const quit_&) const;
 
 private:
+    void checkRpcPath(const dataPath_& commandPath) const;
+
     [[nodiscard]] std::string buildTypeInfo(const std::string& path) const;
 
     template <typename PathType>
diff --git a/src/netconf_access.cpp b/src/netconf_access.cpp
index 6634dc6..5683b76 100644
--- a/src/netconf_access.cpp
+++ b/src/netconf_access.cpp
@@ -58,16 +58,8 @@
     return res;
 }
 
-NetconfAccess::NetconfAccess(const std::string& hostname, uint16_t port, const std::string& user, const std::string& pubKey, const std::string& privKey)
-    : m_context(std::nullopt, libyang::ContextOptions::SetPrivParsed)
-    , m_session(libnetconf::client::Session::connectPubkey(hostname, port, user, pubKey, privKey, m_context))
-    , m_schema(std::make_shared<YangSchema>(m_context))
-{
-    checkNMDA();
-}
-
 NetconfAccess::NetconfAccess(const int source, const int sink)
-    : m_context(std::nullopt, libyang::ContextOptions::SetPrivParsed)
+    : m_context(std::nullopt, libyang::ContextOptions::SetPrivParsed | libyang::ContextOptions::DisableSearchCwd)
     , m_session(libnetconf::client::Session::connectFd(source, sink, m_context))
     , m_schema(std::make_shared<YangSchema>(m_context))
 {
@@ -82,7 +74,7 @@
 }
 
 NetconfAccess::NetconfAccess(const std::string& socketPath)
-    : m_context(std::nullopt, libyang::ContextOptions::SetPrivParsed)
+    : m_context(std::nullopt, libyang::ContextOptions::SetPrivParsed | libyang::ContextOptions::DisableSearchCwd)
     , m_session(libnetconf::client::Session::connectSocket(socketPath, m_context))
     , m_schema(std::make_shared<YangSchema>(m_context))
 {
diff --git a/src/netconf_access.hpp b/src/netconf_access.hpp
index 27e54e2..0f1dbf6 100644
--- a/src/netconf_access.hpp
+++ b/src/netconf_access.hpp
@@ -27,7 +27,6 @@
 
 class NetconfAccess : public DatastoreAccess {
 public:
-    NetconfAccess(const std::string& hostname, uint16_t port, const std::string& user, const std::string& pubKey, const std::string& privKey);
     NetconfAccess(const std::string& socketPath);
     NetconfAccess(const int source, const int sink);
     NetconfAccess(std::unique_ptr<libnetconf::client::Session>&& session);
diff --git a/src/parser.cpp b/src/parser.cpp
index 982be11..1547478 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -85,13 +85,7 @@
 
 void Parser::changeNode(const dataPath_& name)
 {
-    if (name.m_scope == Scope::Absolute) {
-        m_curDir = name;
-    } else {
-        for (const auto& it : name.m_nodes) {
-            m_curDir.pushFragment(it);
-        }
-    }
+    m_curDir = realPath(m_curDir, name);
 }
 
 std::string Parser::currentNode() const
diff --git a/tests/interpreter.cpp b/tests/interpreter.cpp
index 0c03d89..087a9b7 100644
--- a/tests/interpreter.cpp
+++ b/tests/interpreter.cpp
@@ -456,6 +456,9 @@
         {
             REQUIRE_THROWS(boost::apply_visitor(Interpreter(parser, proxyDatastore), command_{cd_{{}, dataPath_{Scope::Absolute, {dataNode_{module_{{"example"}}, container_{"somewhereElse"}}}}}}));
             REQUIRE_THROWS(boost::apply_visitor(Interpreter(parser, proxyDatastore), command_{cd_{{}, dataPath_{Scope::Relative, {dataNode_{nodeup_{}}}}}}));
+
+            // Test that the parser allows to change the current node within the rpc context
+            REQUIRE_NOTHROW(boost::apply_visitor(Interpreter(parser, proxyDatastore), command_{cd_{{}, dataPath_{Scope::Relative, {dataNode_{container_{"payload"}}}}}}));
             boost::apply_visitor(Interpreter(parser, proxyDatastore), command_{cancel_{}});
         }