diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c
index d3a938622..208e4e2e6 100644
--- a/apps/backend/backend_client.c
+++ b/apps/backend/backend_client.c
@@ -1470,7 +1470,6 @@ from_client_compare(clixon_handle h,
goto done;
goto ok;
}
-
/* Alt: see dsref handling in rpc_datastore_diff */
if ((db1 = xml_find_body(xe, "source")) == NULL){
if (netconf_missing_element(cbret, "protocol", "source", NULL) < 0)
@@ -1482,6 +1481,15 @@ from_client_compare(clixon_handle h,
if (netconf_invalid_value(cbret, "protocol", "missing source identifier") < 0)
goto done;
}
+ /* Do not create a private candidate when comparing */
+ if (strcmp(id1, "candidate") == 0 && clicon_option_bool(h, "CLICON_XMLDB_PRIVATE_CANDIDATE")) {
+ if (xmldb_candidate_find(h, "candidate", ce->ce_id, &de1, NULL) < 0)
+ goto done;
+ if (de1 == NULL) {
+ free(id1);
+ id1 = strdup("running");
+ }
+ }
if (xmldb_find_create(h, id1, ce->ce_id, &de1, NULL) < 0)
goto done;
if ((db2 = xml_find_body(xe, "target")) == NULL){
@@ -1494,8 +1502,18 @@ from_client_compare(clixon_handle h,
if (netconf_invalid_value(cbret, "protocol", "missing target identifier") < 0)
goto done;
}
+ /* Do not create a private candidate when comparing */
+ if (strcmp(id2, "candidate") == 0 && clicon_option_bool(h, "CLICON_XMLDB_PRIVATE_CANDIDATE")) {
+ if (xmldb_candidate_find(h, "candidate", ce->ce_id, &de2, NULL) < 0)
+ goto done;
+ if (de2 == NULL) {
+ free(id2);
+ id2 = strdup("running");
+ }
+ }
if (xmldb_find_create(h, id2, ce->ce_id, &de2, NULL) < 0)
goto done;
+
/* filter: subtree-filter or xpath-filter */
if ((xpath_filter = xml_find(xe, "xpath-filter")) != NULL){
if ((xpath0 = xml_body(xpath_filter)) != NULL){
diff --git a/apps/cli/cli_common.c b/apps/cli/cli_common.c
index ff120332d..7a2916ef0 100644
--- a/apps/cli/cli_common.c
+++ b/apps/cli/cli_common.c
@@ -851,6 +851,37 @@ compare_db_names(clixon_handle h,
cxobj *xc2 = NULL;
cxobj *xerr = NULL;
cbuf *cb = NULL;
+ cxobj *xret = NULL;
+ cxobj *xe;
+ cxobj *x;
+ int i;
+
+ if (format == FORMAT_XML) { /* new implementation for xml format using rpc compare */
+ if (clixon_rpc_nmda_compare(h, db1, db2, &xret) < 0) {
+ clixon_err(OE_PLUGIN, 0, "clixon_rpc_nmda_compare %s %s", db1, db2);
+ goto done;
+ }
+ if (xpath_first(xret, NULL, "//no-matches") != NULL) {
+ retval = 0;
+ goto done;
+ }
+ if ((cb = cbuf_new()) == NULL){
+ clixon_err(OE_UNIX, errno, "cbuf_new");
+ goto done;
+ }
+ if ((xe = xpath_first(xret, NULL, "//differences/yang-patch")) == NULL) {
+ clixon_err(OE_XML, ENOENT, "Expected yang-patch in rpc compare reply");
+ goto done;
+ }
+ cligen_output(stdout, "--- %s\n+++ %s\n", db1, db2);
+ i = 0;
+ while ((x = xml_child_iter(xe, &i, -1)) != NULL)
+ clixon_yangpatch2cbuf(cb, x);
+ cligen_output(stdout, "%s", cbuf_get(cb));
+ retval = 0;
+ goto done;
+ }
+ /* xml format handling complete */
if (clicon_rpc_get_config(h, NULL, db1, "/", NULL, NULL, &xc1) < 0)
goto done;
@@ -866,19 +897,10 @@ compare_db_names(clixon_handle h,
goto done;
goto done;
}
- /* Note that XML and TEXT uses a (new) structured in-mem algorithm while
+ /* Note that TEXT uses a (new) structured in-mem algorithm while
* JSON and CLI uses (old) UNIX file diff.
*/
switch (format){
- case FORMAT_XML:
- if ((cb = cbuf_new()) == NULL){
- clixon_err(OE_UNIX, errno, "cbuf_new");
- goto done;
- }
- if (clixon_xml_diff2cbuf(cb, xc1, xc2) < 0)
- goto done;
- cligen_output(stdout, "%s", cbuf_get(cb));
- break;
case FORMAT_TEXT:
if ((cb = cbuf_new()) == NULL){
clixon_err(OE_UNIX, errno, "cbuf_new");
@@ -893,7 +915,7 @@ compare_db_names(clixon_handle h,
if (clixon_compare_xmls(xc1, xc2, format) < 0) /* astext? */
goto done;
default:
- break;
+ goto done;
}
retval = 0;
done:
@@ -903,6 +925,8 @@ compare_db_names(clixon_handle h,
xml_free(xc1);
if (xc2)
xml_free(xc2);
+ if (xret)
+ xml_free(xret);
return retval;
}
diff --git a/lib/clixon/clixon_netconf_lib.h b/lib/clixon/clixon_netconf_lib.h
index b74c82b43..750285f8c 100644
--- a/lib/clixon/clixon_netconf_lib.h
+++ b/lib/clixon/clixon_netconf_lib.h
@@ -80,6 +80,10 @@
*/
#define NETCONF_COMPARE_NAMESPACE "urn:ietf:params:xml:ns:yang:ietf-nmda-compare"
+/* RFC 8342: Network Management Datastore Architecture (NMDA)
+ */
+#define NETCONF_DATASTORES_NAMESPACE "urn:ietf:params:xml:ns:yang:ietf-datastores"
+
/*! draft-ietf-netconf-privcand NETCONF and RESTCONF Private Candidate Datastores
*/
#define NETCONF_PRIVCAND_NAMESPACE "urn:ietf:params:xml:ns:yang:ietf-netconf-private-candidate"
diff --git a/lib/clixon/clixon_proto_client.h b/lib/clixon/clixon_proto_client.h
index 6beb73228..48167c73e 100644
--- a/lib/clixon/clixon_proto_client.h
+++ b/lib/clixon/clixon_proto_client.h
@@ -86,6 +86,7 @@ int clixon_rpc_api_path2xml(clixon_handle h, const char *api_path, const char *b
int clixon_rpc_translate_format(clixon_handle h, enum format_enum format, const char *xpath, cvec *nsc,
cxobj *xt, int pretty, int skiptop, int cli_aware, const char *prepend, cbuf *cb);
int clicon_rpc_restart_plugin(clixon_handle h, const char *plugin);
+int clixon_rpc_nmda_compare(clixon_handle h, const char *db1, const char *db2, cxobj **xt);
/*-- Backward compatible 7.6 --*/
static inline int
diff --git a/lib/clixon/clixon_xml_io.h b/lib/clixon/clixon_xml_io.h
index 90f7ad4c2..58550e3b8 100644
--- a/lib/clixon/clixon_xml_io.h
+++ b/lib/clixon/clixon_xml_io.h
@@ -58,7 +58,7 @@ int clixon_xml_parse_string1(clixon_handle h, const char *str, yang_bind yb, y
int clixon_xml_parse_va(yang_bind yb, yang_stmt *yspec, cxobj **xt, cxobj **xerr,
const char *format, ...) __attribute__ ((format (printf, 5, 6)));
int clixon_xml_attr_copy(cxobj *xin, cxobj *xout, const char *name);
-int clixon_xml_diff2cbuf(cbuf *cb, cxobj *x0, cxobj *x1);
+int clixon_yangpatch2cbuf(cbuf *cb, cxobj *xe);
static inline int
clixon_xml2cbuf(cbuf *cb,
diff --git a/lib/src/clixon_proto_client.c b/lib/src/clixon_proto_client.c
index 9a9cdb206..cbf21c85e 100644
--- a/lib/src/clixon_proto_client.c
+++ b/lib/src/clixon_proto_client.c
@@ -2495,3 +2495,64 @@ clixon_rpc_nacm_autocli_filter(clixon_handle h,
xml_free(xret);
return retval;
}
+
+/* Make a clixon compare call from client to backend server
+ *
+ * @param[in] h Clixon handle
+ * @param[in] db1 Source datastore
+ * @param[in] db2 Target datastore
+ * @param[out] xt Pointer to roc reply to be freed by caller, or NULL
+ * @retval 0 rpc reply ok
+ * @retval -1 Error
+*/
+
+int
+clixon_rpc_nmda_compare(clixon_handle h,
+ const char *db1,
+ const char *db2,
+ cxobj **xt)
+{
+ int retval = -1;
+ cbuf *cb = NULL;
+ cxobj *xret = NULL;
+ char *username;
+ uint32_t session_id;
+
+ clixon_debug(CLIXON_DBG_DEFAULT | CLIXON_DBG_DETAIL, "db1: %s, db2: %s", db1, db2);
+ if (session_id_check(h, &session_id) < 0)
+ goto done;
+ if ((cb = cbuf_new()) == NULL){
+ clixon_err(OE_XML, errno, "cbuf_new");
+ goto done;
+ }
+ cprintf(cb, "", netconf_message_id_next(h));
+ cprintf(cb, "",
+ NETCONF_COMPARE_NAMESPACE, NETCONF_DATASTORES_NAMESPACE);
+ cprintf(cb, "ds:%s", db1);
+ cprintf(cb, "ds:%s", db2);
+ cprintf(cb, "");
+ if (clicon_rpc_msg(h, cb, &xret) < 0)
+ goto done;
+
+ if ((xpath_first(xret, NULL, "//rpc-error")) != NULL){
+ clixon_err_netconf(h, OE_NETCONF, 0, xret, "compare rpc error");
+ goto done;
+ }
+ *xt = xret;
+ xret = NULL;
+ retval = 0;
+ done:
+ clixon_debug(CLIXON_DBG_DEFAULT | CLIXON_DBG_DETAIL, "retval:%d", retval);
+ if (cb)
+ cbuf_free(cb);
+ if (xret)
+ xml_free(xret);
+ return retval;
+}
+
diff --git a/lib/src/clixon_text_syntax.c b/lib/src/clixon_text_syntax.c
index 187c6e5b0..0e4a01f19 100644
--- a/lib/src/clixon_text_syntax.c
+++ b/lib/src/clixon_text_syntax.c
@@ -741,8 +741,6 @@ text_diff_keys(cbuf *cb,
* @param[in] skiptop 0: Include top object 1: Skip top-object, only children,
* @retval 0 Ok
* @retval -1 Error
- * @see xml_diff_ordered_by_user
- * @see text_diff2cbuf_ordered_by_user
*/
static int
text_diff2cbuf_ordered_by_user(cbuf *cb,
@@ -814,7 +812,7 @@ text_diff2cbuf_ordered_by_user(cbuf *cb,
* if (clixon_text_diff2cbuf(cb, 0, x0, x1, 0) < 0)
* err();
* @endcode
- * @see clixon_xml_diff2cbuf
+
* XXX Leaf-list +/- is not correct
* For example, it should be:
* value [
@@ -826,9 +824,7 @@ text_diff2cbuf_ordered_by_user(cbuf *cb,
* + 97
* - 99
* @see clixon_compare_xmls which uses files and is independent of YANG
- * @see xml_diff2cbuf for XML
* @see xml_tree_equal Equal or not
- * @see xml_diff Diff sets
*/
static int
text_diff2cbuf(cbuf *cb,
@@ -1095,7 +1091,6 @@ text_diff2cbuf(cbuf *cb,
* if (clixon_text_diff2cbuf(cb, 0, x0, x1) < 0)
* err();
* @endcode
- * @see clixon_xml_diff2cbuf
*/
int
clixon_text_diff2cbuf(cbuf *cb,
diff --git a/lib/src/clixon_xml_diff.c b/lib/src/clixon_xml_diff.c
index fa08ec1c2..f940ae623 100644
--- a/lib/src/clixon_xml_diff.c
+++ b/lib/src/clixon_xml_diff.c
@@ -1783,18 +1783,24 @@ clixon_xml_diff2patch(cxobj *x1,
{
int retval = -1;
int nr = 1;
+ uint16_t f1 = 0;
+ uint16_t f2 = 0;
- if (x1)
+ if (x1) {
+ f1 = xml_flag(x1, XML_FLAG_TOP);
xml_flag_set(x1, XML_FLAG_TOP);
- if (x2)
+ }
+ if (x2) {
+ f2 = xml_flag(x2, XML_FLAG_TOP);
xml_flag_set(x2, XML_FLAG_TOP);
+ }
if (xml_diff2patch(x1, x2, flags, xpatch, &nr) < 0)
goto done;
retval = 0;
done:
- if (x1)
+ if (x1 && !f1)
xml_flag_reset(x1, XML_FLAG_TOP);
- if (x2)
+ if (x2 && !f2)
xml_flag_reset(x2, XML_FLAG_TOP);
return retval;
}
@@ -1830,3 +1836,4 @@ clixon_xml_diff_nacm_read(clixon_handle h,
done:
return retval;
}
+
diff --git a/lib/src/clixon_xml_io.c b/lib/src/clixon_xml_io.c
index efa86e822..c320278a3 100644
--- a/lib/src/clixon_xml_io.c
+++ b/lib/src/clixon_xml_io.c
@@ -93,9 +93,6 @@
/* Size of xml read buffer */
#define BUFLEN 1024
-/* Forward */
-static int xml_diff2cbuf(cbuf *cb, cxobj *x0, cxobj *x1, int level, int skiptop);
-
/*------------------------------------------------------------------------
* XML printing functions. Output a parse tree to file, string cligen buf
*------------------------------------------------------------------------*/
@@ -1293,446 +1290,60 @@ clixon_xml_attr_copy(cxobj *xin,
return retval;
}
-/*! Print list keys
- */
-static int
-xml_diff_keys(cbuf *cb,
- cxobj *x,
- yang_stmt *y,
- int level)
-{
- cvec *cvk;
- cg_var *cvi;
- char *keyname;
- char *keyval;
-
- if (y && yang_keyword_get(y) == Y_LIST){
- cvk = yang_cvec_get(y); /* Use Y_LIST cache, see ys_populate_list() */
- cvi = NULL;
- while ((cvi = cvec_each(cvk, cvi)) != NULL) {
- keyname = cv_string_get(cvi);
- keyval = xml_find_body(x, keyname);
- cprintf(cb, "%*s<%s>%s%s>\n", level, "", keyname, keyval, keyname);
- }
- }
- return 0;
-}
-
-/*! Print one line of context around diff
- */
-static int
-xml_diff_context(cbuf *cb,
- cxobj *xn,
- int level)
-{
- int retval = -1;
- char *prefix;
- char *namespace = NULL;
-
- prefix = xml_prefix(xn);
- if (xml2ns(xn, prefix, &namespace) < 0)
- goto done;
- cprintf(cb, "%*s<", level, "");
- if (namespace){
- if (prefix)
- cprintf(cb, "%s:", prefix);
- cprintf(cb, "%s xmlns", xml_name(xn));
- if (prefix)
- cprintf(cb, ":%s", prefix);
- cprintf(cb, "=\"%s\"", namespace);
- cprintf(cb, ">\n");
- }
- else
- cprintf(cb, "%s>\n", xml_name(xn));
- retval = 0;
- done:
- return retval;
-}
-
-/*! Handle order-by user(leaf)list for xml_diff2cbuf
+/* Print an XML representation of one edit in a YANG Patch into a cbuf.
*
- * @param[out] cb CLIgen buffer
- * @param[in] x0 First XML tree
- * @param[in] x1 Second XML tree
- * @param[in] x0c Start of sublist in first XML tree
- * @param[in] x1c Start of sublist in second XML tree
- * @param[in] yc Yang of x0c/x1c. If NULL special case of anydata
- * @param[in] level How many spaces to insert before each line
- * @retval 0 Ok
- * @retval -1 Error
- * @see xml_diff_ordered_by_user
- * @see text_diff2cbuf_ordered_by_user
+ * @param[in] *cb CLIgen buffer
+ * @param[in] *xe Edit XML subtree
+ * @retval 0 OK
+ * @retval -1 Error
*/
-static int
-xml_diff2cbuf_ordered_by_user(cbuf *cb,
- cxobj *x0,
- cxobj *x1,
- cxobj *x0c,
- cxobj *x1c,
- int ix0c,
- int ix1c,
- yang_stmt *yc,
- int level)
+int
+clixon_yangpatch2cbuf(cbuf *cb,
+ cxobj *xe)
{
- int retval = 1;
- cxobj *xi;
- cxobj *xj;
- int ixi;
- int ixj;
+ int retval = -1;
+ cxobj *x;
+ const char *op;
+ const char *prefix;
- xj = x1c;
- ixj = ix1c;
- do { /* Mark all x1 as ADD */
- xml_flag_set(xj, XML_FLAG_ADD);
- } while ((xj = xml_child_iter(x1, &ixj, CX_ELMNT)) != NULL &&
- xml_spec(xj) == yc);
- /* If in both sets, unmark add/del */
- xi = x0c;
- ixi = ix0c;
- do {
- xml_flag_set(xi, XML_FLAG_DEL);
- xj = x1c;
- ixj = ix1c;
- do {
- if (xml_flag(xj, XML_FLAG_ADD) &&
- xml_cmp(xi, xj, 0, 0, NULL) == 0){
- /* Unmark node in x0 and x1 */
- xml_flag_reset(xi, XML_FLAG_DEL);
- xml_flag_reset(xj, XML_FLAG_ADD);
- if (xml_diff2cbuf(cb, xi, xj, level+1, 0) < 0)
- goto done;
- break;
- }
- }
- while ((xj = xml_child_iter(x1, &ixj, CX_ELMNT)) != NULL &&
- xml_spec(xj) == yc);
+ if ((x = xml_find(xe, "target")) == NULL) {
+ goto done;
}
- while ((xi = xml_child_iter(x0, &ixi, CX_ELMNT)) != NULL &&
- xml_spec(xi) == yc);
-
- retval = 0;
- done:
- return retval;
-}
-
-/*! xml_diff2cbuf helper function to compute leaf difference
- *
- * @param[out] cb CLIgen buffer
- * @param[in] x0 First XML tree
- * @param[in] x1 Second XML tree
- * @param[in] level How many spaces to insert before each line
- * @param[in] skiptop 0: Include top object 1: Skip top-object, only children,
- * @retval 0 Ok
- * @retval -1 Error
- */
-static int
-xml_diff2cbuf_leaf(cbuf *cb,
- cxobj *x0,
- cxobj *x1,
- int level,
- int skiptop,
- yang_stmt *y0,
- cxobj *x0c,
- cxobj *x1c,
- char *b0,
- char *b1,
- int *nr)
-{
- int retval = -1;
- char *e0 = NULL;
- char *e1 = NULL;
+ cprintf(cb, "%s\n", xml_body(x));
- if (*nr==0 && skiptop==0){
- xml_diff_context(cb, x0, level*PRETTYPRINT_INDENT);
- xml_diff_keys(cb, x0, y0, (level+1)*PRETTYPRINT_INDENT);
- (*nr)++;
+ if ((x = xml_find(xe, "operation")) == NULL) {
+ goto done;
}
- /* Encode data to XML */
- if (b0){
- if (xml_chardata_encode(&e0, 0, "%s", b0) < 0)
+ op = xml_body(x);
+ switch (op[0]) {
+ case 'c': /* create */
+ prefix = "+";
+ break;
+ case 'd': /* delete */
+ prefix = "-";
+ break;
+ case 'r': /* replace*/
+ if ((x = xml_find(xe, "source-value")) == NULL)
goto done;
- }
- else
- e0 = NULL;
- if (b1){
- if (xml_chardata_encode(&e1, 0, "%s", b1) < 0)
+ if (clixon_xml2cbuf1(cb, x, 1, 1, "-", -1, 1, 0, WITHDEFAULTS_REPORT_ALL) < 0)
goto done;
+ prefix = "+";
+ break;
+ case 'm': /* move */
+ prefix = "~";
+ /* not currently supported */
+ goto done;
+ default:
+ goto done;
}
- else
- e1 = NULL;
- cprintf(cb, "-%*s%s>%s%s>\n", ((level+1)*PRETTYPRINT_INDENT-1), "<",
- xml_name(x0c), e0, xml_name(x0c));
- cprintf(cb, "+%*s%s>%s%s>\n", ((level+1)*PRETTYPRINT_INDENT-1), "<",
- xml_name(x1c), e1, xml_name(x1c));
- if (e0){
- free(e0);
- e0 = NULL;
- }
- if (e1){
- free(e1);
- e1 = NULL;
- }
- retval = 0;
- done:
- if (e0)
- free(e0);
- if (e1)
- free(e1);
- return retval;
-}
-
-/*! Print XML diff of two cxobj trees into a cbuf
- *
- * YANG dependent,
- * Skip objects marked with XML_FLAG_DENY
- * Uses underlying XML diff algorithm with better result than clixon_compare_xmls
- * @param[out] cb CLIgen buffer
- * @param[in] x0 First XML tree
- * @param[in] x1 Second XML tree
- * @param[in] level How many spaces to insert before each line
- * @param[in] skiptop 0: Include top object 1: Skip top-object, only children,
- * @retval 0 Ok
- * @retval -1 Error
- * @code
- * cbuf *cb = cbuf_new();
- * if (clixon_xml_diff2cbuf(cb, 0, x0, x1) < 0)
- * err();
- * cligen_output(stdout, "%s", cbuf_get(cb));
- * @endcode
- * @see xml_diff which returns diff sets
- * @see clixon_compare_xmls which uses files and is independent of YANG
- * @see text_diff2cbuf for curly
- * @see xml_tree_equal Equal or not
- * @see xml_diff Diff sets
- */
-static int
-xml_diff2cbuf(cbuf *cb,
- cxobj *x0,
- cxobj *x1,
- int level,
- int skiptop)
-{
- int retval = -1;
- cxobj *x0c = NULL; /* x0 child */
- cxobj *x1c = NULL; /* x1 child */
- yang_stmt *y0;
- yang_stmt *y0c;
- yang_stmt *y1c;
- char *b0;
- char *b1;
- int eq;
- int nr=0;
- int level1;
- cxobj *xi;
- cxobj *xj;
- int extflag;
- int ix0c;
- int ix1c;
- int ixi;
- int ixj;
-
- level1 = level*PRETTYPRINT_INDENT;
- y0 = xml_spec(x0);
- /* Traverse x0 and x1 in lock-step */
- ix0c = ix1c = 0;
- x0c = xml_child_iter(x0, &ix0c, CX_ELMNT);
- x1c = xml_child_iter(x1, &ix1c, CX_ELMNT);
- for (;;){
- if (x0c == NULL && x1c == NULL)
- goto ok;
- /* Skip if marked as DENY by NACM */
- if (x0c && xml_flag(x0c, XML_FLAG_DENY) != 0){
- x0c = xml_child_iter(x0, &ix0c, CX_ELMNT);
- continue;
- }
- else if (x1c && xml_flag(x1c, XML_FLAG_DENY) != 0){
- x1c = xml_child_iter(x1, &ix1c, CX_ELMNT);
- continue;
- }
- y0c = NULL;
- y1c = NULL;
- /* If cl:ignore-compare extension, skip */
- if (x0c && (y0c = xml_spec(x0c)) != NULL){
- if (yang_extension_value(y0c, "ignore-compare", CLIXON_LIB_NS, &extflag, NULL) < 0)
- goto done;
- if (extflag){ /* skip */
- x0c = xml_child_iter(x0, &ix0c, CX_ELMNT);
- continue;
- }
- }
- if (x1c && (y1c = xml_spec(x1c)) != NULL){
- if (yang_extension_value(y1c, "ignore-compare", CLIXON_LIB_NS, &extflag, NULL) < 0)
- goto done;
- if (extflag){ /* skip */
- x1c = xml_child_iter(x1, &ix1c, CX_ELMNT);
- continue;
- }
- }
- if (x0c == NULL){
- /* Check if one or both subtrees are NULL */
- if (nr==0 && skiptop==0){
- xml_diff_context(cb, x1, level1);
- xml_diff_keys(cb, x1, y0, (level+1)*PRETTYPRINT_INDENT);
- nr++;
- }
- if (clixon_xml2cbuf1(cb, x1c, level+1, 1, "+", -1, 0, 0, WITHDEFAULTS_EXPLICIT) < 0)
- goto done;
- x1c = xml_child_iter(x1, &ix1c, CX_ELMNT);
- continue;
- }
- else if (x1c == NULL){
- if (nr==0 && skiptop==0){
- xml_diff_context(cb, x0, level1);
- xml_diff_keys(cb, x0, y0, (level+1)*PRETTYPRINT_INDENT);
- nr++;
- }
- if (clixon_xml2cbuf1(cb, x0c, level+1, 1, "-", -1, 0, 0, WITHDEFAULTS_EXPLICIT) < 0)
- goto done;
- x0c = xml_child_iter(x0, &ix0c, CX_ELMNT);
- continue;
- }
- /* Both x0c and x1c exists, check if yang equal */
- eq = xml_cmp(x0c, x1c, 0, 0, NULL);
- b0 = xml_body(x0c);
- b1 = xml_body(x1c);
- if (eq && y0c && y1c && y0c == y1c && yang_find(y0c, Y_ORDERED_BY, "user")){
- if (xml_diff2cbuf_ordered_by_user(cb, x0, x1, x0c, x1c, ix0c, ix1c, y0c, level) < 0)
- goto done;
- /* Show all marked as DELETE as - entries
- */
- xi = x0c;
- ixi = ix0c;
- do {
- if (xml_flag(xi, XML_FLAG_DEL)){
- xml_flag_reset(xi, XML_FLAG_DEL);
- if (nr==0 && skiptop==0){
- xml_diff_context(cb, x0, level1);
- xml_diff_keys(cb, x0, y0, (level+1)*PRETTYPRINT_INDENT);
- nr++;
- }
- if (clixon_xml2cbuf1(cb, xi, level+1, 1, "-", -1, 0, 0, WITHDEFAULTS_EXPLICIT) < 0)
- goto done;
- }
- }
- while ((xi = xml_child_iter(x0, &ixi, CX_ELMNT)) != NULL &&
- xml_spec(xi) == y0c);
- x0c = xi; /* skip entries in this yang class */
- ix0c = ixi;
- /* Show all marked as ADD as + entries
- */
- xj = x1c;
- ixj = ix1c;
- do {
- if (xml_flag(xj, XML_FLAG_ADD)){
- xml_flag_reset(xj, XML_FLAG_ADD);
- if (nr==0 && skiptop==0){
- xml_diff_context(cb, x1, level1);
- xml_diff_keys(cb, x1, y0, (level+1)*PRETTYPRINT_INDENT);
- nr++;
- }
- if (clixon_xml2cbuf1(cb, xj, level+1, 1, "+", -1, 0, 0, WITHDEFAULTS_EXPLICIT) < 0)
- goto done;
- }
- }
- while ((xj = xml_child_iter(x1, &ixj, CX_ELMNT)) != NULL &&
- xml_spec(xj) == y1c);
- x1c = xj;
- ix1c = ixj;
- continue;
- } /* ordered-by user */
- else if (eq < 0){
- if (nr==0 && skiptop==0){
- xml_diff_context(cb, x0, level1);
- xml_diff_keys(cb, x0, y0, (level+1)*PRETTYPRINT_INDENT);
- nr++;
- }
- if (clixon_xml2cbuf1(cb, x0c, level+1, 1, "-", -1, 0, 0, WITHDEFAULTS_EXPLICIT) < 0)
- goto done;
- x0c = xml_child_iter(x0, &ix0c, CX_ELMNT);
- continue;
- }
- else if (eq > 0){
- if (nr==0 && skiptop==0){
- xml_diff_context(cb, x1, level1);
- xml_diff_keys(cb, x1, y0, (level+1)*PRETTYPRINT_INDENT);
- nr++;
- }
- if (clixon_xml2cbuf1(cb, x1c, level+1, 1, "+", -1, 0, 0, WITHDEFAULTS_EXPLICIT) < 0)
- goto done;
- x1c = xml_child_iter(x1, &ix1c, CX_ELMNT);
- continue;
- }
- else{ /* equal */
- /* xml-spec NULL could happen with anydata children for example,
- * if so, continute compare children but without yang
- */
- if (y0c && y1c && y0c != y1c){ /* choice */
- if (nr==0 && skiptop==0){
- xml_diff_context(cb, x0, level1);
- xml_diff_keys(cb, x0, y0, (level+1)*PRETTYPRINT_INDENT);
- nr++;
- }
- if (clixon_xml2cbuf1(cb, x0c, level+1, 1, "-", -1, 0, 0, WITHDEFAULTS_EXPLICIT) < 0)
- goto done;
- if (clixon_xml2cbuf1(cb, x1c, level+1, 1, "+", -1, 0, 0, WITHDEFAULTS_EXPLICIT) < 0)
- goto done;
- }
- else if (y0c && yang_keyword_get(y0c) == Y_LEAF){
- /* if x0c and x1c are leafs w bodies, then they may be changed */
- if (b0 == NULL && b1 == NULL)
- ;
- else if (b0 == NULL || b1 == NULL || strcmp(b0, b1) != 0){
- if (xml_diff2cbuf_leaf(cb, x0, x1, level, skiptop,
- y0, x0c, x1c, b0, b1, &nr) < 0)
- goto done;
- }
- }
- else if (y0c == NULL && y1c == NULL && (b0 || b1)) { /* Anydata terminals */
- if (b0 == NULL || b1 == NULL || strcmp(b0, b1) != 0){
- if (xml_diff2cbuf_leaf(cb, x0, x1, level, skiptop,
- y0, x0c, x1c, b0, b1, &nr) < 0)
- goto done;
- }
- }
- else if (xml_diff2cbuf(cb, x0c, x1c, level+1, 0) < 0)
- goto done;
+ if ((x = xml_find(xe, "value")) == NULL)
+ goto done;
+ if (clixon_xml2cbuf1(cb, x, 1, 1, prefix, -1, 1, 0, WITHDEFAULTS_REPORT_ALL) < 0)
+ goto done;
- }
- /* Get next */
- x0c = xml_child_iter(x0, &ix0c, CX_ELMNT);
- x1c = xml_child_iter(x1, &ix1c, CX_ELMNT);
- } /* for */
- ok:
- if (nr)
- cprintf(cb, "%*s%s>\n", level*PRETTYPRINT_INDENT, "", xml_name(x0));
- retval = 0;
- done:
- return retval;
+ retval = 0;
+done:
+ clixon_debug(CLIXON_DBG_XML | CLIXON_DBG_DETAIL, "retval: %d\n", retval);
+ return retval;
}
-/*! Print XML diff of two cxobj trees into a cbuf
- *
- * YANG dependent
- * Uses underlying XML diff algorithm with better result than clixon_compare_xmls
- * @param[out] cb CLIgen buffer
- * @param[in] x0 First XML tree
- * @param[in] x1 Second XML tree
- * @retval 0 Ok
- * @retval -1 Error
- * @cod
- * cbuf *cb = cbuf_new();
- * if (clixon_xml_diff2cbuf(cb, 0, x0, x1) < 0)
- * err();
- * cligen_output(stdout, "%s", cbuf_get(cb));
- * @endcode
- * @see xml_diff which returns diff sets
- * @see clixon_compare_xmls which uses files and is independent of YANG
- * @see clixon_text_diff2cbuf
- */
-int
-clixon_xml_diff2cbuf(cbuf *cb,
- cxobj *x0,
- cxobj *x1)
-{
- return xml_diff2cbuf(cb, x0, x1, 0, 1);
-}
diff --git a/test/test_cli_diff.sh b/test/test_cli_diff.sh
index 086543cde..8653c8bd0 100755
--- a/test/test_cli_diff.sh
+++ b/test/test_cli_diff.sh
@@ -73,8 +73,8 @@ module clixon-example {
}
}
}
- }
- }
+ }
+ }
}
EOF
@@ -142,7 +142,7 @@ new "add d"
expectpart "$($clixon_cli -1 -f $cfg set top section x table parameter d value 98)" 0 "^$"
new "check compare xml"
-expectpart "$($clixon_cli -1 -f $cfg show compare xml)" 0 "^+\ *" --not-- "\-" ""
+expectpart "$($clixon_cli -1 -f $cfg show compare xml)" 0 "^--- running" "^+++ candidate" "^/clixon-example:top" "^\+\ *" "^\+\ *a" "^\+\ *17" "^\+\ *" "^\+\ *" "^\+\ *b" "^\+\ *42" "^\+\ *" "^\+\ *" "^\+\ *d" "^\+\ *98" "^\+\ *"
new "check compare text"
expectpart "$($clixon_cli -1 -f $cfg show compare text)" 0 "^+\ *clixon-example:top {" --not-- "^\-" data
@@ -150,6 +150,9 @@ expectpart "$($clixon_cli -1 -f $cfg show compare text)" 0 "^+\ *clixon-example:
new "commit"
expectpart "$($clixon_cli -1 -f $cfg commit)" 0 "^$"
+new "check compare xml no-matches"
+expectpart "$($clixon_cli -1 -f $cfg show compare xml)" 0 "^$"
+
new "check running"
expectpart "$($clixon_cli -1 -f $cfg show config running)" 0 "^$"
@@ -166,8 +169,7 @@ new "check candidate"
expectpart "$($clixon_cli -1 -f $cfg show config candidate)" 0 "^$"
new "check compare xml b"
-echo "$clixon_cli -1 -f $cfg show compare xml"
-expectpart "$($clixon_cli -1 -f $cfg show compare xml)" 0 "" "^\-\ *" "^+\ *" "^\-\ *a" "^+\ *c" --not-- "^+\ *a" "^\-\ *c"
+expectpart "$($clixon_cli -1 -f $cfg show compare xml)" 0 "^/clixon-example:top/section=x/table/parameter=a" "^\-\ *" "^\-\ *a" "^\-\ *17" "^\-\ *" "^/clixon-example:top/section=x/table/parameter=c" "^\+\ *" "^\+\ *c" "^\+\ *72" "^\+\ *" "^/clixon-example:top/section=x/table/parameter=d/value" "\-\ *98" "^\+\ *99"
new "check compare text"
expectpart "$($clixon_cli -1 -f $cfg show compare text)" 0 "^\ *table {" "^\-\ *parameter a {" "^+\ *parameter c {" "^\-\ *value \"98\";" "^+\ *value \"99\";"
@@ -213,10 +215,11 @@ new "add d12 97"
expectpart "$($clixon_cli -1 -f $cfg set top section y multi parameter d1 d2 value 97)" 0 "^$"
new "check compare multi xml"
-expectpart "$($clixon_cli -1 -f $cfg show compare xml)" 0 "^\-\ *a1" "^\-\ *a2" "^\-\ *17" "^\-\ *18" "^+\ *c1" "^+\ *c2" "^+\ *72" "^+\ *73" "^+\ *97" "^\-\ *99" --not-- "98"
+expectpart "$($clixon_cli -1 -f $cfg show compare xml)" 0 "^/clixon-example:top/section=y/multi/parameter=a1,a2" "^\-\ *" "^\-\ *a1" "^\-\ *a2" "^\-\ *17" "^\-\ *18" "^\-\ *" "^\/clixon-example:top/section=y/multi/parameter=c1,c2" "^\+\ *" "^\+\ *c1" "^\+\ *c2" "^\+\ *72" "^\+\ *73" "^\+\ *" "^\/clixon-example:top/section=y/multi/parameter=d1,d2/value=97" "^\+\ *97" "^/clixon-example:top/section=y/multi/parameter=d1,d2/value=99" "^\-\ *99"
new "check compare multi text"
expectpart "$($clixon_cli -1 -f $cfg show compare text)" 0 "^\-\ *parameter a1 a2 {" "^\-\ *17" "^\-\ *18" "^+\ *parameter c1 c2 {" "^+\ *72" "^+\ *73" "^+\ *97" "^\-\ *99" "parameter d1 d2 {" --not-- "parameter b1 b2 {"
+
# XXX --not-- "^+\ *value \["
# NYI: json, cli
diff --git a/test/test_order.sh b/test/test_order.sh
index 80ac8daf9..7fe710ec1 100755
--- a/test/test_order.sh
+++ b/test/test_order.sh
@@ -462,7 +462,7 @@ new "check ordered-by-user: a b c d"
expecteof_netconf "$clixon_netconf -qef $cfg" 0 "$DEFAULTHELLO" "" "" "abcd"
new "show compare xml"
-expectpart "$($clixon_cli -1 -f $cfg show compare xml)" 0 "\-\ *e" --not-- "a" "b" "c" "d" "+ e"
+expectpart "$($clixon_cli -1 -f $cfg show compare xml)" 0 "\+\ *b" "\+\ *c" "\+\ *d" "\-\ *e" "\-\ *b" "\-\ *c" "\-\ *d"
new "show compare curly"
expectpart "$($clixon_cli -1 -f $cfg show compare text)" 0 "\-\ *order-example:y0" "\- e" --not-- "+ order-example:y0" "\- a" "+ e"