Browse Source

Diff implementation + colorize

Serj Kalichev 1 year ago
parent
commit
c7a1f92645
7 changed files with 231 additions and 38 deletions
  1. 1 0
      src/pline.h
  2. 8 0
      src/plugin.c
  3. 13 4
      src/private.h
  4. 99 34
      src/show.c
  5. 7 0
      src/sr_copypaste.c
  6. 94 0
      src/syms.c
  7. 9 0
      xml/sysrepo.xml

+ 1 - 0
src/pline.h

@@ -115,6 +115,7 @@ typedef enum {
 	PPARSE_FIRST_KEY_W_STMT		= 0x00000001,
 	PPARSE_MULTI_KEYS_W_STMT	= 0x00000002,
 	PPARSE_JUNIPER_SHOW		= 0x00010000,
+	PPARSE_COLORIZE			= 0x00008000,
 } pparse_flags_e;
 
 

+ 8 - 0
src/plugin.c

@@ -79,6 +79,7 @@ int kplugin_sysrepo_init(kcontext_t *context)
 	kplugin_add_syms(plugin, ksym_new("srp_rollback", srp_rollback));
 	kplugin_add_syms(plugin, ksym_new("srp_show", srp_show));
 	kplugin_add_syms(plugin, ksym_new("srp_show_running", srp_show_running));
+	kplugin_add_syms(plugin, ksym_new("srp_diff", srp_diff));
 	kplugin_add_syms(plugin, ksym_new("srp_deactivate", srp_deactivate));
 
 	// User-data initialization
@@ -185,6 +186,13 @@ static uint32_t parse_plugin_conf(const char *conf, uint32_t default_flags)
 			flags = flags & (~(uint32_t)PPARSE_MULTI_KEYS_W_STMT);
 	}
 
+	if ((val = faux_ini_find(ini, "Colorize"))) {
+		if (faux_str_cmp(val, "y") == 0)
+			flags = flags | PPARSE_COLORIZE;
+		else if (faux_str_cmp(val, "n") == 0)
+			flags = flags & (~(uint32_t)PPARSE_COLORIZE);
+	}
+
 	faux_ini_free(ini);
 
 	return flags;

+ 13 - 4
src/private.h

@@ -57,19 +57,28 @@ int srp_commit(kcontext_t *context);
 int srp_rollback(kcontext_t *context);
 int srp_show(kcontext_t *context);
 int srp_show_running(kcontext_t *context);
+int srp_diff(kcontext_t *context);
 int srp_deactivate(kcontext_t *context);
 
-// Sysrepo copy-paste
-int sr_ly_module_is_internal(const struct lys_module *ly_mod);
-int sr_module_is_internal(const struct lys_module *ly_mod);
-
 // Plugin's user-data service functions
 uint32_t srp_udata_flags(kcontext_t *context);
 faux_argv_t *srp_udata_path(kcontext_t *context);
 void srp_udata_set_path(kcontext_t *context, faux_argv_t *path);
 
 // Private
+enum diff_op {
+    DIFF_OP_CREATE,
+    DIFF_OP_DELETE,
+    DIFF_OP_REPLACE,
+    DIFF_OP_NONE,
+};
+
 bool_t show_xpath(sr_session_ctx_t *sess, const char *xpath, uint32_t flags);
+void show_subtree(const struct lyd_node *nodes_list, size_t level,
+	enum diff_op op, uint32_t flags);
+
+// Sysrepo copy-paste
+int sr_module_is_internal(const struct lys_module *ly_mod);
 
 C_DECL_END
 

+ 99 - 34
src/show.c

@@ -22,12 +22,17 @@
 #define JUN(flags) (flags & PPARSE_JUNIPER_SHOW)
 
 
-static void show_container(const struct lyd_node *node, size_t level, uint32_t flags);
-static void show_list(const struct lyd_node *node, size_t level, uint32_t flags);
-static void show_leaf(const struct lyd_node *node, size_t level, uint32_t flags);
-static void show_leaflist(const struct lyd_node *node, size_t level, uint32_t flags);
-static void show_node(const struct lyd_node *node, size_t level, uint32_t flags);
-static void show_subtree(const struct lyd_node *nodes_list, size_t level, uint32_t flags);
+static void show_container(const struct lyd_node *node, size_t level,
+	enum diff_op op, uint32_t flags);
+static void show_list(const struct lyd_node *node, size_t level,
+	enum diff_op op, uint32_t flags);
+static void show_leaf(const struct lyd_node *node, size_t level,
+	enum diff_op op, uint32_t flags);
+static void show_leaflist(const struct lyd_node *node, size_t level,
+	enum diff_op op, uint32_t flags);
+static void show_node(const struct lyd_node *node, size_t level,
+	enum diff_op op, uint32_t flags);
+static enum diff_op str2diff_op(const char *str);
 
 
 static char *get_value(const struct lyd_node *node)
@@ -74,20 +79,50 @@ static char *get_value(const struct lyd_node *node)
 }
 
 
-static void show_container(const struct lyd_node *node, size_t level, uint32_t flags)
+static const char *diff_prefix(enum diff_op op, uint32_t flags)
+{
+	bool_t c = flags & PPARSE_COLORIZE;
+
+	if (DIFF_OP_CREATE == op)
+		return c ? "\x1b[32m+" : "+";
+	else if (DIFF_OP_DELETE == op)
+		return c ? "\x1b[31m-" : "-";
+	else if (DIFF_OP_REPLACE == op)
+		return c ? "\x1b[33m=" : "=";
+
+	return "";
+}
+
+
+static const char *diff_suffix(enum diff_op op, uint32_t flags)
+{
+	if (flags & PPARSE_COLORIZE)
+		return "\x1b[0m";
+
+	return "";
+}
+
+
+static void show_container(const struct lyd_node *node, size_t level,
+	enum diff_op op, uint32_t flags)
 {
 	if (!node)
 		return;
 
-	printf("%*s%s%s\n", (int)(level * LEVEL_SPACES_NUM), "",
-		node->schema->name, JUN(flags) ? " {" : "");
-	show_subtree(lyd_child(node), level + 1, flags);
+	printf("%s%*s%s%s%s\n", diff_prefix(op, flags),
+		(int)(level * LEVEL_SPACES_NUM), "",
+		node->schema->name, JUN(flags) ? " {" : "",
+		diff_suffix(op, flags));
+	show_subtree(lyd_child(node), level + 1, op, flags);
 	if (JUN(flags))
-		printf("%*s%s\n", (int)(level * LEVEL_SPACES_NUM), "", "}");
+		printf("%s%*s%s%s\n", diff_prefix(op, flags),
+			(int)(level * LEVEL_SPACES_NUM), "", "}",
+			diff_suffix(op, flags));
 }
 
 
-static void show_list(const struct lyd_node *node, size_t level, uint32_t flags)
+static void show_list(const struct lyd_node *node, size_t level,
+	enum diff_op op, uint32_t flags)
 {
 	size_t keys_num = 0;
 	const struct lyd_node *iter = NULL;
@@ -96,7 +131,8 @@ static void show_list(const struct lyd_node *node, size_t level, uint32_t flags)
 	if (!node)
 		return;
 
-	printf("%*s%s", (int)(level * LEVEL_SPACES_NUM), "", node->schema->name);
+	printf("%s%*s%s", diff_prefix(op, flags),
+		(int)(level * LEVEL_SPACES_NUM), "", node->schema->name);
 
 	LY_LIST_FOR(lyd_child(node), iter) {
 		char *value = NULL;
@@ -113,14 +149,17 @@ static void show_list(const struct lyd_node *node, size_t level, uint32_t flags)
 		faux_str_free(value);
 		first_key = BOOL_FALSE;
 	}
-	printf("%s\n", JUN(flags) ? " {" : "");
-	show_subtree(lyd_child(node), level + 1, flags);
+	printf("%s%s\n", JUN(flags) ? " {" : "", diff_suffix(op, flags));
+	show_subtree(lyd_child(node), level + 1, op, flags);
 	if (JUN(flags))
-		printf("%*s%s\n", (int)(level * LEVEL_SPACES_NUM), "", "}");
+		printf("%s%*s%s%s\n", diff_prefix(op, flags),
+			(int)(level * LEVEL_SPACES_NUM), "", "}",
+			diff_suffix(op, flags));
 }
 
 
-static void show_leaf(const struct lyd_node *node, size_t level, uint32_t flags)
+static void show_leaf(const struct lyd_node *node, size_t level,
+	enum diff_op op, uint32_t flags)
 {
 	struct lysc_node_leaf *leaf = (struct lysc_node_leaf *)node;
 
@@ -129,7 +168,8 @@ static void show_leaf(const struct lyd_node *node, size_t level, uint32_t flags)
 	if (node->schema->flags & LYS_KEY)
 		return;
 
-	printf("%*s%s", (int)(level * LEVEL_SPACES_NUM), "", node->schema->name);
+	printf("%s%*s%s", diff_prefix(op, flags),
+		(int)(level * LEVEL_SPACES_NUM), "", node->schema->name);
 
 	leaf = (struct lysc_node_leaf *)node->schema;
 	if (leaf->type->basetype != LY_TYPE_EMPTY) {
@@ -138,11 +178,12 @@ static void show_leaf(const struct lyd_node *node, size_t level, uint32_t flags)
 		faux_str_free(value);
 	}
 
-	printf("%s\n", JUN(flags) ? ";" : "");
+	printf("%s%s\n", JUN(flags) ? ";" : "", diff_suffix(op, flags));
 }
 
 
-static void show_leaflist(const struct lyd_node *node, size_t level, uint32_t flags)
+static void show_leaflist(const struct lyd_node *node, size_t level,
+	enum diff_op op, uint32_t flags)
 {
 	char *value = NULL;
 
@@ -150,15 +191,20 @@ static void show_leaflist(const struct lyd_node *node, size_t level, uint32_t fl
 		return;
 
 	value = get_value(node);
-	printf("%*s%s %s%s\n", (int)(level * LEVEL_SPACES_NUM), "", node->schema->name,
-		value, JUN(flags) ? ";" : "");
+	printf("%s%*s%s %s%s%s\n", diff_prefix(op, flags),
+		(int)(level * LEVEL_SPACES_NUM), "", node->schema->name,
+		value, JUN(flags) ? ";" : "",
+		diff_suffix(op, flags));
 	faux_str_free(value);
 }
 
 
-static void show_node(const struct lyd_node *node, size_t level, uint32_t flags)
+static void show_node(const struct lyd_node *node, size_t level,
+	enum diff_op op, uint32_t flags)
 {
 	const struct lysc_node *schema = NULL;
+	struct lyd_meta *meta = NULL;
+	enum diff_op cur_op = op;
 
 	if (!node)
 		return;
@@ -173,21 +219,25 @@ static void show_node(const struct lyd_node *node, size_t level, uint32_t flags)
 	if (!(schema->flags & LYS_CONFIG_W))
 		return;
 
+	meta = lyd_find_meta(node->meta, NULL, "yang:operation");
+	if (meta)
+		cur_op = str2diff_op(lyd_get_meta_value(meta));
+
 	// Container
 	if (schema->nodetype & LYS_CONTAINER) {
-		show_container((const struct lyd_node *)node, level, flags);
+		show_container(node, level, cur_op, flags);
 
 	// List
 	} else if (schema->nodetype & LYS_LIST) {
-		show_list((const struct lyd_node *)node, level, flags);
+		show_list(node, level, cur_op, flags);
 
 	// Leaf
 	} else if (schema->nodetype & LYS_LEAF) {
-		show_leaf((const struct lyd_node *)node, level, flags);
+		show_leaf(node, level, cur_op, flags);
 
 	// Leaf-list
 	} else if (schema->nodetype & LYS_LEAFLIST) {
-		show_leaflist((const struct lyd_node *)node, level, flags);
+		show_leaflist(node, level, cur_op, flags);
 
 	} else {
 		return;
@@ -195,7 +245,8 @@ static void show_node(const struct lyd_node *node, size_t level, uint32_t flags)
 }
 
 
-static void show_sorted_list(faux_list_t *list, size_t level, uint32_t flags)
+static void show_sorted_list(faux_list_t *list, size_t level,
+	enum diff_op op, uint32_t flags)
 {
 	faux_list_node_t *iter = NULL;
 	const struct lyd_node *lyd = NULL;
@@ -205,7 +256,7 @@ static void show_sorted_list(faux_list_t *list, size_t level, uint32_t flags)
 
 	iter = faux_list_head(list);
 	while ((lyd = (const struct lyd_node *)faux_list_each(&iter)))
-		show_node(lyd, level, flags);
+		show_node(lyd, level, op, flags);
 }
 
 
@@ -258,7 +309,8 @@ static int leaflist_compare(const void *first, const void *second)
 }
 
 
-static void show_subtree(const struct lyd_node *nodes_list, size_t level, uint32_t flags)
+void show_subtree(const struct lyd_node *nodes_list, size_t level,
+	enum diff_op op, uint32_t flags)
 {
 	const struct lyd_node *iter = NULL;
 	faux_list_t *list = NULL;
@@ -274,7 +326,7 @@ static void show_subtree(const struct lyd_node *nodes_list, size_t level, uint32
 				faux_list_add(list, (void *)iter);
 				continue;
 			}
-			show_sorted_list(list, level, flags);
+			show_sorted_list(list, level, op, flags);
 			faux_list_free(list);
 			list = NULL;
 			saved_lysc = NULL;
@@ -295,11 +347,11 @@ static void show_subtree(const struct lyd_node *nodes_list, size_t level, uint32
 			continue;
 		}
 
-		show_node(iter, level, flags);
+		show_node(iter, level, op, flags);
 	}
 
 	if (list) {
-		show_sorted_list(list, level, flags);
+		show_sorted_list(list, level, op, flags);
 		faux_list_free(list);
 	}
 }
@@ -322,8 +374,21 @@ bool_t show_xpath(sr_session_ctx_t *sess, const char *xpath, uint32_t flags)
 		nodes_list = data->tree;
 	}
 
-	show_subtree(nodes_list, 0, flags);
+	show_subtree(nodes_list, 0, DIFF_OP_NONE, flags);
 	sr_release_data(data);
 
 	return BOOL_TRUE;
 }
+
+
+static enum diff_op str2diff_op(const char *str)
+{
+	if (!strcmp(str, "create"))
+		return DIFF_OP_CREATE;
+	else if (!strcmp(str, "delete"))
+		return DIFF_OP_DELETE;
+	else if (!strcmp(str, "replace"))
+		return DIFF_OP_REPLACE;
+
+	return DIFF_OP_NONE;
+}

+ 7 - 0
src/sr_copypaste.c

@@ -1,6 +1,13 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
 #include <sysrepo.h>
 #include <sysrepo/xpath.h>
 
+#include "private.h"
+
 
 static int
 sr_ly_module_is_internal(const struct lys_module *ly_mod)

+ 94 - 0
src/syms.c

@@ -1032,3 +1032,97 @@ err:
 }
 
 
+int srp_diff(kcontext_t *context)
+{
+	int ret = -1;
+	pline_t *pline = NULL;
+	sr_conn_ctx_t *conn = NULL;
+	sr_session_ctx_t *sess1 = NULL;
+	sr_session_ctx_t *sess2 = NULL;
+	sr_data_t *data1 = NULL;
+	sr_data_t *data2 = NULL;
+	faux_argv_t *cur_path = NULL;
+	const char *xpath = NULL;
+	struct lyd_node *diff = NULL;
+
+	assert(context);
+
+	if (sr_connect(SR_CONN_DEFAULT, &conn))
+		return -1;
+	if (sr_session_start(conn, SR_DS_RUNNING, &sess1)) {
+		sr_disconnect(conn);
+		return -1;
+	}
+	if (sr_session_start(conn, SRP_REPO_EDIT, &sess2)) {
+		sr_disconnect(conn);
+		return -1;
+	}
+
+	cur_path = (faux_argv_t *)srp_udata_path(context);
+
+	if (kpargv_find(kcontext_pargv(context), "path") || cur_path) {
+		faux_argv_t *args = NULL;
+		pexpr_t *expr = NULL;
+
+		args = param2argv(cur_path, kcontext_pargv(context), "path");
+		pline = pline_parse(sess2, args, srp_udata_flags(context));
+		faux_argv_free(args);
+
+		if (pline->invalid) {
+			fprintf(stderr, "Invalid 'show' request\n");
+			goto err;
+		}
+
+		if (faux_list_len(pline->exprs) > 1) {
+			fprintf(stderr, "Can't process more than one object\n");
+			goto err;
+		}
+
+		if (!(expr = (pexpr_t *)faux_list_data(faux_list_head(pline->exprs)))) {
+			fprintf(stderr, "Can't get expression\n");
+			goto err;
+		}
+		if (!(expr->pat & PT_EDIT)) {
+			fprintf(stderr, "Illegal expression for 'show' operation\n");
+			goto err;
+		}
+		if (!expr->xpath) {
+			fprintf(stderr, "Empty expression for 'show' operation\n");
+			goto err;
+		}
+		xpath = expr->xpath;
+	}
+
+	if (!xpath)
+		xpath = "/*";
+
+	if (sr_get_data(sess1, xpath, 0, 0, 0, &data1) != SR_ERR_OK) {
+		fprintf(stderr, "Can't get specified subtree\n");
+		goto err;
+	}
+	if (sr_get_data(sess2, xpath, 0, 0, 0, &data2) != SR_ERR_OK) {
+		fprintf(stderr, "Can't get specified subtree\n");
+		goto err;
+	}
+
+	if (lyd_diff_siblings(data1->tree, data2->tree, 0, &diff) != LY_SUCCESS) {
+		fprintf(stderr, "Can't generate diff\n");
+		goto err;
+	}
+
+	show_subtree(diff, 0, DIFF_OP_NONE, srp_udata_flags(context));
+	lyd_free_siblings(diff);
+
+	ret = 0;
+err:
+	if (data1)
+		sr_release_data(data1);
+	if (data2)
+		sr_release_data(data2);
+
+	pline_free(pline);
+	sr_disconnect(conn);
+
+	return ret;
+}
+

+ 9 - 0
xml/sysrepo.xml

@@ -8,6 +8,7 @@
 	JuniperLikeShow = y
 	FirstKeyWithStatement = n
 	MultiKeysWithStatement = y
+	Colorize = y
 </PLUGIN>
 
 
@@ -191,6 +192,14 @@
 		<ACTION sym="srp_show@sysrepo"/>
 	</ENTRY>
 
+	<ENTRY name="diff" help="Show diff to running-config" mode="sequence">
+		<ENTRY name="COMMAND" purpose="ptype" ref="/COMMAND"/>
+		<ENTRY name="path" min="0" max="100">
+			<ENTRY name="PLINE_EDIT" purpose="ptype" ref="/PLINE_EDIT"/>
+		</ENTRY>
+		<ACTION sym="srp_diff@sysrepo"/>
+	</ENTRY>
+
 <!--
 	<ENTRY name="deactivate" help="Deactivate statement" mode="sequence">
 		<ENTRY name="COMMAND" purpose="ptype" ref="/COMMAND"/>