summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/checkout.c10
-rw-r--r--src/diff.c12
-rw-r--r--src/index.c42
-rw-r--r--src/index.h6
-rw-r--r--src/pathspec.c450
-rw-r--r--src/pathspec.h43
6 files changed, 467 insertions, 96 deletions
diff --git a/src/checkout.c b/src/checkout.c
index 8f9ec64e4..ec9da7e2e 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -246,10 +246,10 @@ static int checkout_action_wd_only(
bool remove = false;
git_checkout_notify_t notify = GIT_CHECKOUT_NOTIFY_NONE;
- if (!git_pathspec_match_path(
+ if (!git_pathspec__match(
pathspec, wd->path,
(data->strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH) != 0,
- git_iterator_ignore_case(workdir), NULL))
+ git_iterator_ignore_case(workdir), NULL, NULL))
return 0;
/* check if item is tracked in the index but not in the checkout diff */
@@ -607,7 +607,7 @@ static int checkout_get_actions(
uint32_t *actions = NULL;
if (data->opts.paths.count > 0 &&
- git_pathspec_init(&pathspec, &data->opts.paths, &pathpool) < 0)
+ git_pathspec__vinit(&pathspec, &data->opts.paths, &pathpool) < 0)
return -1;
if ((error = git_iterator_current(&wditem, workdir)) < 0 &&
@@ -659,7 +659,7 @@ static int checkout_get_actions(
goto fail;
}
- git_pathspec_free(&pathspec);
+ git_pathspec__vfree(&pathspec);
git_pool_clear(&pathpool);
return 0;
@@ -670,7 +670,7 @@ fail:
*actions_ptr = NULL;
git__free(actions);
- git_pathspec_free(&pathspec);
+ git_pathspec__vfree(&pathspec);
git_pool_clear(&pathpool);
return error;
diff --git a/src/diff.c b/src/diff.c
index 0980f412a..56232ebf4 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -81,11 +81,11 @@ static int diff_delta__from_one(
DIFF_FLAG_IS_SET(diff, GIT_DIFF_IGNORE_SUBMODULES))
return 0;
- if (!git_pathspec_match_path(
+ if (!git_pathspec__match(
&diff->pathspec, entry->path,
DIFF_FLAG_IS_SET(diff, GIT_DIFF_DISABLE_PATHSPEC_MATCH),
DIFF_FLAG_IS_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE),
- &matched_pathspec))
+ &matched_pathspec, NULL))
return 0;
delta = diff_delta__alloc(diff, status, entry->path);
@@ -387,7 +387,7 @@ static int diff_list_apply_options(
DIFF_FLAG_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE, icase);
/* initialize pathspec from options */
- if (git_pathspec_init(&diff->pathspec, &opts->pathspec, pool) < 0)
+ if (git_pathspec__vinit(&diff->pathspec, &opts->pathspec, pool) < 0)
return -1;
}
@@ -473,7 +473,7 @@ static void diff_list_free(git_diff_list *diff)
}
git_vector_free(&diff->deltas);
- git_pathspec_free(&diff->pathspec);
+ git_pathspec__vfree(&diff->pathspec);
git_pool_clear(&diff->pool);
git__memzero(diff, sizeof(*diff));
@@ -634,11 +634,11 @@ static int maybe_modified(
bool new_is_workdir = (info->new_iter->type == GIT_ITERATOR_TYPE_WORKDIR);
const char *matched_pathspec;
- if (!git_pathspec_match_path(
+ if (!git_pathspec__match(
&diff->pathspec, oitem->path,
DIFF_FLAG_IS_SET(diff, GIT_DIFF_DISABLE_PATHSPEC_MATCH),
DIFF_FLAG_IS_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE),
- &matched_pathspec))
+ &matched_pathspec, NULL))
return 0;
memset(&noid, 0, sizeof(noid));
diff --git a/src/index.c b/src/index.c
index ffa84e53f..21efd2c63 100644
--- a/src/index.c
+++ b/src/index.c
@@ -101,8 +101,6 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
static bool is_index_extended(git_index *index);
static int write_index(git_index *index, git_filebuf *file);
-static int index_find(size_t *at_pos, git_index *index, const char *path, int stage);
-
static void index_entry_free(git_index_entry *entry);
static void index_entry_reuc_free(git_index_reuc_entry *reuc);
@@ -114,7 +112,7 @@ static int index_srch(const void *key, const void *array_member)
ret = strcmp(srch_key->path, entry->path);
- if (ret == 0)
+ if (ret == 0 && srch_key->stage != GIT_INDEX_STAGE_ANY)
ret = srch_key->stage - GIT_IDXENTRY_STAGE(entry);
return ret;
@@ -128,7 +126,7 @@ static int index_isrch(const void *key, const void *array_member)
ret = strcasecmp(srch_key->path, entry->path);
- if (ret == 0)
+ if (ret == 0 && srch_key->stage != GIT_INDEX_STAGE_ANY)
ret = srch_key->stage - GIT_IDXENTRY_STAGE(entry);
return ret;
@@ -562,7 +560,7 @@ const git_index_entry *git_index_get_bypath(
git_vector_sort(&index->entries);
- if (index_find(&pos, index, path, stage) < 0) {
+ if (git_index__find(&pos, index, path, stage) < 0) {
giterr_set(GITERR_INDEX, "Index does not contain %s", path);
return NULL;
}
@@ -719,7 +717,8 @@ static int index_insert(git_index *index, git_index_entry *entry, int replace)
entry->flags |= GIT_IDXENTRY_NAMEMASK;
/* look if an entry with this path already exists */
- if (!index_find(&position, index, entry->path, GIT_IDXENTRY_STAGE(entry))) {
+ if (!git_index__find(
+ &position, index, entry->path, GIT_IDXENTRY_STAGE(entry))) {
existing = (git_index_entry **)&index->entries.contents[position];
/* update filemode to existing values if stat is not trusted */
@@ -831,7 +830,7 @@ int git_index_remove(git_index *index, const char *path, int stage)
git_vector_sort(&index->entries);
- if (index_find(&position, index, path, stage) < 0) {
+ if (git_index__find(&position, index, path, stage) < 0) {
giterr_set(GITERR_INDEX, "Index does not contain %s at stage %d",
path, stage);
return GIT_ENOTFOUND;
@@ -887,7 +886,8 @@ int git_index_remove_directory(git_index *index, const char *dir, int stage)
return error;
}
-static int index_find(size_t *at_pos, git_index *index, const char *path, int stage)
+int git_index__find(
+ size_t *at_pos, git_index *index, const char *path, int stage)
{
struct entry_srch_key srch_key;
@@ -896,7 +896,8 @@ static int index_find(size_t *at_pos, git_index *index, const char *path, int st
srch_key.path = path;
srch_key.stage = stage;
- return git_vector_bsearch2(at_pos, &index->entries, index->entries_search, &srch_key);
+ return git_vector_bsearch2(
+ at_pos, &index->entries, index->entries_search, &srch_key);
}
int git_index_find(size_t *at_pos, git_index *index, const char *path)
@@ -2053,7 +2054,7 @@ int git_index_add_all(
git_iterator *wditer = NULL;
const git_index_entry *wd = NULL;
git_index_entry *entry;
- git_pathspec_context ps;
+ git_pathspec ps;
const char *match;
size_t existing;
bool no_fnmatch = (flags & GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH) != 0;
@@ -2074,7 +2075,7 @@ int git_index_add_all(
if (git_repository__cvar(&ignorecase, repo, GIT_CVAR_IGNORECASE) < 0)
return -1;
- if ((error = git_pathspec_context_init(&ps, paths)) < 0)
+ if ((error = git_pathspec__init(&ps, paths)) < 0)
return error;
/* optionally check that pathspec doesn't mention any ignored files */
@@ -2091,14 +2092,14 @@ int git_index_add_all(
while (!(error = git_iterator_advance(&wd, wditer))) {
/* check if path actually matches */
- if (!git_pathspec_match_path(
- &ps.pathspec, wd->path, no_fnmatch, ignorecase, &match))
+ if (!git_pathspec__match(
+ &ps.pathspec, wd->path, no_fnmatch, ignorecase, &match, NULL))
continue;
/* skip ignored items that are not already in the index */
if ((flags & GIT_INDEX_ADD_FORCE) == 0 &&
git_iterator_current_is_ignored(wditer) &&
- index_find(&existing, index, wd->path, 0) < 0)
+ git_index__find(&existing, index, wd->path, 0) < 0)
continue;
/* issue notification callback if requested */
@@ -2148,7 +2149,7 @@ int git_index_add_all(
cleanup:
git_iterator_free(wditer);
- git_pathspec_context_free(&ps);
+ git_pathspec__clear(&ps);
return error;
}
@@ -2168,13 +2169,13 @@ static int index_apply_to_all(
{
int error = 0;
size_t i;
- git_pathspec_context ps;
+ git_pathspec ps;
const char *match;
git_buf path = GIT_BUF_INIT;
assert(index);
- if ((error = git_pathspec_context_init(&ps, paths)) < 0)
+ if ((error = git_pathspec__init(&ps, paths)) < 0)
return error;
git_vector_sort(&index->entries);
@@ -2183,8 +2184,9 @@ static int index_apply_to_all(
git_index_entry *entry = git_vector_get(&index->entries, i);
/* check if path actually matches */
- if (!git_pathspec_match_path(
- &ps.pathspec, entry->path, false, index->ignore_case, &match))
+ if (!git_pathspec__match(
+ &ps.pathspec, entry->path, false, index->ignore_case,
+ &match, NULL))
continue;
/* issue notification callback if requested */
@@ -2231,7 +2233,7 @@ static int index_apply_to_all(
}
git_buf_free(&path);
- git_pathspec_context_free(&ps);
+ git_pathspec__clear(&ps);
return error;
}
diff --git a/src/index.h b/src/index.h
index a59107a7b..40577e105 100644
--- a/src/index.h
+++ b/src/index.h
@@ -47,13 +47,17 @@ struct git_index_conflict_iterator {
size_t cur;
};
-extern void git_index_entry__init_from_stat(git_index_entry *entry, struct stat *st);
+extern void git_index_entry__init_from_stat(
+ git_index_entry *entry, struct stat *st);
extern size_t git_index__prefix_position(git_index *index, const char *path);
extern int git_index_entry__cmp(const void *a, const void *b);
extern int git_index_entry__cmp_icase(const void *a, const void *b);
+extern int git_index__find(
+ size_t *at_pos, git_index *index, const char *path, int stage);
+
extern void git_index__set_ignore_case(git_index *index, bool ignore_case);
#endif
diff --git a/src/pathspec.c b/src/pathspec.c
index f029836d0..35421dbef 100644
--- a/src/pathspec.c
+++ b/src/pathspec.c
@@ -5,9 +5,13 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#include "git2/pathspec.h"
#include "pathspec.h"
#include "buf_text.h"
#include "attr_file.h"
+#include "iterator.h"
+#include "repository.h"
+#include "index.h"
/* what is the common non-wildcard prefix for all items in the pathspec */
char *git_pathspec_prefix(const git_strarray *pathspec)
@@ -56,7 +60,7 @@ bool git_pathspec_is_empty(const git_strarray *pathspec)
}
/* build a vector of fnmatch patterns to evaluate efficiently */
-int git_pathspec_init(
+int git_pathspec__vinit(
git_vector *vspec, const git_strarray *strspec, git_pool *strpool)
{
size_t i;
@@ -93,7 +97,7 @@ int git_pathspec_init(
}
/* free data from the pathspec vector */
-void git_pathspec_free(git_vector *vspec)
+void git_pathspec__vfree(git_vector *vspec)
{
git_attr_fnmatch *match;
unsigned int i;
@@ -106,88 +110,436 @@ void git_pathspec_free(git_vector *vspec)
git_vector_free(vspec);
}
+struct pathspec_match_context {
+ int fnmatch_flags;
+ int (*strcomp)(const char *, const char *);
+ int (*strncomp)(const char *, const char *, size_t);
+};
+
+static void pathspec_match_context_init(
+ struct pathspec_match_context *ctxt,
+ bool disable_fnmatch,
+ bool casefold)
+{
+ if (disable_fnmatch)
+ ctxt->fnmatch_flags = -1;
+ else if (casefold)
+ ctxt->fnmatch_flags = FNM_CASEFOLD;
+ else
+ ctxt->fnmatch_flags = 0;
+
+ if (casefold) {
+ ctxt->strcomp = git__strcasecmp;
+ ctxt->strncomp = git__strncasecmp;
+ } else {
+ ctxt->strcomp = git__strcmp;
+ ctxt->strncomp = git__strncmp;
+ }
+}
+
+static int pathspec_match_one(
+ const git_attr_fnmatch *match,
+ struct pathspec_match_context *ctxt,
+ const char *path)
+{
+ int result = (match->flags & GIT_ATTR_FNMATCH_MATCH_ALL) ? 0 : FNM_NOMATCH;
+
+ if (result == FNM_NOMATCH)
+ result = ctxt->strcomp(match->pattern, path) ? FNM_NOMATCH : 0;
+
+ if (ctxt->fnmatch_flags >= 0 && result == FNM_NOMATCH)
+ result = p_fnmatch(match->pattern, path, ctxt->fnmatch_flags);
+
+ /* if we didn't match, look for exact dirname prefix match */
+ if (result == FNM_NOMATCH &&
+ (match->flags & GIT_ATTR_FNMATCH_HASWILD) == 0 &&
+ ctxt->strncomp(path, match->pattern, match->length) == 0 &&
+ path[match->length] == '/')
+ result = 0;
+
+ if (result == 0)
+ return (match->flags & GIT_ATTR_FNMATCH_NEGATIVE) ? 0 : 1;
+ return -1;
+}
+
/* match a path against the vectorized pathspec */
-bool git_pathspec_match_path(
- git_vector *vspec,
+bool git_pathspec__match(
+ const git_vector *vspec,
const char *path,
bool disable_fnmatch,
bool casefold,
- const char **matched_pathspec)
+ const char **matched_pathspec,
+ size_t *matched_at)
{
size_t i;
- git_attr_fnmatch *match;
- int fnmatch_flags = 0;
- int (*use_strcmp)(const char *, const char *);
- int (*use_strncmp)(const char *, const char *, size_t);
+ const git_attr_fnmatch *match;
+ struct pathspec_match_context ctxt;
if (matched_pathspec)
*matched_pathspec = NULL;
+ if (matched_at)
+ *matched_at = GIT_PATHSPEC_NOMATCH;
if (!vspec || !vspec->length)
return true;
- if (disable_fnmatch)
- fnmatch_flags = -1;
- else if (casefold)
- fnmatch_flags = FNM_CASEFOLD;
+ pathspec_match_context_init(&ctxt, disable_fnmatch, casefold);
- if (casefold) {
- use_strcmp = git__strcasecmp;
- use_strncmp = git__strncasecmp;
- } else {
- use_strcmp = git__strcmp;
- use_strncmp = git__strncmp;
+ git_vector_foreach(vspec, i, match) {
+ int result = pathspec_match_one(match, &ctxt, path);
+
+ if (result >= 0) {
+ if (matched_pathspec)
+ *matched_pathspec = match->pattern;
+ if (matched_at)
+ *matched_at = i;
+
+ return (result != 0);
+ }
}
- git_vector_foreach(vspec, i, match) {
- int result = (match->flags & GIT_ATTR_FNMATCH_MATCH_ALL) ? 0 : FNM_NOMATCH;
+ return false;
+}
- if (result == FNM_NOMATCH)
- result = use_strcmp(match->pattern, path) ? FNM_NOMATCH : 0;
- if (fnmatch_flags >= 0 && result == FNM_NOMATCH)
- result = p_fnmatch(match->pattern, path, fnmatch_flags);
+int git_pathspec__init(git_pathspec *ps, const git_strarray *paths)
+{
+ int error = 0;
- /* if we didn't match, look for exact dirname prefix match */
- if (result == FNM_NOMATCH &&
- (match->flags & GIT_ATTR_FNMATCH_HASWILD) == 0 &&
- use_strncmp(path, match->pattern, match->length) == 0 &&
- path[match->length] == '/')
- result = 0;
+ memset(ps, 0, sizeof(*ps));
- if (result == 0) {
- if (matched_pathspec)
- *matched_pathspec = match->pattern;
+ ps->prefix = git_pathspec_prefix(paths);
+
+ if ((error = git_pool_init(&ps->pool, 1, 0)) < 0 ||
+ (error = git_pathspec__vinit(&ps->pathspec, paths, &ps->pool)) < 0)
+ git_pathspec__clear(ps);
+
+ return error;
+}
+
+void git_pathspec__clear(git_pathspec *ps)
+{
+ git__free(ps->prefix);
+ git_pathspec__vfree(&ps->pathspec);
+ git_pool_clear(&ps->pool);
+ memset(ps, 0, sizeof(*ps));
+}
+
+int git_pathspec_new(git_pathspec **out, const git_strarray *pathspec)
+{
+ int error = 0;
+ git_pathspec *ps = git__malloc(sizeof(git_pathspec));
+ GITERR_CHECK_ALLOC(ps);
+
+ if ((error = git_pathspec__init(ps, pathspec)) < 0) {
+ git__free(ps);
+ return error;
+ }
+
+ GIT_REFCOUNT_INC(ps);
+ *out = ps;
+ return 0;
+}
+
+static void pathspec_free(git_pathspec *ps)
+{
+ git_pathspec__clear(ps);
+ git__free(ps);
+}
+
+void git_pathspec_free(git_pathspec *ps)
+{
+ if (!ps)
+ return;
+ GIT_REFCOUNT_DEC(ps, pathspec_free);
+}
- return (match->flags & GIT_ATTR_FNMATCH_NEGATIVE) ? false : true;
+int git_pathspec_matches_path(
+ const git_pathspec *ps, uint32_t flags, const char *path)
+{
+ bool no_fnmatch = (flags & GIT_PATHSPEC_NO_GLOB) != 0;
+ bool casefold = (flags & GIT_PATHSPEC_IGNORE_CASE) != 0;
+
+ assert(ps && path);
+
+ return (0 != git_pathspec__match(
+ &ps->pathspec, path, no_fnmatch, casefold, NULL, NULL));
+}
+
+static void pathspec_match_free(git_pathspec_match_list *m)
+{
+ git_pathspec_free(m->pathspec);
+ m->pathspec = NULL;
+
+ git_array_clear(m->matches);
+ git_array_clear(m->failures);
+ git_pool_clear(&m->pool);
+ git__free(m);
+}
+
+static git_pathspec_match_list *pathspec_match_alloc(git_pathspec *ps)
+{
+ git_pathspec_match_list *m = git__calloc(1, sizeof(git_pathspec_match_list));
+
+ if (m != NULL && git_pool_init(&m->pool, 1, 0) < 0) {
+ pathspec_match_free(m);
+ m = NULL;
+ }
+
+ /* need to keep reference to pathspec and increment refcount because
+ * failures array stores pointers to the pattern strings of the
+ * pathspec that had no matches
+ */
+ GIT_REFCOUNT_INC(ps);
+ m->pathspec = ps;
+
+ return m;
+}
+
+GIT_INLINE(void) pathspec_mark_pattern(uint8_t *used, size_t pos, size_t *ct)
+{
+ if (!used[pos]) {
+ used[pos] = 1;
+ (*ct)++;
+ }
+}
+
+static int pathspec_match_from_iterator(
+ git_pathspec_match_list **out,
+ git_iterator *iter,
+ uint32_t flags,
+ git_pathspec *ps)
+{
+ int error = 0;
+ git_pathspec_match_list *m;
+ const git_index_entry *entry = NULL;
+ struct pathspec_match_context ctxt;
+ git_vector *patterns = &ps->pathspec;
+ bool find_failures = (flags & GIT_PATHSPEC_FIND_FAILURES) != 0;
+ bool failures_only = (flags & GIT_PATHSPEC_FAILURES_ONLY) != 0;
+ size_t pos, used_ct = 0, found_files = 0;
+ git_index *index = NULL;
+ uint8_t *used_patterns = NULL;
+ char **file;
+
+ *out = m = pathspec_match_alloc(ps);
+ GITERR_CHECK_ALLOC(m);
+
+ if ((error = git_iterator_reset(iter, ps->prefix, ps->prefix)) < 0)
+ goto done;
+
+ if (patterns->length > 0) {
+ used_patterns = git__calloc(patterns->length, sizeof(uint8_t));
+ GITERR_CHECK_ALLOC(used_patterns);
+ }
+
+ if (git_iterator_type(iter) == GIT_ITERATOR_TYPE_WORKDIR &&
+ (error = git_repository_index__weakptr(
+ &index, git_iterator_owner(iter))) < 0)
+ goto done;
+
+ pathspec_match_context_init(&ctxt,
+ (flags & GIT_PATHSPEC_NO_GLOB) != 0, git_iterator_ignore_case(iter));
+
+ while (!(error = git_iterator_advance(&entry, iter))) {
+ int result = -1;
+
+ for (pos = 0; pos < patterns->length; ++pos) {
+ const git_attr_fnmatch *pat = git_vector_get(patterns, pos);
+
+ result = pathspec_match_one(pat, &ctxt, entry->path);
+ if (result >= 0)
+ break;
+ }
+
+ /* no matches for this path */
+ if (result < 0)
+ continue;
+
+ /* if result was a negative pattern match, then don't list file */
+ if (!result) {
+ pathspec_mark_pattern(used_patterns, pos, &used_ct);
+ continue;
+ }
+
+ /* check if path is untracked and ignored */
+ if (index != NULL &&
+ git_iterator_current_is_ignored(iter) &&
+ git_index__find(NULL, index, entry->path, GIT_INDEX_STAGE_ANY) < 0)
+ continue;
+
+ /* mark the matched pattern as used */
+ pathspec_mark_pattern(used_patterns, pos, &used_ct);
+ ++found_files;
+
+ /* if find_failures is on, check if any later patterns also match */
+ if (find_failures && used_ct < patterns->length) {
+ for (++pos; pos < patterns->length; ++pos) {
+ const git_attr_fnmatch *pat = git_vector_get(patterns, pos);
+ if (used_patterns[pos])
+ continue;
+
+ if (pathspec_match_one(pat, &ctxt, entry->path) > 0)
+ pathspec_mark_pattern(used_patterns, pos, &used_ct);
+ }
+ }
+
+ /* if only looking at failures, exit early or just continue */
+ if (failures_only) {
+ if (used_ct == patterns->length)
+ break;
+ continue;
+ }
+
+ /* insert matched path into matches array */
+ if ((file = git_array_alloc(m->matches)) == NULL ||
+ (*file = git_pool_strdup(&m->pool, entry->path)) == NULL) {
+ error = -1;
+ goto done;
}
}
- return false;
+ if (error < 0 && error != GIT_ITEROVER)
+ goto done;
+ error = 0;
+
+ /* insert patterns that had no matches into failures array */
+ if (find_failures && used_ct < patterns->length) {
+ for (pos = 0; pos < patterns->length; ++pos) {
+ const git_attr_fnmatch *pat = git_vector_get(patterns, pos);
+ if (used_patterns[pos])
+ continue;
+
+ if ((file = git_array_alloc(m->failures)) == NULL ||
+ (*file = git_pool_strdup(&m->pool, pat->pattern)) == NULL) {
+ error = -1;
+ goto done;
+ }
+ }
+ }
+
+ /* if every pattern failed to match, then we have failed */
+ if ((flags & GIT_PATHSPEC_NO_MATCH_ERROR) != 0 && !found_files) {
+ giterr_set(GITERR_INVALID, "No matching files were found");
+ error = GIT_ENOTFOUND;
+ }
+
+done:
+ git__free(used_patterns);
+
+ if (error < 0) {
+ pathspec_match_free(m);
+ *out = NULL;
+ }
+
+ return error;
}
+static git_iterator_flag_t pathspec_match_iter_flags(uint32_t flags)
+{
+ git_iterator_flag_t f = 0;
+
+ if ((flags & GIT_PATHSPEC_IGNORE_CASE) != 0)
+ f |= GIT_ITERATOR_IGNORE_CASE;
+ else if ((flags & GIT_PATHSPEC_USE_CASE) != 0)
+ f |= GIT_ITERATOR_DONT_IGNORE_CASE;
-int git_pathspec_context_init(
- git_pathspec_context *ctxt, const git_strarray *paths)
+ return f;
+}
+
+int git_pathspec_match_workdir(
+ git_pathspec_match_list **out,
+ git_repository *repo,
+ uint32_t flags,
+ git_pathspec *ps)
{
int error = 0;
+ git_iterator *iter;
+
+ assert(out && repo);
- memset(ctxt, 0, sizeof(*ctxt));
+ if (!(error = git_iterator_for_workdir(
+ &iter, repo, pathspec_match_iter_flags(flags), NULL, NULL))) {
- ctxt->prefix = git_pathspec_prefix(paths);
+ error = pathspec_match_from_iterator(out, iter, flags, ps);
- if ((error = git_pool_init(&ctxt->pool, 1, 0)) < 0 ||
- (error = git_pathspec_init(&ctxt->pathspec, paths, &ctxt->pool)) < 0)
- git_pathspec_context_free(ctxt);
+ git_iterator_free(iter);
+ }
return error;
}
-void git_pathspec_context_free(
- git_pathspec_context *ctxt)
+int git_pathspec_match_index(
+ git_pathspec_match_list **out,
+ git_index *index,
+ uint32_t flags,
+ git_pathspec *ps)
+{
+ int error = 0;
+ git_iterator *iter;
+
+ assert(out && index);
+
+ if (!(error = git_iterator_for_index(
+ &iter, index, pathspec_match_iter_flags(flags), NULL, NULL))) {
+
+ error = pathspec_match_from_iterator(out, iter, flags, ps);
+
+ git_iterator_free(iter);
+ }
+
+ return error;
+}
+
+int git_pathspec_match_tree(
+ git_pathspec_match_list **out,
+ git_tree *tree,
+ uint32_t flags,
+ git_pathspec *ps)
+{
+ int error = 0;
+ git_iterator *iter;
+
+ assert(out && tree);
+
+ if (!(error = git_iterator_for_tree(
+ &iter, tree, pathspec_match_iter_flags(flags), NULL, NULL))) {
+
+ error = pathspec_match_from_iterator(out, iter, flags, ps);
+
+ git_iterator_free(iter);
+ }
+
+ return error;
+}
+
+void git_pathspec_match_list_free(git_pathspec_match_list *m)
+{
+ pathspec_match_free(m);
+}
+
+size_t git_pathspec_match_list_entrycount(
+ const git_pathspec_match_list *m)
+{
+ return git_array_size(m->matches);
+}
+
+const char *git_pathspec_match_list_entry(
+ const git_pathspec_match_list *m, size_t pos)
+{
+ char **entry = git_array_get(m->matches, pos);
+ return entry ? *entry : NULL;
+}
+
+size_t git_pathspec_match_list_failed_entrycount(
+ const git_pathspec_match_list *m)
+{
+ return git_array_size(m->failures);
+}
+
+const char * git_pathspec_match_list_failed_entry(
+ const git_pathspec_match_list *m, size_t pos)
{
- git__free(ctxt->prefix);
- git_pathspec_free(&ctxt->pathspec);
- git_pool_clear(&ctxt->pool);
- memset(ctxt, 0, sizeof(*ctxt));
+ char **entry = git_array_get(m->failures, pos);
+ return entry ? *entry : NULL;
}
diff --git a/src/pathspec.h b/src/pathspec.h
index f6509df4c..e7edfea38 100644
--- a/src/pathspec.h
+++ b/src/pathspec.h
@@ -8,9 +8,27 @@
#define INCLUDE_pathspec_h__
#include "common.h"
+#include <git2/pathspec.h>
#include "buffer.h"
#include "vector.h"
#include "pool.h"
+#include "array.h"
+
+/* public compiled pathspec */
+struct git_pathspec {
+ git_refcount rc;
+ char *prefix;
+ git_vector pathspec;
+ git_pool pool;
+};
+
+/* public interface to pathspec matching */
+struct git_pathspec_match_list {
+ git_pathspec *pathspec;
+ git_array_t(char *) matches;
+ git_array_t(char *) failures;
+ git_pool pool;
+};
/* what is the common non-wildcard prefix for all items in the pathspec */
extern char *git_pathspec_prefix(const git_strarray *pathspec);
@@ -19,36 +37,31 @@ extern char *git_pathspec_prefix(const git_strarray *pathspec);
extern bool git_pathspec_is_empty(const git_strarray *pathspec);
/* build a vector of fnmatch patterns to evaluate efficiently */
-extern int git_pathspec_init(
+extern int git_pathspec__vinit(
git_vector *vspec, const git_strarray *strspec, git_pool *strpool);
/* free data from the pathspec vector */
-extern void git_pathspec_free(git_vector *vspec);
+extern void git_pathspec__vfree(git_vector *vspec);
+
+#define GIT_PATHSPEC_NOMATCH ((size_t)-1)
/*
* Match a path against the vectorized pathspec.
* The matched pathspec is passed back into the `matched_pathspec` parameter,
* unless it is passed as NULL by the caller.
*/
-extern bool git_pathspec_match_path(
- git_vector *vspec,
+extern bool git_pathspec__match(
+ const git_vector *vspec,
const char *path,
bool disable_fnmatch,
bool casefold,
- const char **matched_pathspec);
+ const char **matched_pathspec,
+ size_t *matched_at);
/* easy pathspec setup */
-typedef struct {
- char *prefix;
- git_vector pathspec;
- git_pool pool;
-} git_pathspec_context;
-
-extern int git_pathspec_context_init(
- git_pathspec_context *ctxt, const git_strarray *paths);
+extern int git_pathspec__init(git_pathspec *ps, const git_strarray *paths);
-extern void git_pathspec_context_free(
- git_pathspec_context *ctxt);
+extern void git_pathspec__clear(git_pathspec *ps);
#endif