diff mbox series

[uci] delta: allow clearing delta path

Message ID 20210110182634.368461-1-me@irrelefant.net
State New
Headers show
Series [uci] delta: allow clearing delta path | expand

Commit Message

Leonardo Mörlein Jan. 10, 2021, 6:26 p.m. UTC
The delta path can now be cleared from libuci, lua/uci and the cli. Only
the savedir remains in the delta path after clearing. This enables safely
committing new changes from scripts without also comitting potentially
existing uncommited user changes.

This introduces:
- the cli option '-x'.
- the lua method cur:clear_delta().
- the libuci function uci_clear_delta_path().
- a test case.

To safely commit changes from shell scripts, use:

    local tmp="$(mktemp -d)"
    uci -P "$tmp" config.section.var=val
    uci -P "$tmp" -x commit
    rm -rf "$tmp"

Signed-off-by: Leonardo Mörlein <me@irrelefant.net>
---
 cli.c                                         |  7 +++-
 delta.c                                       | 14 ++++++++
 lua/uci.c                                     | 10 ++++++
 .../cli.options.delta.commit2.result          |  4 +++
 .../cli.options.delta.commit3.result          |  5 +++
 tests/shunit2/tests.d/090_cli_options         | 33 +++++++++++++++++++
 uci.h                                         |  6 ++++
 7 files changed, 78 insertions(+), 1 deletion(-)
 create mode 100644 tests/shunit2/references/cli.options.delta.commit2.result
 create mode 100644 tests/shunit2/references/cli.options.delta.commit3.result
diff mbox series

Patch

diff --git a/cli.c b/cli.c
index 267437d..cee7baa 100644
--- a/cli.c
+++ b/cli.c
@@ -167,6 +167,7 @@  static void uci_usage(void)
 		"\t-N         don't name unnamed sections\n"
 		"\t-p <path>  add a search path for config change files\n"
 		"\t-P <path>  add a search path for config change files and use as default\n"
+		"\t-x         clear search path except for default\n"
 		"\t-q         quiet mode (don't print error messages)\n"
 		"\t-s         force strict mode (stop on parser errors, default)\n"
 		"\t-S         disable strict mode\n"
@@ -706,7 +707,7 @@  int main(int argc, char **argv)
 		return 1;
 	}
 
-	while((c = getopt(argc, argv, "c:d:f:LmnNp:P:sSqX")) != -1) {
+	while((c = getopt(argc, argv, "c:d:f:LmnNp:P:xsSqX")) != -1) {
 		switch(c) {
 			case 'c':
 				uci_set_confdir(ctx, optarg);
@@ -743,6 +744,10 @@  int main(int argc, char **argv)
 			case 'N':
 				ctx->flags &= ~UCI_FLAG_EXPORT_NAME;
 				break;
+			case 'x':
+				uci_clear_delta_path(ctx);
+				flags &= ~CLI_FLAG_NOCOMMIT;
+				break;
 			case 'p':
 				uci_add_delta_path(ctx, optarg);
 				break;
diff --git a/delta.c b/delta.c
index d8bd3a6..33a24a3 100644
--- a/delta.c
+++ b/delta.c
@@ -124,6 +124,20 @@  int uci_set_savedir(struct uci_context *ctx, const char *dir)
 	return 0;
 }
 
+int uci_clear_delta_path(struct uci_context *ctx)
+{
+	struct uci_element *e, *tmp;
+	UCI_HANDLE_ERR(ctx);
+
+	uci_foreach_element_safe(&ctx->delta_path, tmp, e) {
+		if (strcmp(e->name, ctx->savedir)) {
+			uci_list_del(&e->list);
+			uci_free_element(e);
+		}
+	}
+	return 0;
+}
+
 int uci_add_delta_path(struct uci_context *ctx, const char *dir)
 {
 	struct uci_element *e;
diff --git a/lua/uci.c b/lua/uci.c
index 196a25b..70c2b72 100644
--- a/lua/uci.c
+++ b/lua/uci.c
@@ -938,6 +938,15 @@  uci_lua_add_delta(lua_State *L)
 	return uci_push_status(L, ctx, false);
 }
 
+static int
+uci_lua_clear_delta(lua_State *L)
+{
+	struct uci_context *ctx;
+	ctx = find_context(L, NULL);
+	uci_clear_delta_path(ctx);
+	return uci_push_status(L, ctx, false);
+}
+
 static int
 uci_lua_set_savedir(lua_State *L)
 {
@@ -1039,6 +1048,7 @@  static const luaL_Reg uci[] = {
 	{ "foreach", uci_lua_foreach },
 	{ "add_history", uci_lua_add_delta },
 	{ "add_delta", uci_lua_add_delta },
+	{ "clear_delta", uci_lua_clear_delta },
 	{ "get_confdir", uci_lua_get_confdir },
 	{ "set_confdir", uci_lua_set_confdir },
 	{ "get_savedir", uci_lua_get_savedir },
diff --git a/tests/shunit2/references/cli.options.delta.commit2.result b/tests/shunit2/references/cli.options.delta.commit2.result
new file mode 100644
index 0000000..5beb9f7
--- /dev/null
+++ b/tests/shunit2/references/cli.options.delta.commit2.result
@@ -0,0 +1,4 @@ 
+
+config sectype 'sec0'
+	list li0 '1'
+
diff --git a/tests/shunit2/references/cli.options.delta.commit3.result b/tests/shunit2/references/cli.options.delta.commit3.result
new file mode 100644
index 0000000..3119b6f
--- /dev/null
+++ b/tests/shunit2/references/cli.options.delta.commit3.result
@@ -0,0 +1,5 @@ 
+
+config sectype 'sec0'
+	list li0 '1'
+	list li0 '0'
+
diff --git a/tests/shunit2/tests.d/090_cli_options b/tests/shunit2/tests.d/090_cli_options
index 55920a2..0fbec69 100644
--- a/tests/shunit2/tests.d/090_cli_options
+++ b/tests/shunit2/tests.d/090_cli_options
@@ -44,3 +44,36 @@  delta.sec0.li0+='1'" "$cmdoutput"
 	rm -f "$config_delta"
 }
 
+test_clear_delta() {
+	local new_savedir="$TMP_DIR/new_savedir"
+	local config_delta="$CONFIG_DIR/delta"
+	local cmdoutput
+
+	# commit normal changes
+	touch "$config_delta"
+	$UCI set delta.sec0=sectype
+	$UCI commit
+
+	# add uncommited changes
+	$UCI add_list delta.sec0.li0=0
+
+	# save new changes in "$new_savedir"
+	mkdir -p "$new_savedir"
+	touch "$new_savedir/delta"
+	$UCI -P "$new_savedir" set delta.sec0=sectype
+	$UCI -P "$new_savedir" add_list delta.sec0.li0=1
+
+	# only commit changes in $new_savedir but not normal changes
+	$UCI -P "$new_savedir" -x commit
+	assertTrue "$?"
+	assertSameFile "$REF_DIR/cli.options.delta.commit2.result" "$config_delta"
+
+	# do normal commit
+	$UCI commit
+	assertTrue "$?"
+	assertSameFile "$REF_DIR/cli.options.delta.commit3.result" "$config_delta"
+
+	rm -rf "$new_savedir"
+	rm -f "$config_delta"
+}
+
diff --git a/uci.h b/uci.h
index b385e2b..e644d3a 100644
--- a/uci.h
+++ b/uci.h
@@ -277,6 +277,12 @@  extern int uci_set_confdir(struct uci_context *ctx, const char *dir);
  */
 extern int uci_add_delta_path(struct uci_context *ctx, const char *dir);
 
+/**
+ * uci_clear_delta_path: remove all paths from the delta path except for savedir
+ * @ctx: uci context
+ */
+extern int uci_clear_delta_path(struct uci_context *ctx);
+
 /**
  * uci_revert: revert all changes to a config item
  * @ctx: uci context