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

[PATCH v4 8/8] attr: Expand macros immediately when encountered.

From
Henrik Grubbström (Grubba) <grubba@grubba.org>
Date
Apr 6, 2010, 12:46 UTC
Message-ID
<81e89ac808ac41d2e6914635974fa45564f73279.1270554878.git.grubba@grubba.org>
In-Reply-To
<cover.1270554878.git.grubba@grubba.org>

When using macros it is otherwise hard to know whether an attribute set by the macro should override an already set attribute. Consider the following .gitattributes file:

[attr]mybinary binary -ident * ident foo.bin mybinary bar.bin mybinary ident

Without this patch both foo.bin and bar.bin will have the ident attribute set, which is probably not what the user expects. With this patch foo.bin will have an unset ident attribute, while bar.bin will have it set.

Signed-off-by: Henrik Grubbström <grubba@grubba.org>
---
FYI: The use case I attempted was:
 *.c			crlf ident
 [attr]foreign_ident	-ident block_commit=Remove-foreign_ident-attribute.
 src/version.c		foreign_ident
Which currently causes src/version.c to have the ident attribute set.
 attr.c                |   32 ++++++++++++++++++++------------
 t/t0003-attributes.sh |    9 +++++++++
 2 files changed, 29 insertions(+), 12 deletions(-)
diff --git a/attr.c b/attr.c
index 968fb8b..f90bb8e 100644
--- a/attr.c
+++ b/attr.c
@@ -594,6 +594,8 @@ static int path_matches(const char *pathname, int pathlen,
 	return fnmatch(pattern, pathname + baselen, FNM_PATHNAME) == 0;
 }
 
+static int macroexpand_one(int attr_nr, int rem);
+
 static int fill_one(const char *what, struct match_attr *a, int rem)
 {
 	struct git_attr_check *check = check_all_attr;
@@ -610,6 +612,7 @@ static int fill_one(const char *what, struct match_attr *a, int rem)
 				  attr, v);
 			*n = v;
 			rem--;
+			rem = macroexpand_one(attr->attr_nr, rem);
 		}
 	}
 	return rem;
@@ -631,19 +634,27 @@ static int fill(const char *path, int pathlen, struct attr_stack *stk, int rem)
 	return rem;
 }
 
-static int macroexpand(struct attr_stack *stk, int rem)
+static int macroexpand_one(int attr_nr, int rem)
 {
+	struct attr_stack *stk;
+	struct match_attr *a = NULL;
 	int i;
-	struct git_attr_check *check = check_all_attr;
 
-	for (i = stk->num_matches - 1; 0 < rem && 0 <= i; i--) {
-		struct match_attr *a = stk->attrs[i];
-		if (!a->is_macro)
-			continue;
-		if (check[a->u.attr->attr_nr].value != ATTR__TRUE)
-			continue;
+	if (check_all_attr[attr_nr].value != ATTR__TRUE)
+		return rem;
+
+	for (stk = attr_stack; !a && stk; stk = stk->prev)
+		for (i = stk->num_matches - 1; !a && 0 <= i; i--) {
+			struct match_attr *ma = stk->attrs[i];
+			if (!ma->is_macro)
+				continue;
+			if (ma->u.attr->attr_nr == attr_nr)
+				a = ma;
+		}
+
+	if (a)
 		rem = fill_one("expand", a, rem);
-	}
+
 	return rem;
 }
 
@@ -668,9 +679,6 @@ int git_checkattr(const char *path, int num, struct git_attr_check *check)
 	for (stk = attr_stack; 0 < rem && stk; stk = stk->prev)
 		rem = fill(path, pathlen, stk, rem);
 
-	for (stk = attr_stack; 0 < rem && stk; stk = stk->prev)
-		rem = macroexpand(stk, rem);
-
 	for (i = 0; i < num; i++) {
 		const char *value = check_all_attr[check[i].attr->attr_nr].value;
 		if (value == ATTR__UNKNOWN)
diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh
index bd9c8de..53bd7fc 100755
--- a/t/t0003-attributes.sh
+++ b/t/t0003-attributes.sh
@@ -20,10 +20,12 @@ test_expect_success 'setup' '
 
 	mkdir -p a/b/d a/c &&
 	(
+		echo "[attr]notest !test"
 		echo "f	test=f"
 		echo "a/i test=a/i"
 		echo "onoff test -test"
 		echo "offon -test test"
+		echo "no notest"
 	) >.gitattributes &&
 	(
 		echo "g test=a/g" &&
@@ -32,6 +34,7 @@ test_expect_success 'setup' '
 	(
 		echo "h test=a/b/h" &&
 		echo "d/* test=a/b/d/*"
+		echo "d/yes notest"
 	) >a/b/.gitattributes
 
 '
@@ -48,6 +51,9 @@ test_expect_success 'attribute test' '
 	attr_check a/b/d/g "a/b/d/*"
 	attr_check onoff unset
 	attr_check offon set
+	attr_check no unspecified
+	attr_check a/b/d/no "a/b/d/*"
+	attr_check a/b/d/yes unspecified
 
 '
 
@@ -64,6 +70,9 @@ a/b/h: test: a/b/h
 a/b/d/g: test: a/b/d/*
 onoff: test: unset
 offon: test: set
+no: test: unspecified
+a/b/d/no: test: a/b/d/*
+a/b/d/yes: test: unspecified
 EOF
 
 	sed -e "s/:.*//" < expect | git check-attr --stdin test > actual &&
-- 
1.7.0.3.316.g33b5e
Previous: Henrik Grubbström (Grubba)
Message 14 of 14 in “Attribute and conversion patches”
  1. 0/8 Attribute and conversion patchesHenrik Grubbström (Grubba), Apr 6, 2010
  2. 1/8 convert: Safer handling of $Id$ contraction.Henrik Grubbström (Grubba), Apr 6, 2010
  3. 2/8 convert: Keep foreign $Id$ on checkout.Henrik Grubbström (Grubba), Apr 6, 2010
  4. 3/8 status: Added missing calls to diff_unmodified_pair() in format_callbacks.Henrik Grubbström (Grubba), Apr 6, 2010
  5. Junio C HamanoApr 10, 2010
  6. Henrik GrubbströmApr 12, 2010
  7. Junio C HamanoApr 10, 2010
  8. 4/8 diff: Filter files that have changed only due to conversion changes.Henrik Grubbström (Grubba), Apr 6, 2010
  9. Junio C HamanoApr 10, 2010
  10. Henrik GrubbströmApr 16, 2010
  11. 5/8 convert: Added core.refilteronadd feature.Henrik Grubbström (Grubba), Apr 6, 2010
  12. 6/8 attr: Fixed debug output for macro expansion.Henrik Grubbström (Grubba), Apr 6, 2010
  13. 7/8 attr: Allow multiple changes to an attribute on the same line.Henrik Grubbström (Grubba), Apr 6, 2010
  14. 8/8 attr: Expand macros immediately when encountered.Henrik Grubbström (Grubba), Apr 6, 2010

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.