summaryrefslogtreecommitdiff
path: root/dir.c
diff options
context:
space:
mode:
authorBrandon Williams <bmwill@google.com>2017-03-13 11:23:21 -0700
committerJunio C Hamano <gitster@pobox.com>2017-03-13 15:28:54 -0700
commitb0db70465246bb8309d3d12c9bc34ac3f0c1e203 (patch)
treea82cfca2e400ddd21f22cec61e2d664462e4a38f /dir.c
parent625568cd8813bf32b2172eaf59e45e9da5978ce3 (diff)
downloadgit-b0db70465246bb8309d3d12c9bc34ac3f0c1e203.tar.gz
pathspec: allow querying for attributes
The pathspec mechanism is extended via the new ":(attr:eol=input)pattern/to/match" syntax to filter paths so that it requires paths to not just match the given pattern but also have the specified attrs attached for them to be chosen. Based on a patch by Stefan Beller <sbeller@google.com> Signed-off-by: Brandon Williams <bmwill@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'dir.c')
-rw-r--r--dir.c43
1 files changed, 40 insertions, 3 deletions
diff --git a/dir.c b/dir.c
index 4541f9e146..2fe7acbcf2 100644
--- a/dir.c
+++ b/dir.c
@@ -9,6 +9,7 @@
*/
#include "cache.h"
#include "dir.h"
+#include "attr.h"
#include "refs.h"
#include "wildmatch.h"
#include "pathspec.h"
@@ -134,7 +135,8 @@ static size_t common_prefix_len(const struct pathspec *pathspec)
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 @@ int within_depth(const char *name, int namelen,
#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 @@ static int match_pathspec_item(const struct pathspec_item *item, int prefix,
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 @@ static int do_match_pathspec(const struct pathspec *ps,
PATHSPEC_LITERAL |
PATHSPEC_GLOB |
PATHSPEC_ICASE |
- PATHSPEC_EXCLUDE);
+ PATHSPEC_EXCLUDE |
+ PATHSPEC_ATTR);
if (!ps->nr) {
if (!ps->recursive ||
@@ -1361,7 +1397,8 @@ static int simplify_away(const char *path, int pathlen,
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];