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

[PATCH 3/5] refactor userdiff textconv code

From
Jeff King <peff@peff.net>
Date
Oct 24, 2008, 02:53 UTC
Message-ID
<20081024025330.GC2831@coredump.intra.peff.net>
In-Reply-To
<20081024024631.GA20365@coredump.intra.peff.net>

The initial implementation inserted itself at the level of fill_mmfile. That is, the diff_filespec always contained the actual file data, but we set up the xdl mmfile with the fake data. This had several disadvantages:

 - fill_mmfile gets called from several places, but we don't
   necessarily want all of them to see the textconv'd
   version (e.g., whitespace checking should probably
   consider it binary)
 - the filespec itself carried no information about
   binaryness. If we have textconv'd it, then it is no
   longer binary and we need to mark that somehow (which
   lets us avoid having to manually set the filetype to
   non-binary in the diff driver config)

This patch moves the text conversion to a diff_filespec_textconv function; this function can be called to insert the text-converted contents of the file into the filespec. These contents will survive through any diff_populate_filespec calls, meaning that it is safe to pass the resulting filespec to other diff functions which will look at the content.

We now turn on the text conversion only for actual diffs, not diffstats or whitespace checking. We may eventually want it for other formats, too, but we will be conservative for now.

Signed-off-by: Jeff King <peff@peff.net>
---
I think this is much cleaner. I have a nagging worry that a
text-converted filespec might live longer than I expect. Maybe it would
make sense to free the filespec data after the diff has been generated
(and then further populate_filespec calls would just restore the
original data).

Also, I'm happy to hear comments on which functionality should get text-converted. I think I like seeing the --stat report the binary changes.

 diff.c                   |   51 +++++++++++++++++++++++++++++++++++----------
 diffcore.h               |    1 +
 t/t4030-diff-textconv.sh |    6 +---
 3 files changed, 42 insertions(+), 16 deletions(-)
diff --git a/diff.c b/diff.c
index d1fd594..89bd2ff 100644
--- a/diff.c
+++ b/diff.c
@@ -284,6 +284,36 @@ static void emit_rewrite_diff(const char *name_a,
 		copy_file_with_prefix(o->file, '+', two->data, two->size, new, reset);
 }
 
+static int diff_filespec_textconv(struct diff_filespec *one)
+{
+	size_t size;
+	char *buf;
+
+	if (one->data_is_textconv)
+		return 0;
+
+	if (!DIFF_FILE_VALID(one))
+		return 0;
+
+	diff_filespec_load_driver(one);
+	if (!one->driver->textconv)
+		return 0;
+
+	if (diff_populate_filespec(one, 0) < 0)
+		return -1;
+
+	buf = run_textconv(one->driver->textconv, one, &size);
+	if (!buf)
+		return -1;
+
+	diff_free_filespec_blob(one);
+	one->data = buf;
+	one->size = size;
+	one->should_free = 1;
+	one->data_is_textconv = 1;
+	return 0;
+}
+
 static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one)
 {
 	if (!DIFF_FILE_VALID(one)) {
@@ -294,18 +324,8 @@ static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one)
 	else if (diff_populate_filespec(one, 0))
 		return -1;
 
-	diff_filespec_load_driver(one);
-	if (one->driver->textconv) {
-		size_t size;
-		mf->ptr = run_textconv(one->driver->textconv, one, &size);
-		if (!mf->ptr)
-			return -1;
-		mf->size = size;
-	}
-	else {
-		mf->ptr = one->data;
-		mf->size = one->size;
-	}
+	mf->ptr = one->data;
+	mf->size = one->size;
 	return 0;
 }
 
@@ -1292,6 +1312,8 @@ static void diff_filespec_load_driver(struct diff_filespec *one)
 
 int diff_filespec_is_binary(struct diff_filespec *one)
 {
+	if (one->data_is_textconv)
+		return 0;
 	if (one->is_binary == -1) {
 		diff_filespec_load_driver(one);
 		if (one->driver->binary != -1)
@@ -1387,6 +1409,10 @@ static void builtin_diff(const char *name_a,
 		}
 	}
 
+	if (diff_filespec_textconv(one) < 0 ||
+	    diff_filespec_textconv(two) < 0)
+			die("unable to read files to diff");
+
 	if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
 		die("unable to read files to diff");
 
@@ -1778,6 +1804,7 @@ void diff_free_filespec_blob(struct diff_filespec *s)
 		s->should_free = s->should_munmap = 0;
 		s->data = NULL;
 	}
+	s->data_is_textconv = 0;
 }
 
 void diff_free_filespec_data(struct diff_filespec *s)
diff --git a/diffcore.h b/diffcore.h
index 713cca7..33aebc2 100644
--- a/diffcore.h
+++ b/diffcore.h
@@ -42,6 +42,7 @@ struct diff_filespec {
 #define DIFF_FILE_VALID(spec) (((spec)->mode) != 0)
 	unsigned should_free : 1; /* data should be free()'ed */
 	unsigned should_munmap : 1; /* data should be munmap()'ed */
+	unsigned data_is_textconv : 1;
 
 	struct userdiff_driver *driver;
 	/* data should be considered "binary"; -1 means "don't know yet" */
diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh
index d0d7691..28d3640 100755
--- a/t/t4030-diff-textconv.sh
+++ b/t/t4030-diff-textconv.sh
@@ -51,7 +51,7 @@ test_expect_success 'setup textconv filter' '
 	git config diff.foo.textconv "$PWD"/hexdump
 '
 
-test_expect_failure 'diff produces text' '
+test_expect_success 'diff produces text' '
 	git diff HEAD^ HEAD >diff &&
 	find_diff <diff >actual &&
 	test_cmp expect.text actual
@@ -63,14 +63,12 @@ test_expect_success 'diff-tree produces binary' '
 	test_cmp expect.binary actual
 '
 
-test_expect_failure 'log produces text' '
+test_expect_success 'log produces text' '
 	git log -1 -p >log &&
 	find_diff <log >actual &&
 	test_cmp expect.text actual
 '
 
-# actually passes, but only because textconv is broken
-# and its failure mode happens to be the same as success
 test_expect_failure 'format-patch produces binary' '
 	git format-patch --no-binary --stdout HEAD^ >patch &&
 	find_diff <patch >actual &&
-- 
1.6.0.3.518.gdb328.dirty
Previous: Jeff KingNext: Johannes Sixt
Message 34 of 85 in “Implementation of a "textconv" filter for easy custom diff.”
  1. Matthieu MoySep 28, 2008
  2. Facility to have multiple kinds of drivers for diff.Matthieu Moy, Sep 28, 2008
  3. Implement run_command_to_buf (spawn a process and reads its stdout)Matthieu Moy, Sep 28, 2008
  4. Implement a textconv filter for "git diff"Matthieu Moy, Sep 28, 2008
  5. Document the textconv filter.Matthieu Moy, Sep 28, 2008
  6. Add a basic test for the textconv filter.Matthieu Moy, Sep 28, 2008
  7. Johannes SixtSep 28, 2008
  8. Matthieu MoySep 28, 2008
  9. Jeff KingSep 28, 2008
  10. Matthieu MoySep 28, 2008
  11. Jeff KingSep 28, 2008
  12. Jeff KingSep 28, 2008
  13. Matthieu MoySep 28, 2008
  14. Jeff KingSep 28, 2008
  15. Matthieu MoySep 30, 2008
  16. Jeff KingSep 30, 2008
  17. 0/4 diff text conversion filterJeff King, Oct 5, 2008
  18. 1/4 t4012: use test_cmp instead of cmpJeff King, Oct 5, 2008
  19. 2/4 diff: unify external diff and funcname parsing codeJeff King, Oct 5, 2008
  20. 3/4 diff: introduce diff.<driver>.binaryJeff King, Oct 5, 2008
  21. Johannes SixtOct 7, 2008
  22. Jeff KingOct 7, 2008
  23. Johannes SixtOct 7, 2008
  24. Junio C HamanoOct 12, 2008
  25. Jeff KingOct 13, 2008
  26. Junio C HamanoOct 13, 2008
  27. Jeff KingOct 13, 2008
  28. Johannes SixtOct 13, 2008
  29. Junio C HamanoOct 13, 2008
  30. Matthieu MoyOct 13, 2008
  31. Jeff KingOct 24, 2008
  32. 1/5 diff: add missing static declarationJeff King, Oct 24, 2008
  33. 2/5 add userdiff textconv testsJeff King, Oct 24, 2008
  34. 3/5 refactor userdiff textconv codeJeff King, Oct 24, 2008
  35. Johannes SixtOct 24, 2008
  36. Jeff KingOct 24, 2008
  37. Jeff KingOct 24, 2008
  38. Johannes SixtOct 24, 2008
  39. Jeff KingOct 24, 2008
  40. Junio C HamanoOct 24, 2008
  41. Jeff KingOct 24, 2008
  42. Jeff KingOct 24, 2008
  43. Jeff KingOct 25, 2008
  44. 1/7 diff: add missing static declarationJeff King, Oct 25, 2008
  45. 2/7 add userdiff textconv testsJeff King, Oct 25, 2008
  46. 3/7 textconv: assume text-converted contents are not binaryJeff King, Oct 25, 2008
  47. 4/7 textconv: don't convert for every operationJeff King, Oct 25, 2008
  48. Junio C HamanoOct 25, 2008
  49. Jeff KingOct 25, 2008
  50. Junio C HamanoOct 25, 2008
  51. Jeff KingOct 25, 2008
  52. Junio C HamanoOct 25, 2008
  53. Junio C HamanoOct 25, 2008
  54. Jeff KingOct 26, 2008
  55. Jeff KingOct 26, 2008
  56. 1/8 diff: add missing static declarationJeff King, Oct 26, 2008
  57. 2/8 document the diff driver textconv featureJeff King, Oct 26, 2008
  58. 3/8 add userdiff textconv testsJeff King, Oct 26, 2008
  59. 4/8 refactor userdiff textconv codeJeff King, Oct 26, 2008
  60. 5/8 userdiff: require explicitly allowing textconvJeff King, Oct 26, 2008
  61. 6/8 only textconv regular filesJeff King, Oct 26, 2008
  62. 7/8 wt-status: load diff ui configJeff King, Oct 26, 2008
  63. Junio C HamanoOct 27, 2008
  64. Jeff KingOct 27, 2008
  65. 8/8 enable textconv for diff in verbose status/commitJeff King, Oct 26, 2008
  66. 5/7 userdiff: require explicitly allowing textconvJeff King, Oct 25, 2008
  67. 6/7 document the diff driver textconv featureJeff King, Oct 25, 2008
  68. 7/7 only textconv regular filesJeff King, Oct 25, 2008
  69. 4/5 userdiff: require explicitly allowing textconvJeff King, Oct 24, 2008
  70. Johannes SixtOct 24, 2008
  71. 5/5 document the diff driver textconv featureJeff King, Oct 24, 2008
  72. Johannes SixtOct 24, 2008
  73. 4/4 diff: add filter for converting binary to textJeff King, Oct 5, 2008
  74. Jakub NarebskiOct 5, 2008
  75. Johannes SixtOct 6, 2008
  76. Jeff KingOct 6, 2008
  77. Johannes SixtOct 6, 2008
  78. Matthieu MoyOct 6, 2008
  79. Jeff KingOct 7, 2008
  80. Johannes SixtOct 7, 2008
  81. Jeff KingOct 7, 2008
  82. Matthieu MoyOct 7, 2008
  83. Jeff KingOct 7, 2008
  84. Johannes SixtOct 7, 2008
  85. Jeff KingOct 13, 2008

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.