summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenrik Grubbström <grubba@grubba.org>2010-04-06 14:46:44 +0200
committerJunio C Hamano <gitster@pobox.com>2010-04-10 18:36:00 -0700
commitec775c41dc4bb7382ebbbb61ede59e63846b3644 (patch)
tree0a9084ef6cdf11d8a3b627d07b2aeb934ab61984
parent969f9d73228f233aff071a0d07ba28afdb79dbc4 (diff)
downloadgit-ec775c41dc4bb7382ebbbb61ede59e63846b3644.tar.gz
attr: Expand macros immediately when encountered.
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> Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r--attr.c32
-rwxr-xr-xt/t0003-attributes.sh9
2 files changed, 29 insertions, 12 deletions
diff --git a/attr.c b/attr.c
index 53cf07e913..7467baf2d6 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 bd9c8deb4c..53bd7fcc4a 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 &&