diff FEATURE diff merge defaults flag
Which allows explicit operations on default nodes.
That is allowed in operational datastore.
diff --git a/src/diff.c b/src/diff.c
index 08d100e..0008277 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -1189,21 +1189,21 @@
* @param[in] diff_match Node from the diff.
* @param[in] cur_op Current operation of the diff node.
* @param[in] src_diff Current source diff node.
+ * @param[in] options Diff merge options.
* @return LY_ERR value.
*/
static LY_ERR
-lyd_diff_merge_create(struct lyd_node *diff_match, enum lyd_diff_op cur_op, const struct lyd_node *src_diff)
+lyd_diff_merge_create(struct lyd_node *diff_match, enum lyd_diff_op cur_op, const struct lyd_node *src_diff, uint16_t options)
{
struct lyd_node *child;
- const struct lysc_node_leaf *sleaf;
+ const struct lysc_node_leaf *sleaf = NULL;
uint32_t trg_flags;
switch (cur_op) {
case LYD_DIFF_OP_DELETE:
- if (diff_match->schema->nodetype == LYS_LEAF) {
+ if ((options & LYD_DIFF_MERGE_DEFAULTS) && (diff_match->schema->nodetype == LYS_LEAF)) {
+ /* we are dealing with a leaf and are handling default values specially (as explicit nodes) */
sleaf = (struct lysc_node_leaf *)diff_match->schema;
- } else {
- sleaf = NULL;
}
/* remember current flags */
@@ -1382,12 +1382,13 @@
* @param[in] diff_parent Current sysrepo diff parent.
* @param[in] diff_cb Optional diff callback.
* @param[in] cb_data User data for @p diff_cb.
+ * @param[in] options Diff merge options.
* @param[in,out] diff Diff root node.
* @return LY_ERR value.
*/
static LY_ERR
lyd_diff_merge_r(const struct lyd_node *src_diff, struct lyd_node *diff_parent, lyd_diff_cb diff_cb, void *cb_data,
- struct lyd_node **diff)
+ uint16_t options, struct lyd_node **diff)
{
LY_ERR ret = LY_SUCCESS;
struct lyd_node *child, *diff_node = NULL;
@@ -1409,7 +1410,7 @@
ret = lyd_diff_merge_replace(diff_node, cur_op, src_diff);
break;
case LYD_DIFF_OP_CREATE:
- ret = lyd_diff_merge_create(diff_node, cur_op, src_diff);
+ ret = lyd_diff_merge_create(diff_node, cur_op, src_diff, options);
break;
case LYD_DIFF_OP_DELETE:
ret = lyd_diff_merge_delete(diff_node, cur_op, src_diff);
@@ -1435,7 +1436,7 @@
/* merge src_diff recursively */
LY_LIST_FOR(lyd_child_no_keys(src_diff), child) {
- LY_CHECK_RET(lyd_diff_merge_r(child, diff_parent, diff_cb, cb_data, diff));
+ LY_CHECK_RET(lyd_diff_merge_r(child, diff_parent, diff_cb, cb_data, options, diff));
}
} else {
/* add new diff node with all descendants */
@@ -1472,7 +1473,7 @@
API LY_ERR
lyd_diff_merge_module(struct lyd_node **diff, const struct lyd_node *src_diff, const struct lys_module *mod,
- lyd_diff_cb diff_cb, void *cb_data)
+ lyd_diff_cb diff_cb, void *cb_data, uint16_t options)
{
const struct lyd_node *src_root;
@@ -1483,7 +1484,7 @@
}
/* apply relevant nodes from the diff datatree */
- LY_CHECK_RET(lyd_diff_merge_r(src_root, NULL, diff_cb, cb_data, diff));
+ LY_CHECK_RET(lyd_diff_merge_r(src_root, NULL, diff_cb, cb_data, options, diff));
}
return LY_SUCCESS;
@@ -1491,19 +1492,19 @@
API LY_ERR
lyd_diff_merge_tree(struct lyd_node **diff_first, struct lyd_node *diff_parent, const struct lyd_node *src_sibling,
- lyd_diff_cb diff_cb, void *cb_data)
+ lyd_diff_cb diff_cb, void *cb_data, uint16_t options)
{
if (!src_sibling) {
return LY_SUCCESS;
}
- return lyd_diff_merge_r(src_sibling, diff_parent, diff_cb, cb_data, diff_first);
+ return lyd_diff_merge_r(src_sibling, diff_parent, diff_cb, cb_data, options, diff_first);
}
API LY_ERR
-lyd_diff_merge_all(struct lyd_node **diff, const struct lyd_node *src_diff)
+lyd_diff_merge_all(struct lyd_node **diff, const struct lyd_node *src_diff, uint16_t options)
{
- return lyd_diff_merge_module(diff, src_diff, NULL, NULL, NULL);
+ return lyd_diff_merge_module(diff, src_diff, NULL, NULL, NULL, options);
}
static LY_ERR
diff --git a/src/tree_data.h b/src/tree_data.h
index 1fe05c9..e431940 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -1504,6 +1504,21 @@
LY_ERR lyd_diff_apply_all(struct lyd_node **data, const struct lyd_node *diff);
/**
+ * @ingroup datatree
+ * @defgroup diffmergeoptions Data diff merge options.
+ *
+ * Various options to change ::lyd_diff_merge_module(), ::lyd_diff_merge_tree(), and ::lyd_diff_merge_all() behavior.
+ *
+ * Default behavior:
+ * - any default nodes are expected to be a result of validation corrections and not explicitly modified.
+ * @{
+ */
+
+#define LYD_DIFF_MERGE_DEFAULTS 0x01 /**< Default nodes in the diffs are treated as possibly explicitly modified. */
+
+/** @} diffoptions */
+
+/**
* @brief Merge 2 diffs into each other but restrict the operation to one module.
*
* The diffs must be possible to be merged, which is guaranteed only if the source diff was
@@ -1521,11 +1536,12 @@
* @param[in] mod Module, whose diff only to consider, NULL for all modules.
* @param[in] diff_cb Optional diff callback that will be called for every changed node.
* @param[in] cb_data Arbitrary callback data.
+ * @param[in] options Bitmask of options flags, see @ref diffmergeoptions.
* @return LY_SUCCESS on success,
* @return LY_ERR on error.
*/
LY_ERR lyd_diff_merge_module(struct lyd_node **diff, const struct lyd_node *src_diff, const struct lys_module *mod,
- lyd_diff_cb diff_cb, void *cb_data);
+ lyd_diff_cb diff_cb, void *cb_data, uint16_t options);
/**
* @brief Merge 2 diff trees into each other.
@@ -1535,21 +1551,23 @@
* @param[in] src_sibling Source diff sibling to merge.
* @param[in] diff_cb Optional diff callback that will be called for every changed node.
* @param[in] cb_data Arbitrary callback data.
+ * @param[in] options Bitmask of options flags, see @ref diffmergeoptions.
* @return LY_SUCCESS on success,
* @return LY_ERR on error.
*/
LY_ERR lyd_diff_merge_tree(struct lyd_node **diff_first, struct lyd_node *diff_parent, const struct lyd_node *src_sibling,
- lyd_diff_cb diff_cb, void *cb_data);
+ lyd_diff_cb diff_cb, void *cb_data, uint16_t options);
/**
* @brief Merge 2 diffs into each other.
*
* @param[in,out] diff Target diff to merge into.
* @param[in] src_diff Source diff.
+ * @param[in] options Bitmask of options flags, see @ref diffmergeoptions.
* @return LY_SUCCESS on success,
* @return LY_ERR on error.
*/
-LY_ERR lyd_diff_merge_all(struct lyd_node **diff, const struct lyd_node *src_diff);
+LY_ERR lyd_diff_merge_all(struct lyd_node **diff, const struct lyd_node *src_diff, uint16_t options);
/**
* @brief Reverse a diff and make the opposite changes. Meaning change create to delete, delete to create,
diff --git a/src/validation.c b/src/validation.c
index 3eeacb8..a83ac95 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -47,7 +47,7 @@
LY_CHECK_RET(lyd_diff_add(node, op, NULL, NULL, NULL, NULL, NULL, &new_diff));
/* merge into existing diff */
- ret = lyd_diff_merge_all(diff, new_diff);
+ ret = lyd_diff_merge_all(diff, new_diff, 0);
lyd_free_tree(new_diff);
return ret;
diff --git a/tests/utests/data/test_diff.c b/tests/utests/data/test_diff.c
index f179b54..16658a6 100644
--- a/tests/utests/data/test_diff.c
+++ b/tests/utests/data/test_diff.c
@@ -472,7 +472,7 @@
assert_string_equal(st->xml1, st->xml2);
/* merge */
- assert_int_equal(lyd_diff_merge_all(&st->diff1, st->diff2), LY_SUCCESS);
+ assert_int_equal(lyd_diff_merge_all(&st->diff1, st->diff2, 0), LY_SUCCESS);
free(st->xml);
lyd_print_mem(&st->xml, st->diff1, LYD_XML, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_SHRINK);
@@ -565,7 +565,7 @@
assert_string_equal(st->xml1, st->xml2);
/* merge */
- assert_int_equal(lyd_diff_merge_all(&st->diff1, st->diff2), LY_SUCCESS);
+ assert_int_equal(lyd_diff_merge_all(&st->diff1, st->diff2, 0), LY_SUCCESS);
free(st->xml);
lyd_print_mem(&st->xml, st->diff1, LYD_XML, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_SHRINK);
@@ -653,7 +653,7 @@
assert_string_equal(st->xml1, st->xml2);
/* merge */
- assert_int_equal(lyd_diff_merge_all(&st->diff1, st->diff2), LY_SUCCESS);
+ assert_int_equal(lyd_diff_merge_all(&st->diff1, st->diff2, 0), LY_SUCCESS);
free(st->xml);
lyd_print_mem(&st->xml, st->diff1, LYD_XML, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_SHRINK);
@@ -736,7 +736,7 @@
assert_string_equal(st->xml1, st->xml2);
/* merge */
- assert_int_equal(lyd_diff_merge_all(&st->diff1, st->diff2), LY_SUCCESS);
+ assert_int_equal(lyd_diff_merge_all(&st->diff1, st->diff2, 0), LY_SUCCESS);
free(st->xml);
lyd_print_mem(&st->xml, st->diff1, LYD_XML, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_SHRINK);
@@ -812,7 +812,7 @@
assert_string_equal(st->xml1, st->xml2);
/* merge */
- assert_int_equal(lyd_diff_merge_all(&st->diff1, st->diff2), LY_SUCCESS);
+ assert_int_equal(lyd_diff_merge_all(&st->diff1, st->diff2, 0), LY_SUCCESS);
free(st->xml);
lyd_print_mem(&st->xml, st->diff1, LYD_XML, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_SHRINK);
@@ -890,7 +890,7 @@
assert_string_equal(st->xml1, st->xml2);
/* merge */
- assert_int_equal(lyd_diff_merge_all(&st->diff1, st->diff2), LY_SUCCESS);
+ assert_int_equal(lyd_diff_merge_all(&st->diff1, st->diff2, 0), LY_SUCCESS);
free(st->xml);
lyd_print_mem(&st->xml, st->diff1, LYD_XML, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_WD_ALL | LYD_PRINT_SHRINK);