libsrx: new api, srx_get_changes()

Reduces the overhead/repetition for module callbacks by combining the
forces of srx_get_diff() and lydx_get_descendant() into one API.  The
resulting function supports both XPath and simplified paths to get the
subtree of changes applicable to the callback.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg
2024-08-26 20:54:49 +02:00
parent 961306d1a3
commit 18b59229f3
2 changed files with 104 additions and 0 deletions
+100
View File
@@ -2,9 +2,11 @@
#include <errno.h>
#include <stdarg.h>
#include <stdbool.h>
#include <string.h>
#include <sysrepo/values.h>
#include "common.h"
#include "lyx.h"
sr_error_t srx_get_diff(sr_session_ctx_t *session, struct lyd_node **treep)
{
@@ -25,6 +27,104 @@ sr_error_t srx_get_diff(sr_session_ctx_t *session, struct lyd_node **treep)
return err;
}
/* Helper tokenizer to srx_get_changes() */
static char *token(char *ptr)
{
char *token;
if (ptr && *ptr == '/')
ptr++;
token = strtok(ptr, "/");
if (token && (ptr = strchr(token, ':')))
token = &ptr[1]; /* skip any module prefix */
return token;
}
/*
* This is a combination of srx_get_diff() + lydx_get_descendant() that
* gives you the subtree relevant to your change callback.
*
* Usage: 1) set up change callback with /module:xpath/to/array//.
* 2) call this function with the /module:xpath/to/array XPath
* 3) over all items in array with LYX_LIST_FOR_EACH()
*
* The XPath to the change callback has //. to ensure it is called for
* *any* change below that path. Meaning: any depth and any augmented
* model inside that scope.
*
* Both the srx_*() and lyx?*() family APIs are supported after calling
* this function. Either traverse further down using XPath, or using
* the lydx_*() APIs. The latter have all the metadata for checking if
* a node/tree has been removed or added, which is sometimes preferable,
* sometimes data from the subtrees is regenerated every time anyway, so
* it depends.
*
* When done, call srx_free_changes(treep);
*/
int srx_get_changes(sr_session_ctx_t *session, const char *path, struct lyd_node **treep)
{
struct lyd_node *node, *tree;
sr_change_iter_t *iter;
char *xpath = NULL;
char *name = NULL;
int err;
err = sr_dup_changes_iter(session, "/ietf-system:system//.", &iter);
if (err)
return err;
/*
* WARNING: sr_change_iter_t is opaque, we rely on the diff
* tree being the first member.
*/
tree = node = *((struct lyd_node **)iter);
if (path) {
xpath = strdup(path);
if (!xpath) {
err = SR_ERR_NO_MEMORY;
goto fail;
}
name = token(xpath);
}
while (name) {
tree = lydx_get_sibling(node, name);
if (!tree)
break;
node = lyd_child(tree);
name = token(NULL);
}
if (tree) {
if (lyd_dup_siblings(tree, NULL, LYD_DUP_RECURSIVE, treep))
err = SR_ERR_LY;
} else
err = SR_ERR_NOT_FOUND;
if (xpath)
free(xpath);
fail:
sr_free_change_iter(iter);
return err;
}
/*
* Free changes from srx_get_changes() or srx_get_diff().
*/
int srx_free_changes(struct lyd_node *tree)
{
if (!tree)
return SR_ERR_INVAL_ARG;
lyd_free_tree(tree);
return 0;
}
/* check if string at xpath (fmt) is set (non-zero length) */
bool srx_isset(sr_session_ctx_t *session, const char *fmt, ...)
{
+4
View File
@@ -10,6 +10,10 @@
#define SRX_GET_UINT32(s,v,fmt,...) srx_get_int(s, &v, SR_UINT32_T, fmt, ##__VA_ARGS__)
sr_error_t srx_get_diff(sr_session_ctx_t *session, struct lyd_node **treep);
int srx_get_changes(sr_session_ctx_t *session, const char *path, struct lyd_node **treep);
int srx_free_changes(struct lyd_node *tree);
bool srx_isset(sr_session_ctx_t *session, const char *fmt, ...);
int srx_set_item(sr_session_ctx_t *, const sr_val_t *, sr_edit_options_t, const char *, ...)