git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v4 12/12] convert: add filter.<driver>.process shutdown command option

From
larsxschneider@gmail.com <larsxschneider@gmail.com>
Date
Aug 3, 2016, 16:42 UTC
Message-ID
<20160803164225.46355-13-larsxschneider@gmail.com>
In-Reply-To
<20160803164225.46355-1-larsxschneider@gmail.com>
From: Lars Schneider <larsxschneider@gmail.com>

Add the "shutdown" capability to the `filter.<driver>.process` filter protocol. If a filter supports this capability then Git will send the "shutdown" command and wait until the filter answers. This gives the filter the opportunity to perform cleanup tasks. Afterwards the filter is expected to exit.

Signed-off-by: Lars Schneider <larsxschneider@gmail.com>
---
 Documentation/gitattributes.txt | 12 ++++++-
 convert.c                       | 35 ++++++++++++++++++++
 t/t0021-conversion.sh           | 71 +++++++++++++++++++++++++++++++++++++++++
 t/t0021/rot13-filter.pl         |  7 ++++
 4 files changed, 124 insertions(+), 1 deletion(-)
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 49514ab..5556cc0 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -400,7 +400,8 @@ packet:          git< git-filter-protocol\n
 packet:          git< version=2\n
 packet:          git< capabilities=clean smudge\n
 ------------------------
-Supported filter capabilities are "clean" and "smudge".
+Supported filter capabilities are "clean", "smudge", and
+"shutdown".
 
 Afterwards Git sends a command (based on the supported
 capabilities), the pathname of a file relative to the
@@ -453,6 +454,15 @@ After the filter has processed a blob it is expected to wait for
 the next command. When the Git process terminates, it will send
 a kill signal to the filter in that stage.
 
+If the filter supports the "shutdown" capability then Git will
+send the "shutdown" command and wait until the filter answers
+with "done". This gives the filter the opportunity to perform
+cleanup tasks. Afterwards the filter is expected to exit.
+------------------------
+packet:          git> command=shutdown\n
+packet:          git< result=success\n
+------------------------
+
 A long running filter demo implementation can be found in
 `t/t0021/rot13-filter.pl` located in the Git core repository.
 If you develop your own long running filter process then the
diff --git a/convert.c b/convert.c
index 130430a..41e3229 100644
--- a/convert.c
+++ b/convert.c
@@ -478,8 +478,10 @@ static int apply_single_file_filter(const char *path, const char *src, size_t le
 
 #define FILTER_CAPABILITIES_CLEAN    (1u<<0)
 #define FILTER_CAPABILITIES_SMUDGE   (1u<<1)
+#define FILTER_CAPABILITIES_SHUTDOWN (1u<<2)
 #define FILTER_SUPPORTS_CLEAN(type)  ((type) & FILTER_CAPABILITIES_CLEAN)
 #define FILTER_SUPPORTS_SMUDGE(type) ((type) & FILTER_CAPABILITIES_SMUDGE)
+#define FILTER_SUPPORTS_SHUTDOWN(type) ((type) & FILTER_CAPABILITIES_SHUTDOWN)
 
 struct cmd2process {
 	struct hashmap_entry ent; /* must be the first member! */
@@ -520,6 +522,35 @@ static void kill_multi_file_filter(struct hashmap *hashmap, struct cmd2process *
 	free(entry);
 }
 
+void shutdown_multi_file_filter(pid_t pid)
+{
+	int did_fail;
+	struct cmd2process *entry;
+	struct hashmap_iter iter;
+	static const char shutdown[] = "command=shutdown\n";
+	char *result = NULL;
+
+	if (!cmd_process_map_initialized)
+		return;
+
+	hashmap_iter_init(&cmd_process_map, &iter);
+	while ((entry = hashmap_iter_next(&iter))) {
+		if (entry->process.pid == pid &&
+			FILTER_SUPPORTS_SHUTDOWN(entry->supported_capabilities)
+		) {
+			did_fail = direct_packet_write_data(
+				entry->process.in, shutdown, strlen(shutdown), 1);
+			if (!did_fail)
+				result = packet_read_line(entry->process.out, NULL);
+			close(entry->process.in);
+			close(entry->process.out);
+
+			if (did_fail || !result || strcmp(result, "result=success"))
+				error("shutdown of external filter '%s' failed", entry->cmd);
+		}
+	}
+}
+
 static struct cmd2process *start_multi_file_filter(struct hashmap *hashmap, const char *cmd)
 {
 	int did_fail;
@@ -543,6 +574,8 @@ static struct cmd2process *start_multi_file_filter(struct hashmap *hashmap, cons
 	process->use_shell = 1;
 	process->in = -1;
 	process->out = -1;
+	process->clean_on_exit = 1;
+	process->clean_on_exit_handler = shutdown_multi_file_filter;
 
 	if (start_command(process)) {
 		error("cannot fork to run external filter '%s'", cmd);
@@ -575,6 +608,8 @@ static struct cmd2process *start_multi_file_filter(struct hashmap *hashmap, cons
 				entry->supported_capabilities |= FILTER_CAPABILITIES_CLEAN;
 			} else if (!strcmp(requested, "smudge")) {
 				entry->supported_capabilities |= FILTER_CAPABILITIES_SMUDGE;
+			} else if (!strcmp(requested, "shutdown")) {
+				entry->supported_capabilities |= FILTER_CAPABILITIES_SHUTDOWN;
 			} else {
 				warning(
 					"external filter '%s' requested unsupported filter capability '%s'",
diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index c1a22f4..613e370 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -417,6 +417,77 @@ test_expect_success PERL 'required process filter should filter data' '
 	)
 '
 
+test_expect_success PERL 'required process filter should filter data with shutdown' '
+	test_config_global filter.protocol.process "$TEST_DIRECTORY/t0021/rot13-filter.pl clean smudge shutdown" &&
+	test_config_global filter.protocol.required true &&
+	rm -rf repo &&
+	mkdir repo &&
+	(
+		cd repo &&
+		git init &&
+
+		echo "*.r filter=protocol" >.gitattributes &&
+		git add . &&
+		git commit . -m "test commit" &&
+		git branch empty &&
+
+		cat ../test.o >test.r &&
+		cat ../test2.o >test2.r &&
+
+		check_filter \
+			git add . \
+				<<-\EOF &&
+					1 IN: clean test.r 57 [OK] -- OUT: 57 [OK]
+					1 IN: clean test2.r 14 [OK] -- OUT: 14 [OK]
+					1 IN: shutdown -- [OK]
+					1 start
+					1 wrote filter header
+				EOF
+
+		check_filter_count_clean \
+			git commit . -m "test commit" \
+				<<-\EOF &&
+					x IN: clean test.r 57 [OK] -- OUT: 57 [OK]
+					x IN: clean test2.r 14 [OK] -- OUT: 14 [OK]
+					1 IN: shutdown -- [OK]
+					1 start
+					1 wrote filter header
+				EOF
+
+		rm -f test?.r testsubdir/test3-subdir.r &&
+
+		check_filter_ignore_clean \
+			git checkout . \
+				<<-\EOF &&
+					start
+					wrote filter header
+					IN: smudge test2.r 14 [OK] -- OUT: 14 [OK]
+					IN: shutdown -- [OK]
+				EOF
+
+		check_filter_ignore_clean \
+			git checkout empty \
+				<<-\EOF &&
+					start
+					wrote filter header
+					IN: shutdown -- [OK]
+				EOF
+
+		check_filter_ignore_clean \
+			git checkout master \
+				<<-\EOF &&
+					start
+					wrote filter header
+					IN: smudge test.r 57 [OK] -- OUT: 57 [OK]
+					IN: smudge test2.r 14 [OK] -- OUT: 14 [OK]
+					IN: shutdown -- [OK]
+				EOF
+
+		check_rot13 ../test.o test.r &&
+		check_rot13 ../test2.o test2.r
+	)
+'
+
 test_expect_success PERL 'required process filter should filter smudge data and one-shot filter should clean' '
 	test_config_global filter.protocol.clean ./../rot13.sh &&
 	test_config_global filter.protocol.process "$TEST_DIRECTORY/t0021/rot13-filter.pl smudge" &&
diff --git a/t/t0021/rot13-filter.pl b/t/t0021/rot13-filter.pl
index ca6d5e4..654741b 100755
--- a/t/t0021/rot13-filter.pl
+++ b/t/t0021/rot13-filter.pl
@@ -84,6 +84,13 @@ while (1) {
     print $debug "IN: $command";
     $debug->flush();
 
+    if ( $command eq "shutdown" ) {
+        print $debug " -- [OK]";
+        $debug->flush();
+        packet_write("result=success\n");
+        exit();
+    }
+
     my ($pathname) = packet_read() =~ /^pathname=([^=]+)\n$/;
     print $debug " $pathname";
     $debug->flush();
-- 
2.9.0
Previous: larsxschneider@gmail.comNext: larsxschneider@gmail.com
Message 45 of 100 in “Git filter protocol”
  1. 00/10 Git filter protocollarsxschneider@gmail.com, Jul 29, 2016
  2. 01/10 pkt-line: extract set_packet_header()larsxschneider@gmail.com, Jul 29, 2016
  3. 02/10 pkt-line: add direct_packet_write() and direct_packet_write_data()larsxschneider@gmail.com, Jul 29, 2016
  4. 03/10 pkt-line: add packet_flush_gentle()larsxschneider@gmail.com, Jul 29, 2016
  5. 04/10 pkt-line: call packet_trace() only if a packet is actually sendlarsxschneider@gmail.com, Jul 29, 2016
  6. 05/10 pack-protocol: fix maximum pkt-line sizelarsxschneider@gmail.com, Jul 29, 2016
  7. 07/10 convert: quote filter names in error messageslarsxschneider@gmail.com, Jul 29, 2016
  8. 06/10 run-command: add clean_on_exit_handlerlarsxschneider@gmail.com, Jul 29, 2016
  9. 08/10 convert: modernize testslarsxschneider@gmail.com, Jul 29, 2016
  10. 09/10 convert: generate large test files only oncelarsxschneider@gmail.com, Jul 29, 2016
  11. 10/10 convert: add filter.<driver>.process optionlarsxschneider@gmail.com, Jul 29, 2016
  12. Johannes SixtJul 30, 2016
  13. Jakub NarębskiJul 30, 2016
  14. Jakub NarębskiJul 30, 2016
  15. Jakub NarębskiJul 30, 2016
  16. Jakub NarębskiJul 30, 2016
  17. Jakub NarębskiJul 30, 2016
  18. Jakub NarębskiJul 30, 2016
  19. Jakub NarębskiJul 31, 2016
  20. Lars SchneiderJul 31, 2016
  21. Torstem BögershausenJul 31, 2016
  22. Lars SchneiderJul 31, 2016
  23. Jakub NarębskiJul 31, 2016
  24. Jakub NarębskiJul 31, 2016
  25. Lars SchneiderAug 1, 2016
  26. Lars SchneiderAug 1, 2016
  27. Lars SchneiderAug 1, 2016
  28. Lars SchneiderAug 1, 2016
  29. Lars SchneiderAug 1, 2016
  30. Lars SchneiderAug 1, 2016
  31. Lars SchneiderAug 1, 2016
  32. Lars SchneiderAug 1, 2016
  33. Johannes SixtAug 2, 2016
  34. Lars SchneiderAug 2, 2016
  35. Torsten BögershausenAug 2, 2016
  36. Lars SchneiderAug 3, 2016
  37. 01/12 pkt-line: extract set_packet_header()larsxschneider@gmail.com, Aug 3, 2016
  38. 07/12 run-command: add clean_on_exit_handlerlarsxschneider@gmail.com, Aug 3, 2016
  39. 03/12 pkt-line: add packet_flush_gentle()larsxschneider@gmail.com, Aug 3, 2016
  40. 02/12 pkt-line: add direct_packet_write() and direct_packet_write_data()larsxschneider@gmail.com, Aug 3, 2016
  41. 08/12 convert: quote filter names in error messageslarsxschneider@gmail.com, Aug 3, 2016
  42. 05/12 pkt-line: add functions to read/write flush terminated packet streamslarsxschneider@gmail.com, Aug 3, 2016
  43. 09/12 convert: modernize testslarsxschneider@gmail.com, Aug 3, 2016
  44. 00/12 Git filter protocollarsxschneider@gmail.com, Aug 3, 2016
  45. 12/12 convert: add filter.<driver>.process shutdown command optionlarsxschneider@gmail.com, Aug 3, 2016
  46. 06/12 pack-protocol: fix maximum pkt-line sizelarsxschneider@gmail.com, Aug 3, 2016
  47. 04/12 pkt-line: call packet_trace() only if a packet is actually sendlarsxschneider@gmail.com, Aug 3, 2016
  48. 11/12 convert: add filter.<driver>.process optionlarsxschneider@gmail.com, Aug 3, 2016
  49. 10/12 convert: generate large test files only oncelarsxschneider@gmail.com, Aug 3, 2016
  50. Junio C HamanoAug 3, 2016
  51. Designing the filter process protocol (was: Re: [PATCH v3 10/10] convert: add filter.<driver>.process option)Jakub Narębski, Aug 3, 2016
  52. Jakub NarębskiAug 3, 2016
  53. Junio C HamanoAug 3, 2016
  54. Jakub NarębskiAug 3, 2016
  55. Jakub NarębskiAug 3, 2016
  56. Junio C HamanoAug 3, 2016
  57. Jeff KingAug 3, 2016
  58. Jeff KingAug 3, 2016
  59. Jeff KingAug 3, 2016
  60. Lars SchneiderAug 3, 2016
  61. Lars SchneiderAug 3, 2016
  62. Jeff KingAug 3, 2016
  63. Lars SchneiderAug 3, 2016
  64. Junio C HamanoAug 3, 2016
  65. Lars SchneiderAug 3, 2016
  66. Lars SchneiderAug 3, 2016
  67. Jeff KingAug 3, 2016
  68. Jakub NarębskiAug 3, 2016
  69. Jeff KingAug 3, 2016
  70. Lars SchneiderAug 3, 2016
  71. Jeff KingAug 3, 2016
  72. Jakub NarębskiAug 4, 2016
  73. Jakub NarębskiAug 4, 2016
  74. Junio C HamanoAug 4, 2016
  75. Junio C HamanoAug 4, 2016
  76. Lars SchneiderAug 5, 2016
  77. Lars SchneiderAug 5, 2016
  78. Lars SchneiderAug 5, 2016
  79. Lars SchneiderAug 5, 2016
  80. Lars SchneiderAug 5, 2016
  81. Lars SchneiderAug 5, 2016
  82. Lars SchneiderAug 5, 2016
  83. Lars SchneiderAug 5, 2016
  84. Junio C HamanoAug 5, 2016
  85. Lars SchneiderAug 5, 2016
  86. Junio C HamanoAug 5, 2016
  87. Torsten BögershausenAug 5, 2016
  88. Torsten BögershausenAug 5, 2016
  89. Lars SchneiderAug 5, 2016
  90. Lars SchneiderAug 5, 2016
  91. Junio C HamanoAug 5, 2016
  92. Jeff KingAug 5, 2016
  93. Jeff KingAug 6, 2016
  94. Lars SchneiderAug 6, 2016
  95. Lars SchneiderAug 6, 2016
  96. Lars SchneiderAug 6, 2016
  97. Torsten BögershausenAug 6, 2016
  98. Jeff KingAug 8, 2016
  99. Lars SchneiderAug 8, 2016
  100. Jeff KingAug 8, 2016

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.