Files
infix/patches/libyang-cpp/UPSTREAM-port-to-libyang3.patch
T

301 lines
13 KiB
Diff

From 0a09b00dab204bb5890978a17bb23c4c25280580 Mon Sep 17 00:00:00 2001
From: Jan Kundrát <jan.kundrat@cesnet.cz>
Date: Sun, 24 Mar 2024 20:41:25 +0100
Subject: [PATCH] Port to libyang v3
Four parts, really:
- some enum reshuffling when creating new nodes
- a more capable XPath finding, but we have not been exporting any
"non-JSON XPaths", whatever that might be
- system-ordered lists are now ordered alphabetically
- a more capable error handling API
Change-Id: Ic6de06f004c16e56cef93fae0136c07d903394c0
---
diff --git a/.zuul.yaml b/.zuul.yaml
index d9d95e1..b41c490 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -4,13 +4,13 @@
- f38-gcc-cover:
required-projects:
- name: github/CESNET/libyang
- override-checkout: cesnet/2024-03--v2-latest
+ override-checkout: devel
- name: github/onqtam/doctest
override-checkout: v2.3.6
- f38-clang-asan-ubsan:
required-projects: &projects
- name: github/CESNET/libyang
- override-checkout: cesnet/2024-03--v2-latest
+ override-checkout: devel
- name: github/onqtam/doctest
override-checkout: v2.4.11
- f38-clang-tsan:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 288b62a..6e54707 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -28,7 +28,7 @@
option(BUILD_SHARED_LIBS "By default, shared libs are enabled. Turn off for a static build." ON)
find_package(PkgConfig REQUIRED)
-pkg_check_modules(LIBYANG REQUIRED libyang>=2.1.140 IMPORTED_TARGET)
+pkg_check_modules(LIBYANG REQUIRED libyang>=2.2.3 IMPORTED_TARGET)
set(LIBYANG_CPP_PKG_VERSION "1.1.0")
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
diff --git a/README.md b/README.md
index 5e79a23..9009a54 100644
--- a/README.md
+++ b/README.md
@@ -8,8 +8,7 @@
Object lifetimes are managed automatically via RAII.
## Dependencies
-- [libyang](https://github.com/CESNET/libyang) - ~~the `devel` branch (even for the `master` branch of *libyang-cpp*)~~
- - temporarily (March 2024) this requires the [pre-v3 API of libyang (commit `b3d079fc3`)](https://github.com/CESNET/libyang/tree/b3d079fc37ac119f5a2a4a120b86d1c7102c3a08)
+- [libyang v3](https://github.com/CESNET/libyang) - the `devel` branch (even for the `master` branch of *libyang-cpp*)
- C++20 compiler (e.g., GCC 10.x+, clang 10+)
- CMake 3.19+
diff --git a/include/libyang-cpp/Context.hpp b/include/libyang-cpp/Context.hpp
index 1dab9f3..6f6e233 100644
--- a/include/libyang-cpp/Context.hpp
+++ b/include/libyang-cpp/Context.hpp
@@ -69,7 +69,9 @@
LogLevel level;
std::string message;
ErrorCode code;
- std::optional<std::string> path;
+ std::optional<std::string> dataPath;
+ std::optional<std::string> schemaPath;
+ uint64_t line;
ValidationErrorCode validationCode;
};
diff --git a/include/libyang-cpp/Enum.hpp b/include/libyang-cpp/Enum.hpp
index 3ded4d2..85dcc83 100644
--- a/include/libyang-cpp/Enum.hpp
+++ b/include/libyang-cpp/Enum.hpp
@@ -115,11 +115,15 @@
};
enum class CreationOptions : uint32_t {
- Update = 0x01,
- Output = 0x02,
- Opaque = 0x04,
- // BinaryLyb = 0x08, TODO
- CanonicalValue = 0x10
+ Output = 0x01,
+ StoreOnly = 0x02,
+ // BinaryLyb = 0x04, TODO
+ CanonicalValue = 0x08,
+ ClearDefaultFromParents = 0x10,
+ Update = 0x20,
+ Opaque = 0x40,
+ PathWithOpaque = 0x80,
+ // LYD_NEW_ANY_USE_VALUE is not relevant
};
/**
diff --git a/src/Context.cpp b/src/Context.cpp
index 337070f..713c50f 100644
--- a/src/Context.cpp
+++ b/src/Context.cpp
@@ -579,8 +579,10 @@
.appTag = errIt->apptag ? std::optional{errIt->apptag} : std::nullopt,
.level = utils::toLogLevel(errIt->level),
.message = errIt->msg,
- .code = static_cast<ErrorCode>(errIt->no),
- .path = errIt->path ? std::optional{errIt->path} : std::nullopt,
+ .code = static_cast<ErrorCode>(errIt->err),
+ .dataPath = errIt->data_path ? std::optional{errIt->data_path} : std::nullopt,
+ .schemaPath = errIt->schema_path ? std::optional{errIt->schema_path} : std::nullopt,
+ .line = errIt->line,
.validationCode = utils::toValidationErrorCode(errIt->vecode)
});
diff --git a/src/DataNode.cpp b/src/DataNode.cpp
index ab8cb4a..0e609c4 100644
--- a/src/DataNode.cpp
+++ b/src/DataNode.cpp
@@ -1187,7 +1187,8 @@
const std::string& xpath)
{
ly_set* set;
- auto ret = lyd_find_xpath3(contextNode ? contextNode->m_node : nullptr, forest.m_node, xpath.c_str(), nullptr, &set);
+ auto ret = lyd_find_xpath3(contextNode ? contextNode->m_node : nullptr, forest.m_node, xpath.c_str(),
+ LY_VALUE_JSON, nullptr, nullptr, &set);
throwIfError(ret, "libyang::findXPathAt:");
diff --git a/src/utils/enum.hpp b/src/utils/enum.hpp
index 7674fc6..5e02d24 100644
--- a/src/utils/enum.hpp
+++ b/src/utils/enum.hpp
@@ -72,11 +72,14 @@
{
return static_cast<uint32_t>(flags);
}
-static_assert(LYD_NEW_PATH_UPDATE == toCreationOptions(CreationOptions::Update));
-static_assert(LYD_NEW_PATH_OUTPUT == toCreationOptions(CreationOptions::Output));
-static_assert(LYD_NEW_PATH_OPAQ == toCreationOptions(CreationOptions::Opaque));
+static_assert(LYD_NEW_VAL_OUTPUT == toCreationOptions(CreationOptions::Output));
+static_assert(LYD_NEW_VAL_STORE_ONLY == toCreationOptions(CreationOptions::StoreOnly));
// static_assert(LYD_NEW_PATH_BIN_VALUE == toCreationOptions(CreationOptions::BinaryLyb));
-static_assert(LYD_NEW_PATH_CANON_VALUE == toCreationOptions(CreationOptions::CanonicalValue));
+static_assert(LYD_NEW_VAL_CANON == toCreationOptions(CreationOptions::CanonicalValue));
+static_assert(LYD_NEW_META_CLEAR_DFLT == toCreationOptions(CreationOptions::ClearDefaultFromParents));
+static_assert(LYD_NEW_PATH_UPDATE == toCreationOptions(CreationOptions::Update));
+static_assert(LYD_NEW_PATH_OPAQ == toCreationOptions(CreationOptions::Opaque));
+static_assert(LYD_NEW_PATH_WITH_OPAQ == toCreationOptions(CreationOptions::PathWithOpaque));
constexpr uint32_t toDuplicationOptions(const DuplicationOptions options)
{
diff --git a/tests/context.cpp b/tests/context.cpp
index d19f78b..cb629ef 100644
--- a/tests/context.cpp
+++ b/tests/context.cpp
@@ -457,7 +457,9 @@
.level = libyang::LogLevel::Error,
.message = "Invalid character sequence \"invalid\", expected a keyword.",
.code = libyang::ErrorCode::ValidationFailure,
- .path = "Line number 1.",
+ .dataPath = std::nullopt,
+ .schemaPath = std::nullopt,
+ .line = 1,
.validationCode = libyang::ValidationErrorCode::Syntax,
}
};
@@ -476,7 +478,9 @@
.level = libyang::LogLevel::Error,
.message = "Value \"9001\" is out of type int8 min/max bounds.",
.code = libyang::ErrorCode::ValidationFailure,
- .path = "Schema location \"/example-schema:leafInt8\".",
+ .dataPath = std::nullopt,
+ .schemaPath = "/example-schema:leafInt8",
+ .line = 0,
.validationCode = libyang::ValidationErrorCode::Data,
}
};
@@ -491,7 +495,9 @@
.level = libyang::LogLevel::Error,
.message = "Invalid type int8 empty value.",
.code = libyang::ErrorCode::ValidationFailure,
- .path = "Schema location \"/example-schema:leafInt8\".",
+ .dataPath = std::nullopt,
+ .schemaPath = "/example-schema:leafInt8",
+ .line = 0,
.validationCode = libyang::ValidationErrorCode::Data,
},
libyang::ErrorInfo {
@@ -499,7 +505,9 @@
.level = libyang::LogLevel::Error,
.message = "Value \"9001\" is out of type int8 min/max bounds.",
.code = libyang::ErrorCode::ValidationFailure,
- .path = "Schema location \"/example-schema:leafInt8\".",
+ .dataPath = std::nullopt,
+ .schemaPath = "/example-schema:leafInt8",
+ .line = 0,
.validationCode = libyang::ValidationErrorCode::Data,
}
};
diff --git a/tests/data_node.cpp b/tests/data_node.cpp
index 15fb727..2d27979 100644
--- a/tests/data_node.cpp
+++ b/tests/data_node.cpp
@@ -1026,12 +1026,12 @@
"/example-schema:bigTree/one",
"/example-schema:bigTree/one/myLeaf",
"/example-schema:bigTree/two",
- "/example-schema:bigTree/two/myList[thekey='43221']",
- "/example-schema:bigTree/two/myList[thekey='43221']/thekey",
+ "/example-schema:bigTree/two/myList[thekey='213']",
+ "/example-schema:bigTree/two/myList[thekey='213']/thekey",
"/example-schema:bigTree/two/myList[thekey='432']",
"/example-schema:bigTree/two/myList[thekey='432']/thekey",
- "/example-schema:bigTree/two/myList[thekey='213']",
- "/example-schema:bigTree/two/myList[thekey='213']/thekey"
+ "/example-schema:bigTree/two/myList[thekey='43221']",
+ "/example-schema:bigTree/two/myList[thekey='43221']/thekey",
};
REQUIRE(res == expected);
@@ -1255,6 +1255,7 @@
DOCTEST_SUBCASE("DataNode::findXPath")
{
+ // libyang v3 sorts these alphabetically
const auto data3 = R"({
"example-schema:person": [
{
@@ -1308,13 +1309,13 @@
auto set = node->findXPath("/example-schema:person");
REQUIRE(set.size() == 3);
- REQUIRE(set.front().path() == "/example-schema:person[name='John']");
- REQUIRE(set.back().path() == "/example-schema:person[name='David']");
+ REQUIRE(set.front().path() == "/example-schema:person[name='Dan']");
+ REQUIRE(set.back().path() == "/example-schema:person[name='John']");
auto iter = set.begin();
- REQUIRE((iter++)->path() == "/example-schema:person[name='John']");
REQUIRE((iter++)->path() == "/example-schema:person[name='Dan']");
REQUIRE((iter++)->path() == "/example-schema:person[name='David']");
+ REQUIRE((iter++)->path() == "/example-schema:person[name='John']");
REQUIRE(iter == set.end());
REQUIRE_THROWS_WITH_AS(*iter, "Dereferenced an .end() iterator", std::out_of_range);
}
@@ -1324,23 +1325,23 @@
auto set = node->findXPath("/example-schema:person");
REQUIRE((set.begin() + 0) == set.begin());
- REQUIRE((set.begin() + 0)->path() == "/example-schema:person[name='John']");
- REQUIRE((set.begin() + 1)->path() == "/example-schema:person[name='Dan']");
- REQUIRE((set.begin() + 2)->path() == "/example-schema:person[name='David']");
+ REQUIRE((set.begin() + 0)->path() == "/example-schema:person[name='Dan']");
+ REQUIRE((set.begin() + 1)->path() == "/example-schema:person[name='David']");
+ REQUIRE((set.begin() + 2)->path() == "/example-schema:person[name='John']");
REQUIRE((set.begin() + 3) == set.end());
REQUIRE_THROWS(set.begin() + 4);
REQUIRE((set.end() - 0) == set.end());
- REQUIRE((set.end() - 1)->path() == "/example-schema:person[name='David']");
- REQUIRE((set.end() - 2)->path() == "/example-schema:person[name='Dan']");
- REQUIRE((set.end() - 3)->path() == "/example-schema:person[name='John']");
+ REQUIRE((set.end() - 1)->path() == "/example-schema:person[name='John']");
+ REQUIRE((set.end() - 2)->path() == "/example-schema:person[name='David']");
+ REQUIRE((set.end() - 3)->path() == "/example-schema:person[name='Dan']");
REQUIRE((set.end() - 3) == set.begin());
REQUIRE_THROWS(set.end() - 4);
auto iter = set.end();
+ REQUIRE((--iter)->path() == "/example-schema:person[name='John']");
REQUIRE((--iter)->path() == "/example-schema:person[name='David']");
REQUIRE((--iter)->path() == "/example-schema:person[name='Dan']");
- REQUIRE((--iter)->path() == "/example-schema:person[name='John']");
REQUIRE_THROWS(--iter);
}
diff --git a/tests/pretty_printers.hpp b/tests/pretty_printers.hpp
index 6ae8934..6bbc16f 100644
--- a/tests/pretty_printers.hpp
+++ b/tests/pretty_printers.hpp
@@ -59,7 +59,9 @@
oss << "appTag: " << (err.appTag ? *err.appTag : "std::nullopt") << "\n ";
oss << "code: " << err.code << "\n ";
oss << "message: " << err.message << "\n ";
- oss << "path: " << (err.path ? *err.path : "std::nullopt") << "\n ";
+ oss << "dataPath: " << (err.dataPath ? *err.dataPath : "std::nullopt") << "\n ";
+ oss << "schemaPath: " << (err.schemaPath ? *err.schemaPath : "std::nullopt") << "\n ";
+ oss << "line: " << err.line << "\n ";
oss << "level: " << err.level << "\n ";
oss << "validationCode: " << err.validationCode << "\n }";
return oss.str();