Skip to content

Commit

Permalink
attr: Expand macros immediately when encountered.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Henrik Grubbström authored and Junio C Hamano committed Apr 11, 2010
1 parent 969f9d7 commit ec775c4
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 12 deletions.
32 changes: 20 additions & 12 deletions attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
}

Expand All @@ -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)
Expand Down
9 changes: 9 additions & 0 deletions t/t0003-attributes.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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" &&
Expand All @@ -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
'
Expand All @@ -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
'

Expand All @@ -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 &&
Expand Down

0 comments on commit ec775c4

Please sign in to comment.