Merge branch 'bw/attr-pathspec'
authorJunio C Hamano <gitster@pobox.com>
Fri, 17 Mar 2017 20:50:26 +0000 (13:50 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 17 Mar 2017 20:50:26 +0000 (13:50 -0700)
The pathspec mechanism learned to further limit the paths that
match the pattern to those that have specified attributes attached
via the gitattributes mechanism.

* bw/attr-pathspec:
pathspec: allow escaped query values
pathspec: allow querying for attributes

1  2 
dir.c
diff --combined dir.c
index aeeb5ce10490ef1e0adb907d1e21bcbbbbb401ac,2fe7acbcf2ce185a03421e7fd38bd34181c7d27a..837ff965a470e74028fce6019f4584e55dcf445c
--- 1/dir.c
--- 2/dir.c
+++ b/dir.c
@@@ -9,6 -9,7 +9,7 @@@
   */
  #include "cache.h"
  #include "dir.h"
+ #include "attr.h"
  #include "refs.h"
  #include "wildmatch.h"
  #include "pathspec.h"
@@@ -134,7 -135,8 +135,8 @@@ static size_t common_prefix_len(const s
                       PATHSPEC_LITERAL |
                       PATHSPEC_GLOB |
                       PATHSPEC_ICASE |
-                      PATHSPEC_EXCLUDE);
+                      PATHSPEC_EXCLUDE |
+                      PATHSPEC_ATTR);
  
        for (n = 0; n < pathspec->nr; n++) {
                size_t i = 0, len = 0, item_len;
@@@ -209,6 -211,36 +211,36 @@@ int within_depth(const char *name, int 
  #define DO_MATCH_DIRECTORY (1<<1)
  #define DO_MATCH_SUBMODULE (1<<2)
  
+ static int match_attrs(const char *name, int namelen,
+                      const struct pathspec_item *item)
+ {
+       int i;
+       git_check_attr(name, item->attr_check);
+       for (i = 0; i < item->attr_match_nr; i++) {
+               const char *value;
+               int matched;
+               enum attr_match_mode match_mode;
+               value = item->attr_check->items[i].value;
+               match_mode = item->attr_match[i].match_mode;
+               if (ATTR_TRUE(value))
+                       matched = (match_mode == MATCH_SET);
+               else if (ATTR_FALSE(value))
+                       matched = (match_mode == MATCH_UNSET);
+               else if (ATTR_UNSET(value))
+                       matched = (match_mode == MATCH_UNSPECIFIED);
+               else
+                       matched = (match_mode == MATCH_VALUE &&
+                                  !strcmp(item->attr_match[i].value, value));
+               if (!matched)
+                       return 0;
+       }
+       return 1;
+ }
  /*
   * Does 'match' match the given name?
   * A match is found if
@@@ -261,6 -293,9 +293,9 @@@ static int match_pathspec_item(const st
            strncmp(item->match, name - prefix, item->prefix))
                return 0;
  
+       if (item->attr_match_nr && !match_attrs(name, namelen, item))
+               return 0;
        /* If the match was just the prefix, we matched */
        if (!*match)
                return MATCHED_RECURSIVELY;
@@@ -339,7 -374,8 +374,8 @@@ static int do_match_pathspec(const stru
                       PATHSPEC_LITERAL |
                       PATHSPEC_GLOB |
                       PATHSPEC_ICASE |
-                      PATHSPEC_EXCLUDE);
+                      PATHSPEC_EXCLUDE |
+                      PATHSPEC_ATTR);
  
        if (!ps->nr) {
                if (!ps->recursive ||
@@@ -1361,7 -1397,8 +1397,8 @@@ static int simplify_away(const char *pa
                       PATHSPEC_LITERAL |
                       PATHSPEC_GLOB |
                       PATHSPEC_ICASE |
-                      PATHSPEC_EXCLUDE);
+                      PATHSPEC_EXCLUDE |
+                      PATHSPEC_ATTR);
  
        for (i = 0; i < pathspec->nr; i++) {
                const struct pathspec_item *item = &pathspec->items[i];
@@@ -2730,8 -2767,8 +2767,8 @@@ void connect_work_tree_and_git_dir(cons
  {
        struct strbuf file_name = STRBUF_INIT;
        struct strbuf rel_path = STRBUF_INIT;
 -      char *git_dir = real_pathdup(git_dir_);
 -      char *work_tree = real_pathdup(work_tree_);
 +      char *git_dir = real_pathdup(git_dir_, 1);
 +      char *work_tree = real_pathdup(work_tree_, 1);
  
        /* Update gitfile */
        strbuf_addf(&file_name, "%s/.git", work_tree);