Introduce a glob-filtering iterator If the backend doesn't provide support for it, the matching is done in refdb on top of a normal iterator.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
diff --git a/include/git2/sys/refdb_backend.h b/include/git2/sys/refdb_backend.h
index f5eacd1..8dbf38c 100644
--- a/include/git2/sys/refdb_backend.h
+++ b/include/git2/sys/refdb_backend.h
@@ -30,10 +30,11 @@ GIT_BEGIN_DECL
* ...
* }
*
- * and assing `iter->parent.backend` to your `git_refdb_backend`.
+ * and assign `iter->parent.backend` to your `git_refdb_backend`.
*/
struct git_reference_iterator {
git_refdb_backend *backend;
+ char *glob;
};
/** An instance for a custom backend */
@@ -68,6 +69,17 @@ struct git_refdb_backend {
struct git_refdb_backend *backend);
/**
+ * Allocate a glob-filtering iterator object for the backend.
+ *
+ * A refdb implementation may provide this function. If it's
+ * not available, the glob matching will be done by the frontend.
+ */
+ int (*iterator_glob)(
+ git_reference_iterator **iter,
+ struct git_refdb_backend *backend,
+ const char *glob);
+
+ /**
* Return the current value and advance the iterator.
*
* A refdb implementation must provide this function.
diff --git a/src/refdb.c b/src/refdb.c
index 5e33c2e..9f9037c 100644
--- a/src/refdb.c
+++ b/src/refdb.c
@@ -126,29 +126,59 @@ int git_refdb_lookup(git_reference **out, git_refdb *db, const char *ref_name)
int git_refdb_iterator(git_reference_iterator **out, git_refdb *db)
{
- git_reference_iterator *iter;
-
if (!db->backend || !db->backend->iterator) {
giterr_set(GITERR_REFERENCE, "This backend doesn't support iterators");
return -1;
}
- if (db->backend->iterator(&iter, db->backend) < 0) {
- git__free(iter);
+ if (db->backend->iterator(out, db->backend) < 0)
+ return -1;
+
+ return 0;
+}
+
+int git_refdb_iterator_glob(git_reference_iterator **out, git_refdb *db, const char *glob)
+{
+ if (!db->backend) {
+ giterr_set(GITERR_REFERENCE, "There are no backends loaded");
+ return -1;
+ }
+
+ if (db->backend->iterator_glob)
+ return db->backend->iterator_glob(out, db->backend, glob);
+
+ /* If the backend doesn't support glob-filtering themselves, we have to do it */
+ if (db->backend->iterator(out, db->backend) < 0)
+ return -1;
+
+ (*out)->glob = git__strdup(glob);
+ if (!(*out)->glob) {
+ db->backend->iterator_free(*out);
return -1;
}
- *out = iter;
return 0;
}
int git_refdb_next(const char **out, git_reference_iterator *iter)
{
- return iter->backend->next(out, iter);
+ int error;
+
+ if (!iter->glob)
+ return iter->backend->next(out, iter);
+
+ /* If the iterator has a glob, we need to filter */
+ while ((error = iter->backend->next(out, iter)) == 0) {
+ if (!p_fnmatch(iter->glob, *out, 0))
+ break;
+ }
+
+ return error;
}
void git_refdb_iterator_free(git_reference_iterator *iter)
{
+ git__free(iter->glob);
iter->backend->iterator_free(iter);
}
diff --git a/src/refdb.h b/src/refdb.h
index e88dead..2edd05d 100644
--- a/src/refdb.h
+++ b/src/refdb.h
@@ -27,6 +27,7 @@ int git_refdb_lookup(
const char *ref_name);
int git_refdb_iterator(git_reference_iterator **out, git_refdb *db);
+int git_refdb_iterator_glob(git_reference_iterator **out, git_refdb *db, const char *glob);
int git_refdb_next(const char **out, git_reference_iterator *iter);
void git_refdb_iterator_free(git_reference_iterator *iter);
diff --git a/src/refs.c b/src/refs.c
index a7be117..fc6652f 100644
--- a/src/refs.c
+++ b/src/refs.c
@@ -593,6 +593,16 @@ int git_reference_iterator_new(git_reference_iterator **out, git_repository *rep
return git_refdb_iterator(out, refdb);
}
+int git_reference_iterator_glob_new(git_reference_iterator **out, git_repository *repo, const char *glob)
+{
+ git_refdb *refdb;
+
+ if (git_repository_refdb__weakptr(&refdb, repo) < 0)
+ return -1;
+
+ return git_refdb_iterator_glob(out, refdb, glob);
+}
+
int git_reference_next(const char **out, git_reference_iterator *iter)
{
return git_refdb_next(out, iter);
@@ -928,13 +938,10 @@ int git_reference_foreach_glob(
const char *name;
int error;
- if (git_reference_iterator_new(&iter, repo) < 0)
+ if (git_reference_iterator_glob_new(&iter, repo, glob) < 0)
return -1;
while ((error = git_reference_next(&name, iter)) == 0) {
- if (p_fnmatch(glob, name, 0))
- continue;
-
if (callback(name, payload)) {
error = GIT_EUSER;
goto out;
diff --git a/tests-clar/refdb/testdb.c b/tests-clar/refdb/testdb.c
index 4d11856..961e18d 100644
--- a/tests-clar/refdb/testdb.c
+++ b/tests-clar/refdb/testdb.c
@@ -123,7 +123,7 @@ static int refdb_test_backend__iterator(git_reference_iterator **out, git_refdb_
GIT_UNUSED(_backend);
- iter = git__malloc(sizeof(refdb_test_iter));
+ iter = git__calloc(1, sizeof(refdb_test_iter));
GITERR_CHECK_ALLOC(iter);
iter->parent.backend = _backend;