diff --git a/CHANGELOG.md b/CHANGELOG.md
index b80e4c9e..5fd3cc39 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -28,6 +28,8 @@ Expected: February 2024
### C/CLI-API changes on existing features
Developers may need to change their code
+* New `clixon-lib@2024-01-01.yang` revision
+ * Replaced container creators to grouping/uses
* Changed ca_errmsg callback to a more generic variant
* Includes all error, log and debug messages
* See [Customized NETCONF error message](https://github.com/clicon/clixon/issues/454)
diff --git a/lib/clixon/clixon_xml.h b/lib/clixon/clixon_xml.h
index 9fdb3a6b..2aced51e 100644
--- a/lib/clixon/clixon_xml.h
+++ b/lib/clixon/clixon_xml.h
@@ -170,10 +170,10 @@ typedef struct xml cxobj; /* struct defined in clicon_xml.c */
*
* @param[in] x XML node
* @param[in] arg General-purpose argument
- * @retval -1 Error, aborted at first error encounter, return -1 to end user
- * @retval 0 OK, continue
- * @retval 1 Abort, dont continue with others, return 1 to end user
* @retval 2 Locally abort this subtree, continue with others
+ * @retval 1 Abort, dont continue with others, return 1 to end user
+ * @retval 0 OK, continue
+ * @retval -1 Error, aborted at first error encounter, return -1 to end user
*/
typedef int (xml_applyfn_t)(cxobj *x, void *arg);
@@ -239,7 +239,6 @@ size_t xml_creator_len(cxobj *xn);
cvec *xml_creator_get(cxobj *xn);
int xml_creator_copy_one(cxobj *x0, cxobj *x1);
int xml_creator_copy_all(cxobj *x0, cxobj *x1);
-int xml_creator_print(FILE *f, cxobj *xn);
char *xml_value(cxobj *xn);
int xml_value_set(cxobj *xn, char *val);
diff --git a/lib/clixon/clixon_xml_map.h b/lib/clixon/clixon_xml_map.h
index 7d8d2c13..e3f84489 100644
--- a/lib/clixon/clixon_xml_map.h
+++ b/lib/clixon/clixon_xml_map.h
@@ -77,5 +77,6 @@ int xml_rpc_isaction(cxobj *xn);
int xml_find_action(cxobj *xn, int top, cxobj **xap);
int purge_tagged_nodes(cxobj *xn, char *ns, char *name, char *value, int keepnode);
int clixon_compare_xmls(cxobj *xc1, cxobj *xc2, enum format_enum format);
+int xml_creator_tree(cxobj *xt, cxobj **xcreator);
#endif /* _CLIXON_XML_MAP_H_ */
diff --git a/lib/src/clixon_xml.c b/lib/src/clixon_xml.c
index 7a211899..d06423b6 100644
--- a/lib/src/clixon_xml.c
+++ b/lib/src/clixon_xml.c
@@ -819,41 +819,6 @@ xml_creator_copy_all(cxobj *x0,
return retval;
}
-/*! Print XML and creator tags where they exists, apply help function
- *
- * @param[in] x XML tree
- * @param[in] arg FIle
- * @retval see xml_apply
- */
-static int
-creator_print_fn(cxobj *x,
- void *arg)
-{
- FILE *f = (FILE *)arg;
- cg_var *cv;
-
- if (x->x_creators == NULL)
- return 0;
- cv = NULL;
- while ((cv = cvec_each(x->x_creators, cv)) != NULL){
- fprintf(f, "%s ", cv_name_get(cv));
- }
- fprintf(f, ":\n");
- clixon_xml2file(f, x, 3, 1, NULL, cligen_output, 0, 0);
- return 2; /* Locally abort this subtree, continue with others */
-}
-
-/*! Print XML and creator tags where they exists recursively, for debugging
- *
- * @param[in] xn XML tree
- * @retval see xml_apply
- */
-int
-xml_creator_print(FILE *f,
- cxobj *xn)
-{
- return xml_apply0(xn, CX_ELMNT, creator_print_fn, f);
-}
/*! Get value of xnode
*
diff --git a/lib/src/clixon_xml_io.c b/lib/src/clixon_xml_io.c
index 5ee9b0be..a9ae7ab8 100644
--- a/lib/src/clixon_xml_io.c
+++ b/lib/src/clixon_xml_io.c
@@ -81,6 +81,9 @@
/* 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
*------------------------------------------------------------------------*/
@@ -1037,7 +1040,7 @@ xml_diff2cbuf_ordered_by_user(cbuf *cb,
* @see clixon_compare_xmls which uses files and is independent of YANG
* @see text_diff2cbuf
*/
-int
+static int
xml_diff2cbuf(cbuf *cb,
cxobj *x0,
cxobj *x1,
diff --git a/lib/src/clixon_xml_map.c b/lib/src/clixon_xml_map.c
index db1dd011..89bbffcd 100644
--- a/lib/src/clixon_xml_map.c
+++ b/lib/src/clixon_xml_map.c
@@ -2034,3 +2034,90 @@ clixon_compare_xmls(cxobj *xc1,
unlink(filename2);
return retval;
}
+
+/*! Add creator data to metadata xml object on the form name:xpath*
+ *
+ * Callback function type for xml_apply
+ * @param[in] x XML node
+ * @param[in] arg General-purpose argument
+ * @retval 2 Locally abort this subtree, continue with others
+ * @retval 1 Abort, dont continue with others, return 1 to end user
+ * @retval 0 OK, continue
+ * @retval -1 Error, aborted at first error encounter, return -1 to end user
+ * On the form:
+ *
+ * testA[name='foo']
+ * ...
+ * ...
+ *
+ */
+static int
+xml_creator_one(cxobj *x,
+ void *arg)
+{
+ int retval = -1;
+ cxobj *xmeta = (cxobj*)arg;
+ cxobj *xmc;
+ cvec *cvv;
+ cg_var *cv;
+ char *val;
+ cvec *nsc = NULL;
+ char *xpath = NULL;
+
+ if ((cvv = xml_creator_get(x)) == NULL){
+ retval = 0;
+ goto done;
+ }
+ /* Note this requires x to have YANG spec */
+ if (xml2xpath(x, nsc, 0, 0, &xpath) < 0)
+ goto done;
+ cv = NULL;
+ while ((cv = cvec_each(cvv, cv)) != NULL){
+ val = cv_name_get(cv);
+ /* Find existing entry where name is val */
+ xmc = NULL;
+ while ((xmc = xml_child_each(xmeta, xmc, CX_ELMNT)) != NULL){
+ if (strcmp(xml_find_body(xmc, "name"), val) == 0)
+ break;
+ }
+ if (xmc != NULL){
+ if (clixon_xml_parse_va(YB_NONE, NULL, &xmc, NULL, "%s", xpath) < 0)
+ goto done;
+ }
+ else {
+ if (clixon_xml_parse_va(YB_NONE, NULL, &xmeta, NULL,
+ "%s%s",
+ val, xpath) < 0)
+ goto done;
+ }
+ }
+ retval = 2;
+ done:
+ if (xpath)
+ free(xpath);
+ return retval;
+}
+
+/*! Create creator data tree on the form (name:xpath*)*
+ *
+ * @param[in] xt XML top-level node, where to look for creator attributes
+ * @param[out] xcreators Created XML tree on the form ...
+ * @retval 0 OK
+ * @retval -1 Error
+ */
+int
+xml_creator_tree(cxobj *xt,
+ cxobj **xcreators)
+{
+ int retval = -1;
+
+ if ((*xcreators = xml_new("creators", NULL, CX_ELMNT)) == NULL)
+ goto done;
+ if (xmlns_set(*xcreators, NULL, CLIXON_LIB_NS) < 0)
+ goto done;
+ if (xml_apply(xt, CX_ELMNT, xml_creator_one, *xcreators) < 0)
+ goto done;
+ retval = 0;
+ done:
+ return retval;
+}
diff --git a/test/config.sh.in b/test/config.sh.in
index aa0576a2..12a40d3f 100755
--- a/test/config.sh.in
+++ b/test/config.sh.in
@@ -76,7 +76,7 @@ DATASTORE_TOP="config"
# clixon yang revisions occuring in tests (see eg yang/clixon/Makefile.in)
CLIXON_AUTOCLI_REV="2023-09-01"
-CLIXON_LIB_REV="2023-11-01"
+CLIXON_LIB_REV="2024-01-01"
CLIXON_CONFIG_REV="2023-05-01"
CLIXON_RESTCONF_REV="2022-08-01"
CLIXON_EXAMPLE_REV="2022-11-01"
diff --git a/yang/clixon/Makefile.in b/yang/clixon/Makefile.in
index b5615e34..07ca2873 100644
--- a/yang/clixon/Makefile.in
+++ b/yang/clixon/Makefile.in
@@ -44,6 +44,7 @@ YANG_INSTALLDIR = @YANG_INSTALLDIR@
# Note: mirror these to test/config.sh.in
YANGSPECS = clixon-config@2023-11-01.yang # 6.5
YANGSPECS += clixon-lib@2023-11-01.yang # 6.5
+YANGSPECS += clixon-lib@2024-01-01.yang # 6.6
YANGSPECS += clixon-rfc5277@2008-07-01.yang
YANGSPECS += clixon-xml-changelog@2019-03-21.yang
YANGSPECS += clixon-restconf@2022-08-01.yang # 5.9
diff --git a/yang/clixon/clixon-lib@2023-05-01.yang b/yang/clixon/clixon-lib@2024-01-01.yang
similarity index 90%
rename from yang/clixon/clixon-lib@2023-05-01.yang
rename to yang/clixon/clixon-lib@2024-01-01.yang
index 04c689f5..6b46e019 100644
--- a/yang/clixon/clixon-lib@2023-05-01.yang
+++ b/yang/clixon/clixon-lib@2024-01-01.yang
@@ -68,6 +68,18 @@ module clixon-lib {
- objectexisted
";
+ revision 2024-01-01 {
+ description
+ "Moved container creators to grouping/uses
+ Released in 6.6.0";
+ }
+ revision 2023-11-01 {
+ description
+ "Added ignore-compare extension
+ Added creator meta configuration
+ Removed obsolete extension autocli-op
+ Released in 6.5.0";
+ }
revision 2023-05-01 {
description
"Restructured and extended stats rpc to schema mountpoints
@@ -179,7 +191,7 @@ module clixon-lib {
}
identity restconf {
description
- "RESTCONF either as HTTP/1 or /2, TLS or not, reverese proxy (eg fcgi/nginx) or native";
+ "RESTCONF either as HTTP/1 or /2, TLS or not, reverse proxy (eg fcgi/nginx) or native";
base ncm:transport;
}
identity cli {
@@ -187,20 +199,12 @@ module clixon-lib {
"A CLI session";
base ncm:transport;
}
- extension autocli-op {
- description
- "Takes an argument an operation defing how to modify the clispec at
- this point in the YANG tree for the automated generated CLI.
- Note that this extension is only used in clixon_cli.
- Operations is expected to be extended, but the following operations are defined:
- - hide This command is active but not shown by ? or TAB (meaning, it hides the auto-completion of commands)
- - hide-database This command hides the database
- - hide-database-auto-completion This command hides the database and the auto completion (meaning, this command acts as both commands above)
- Obsolete: use clixon-autocli:hide and clixon-autocli:hide-show instead";
- argument cliop;
- status obsolete;
+ extension ignore-compare {
+ description
+ "The object should be ignored when comparing device configs for equality.
+ One example is auto-created objects by the server, such as uid.
+ Another example is a plain-text password is changed to an encrypted by the server.";
}
-
md:annotation creator {
type string;
description
@@ -209,8 +213,26 @@ module clixon-lib {
create the same object. When such a service is deleted (or changed) one needs to keep
track of which service created what.
Limitations: only objects that are actually added or deleted.
- A sub-object wil not be noted";
+ A sub-object will not be noted";
}
+ grouping clixon-creators{
+ container creators{
+ config false;
+ description "Meta-data for creator attribute.";
+ list creator {
+ key name;
+ leaf name {
+ description "Name of creator / service (instance) name";
+ type string;
+ }
+ leaf-list path {
+ description "Path to object";
+ type string;
+ }
+ }
+ }
+ }
+ uses clixon-creators;
rpc debug {
description "Set debug level of backend.";
input {