Re: [PATCH 1/2] pathspec: allow querying for attributes
- From
- Jonathan Tan <jonathantanmy@google.com>
- Date
- Mar 9, 2017, 22:19 UTC
- Message-ID
- <e8ef511f-563b-8b22-d8c6-daec2291f2aa@google.com>
- In-Reply-To
- <20170309210756.105566-2-bmwill@google.com>
On 03/09/2017 01:07 PM, Brandon Williams wrote:
Show 18 quoted lines
> diff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.txt > index fc9320e59..5c32d1905 100644 > --- a/Documentation/glossary-content.txt > +++ b/Documentation/glossary-content.txt > @@ -384,6 +384,26 @@ full pathname may have special meaning: > + > Glob magic is incompatible with literal magic. > > +attr;; > +After `attr:` comes a space separated list of "attribute > +requirements", all of which must be met in order for the > +path to be considered a match; this is in addition to the > +usual non-magic pathspec pattern matching. > ++ > +Each of the attribute requirements for the path takes one of > +these forms: > + > +- "`ATTR`" requires that the attribute `ATTR` must be set.
As a relative newcomer to attributes, I was confused by the fact that "set" and "set to a value" is different (and likewise "unset" and "unspecified"). Maybe it's worthwhile including a link to "gitattributes" to explain the different (exclusive) states that an attribute can be in.
Show 8 quoted lines
> + > +- "`-ATTR`" requires that the attribute `ATTR` must be unset. > + > +- "`ATTR=VALUE`" requires that the attribute `ATTR` must be > + set to the string `VALUE`. > + > +- "`!ATTR`" requires that the attribute `ATTR` must be > + unspecified.
It would read better to me if you omitted "must" in all 4 bullet points (and it is redundant anyway with "requires"), but I don't feel too strongly about this.
Show 17 quoted lines
> diff --git a/pathspec.c b/pathspec.c
> index b961f00c8..583ed5208 100644
> --- a/pathspec.c
> +++ b/pathspec.c
> @@ -87,6 +89,72 @@ static void prefix_magic(struct strbuf *sb, int prefixlen, unsigned magic)
> strbuf_addf(sb, ",prefix:%d)", prefixlen);
> }
>
> +static void parse_pathspec_attr_match(struct pathspec_item *item, const char *value)
> +{
> + struct string_list_item *si;
> + struct string_list list = STRING_LIST_INIT_DUP;
> +
> + if (item->attr_check)
> + die(_("Only one 'attr:' specification is allowed."));
> +
> + if (!value || !strlen(value))You can write `!*value` instead of `!strlen(value)`.
> + die(_("attr spec must not be empty"));
> +
> + string_list_split(&list, value, ' ', -1);You could avoid some allocations by using the in-place variant (since value is a newly allocated string not used elsewhere) but it is probably not that important in this argument parsing case.
Show 6 quoted lines
> + string_list_remove_empty_items(&list, 0); > + > + item->attr_check = attr_check_alloc(); > + ALLOC_GROW(item->attr_match, > + item->attr_match_nr + list.nr, > + item->attr_match_alloc);
Is there a time when this function is called while item->attr_match_nr is not zero?
Show 46 quoted lines
> +
> + for_each_string_list_item(si, &list) {
> + size_t attr_len;
> + char *attr_name;
> + const struct git_attr *a;
> +
> + int j = item->attr_match_nr++;
> + const char *attr = si->string;
> + struct attr_match *am = &item->attr_match[j];
> +
> + switch (*attr) {
> + case '!':
> + am->match_mode = MATCH_UNSPECIFIED;
> + attr++;
> + attr_len = strlen(attr);
> + break;
> + case '-':
> + am->match_mode = MATCH_UNSET;
> + attr++;
> + attr_len = strlen(attr);
> + break;
> + default:
> + attr_len = strcspn(attr, "=");
> + if (attr[attr_len] != '=')
> + am->match_mode = MATCH_SET;
> + else {
> + am->match_mode = MATCH_VALUE;
> + am->value = xstrdup(&attr[attr_len + 1]);
> + if (strchr(am->value, '\\'))
> + die(_("attr spec values must not contain backslashes"));
> + }
> + break;
> + }
> +
> + attr_name = xmemdupz(attr, attr_len);
> + a = git_attr(attr_name);
> + if (!a)
> + die(_("invalid attribute name %s"), attr_name);
> +
> + attr_check_append(item->attr_check, a);
> +
> + free(attr_name);
> + }
> +
> + string_list_clear(&list, 0);
> + return;Redundant return?
Show 8 quoted lines
> @@ -544,6 +628,10 @@ void parse_pathspec(struct pathspec *pathspec,
> if (item[i].nowildcard_len < item[i].len)
> pathspec->has_wildcard = 1;
> pathspec->magic |= item[i].magic;
> +
> + if (item[i].attr_check &&
> + item[i].attr_check->nr != item[i].attr_match_nr)
> + die("BUG: should have same number of entries");I'm not sure if this check is giving us any benefit - I would expect this type of code before some other code that assumed that the numbers matched, and that will potentially segfault if not.