Merge pull request #785 from nulltoken/topic/refs-fromglob Topic/refs fromglob
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 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
diff --git a/include/git2/refs.h b/include/git2/refs.h
index 2918215..2aa0ac2 100644
--- a/include/git2/refs.h
+++ b/include/git2/refs.h
@@ -258,7 +258,6 @@ GIT_EXTERN(int) git_reference_packall(git_repository *repo);
*/
GIT_EXTERN(int) git_reference_list(git_strarray *array, git_repository *repo, unsigned int list_flags);
-
/**
* Perform an operation on each reference in the repository
*
@@ -324,6 +323,36 @@ GIT_EXTERN(void) git_reference_free(git_reference *ref);
*/
GIT_EXTERN(int) git_reference_cmp(git_reference *ref1, git_reference *ref2);
+/**
+ * Loop over all the references and issue a callback for each one
+ * which name matches the given glob pattern.
+ *
+ * The processed references may be filtered by type, or using
+ * a bitwise OR of several types. Use the magic value
+ * `GIT_REF_LISTALL` to obtain all references, including
+ * packed ones.
+ *
+ * @param repo Repository where to find the references.
+ *
+ * @param list_flags Filtering flags for the reference
+ * listing.
+ *
+ * @param callback Callback to invoke per found reference.
+ *
+ * @param payload Extra parameter to callback function.
+ *
+ * @return 0 or an error code.
+ */
+GIT_EXTERN(int) git_reference_foreach_glob(
+ git_repository *repo,
+ const char *glob,
+ unsigned int list_flags,
+ int (*callback)(
+ const char *reference_name,
+ void *payload),
+ void *payload
+);
+
/** @} */
GIT_END_DECL
#endif
diff --git a/src/refs.c b/src/refs.c
index 1046857..ee076b3 100644
--- a/src/refs.c
+++ b/src/refs.c
@@ -1764,3 +1764,40 @@ int git_reference__update(git_repository *repo, const git_oid *oid, const char *
git_reference_free(ref);
return res;
}
+
+struct glob_cb_data {
+ const char *glob;
+ int (*callback)(const char *, void *);
+ void *payload;
+};
+
+static int fromglob_cb(const char *reference_name, void *payload)
+{
+ struct glob_cb_data *data = (struct glob_cb_data *)payload;
+
+ if (!p_fnmatch(data->glob, reference_name, 0))
+ return data->callback(reference_name, data->payload);
+
+ return 0;
+}
+
+int git_reference_foreach_glob(
+ git_repository *repo,
+ const char *glob,
+ unsigned int list_flags,
+ int (*callback)(
+ const char *reference_name,
+ void *payload),
+ void *payload)
+{
+ struct glob_cb_data data;
+
+ assert(repo && glob && callback);
+
+ data.glob = glob;
+ data.callback = callback;
+ data.payload = payload;
+
+ return git_reference_foreach(
+ repo, list_flags, fromglob_cb, &data);
+}
diff --git a/src/revwalk.c b/src/revwalk.c
index 13d54b7..7bcdc4a 100644
--- a/src/revwalk.c
+++ b/src/revwalk.c
@@ -540,7 +540,6 @@ static int push_ref(git_revwalk *walk, const char *refname, int hide)
struct push_cb_data {
git_revwalk *walk;
- const char *glob;
int hide;
};
@@ -548,10 +547,7 @@ static int push_glob_cb(const char *refname, void *data_)
{
struct push_cb_data *data = (struct push_cb_data *)data_;
- if (!p_fnmatch(data->glob, refname, 0))
- return push_ref(data->walk, refname, data->hide);
-
- return 0;
+ return push_ref(data->walk, refname, data->hide);
}
static int push_glob(git_revwalk *walk, const char *glob, int hide)
@@ -584,11 +580,10 @@ static int push_glob(git_revwalk *walk, const char *glob, int hide)
goto on_error;
data.walk = walk;
- data.glob = git_buf_cstr(&buf);
data.hide = hide;
- if (git_reference_foreach(
- walk->repo, GIT_REF_LISTALL, push_glob_cb, &data) < 0)
+ if (git_reference_foreach_glob(
+ walk->repo, git_buf_cstr(&buf), GIT_REF_LISTALL, push_glob_cb, &data) < 0)
goto on_error;
regfree(&preg);
diff --git a/tests-clar/refs/foreachglob.c b/tests-clar/refs/foreachglob.c
new file mode 100644
index 0000000..8bbcd71
--- /dev/null
+++ b/tests-clar/refs/foreachglob.c
@@ -0,0 +1,70 @@
+#include "clar_libgit2.h"
+#include "refs.h"
+
+static git_repository *repo;
+static git_reference *fake_remote;
+
+void test_refs_foreachglob__initialize(void)
+{
+ git_oid id;
+
+ cl_fixture_sandbox("testrepo.git");
+ cl_git_pass(git_repository_open(&repo, "testrepo.git"));
+
+ cl_git_pass(git_oid_fromstr(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"));
+ cl_git_pass(git_reference_create_oid(&fake_remote, repo, "refs/remotes/nulltoken/master", &id, 0));
+}
+
+void test_refs_foreachglob__cleanup(void)
+{
+ git_reference_free(fake_remote);
+ git_repository_free(repo);
+
+ cl_fixture_cleanup("testrepo.git");
+}
+
+static int count_cb(const char *reference_name, void *payload)
+{
+ int *count = (int *)payload;
+
+ GIT_UNUSED(reference_name);
+
+ (*count)++;
+
+ return 0;
+}
+
+static void assert_retrieval(const char *glob, unsigned int flags, int expected_count)
+{
+ int count = 0;
+
+ cl_git_pass(git_reference_foreach_glob(repo, glob, flags, count_cb, &count));
+
+ cl_assert_equal_i(expected_count, count);
+}
+
+void test_refs_foreachglob__retrieve_all_refs(void)
+{
+ /* 7 heads (including one packed head) + 1 note + 2 remotes + 6 tags */
+ assert_retrieval("*", GIT_REF_LISTALL, 16);
+}
+
+void test_refs_foreachglob__retrieve_remote_branches(void)
+{
+ assert_retrieval("refs/remotes/*", GIT_REF_LISTALL, 2);
+}
+
+void test_refs_foreachglob__retrieve_local_branches(void)
+{
+ assert_retrieval("refs/heads/*", GIT_REF_LISTALL, 7);
+}
+
+void test_refs_foreachglob__retrieve_partially_named_references(void)
+{
+ /*
+ * refs/heads/packed-test, refs/heads/test
+ * refs/remotes/test/master, refs/tags/test
+ */
+
+ assert_retrieval("*test*", GIT_REF_LISTALL, 4);
+}