{"thread":{"id":"23308","subject":"[PATCH v2 0/3] Handling of gitattribute macro expansion","startedAt":"2010-04-02T19:33:38Z","lastAt":"2010-04-02T19:33:41Z","messageCount":4,"participants":["Henrik Grubbström (Grubba)"],"isPatch":true,"patchVersion":2,"patchTotal":3},"messages":[{"id":"138451","messageId":"cover.1270236242.git.grubba@grubba.org","threadId":"23308","inReplyTo":null,"subject":"[PATCH v2 0/3] Handling of gitattribute macro expansion","fromName":"Henrik Grubbström (Grubba)","fromEmail":"grubba@grubba.org","sentAt":"2010-04-02T19:33:38Z","receivedAt":"2010-04-02T19:33:38Z","isPatch":true,"sender":{"key":"grubba@grubba.org","avatar":"https://avatars.githubusercontent.com/u/1169458?v=4"},"body":"Second try at handling macro expansion in gitattribute files\nin a deterministic way.\n\nHenrik Grubbström (Grubba) (3):\n  Attr: Fixed debug output for macro expansion.\n  Attr: Allow multiple changes to an attribute on the same line.\n  Attr: Expand macros immediately when encountered.\n\n attr.c                |   38 ++++++++++++++++++++++++--------------\n t/t0003-attributes.sh |   15 +++++++++++++++\n 2 files changed, 39 insertions(+), 14 deletions(-)\n"},{"id":"138453","messageId":"ca1f7f974d72a036dd8369309d487bbd047a8e2d.1270236242.git.grubba@grubba.org","threadId":"23308","inReplyTo":"cover.1270236242.git.grubba@grubba.org","subject":"[PATCH 1/3] Attr: Fixed debug output for macro expansion.","fromName":"Henrik Grubbström (Grubba)","fromEmail":"grubba@grubba.org","sentAt":"2010-04-02T19:33:39Z","receivedAt":"2010-04-02T19:33:39Z","isPatch":true,"sender":{"key":"grubba@grubba.org","avatar":"https://avatars.githubusercontent.com/u/1169458?v=4"},"body":"When debug_set() was called during macro expansion, it\nreceived a pointer to a struct git_attr rather than a\nstring.\n\nSigned-off-by: Henrik Grubbström <grubba@grubba.org>\n---\n attr.c |    4 +++-\n 1 files changed, 3 insertions(+), 1 deletions(-)\n\ndiff --git a/attr.c b/attr.c\nindex f5346ed..5c6464e 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -605,7 +605,9 @@ static int fill_one(const char *what, struct match_attr *a, int rem)\n \t\tconst char *v = a->state[i].setto;\n \n \t\tif (*n == ATTR__UNKNOWN) {\n-\t\t\tdebug_set(what, a->u.pattern, attr, v);\n+\t\t\tdebug_set(what,\n+\t\t\t\t  a->is_macro?a->u.attr->name:a->u.pattern,\n+\t\t\t\t  attr, v);\n \t\t\t*n = v;\n \t\t\trem--;\n \t\t}\n-- \n1.7.0.3.316.g33b5e\n"},{"id":"138452","messageId":"def1a3522057cf3a172b60d8e41fc552e728b5af.1270236242.git.grubba@grubba.org","threadId":"23308","inReplyTo":"cover.1270236242.git.grubba@grubba.org","subject":"[PATCH v2 2/3] Attr: Allow multiple changes to an attribute on the same line.","fromName":"Henrik Grubbström (Grubba)","fromEmail":"grubba@grubba.org","sentAt":"2010-04-02T19:33:40Z","receivedAt":"2010-04-02T19:33:40Z","isPatch":true,"sender":{"key":"grubba@grubba.org","avatar":"https://avatars.githubusercontent.com/u/1169458?v=4"},"body":"When using macros it isn't inconceivable to have an attribute\nbeing set by a macro, and then being reset explicitly. Always\nuse the latest value.\n\nSigned-off-by: Henrik Grubbström <grubba@grubba.org>\n---\n attr.c                |    2 +-\n t/t0003-attributes.sh |    6 ++++++\n 2 files changed, 7 insertions(+), 1 deletions(-)\n\ndiff --git a/attr.c b/attr.c\nindex 5c6464e..968fb8b 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -599,7 +599,7 @@ static int fill_one(const char *what, struct match_attr *a, int rem)\n \tstruct git_attr_check *check = check_all_attr;\n \tint i;\n \n-\tfor (i = 0; 0 < rem && i < a->num_attr; i++) {\n+\tfor (i = a->num_attr - 1; 0 < rem && 0 <= i; i--) {\n \t\tstruct git_attr *attr = a->state[i].attr;\n \t\tconst char **n = &(check[attr->attr_nr].value);\n \t\tconst char *v = a->state[i].setto;\ndiff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh\nindex 1c77192..bd9c8de 100755\n--- a/t/t0003-attributes.sh\n+++ b/t/t0003-attributes.sh\n@@ -22,6 +22,8 @@ test_expect_success 'setup' '\n \t(\n \t\techo \"f\ttest=f\"\n \t\techo \"a/i test=a/i\"\n+\t\techo \"onoff test -test\"\n+\t\techo \"offon -test test\"\n \t) >.gitattributes &&\n \t(\n \t\techo \"g test=a/g\" &&\n@@ -44,6 +46,8 @@ test_expect_success 'attribute test' '\n \tattr_check b/g unspecified &&\n \tattr_check a/b/h a/b/h &&\n \tattr_check a/b/d/g \"a/b/d/*\"\n+\tattr_check onoff unset\n+\tattr_check offon set\n \n '\n \n@@ -58,6 +62,8 @@ a/b/g: test: a/b/g\n b/g: test: unspecified\n a/b/h: test: a/b/h\n a/b/d/g: test: a/b/d/*\n+onoff: test: unset\n+offon: test: set\n EOF\n \n \tsed -e \"s/:.*//\" < expect | git check-attr --stdin test > actual &&\n-- \n1.7.0.3.316.g33b5e\n"},{"id":"138454","messageId":"11d7b9c938dd84cfff7d12798ac402ee8a28c91b.1270236242.git.grubba@grubba.org","threadId":"23308","inReplyTo":"cover.1270236242.git.grubba@grubba.org","subject":"[PATCH v2 3/3] Attr: Expand macros immediately when encountered.","fromName":"Henrik Grubbström (Grubba)","fromEmail":"grubba@grubba.org","sentAt":"2010-04-02T19:33:41Z","receivedAt":"2010-04-02T19:33:41Z","isPatch":true,"sender":{"key":"grubba@grubba.org","avatar":"https://avatars.githubusercontent.com/u/1169458?v=4"},"body":"When using macros it is otherwise hard to know whether an\nattribute set by the macro should override an already set\nattribute. Consider the following .gitattributes file:\n\n[attr]mybinary\tbinary -ident\n*\t\tident\nfoo.bin\t\tmybinary\nbar.bin\t\tmybinary ident\n\nWithout this patch both foo.bin and bar.bin will have\nthe ident attribute set, which is probably not what\nthe user expects. With this patch foo.bin will have an\nunset ident attribute, while bar.bin will have it set.\n\nSigned-off-by: Henrik Grubbström <grubba@grubba.org>\n---\n attr.c                |   32 ++++++++++++++++++++------------\n t/t0003-attributes.sh |    9 +++++++++\n 2 files changed, 29 insertions(+), 12 deletions(-)\n\ndiff --git a/attr.c b/attr.c\nindex 968fb8b..f90bb8e 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -594,6 +594,8 @@ static int path_matches(const char *pathname, int pathlen,\n \treturn fnmatch(pattern, pathname + baselen, FNM_PATHNAME) == 0;\n }\n \n+static int macroexpand_one(int attr_nr, int rem);\n+\n static int fill_one(const char *what, struct match_attr *a, int rem)\n {\n \tstruct git_attr_check *check = check_all_attr;\n@@ -610,6 +612,7 @@ static int fill_one(const char *what, struct match_attr *a, int rem)\n \t\t\t\t  attr, v);\n \t\t\t*n = v;\n \t\t\trem--;\n+\t\t\trem = macroexpand_one(attr->attr_nr, rem);\n \t\t}\n \t}\n \treturn rem;\n@@ -631,19 +634,27 @@ static int fill(const char *path, int pathlen, struct attr_stack *stk, int rem)\n \treturn rem;\n }\n \n-static int macroexpand(struct attr_stack *stk, int rem)\n+static int macroexpand_one(int attr_nr, int rem)\n {\n+\tstruct attr_stack *stk;\n+\tstruct match_attr *a = NULL;\n \tint i;\n-\tstruct git_attr_check *check = check_all_attr;\n \n-\tfor (i = stk->num_matches - 1; 0 < rem && 0 <= i; i--) {\n-\t\tstruct match_attr *a = stk->attrs[i];\n-\t\tif (!a->is_macro)\n-\t\t\tcontinue;\n-\t\tif (check[a->u.attr->attr_nr].value != ATTR__TRUE)\n-\t\t\tcontinue;\n+\tif (check_all_attr[attr_nr].value != ATTR__TRUE)\n+\t\treturn rem;\n+\n+\tfor (stk = attr_stack; !a && stk; stk = stk->prev)\n+\t\tfor (i = stk->num_matches - 1; !a && 0 <= i; i--) {\n+\t\t\tstruct match_attr *ma = stk->attrs[i];\n+\t\t\tif (!ma->is_macro)\n+\t\t\t\tcontinue;\n+\t\t\tif (ma->u.attr->attr_nr == attr_nr)\n+\t\t\t\ta = ma;\n+\t\t}\n+\n+\tif (a)\n \t\trem = fill_one(\"expand\", a, rem);\n-\t}\n+\n \treturn rem;\n }\n \n@@ -668,9 +679,6 @@ int git_checkattr(const char *path, int num, struct git_attr_check *check)\n \tfor (stk = attr_stack; 0 < rem && stk; stk = stk->prev)\n \t\trem = fill(path, pathlen, stk, rem);\n \n-\tfor (stk = attr_stack; 0 < rem && stk; stk = stk->prev)\n-\t\trem = macroexpand(stk, rem);\n-\n \tfor (i = 0; i < num; i++) {\n \t\tconst char *value = check_all_attr[check[i].attr->attr_nr].value;\n \t\tif (value == ATTR__UNKNOWN)\ndiff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh\nindex bd9c8de..53bd7fc 100755\n--- a/t/t0003-attributes.sh\n+++ b/t/t0003-attributes.sh\n@@ -20,10 +20,12 @@ test_expect_success 'setup' '\n \n \tmkdir -p a/b/d a/c &&\n \t(\n+\t\techo \"[attr]notest !test\"\n \t\techo \"f\ttest=f\"\n \t\techo \"a/i test=a/i\"\n \t\techo \"onoff test -test\"\n \t\techo \"offon -test test\"\n+\t\techo \"no notest\"\n \t) >.gitattributes &&\n \t(\n \t\techo \"g test=a/g\" &&\n@@ -32,6 +34,7 @@ test_expect_success 'setup' '\n \t(\n \t\techo \"h test=a/b/h\" &&\n \t\techo \"d/* test=a/b/d/*\"\n+\t\techo \"d/yes notest\"\n \t) >a/b/.gitattributes\n \n '\n@@ -48,6 +51,9 @@ test_expect_success 'attribute test' '\n \tattr_check a/b/d/g \"a/b/d/*\"\n \tattr_check onoff unset\n \tattr_check offon set\n+\tattr_check no unspecified\n+\tattr_check a/b/d/no \"a/b/d/*\"\n+\tattr_check a/b/d/yes unspecified\n \n '\n \n@@ -64,6 +70,9 @@ a/b/h: test: a/b/h\n a/b/d/g: test: a/b/d/*\n onoff: test: unset\n offon: test: set\n+no: test: unspecified\n+a/b/d/no: test: a/b/d/*\n+a/b/d/yes: test: unspecified\n EOF\n \n \tsed -e \"s/:.*//\" < expect | git check-attr --stdin test > actual &&\n-- \n1.7.0.3.316.g33b5e\n"}]}