Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/libgit2.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/general.c2
-rw-r--r--include/git2/refs.h44
-rw-r--r--include/git2/sys/refdb_backend.h64
-rw-r--r--include/git2/types.h4
-rw-r--r--src/branch.c57
-rw-r--r--src/clone.c1
-rw-r--r--src/refdb.c80
-rw-r--r--src/refdb.h16
-rw-r--r--src/refdb_fs.c172
-rw-r--r--src/refs.c84
-rw-r--r--src/remote.c33
-rw-r--r--src/repository.c2
-rw-r--r--src/revwalk.c2
-rw-r--r--src/tag.c2
-rw-r--r--src/transports/local.c2
-rw-r--r--src/transports/smart_protocol.c2
-rw-r--r--tests-clar/network/fetchlocal.c6
-rw-r--r--tests-clar/refdb/inmemory.c4
-rw-r--r--tests-clar/refdb/testdb.c56
-rw-r--r--tests-clar/refs/foreachglob.c14
-rw-r--r--tests-clar/refs/iterator.c94
-rw-r--r--tests-clar/refs/list.c15
-rw-r--r--tests-clar/refs/listall.c4
23 files changed, 502 insertions, 258 deletions
diff --git a/examples/general.c b/examples/general.c
index adc7ed8d2..d7a58479c 100644
--- a/examples/general.c
+++ b/examples/general.c
@@ -453,7 +453,7 @@ int main (int argc, char** argv)
// Here we will implement something like `git for-each-ref` simply listing
// out all available references and the object SHA they resolve to.
git_strarray ref_list;
- git_reference_list(&ref_list, repo, GIT_REF_LISTALL);
+ git_reference_list(&ref_list, repo);
const char *refname;
git_reference *ref;
diff --git a/include/git2/refs.h b/include/git2/refs.h
index e78873408..754bda785 100644
--- a/include/git2/refs.h
+++ b/include/git2/refs.h
@@ -297,12 +297,6 @@ GIT_EXTERN(int) git_reference_delete(git_reference *ref);
/**
* Fill a list with all the references that can be found in a repository.
*
- * Using the `list_flags` parameter, the listed references may be filtered
- * by type (`GIT_REF_OID` or `GIT_REF_SYMBOLIC`) or using a bitwise OR of
- * `git_ref_t` values. To include packed refs, include `GIT_REF_PACKED`.
- * For convenience, use the value `GIT_REF_LISTALL` to obtain all
- * references, including packed ones.
- *
* The string array will be filled with the names of all references; these
* values are owned by the user and should be free'd manually when no
* longer needed, using `git_strarray_free()`.
@@ -310,36 +304,27 @@ GIT_EXTERN(int) git_reference_delete(git_reference *ref);
* @param array Pointer to a git_strarray structure where
* the reference names will be stored
* @param repo Repository where to find the refs
- * @param list_flags Filtering flags for the reference listing
* @return 0 or an error code
*/
-GIT_EXTERN(int) git_reference_list(git_strarray *array, git_repository *repo, unsigned int list_flags);
+GIT_EXTERN(int) git_reference_list(git_strarray *array, git_repository *repo);
typedef int (*git_reference_foreach_cb)(const char *refname, void *payload);
/**
* Perform a callback on each reference in the repository.
*
- * Using the `list_flags` parameter, the references may be filtered by
- * type (`GIT_REF_OID` or `GIT_REF_SYMBOLIC`) or using a bitwise OR of
- * `git_ref_t` values. To include packed refs, include `GIT_REF_PACKED`.
- * For convenience, use the value `GIT_REF_LISTALL` to obtain all
- * references, including packed ones.
- *
* The `callback` function will be called for each reference in the
* repository, receiving the name of the reference and the `payload` value
* passed to this method. Returning a non-zero value from the callback
* will terminate the iteration.
*
* @param repo Repository where to find the refs
- * @param list_flags Filtering flags for the reference listing.
* @param callback Function which will be called for every listed ref
* @param payload Additional data to pass to the callback
* @return 0 on success, GIT_EUSER on non-zero callback, or error code
*/
GIT_EXTERN(int) git_reference_foreach(
git_repository *repo,
- unsigned int list_flags,
git_reference_foreach_cb callback,
void *payload);
@@ -360,6 +345,31 @@ GIT_EXTERN(void) git_reference_free(git_reference *ref);
GIT_EXTERN(int) git_reference_cmp(git_reference *ref1, git_reference *ref2);
/**
+ * Create an iterator for the repo's references
+ *
+ * @param out pointer in which to store the iterator
+ * @param repo the repository
+ * @return 0 or an error code
+ */
+GIT_EXTERN(int) git_reference_iterator_new(git_reference_iterator **out, git_repository *repo);
+
+/**
+ * Get the next reference name
+ *
+ * @param out pointer in which to store the string
+ * @param iter the iterator
+ * @param 0, GIT_ITEROVER if there are no more; or an error code
+ */
+GIT_EXTERN(int) git_reference_next(const char **out, git_reference_iterator *iter);
+
+/**
+ * Free the iterator and its associated resources
+ *
+ * @param iter the iterator to free
+ */
+GIT_EXTERN(void) git_reference_iterator_free(git_reference_iterator *iter);
+
+/**
* Perform a callback on each reference in the repository whose name
* matches the given pattern.
*
@@ -373,7 +383,6 @@ GIT_EXTERN(int) git_reference_cmp(git_reference *ref1, git_reference *ref2);
*
* @param repo Repository where to find the refs
* @param glob Pattern to match (fnmatch-style) against reference name.
- * @param list_flags Filtering flags for the reference listing.
* @param callback Function which will be called for every listed ref
* @param payload Additional data to pass to the callback
* @return 0 on success, GIT_EUSER on non-zero callback, or error code
@@ -381,7 +390,6 @@ GIT_EXTERN(int) git_reference_cmp(git_reference *ref1, git_reference *ref2);
GIT_EXTERN(int) git_reference_foreach_glob(
git_repository *repo,
const char *glob,
- unsigned int list_flags,
git_reference_foreach_cb callback,
void *payload);
diff --git a/include/git2/sys/refdb_backend.h b/include/git2/sys/refdb_backend.h
index d5f599fec..8dbf38ca9 100644
--- a/include/git2/sys/refdb_backend.h
+++ b/include/git2/sys/refdb_backend.h
@@ -20,6 +20,23 @@
*/
GIT_BEGIN_DECL
+
+/**
+ * Every backend's iterator must have a pointer to itself as the first
+ * element, so the API can talk to it. You'd define your iterator as
+ *
+ * struct my_iterator {
+ * git_reference_iterator parent;
+ * ...
+ * }
+ *
+ * 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 */
struct git_refdb_backend {
unsigned int version;
@@ -43,29 +60,42 @@ struct git_refdb_backend {
const char *ref_name);
/**
- * Enumerates each reference in the refdb. A refdb implementation must
- * provide this function.
+ * Allocate an iterator object for the backend.
+ *
+ * A refdb implementation must provide this function.
*/
- int (*foreach)(
- git_refdb_backend *backend,
- unsigned int list_flags,
- git_reference_foreach_cb callback,
- void *payload);
+ int (*iterator)(
+ git_reference_iterator **iter,
+ struct git_refdb_backend *backend);
/**
- * Enumerates each reference in the refdb that matches the given
- * glob string. A refdb implementation may provide this function;
- * if it is not provided, foreach will be used and the results filtered
- * against the glob.
+ * 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 (*foreach_glob)(
- git_refdb_backend *backend,
- const char *glob,
- unsigned int list_flags,
- git_reference_foreach_cb callback,
- void *payload);
+ 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.
+ */
+ int (*next)(
+ const char **name,
+ git_reference_iterator *iter);
/**
+ * Free the iterator
+ *
+ * A refdb implementation must provide this function.
+ */
+ void (*iterator_free)(
+ git_reference_iterator *iter);
+ /*
* Writes the given reference to the refdb. A refdb implementation
* must provide this function.
*/
diff --git a/include/git2/types.h b/include/git2/types.h
index aca9ed927..43751d3b0 100644
--- a/include/git2/types.h
+++ b/include/git2/types.h
@@ -165,6 +165,10 @@ typedef struct git_signature {
/** In-memory representation of a reference. */
typedef struct git_reference git_reference;
+/** Iterator for references */
+typedef struct git_reference_iterator git_reference_iterator;
+
+
/** Basic type of any Git reference. */
typedef enum {
GIT_REF_INVALID = 0, /** Invalid reference */
diff --git a/src/branch.c b/src/branch.c
index 830294941..dd6dc68f4 100644
--- a/src/branch.c
+++ b/src/branch.c
@@ -124,40 +124,43 @@ on_error:
return error;
}
-typedef struct {
- git_branch_foreach_cb branch_cb;
- void *callback_payload;
- unsigned int branch_type;
-} branch_foreach_filter;
-
-static int branch_foreach_cb(const char *branch_name, void *payload)
-{
- branch_foreach_filter *filter = (branch_foreach_filter *)payload;
-
- if (filter->branch_type & GIT_BRANCH_LOCAL &&
- git__prefixcmp(branch_name, GIT_REFS_HEADS_DIR) == 0)
- return filter->branch_cb(branch_name + strlen(GIT_REFS_HEADS_DIR), GIT_BRANCH_LOCAL, filter->callback_payload);
-
- if (filter->branch_type & GIT_BRANCH_REMOTE &&
- git__prefixcmp(branch_name, GIT_REFS_REMOTES_DIR) == 0)
- return filter->branch_cb(branch_name + strlen(GIT_REFS_REMOTES_DIR), GIT_BRANCH_REMOTE, filter->callback_payload);
-
- return 0;
-}
-
int git_branch_foreach(
git_repository *repo,
unsigned int list_flags,
- git_branch_foreach_cb branch_cb,
+ git_branch_foreach_cb callback,
void *payload)
{
- branch_foreach_filter filter;
+ git_reference_iterator *iter;
+ const char *name;
+ int error;
+
+ if (git_reference_iterator_new(&iter, repo) < 0)
+ return -1;
+
+ while ((error = git_reference_next(&name, iter)) == 0) {
+ if (list_flags & GIT_BRANCH_LOCAL &&
+ git__prefixcmp(name, GIT_REFS_HEADS_DIR) == 0) {
+ if (callback(name + strlen(GIT_REFS_HEADS_DIR), GIT_BRANCH_LOCAL, payload)) {
+ error = GIT_EUSER;
+ break;
+ }
+ }
+
+ if (list_flags & GIT_BRANCH_REMOTE &&
+ git__prefixcmp(name, GIT_REFS_REMOTES_DIR) == 0) {
+ if (callback(name + strlen(GIT_REFS_REMOTES_DIR), GIT_BRANCH_REMOTE, payload)) {
+ error = GIT_EUSER;
+ break;
+ }
+ }
+ }
- filter.branch_cb = branch_cb;
- filter.branch_type = list_flags;
- filter.callback_payload = payload;
+ if (error == GIT_ITEROVER)
+ error = 0;
+
+ git_reference_iterator_free(iter);
+ return error;
- return git_reference_foreach(repo, GIT_REF_LISTALL, &branch_foreach_cb, (void *)&filter);
}
int git_branch_move(
diff --git a/src/clone.c b/src/clone.c
index 2ff119ee3..499195dcc 100644
--- a/src/clone.c
+++ b/src/clone.c
@@ -243,7 +243,6 @@ static int update_head_to_remote(git_repository *repo, git_remote *remote)
/* Not master. Check all the other refs. */
if (git_reference_foreach(
repo,
- GIT_REF_LISTALL,
reference_matches_remote_head,
&head_info) < 0)
goto cleanup;
diff --git a/src/refdb.c b/src/refdb.c
index 33a1934d1..9f9037ce7 100644
--- a/src/refdb.c
+++ b/src/refdb.c
@@ -124,60 +124,70 @@ int git_refdb_lookup(git_reference **out, git_refdb *db, const char *ref_name)
return error;
}
-int git_refdb_foreach(
- git_refdb *db,
- unsigned int list_flags,
- git_reference_foreach_cb callback,
- void *payload)
+int git_refdb_iterator(git_reference_iterator **out, git_refdb *db)
{
- assert(db && db->backend);
+ if (!db->backend || !db->backend->iterator) {
+ giterr_set(GITERR_REFERENCE, "This backend doesn't support iterators");
+ return -1;
+ }
- return db->backend->foreach(db->backend, list_flags, callback, payload);
-}
+ if (db->backend->iterator(out, db->backend) < 0)
+ return -1;
-struct glob_cb_data {
- const char *glob;
- git_reference_foreach_cb callback;
- void *payload;
-};
+ return 0;
+}
-static int fromglob_cb(const char *reference_name, void *payload)
+int git_refdb_iterator_glob(git_reference_iterator **out, git_refdb *db, const char *glob)
{
- struct glob_cb_data *data = (struct glob_cb_data *)payload;
+ if (!db->backend) {
+ giterr_set(GITERR_REFERENCE, "There are no backends loaded");
+ return -1;
+ }
- if (!p_fnmatch(data->glob, reference_name, 0))
- return data->callback(reference_name, data->payload);
+ 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;
+ }
return 0;
}
-int git_refdb_foreach_glob(
- git_refdb *db,
- const char *glob,
- unsigned int list_flags,
- git_reference_foreach_cb callback,
- void *payload)
+int git_refdb_next(const char **out, git_reference_iterator *iter)
{
int error;
- struct glob_cb_data data;
- assert(db && db->backend && glob && callback);
+ if (!iter->glob)
+ return iter->backend->next(out, iter);
- if(db->backend->foreach_glob != NULL)
- error = db->backend->foreach_glob(db->backend,
- glob, list_flags, callback, payload);
- else {
- data.glob = glob;
- data.callback = callback;
- data.payload = payload;
-
- error = db->backend->foreach(db->backend,
- list_flags, fromglob_cb, &data);
+ /* 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);
+}
+
+struct glob_cb_data {
+ const char *glob;
+ git_reference_foreach_cb callback;
+ void *payload;
+};
+
int git_refdb_write(git_refdb *db, const git_reference *ref)
{
assert(db && db->backend);
diff --git a/src/refdb.h b/src/refdb.h
index 047113ac8..2edd05d18 100644
--- a/src/refdb.h
+++ b/src/refdb.h
@@ -26,18 +26,10 @@ int git_refdb_lookup(
git_refdb *refdb,
const char *ref_name);
-int git_refdb_foreach(
- git_refdb *refdb,
- unsigned int list_flags,
- git_reference_foreach_cb callback,
- void *payload);
-
-int git_refdb_foreach_glob(
- git_refdb *refdb,
- const char *glob,
- unsigned int list_flags,
- git_reference_foreach_cb callback,
- void *payload);
+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);
int git_refdb_write(git_refdb *refdb, const git_reference *ref);
diff --git a/src/refdb_fs.c b/src/refdb_fs.c
index bb2cd0a73..9d0af579e 100644
--- a/src/refdb_fs.c
+++ b/src/refdb_fs.c
@@ -13,6 +13,7 @@
#include "reflog.h"
#include "refdb.h"
#include "refdb_fs.h"
+#include "iterator.h"
#include <git2/tag.h>
#include <git2/object.h>
@@ -180,6 +181,9 @@ static int packed_load(refdb_fs_backend *backend)
GITERR_CHECK_ALLOC(ref_cache->packfile);
}
+ if (backend->path == NULL)
+ return 0;
+
result = reference_read(&packfile, &ref_cache->packfile_time,
backend->path, GIT_PACKEDREFS_FILE, &updated);
@@ -558,98 +562,126 @@ struct dirent_list_data {
int callback_error;
};
-static git_ref_t loose_guess_rtype(const git_buf *full_path)
+typedef struct {
+ git_reference_iterator parent;
+ unsigned int loose;
+ /* packed */
+ git_strmap *h;
+ khiter_t k;
+ /* loose */
+ git_iterator *fsiter;
+ git_buf buf;
+} refdb_fs_iter;
+
+static int refdb_fs_backend__iterator(git_reference_iterator **out, git_refdb_backend *_backend)
{
- git_buf ref_file = GIT_BUF_INIT;
- git_ref_t type;
+ refdb_fs_iter *iter;
+ refdb_fs_backend *backend;
- type = GIT_REF_INVALID;
+ assert(_backend);
+ backend = (refdb_fs_backend *)_backend;
- if (git_futils_readbuffer(&ref_file, full_path->ptr) == 0) {
- if (git__prefixcmp((const char *)(ref_file.ptr), GIT_SYMREF) == 0)
- type = GIT_REF_SYMBOLIC;
- else
- type = GIT_REF_OID;
- }
+ if (packed_load(backend) < 0)
+ return -1;
- git_buf_free(&ref_file);
- return type;
+ iter = git__calloc(1, sizeof(refdb_fs_iter));
+ GITERR_CHECK_ALLOC(iter);
+
+ iter->parent.backend = _backend;
+ iter->h = backend->refcache.packfile;
+ iter->k = kh_begin(backend->refcache.packfile);
+
+ *out = (git_reference_iterator *)iter;
+
+ return 0;
}
-static int _dirent_loose_listall(void *_data, git_buf *full_path)
+static void refdb_fs_backend__iterator_free(git_reference_iterator *_iter)
{
- struct dirent_list_data *data = (struct dirent_list_data *)_data;
- const char *file_path = full_path->ptr + data->repo_path_len;
-
- if (git_path_isdir(full_path->ptr) == true)
- return git_path_direach(full_path, _dirent_loose_listall, _data);
+ refdb_fs_iter *iter = (refdb_fs_iter *) _iter;
- /* do not add twice a reference that exists already in the packfile */
- if (git_strmap_exists(data->backend->refcache.packfile, file_path))
- return 0;
+ git_buf_free(&iter->buf);
+ git_iterator_free(iter->fsiter);
+ git__free(iter);
+}
- if (data->list_type != GIT_REF_LISTALL) {
- if ((data->list_type & loose_guess_rtype(full_path)) == 0)
- return 0; /* we are filtering out this reference */
+static int iter_packed(const char **out, refdb_fs_iter *iter)
+{
+ /* Move forward to the next entry */
+ while (!kh_exist(iter->h, iter->k)) {
+ iter->k++;
+ if (iter->k == kh_end(iter->h))
+ return GIT_ITEROVER;
}
- /* Locked references aren't returned */
- if (!git__suffixcmp(file_path, GIT_FILELOCK_EXTENSION))
- return 0;
+ *out = kh_key(iter->h, iter->k);
+ iter->k++;
- if (data->callback(file_path, data->callback_payload))
- data->callback_error = GIT_EUSER;
-
- return data->callback_error;
+ return 0;
}
-static int refdb_fs_backend__foreach(
- git_refdb_backend *_backend,
- unsigned int list_type,
- git_reference_foreach_cb callback,
- void *payload)
+static int iter_loose(const char **out, refdb_fs_iter *iter)
{
- refdb_fs_backend *backend;
- int result;
- struct dirent_list_data data;
- git_buf refs_path = GIT_BUF_INIT;
- const char *ref_name;
- void *ref = NULL;
+ const git_index_entry *entry;
+ int retry;
+ git_strmap *packfile_refs;
+ refdb_fs_backend *backend = (refdb_fs_backend *) iter->parent.backend;
- GIT_UNUSED(ref);
+ packfile_refs = backend->refcache.packfile;
- assert(_backend);
- backend = (refdb_fs_backend *)_backend;
+ do {
+ khiter_t pos;
+ if (git_iterator_current(&entry, iter->fsiter) < 0)
+ return -1;
- if (packed_load(backend) < 0)
- return -1;
+ git_buf_clear(&iter->buf);
+ if (!entry)
+ return GIT_ITEROVER;
- /* list all the packed references first */
- if (list_type & GIT_REF_OID) {
- git_strmap_foreach(backend->refcache.packfile, ref_name, ref, {
- if (callback(ref_name, payload))
- return GIT_EUSER;
- });
- }
+ if (git_buf_printf(&iter->buf, "refs/%s", entry->path) < 0)
+ return -1;
- /* now list the loose references, trying not to
- * duplicate the ref names already in the packed-refs file */
+ git_iterator_advance(NULL, iter->fsiter);
- data.repo_path_len = strlen(backend->path);
- data.list_type = list_type;
- data.backend = backend;
- data.callback = callback;
- data.callback_payload = payload;
- data.callback_error = 0;
+ /* Skip this one if we already listed it in packed */
+ pos = git_strmap_lookup_index(packfile_refs, git_buf_cstr(&iter->buf));
+ retry = 0;
+ if (git_strmap_valid_index(packfile_refs, pos) ||
+ !git_reference_is_valid_name(git_buf_cstr(&iter->buf)))
+ retry = 1;
- if (git_buf_joinpath(&refs_path, backend->path, GIT_REFS_DIR) < 0)
+ *out = git_buf_cstr(&iter->buf);
+ } while (retry);
+
+ return 0;
+}
+
+static int iter_loose_setup(refdb_fs_iter *iter)
+{
+ refdb_fs_backend *backend = (refdb_fs_backend *) iter->parent.backend;
+
+ git_buf_clear(&iter->buf);
+ if (git_buf_printf(&iter->buf, "%s/refs", backend->path) < 0)
return -1;
- result = git_path_direach(&refs_path, _dirent_loose_listall, &data);
+ return git_iterator_for_filesystem(&iter->fsiter, git_buf_cstr(&iter->buf), 0, NULL, NULL);
+}
- git_buf_free(&refs_path);
+static int refdb_fs_backend__next(const char **out, git_reference_iterator *_iter)
+{
+ refdb_fs_iter *iter = (refdb_fs_iter *)_iter;
- return data.callback_error ? GIT_EUSER : result;
+ /* First round of checks to make sure where we are */
+ if (!iter->loose && iter->k == kh_end(iter->h)) {
+ if (iter_loose_setup(iter) < 0)
+ return -1;
+ iter->loose = 1;
+ }
+
+ if (!iter->loose)
+ return iter_packed(out, iter);
+ else
+ return iter_loose(out, iter);
}
static int loose_write(refdb_fs_backend *backend, const git_reference *ref)
@@ -1027,6 +1059,10 @@ static int setup_namespace(git_buf *path, git_repository *repo)
{
char *parts, *start, *end;
+ /* Not all repositories have a path */
+ if (repo->path_repository == NULL)
+ return 0;
+
/* Load the path to the repo first */
git_buf_puts(path, repo->path_repository);
@@ -1081,7 +1117,9 @@ int git_refdb_backend_fs(
backend->parent.exists = &refdb_fs_backend__exists;
backend->parent.lookup = &refdb_fs_backend__lookup;
- backend->parent.foreach = &refdb_fs_backend__foreach;
+ backend->parent.iterator = &refdb_fs_backend__iterator;
+ backend->parent.next = &refdb_fs_backend__next;
+ backend->parent.iterator_free = &refdb_fs_backend__iterator_free;
backend->parent.write = &refdb_fs_backend__write;
backend->parent.delete = &refdb_fs_backend__delete;
backend->parent.compress = &refdb_fs_backend__compress;
diff --git a/src/refs.c b/src/refs.c
index 684c54cd1..9c6c5c623 100644
--- a/src/refs.c
+++ b/src/refs.c
@@ -139,7 +139,7 @@ static int reference_path_available(
data.available = 1;
error = git_reference_foreach(
- repo, GIT_REF_LISTALL, _reference_available_cb, (void *)&data);
+ repo, _reference_available_cb, (void *)&data);
if (error < 0)
return error;
@@ -619,14 +619,59 @@ int git_reference_resolve(git_reference **ref_out, const git_reference *ref)
int git_reference_foreach(
git_repository *repo,
- unsigned int list_flags,
git_reference_foreach_cb callback,
void *payload)
{
+ git_reference_iterator *iter;
+ const char *name;
+ int error;
+
+ if (git_reference_iterator_new(&iter, repo) < 0)
+ return -1;
+
+ while ((error = git_reference_next(&name, iter)) == 0) {
+ if (callback(name, payload)) {
+ error = GIT_EUSER;
+ goto out;
+ }
+ }
+
+ if (error == GIT_ITEROVER)
+ error = 0;
+
+out:
+ git_reference_iterator_free(iter);
+ return error;
+}
+
+int git_reference_iterator_new(git_reference_iterator **out, git_repository *repo)
+{
+ git_refdb *refdb;
+
+ if (git_repository_refdb__weakptr(&refdb, repo) < 0)
+ return -1;
+
+ 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;
- git_repository_refdb__weakptr(&refdb, repo);
- return git_refdb_foreach(refdb, list_flags, callback, payload);
+ 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);
+}
+
+void git_reference_iterator_free(git_reference_iterator *iter)
+{
+ git_refdb_iterator_free(iter);
}
static int cb__reflist_add(const char *ref, void *data)
@@ -636,8 +681,7 @@ static int cb__reflist_add(const char *ref, void *data)
int git_reference_list(
git_strarray *array,
- git_repository *repo,
- unsigned int list_flags)
+ git_repository *repo)
{
git_vector ref_list;
@@ -650,7 +694,7 @@ int git_reference_list(
return -1;
if (git_reference_foreach(
- repo, list_flags, &cb__reflist_add, (void *)&ref_list) < 0) {
+ repo, &cb__reflist_add, (void *)&ref_list) < 0) {
git_vector_free(&ref_list);
return -1;
}
@@ -950,19 +994,29 @@ int git_reference__update_terminal(
int git_reference_foreach_glob(
git_repository *repo,
const char *glob,
- unsigned int list_flags,
- int (*callback)(
- const char *reference_name,
- void *payload),
+ git_reference_foreach_cb callback,
void *payload)
{
- git_refdb *refdb;
+ git_reference_iterator *iter;
+ const char *name;
+ int error;
- assert(repo && glob && callback);
+ if (git_reference_iterator_glob_new(&iter, repo, glob) < 0)
+ return -1;
- git_repository_refdb__weakptr(&refdb, repo);
+ while ((error = git_reference_next(&name, iter)) == 0) {
+ if (callback(name, payload)) {
+ error = GIT_EUSER;
+ goto out;
+ }
+ }
- return git_refdb_foreach_glob(refdb, glob, list_flags, callback, payload);
+ if (error == GIT_ITEROVER)
+ error = 0;
+
+out:
+ git_reference_iterator_free(iter);
+ return error;
}
int git_reference_has_log(
diff --git a/src/remote.c b/src/remote.c
index 8a2982c3b..e5a7df75e 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -1251,14 +1251,6 @@ static int update_branch_remote_config_entry(
update_config_entries_cb, &data);
}
-static int rename_cb(const char *ref, void *data)
-{
- if (git__prefixcmp(ref, GIT_REFS_REMOTES_DIR))
- return 0;
-
- return git_vector_insert((git_vector *)data, git__strdup(ref));
-}
-
static int rename_one_remote_reference(
git_repository *repo,
const char *reference_name,
@@ -1298,16 +1290,29 @@ static int rename_remote_references(
int error = -1;
unsigned int i;
char *name;
+ const char *refname;
+ git_reference_iterator *iter;
if (git_vector_init(&refnames, 8, NULL) < 0)
+ return -1;
+
+ if (git_reference_iterator_new(&iter, repo) < 0)
goto cleanup;
- if (git_reference_foreach(
- repo,
- GIT_REF_LISTALL,
- rename_cb,
- &refnames) < 0)
- goto cleanup;
+ while ((error = git_reference_next(&refname, iter)) == 0) {
+ if (git__prefixcmp(refname, GIT_REFS_REMOTES_DIR))
+ continue;
+
+ if ((error = git_vector_insert(&refnames, git__strdup(refname))) < 0)
+ break;
+
+ }
+
+ git_reference_iterator_free(iter);
+ if (error == GIT_ITEROVER)
+ error = 0;
+ else
+ goto cleanup;
git_vector_foreach(&refnames, i, name) {
if ((error = rename_one_remote_reference(repo, name, old_name, new_name)) < 0)
diff --git a/src/repository.c b/src/repository.c
index 0b8fc395b..4ab3921bb 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -1473,7 +1473,7 @@ static int at_least_one_cb(const char *refname, void *payload)
static int repo_contains_no_reference(git_repository *repo)
{
- int error = git_reference_foreach(repo, GIT_REF_LISTALL, at_least_one_cb, NULL);
+ int error = git_reference_foreach(repo, at_least_one_cb, NULL);
if (error == GIT_EUSER)
return 0;
diff --git a/src/revwalk.c b/src/revwalk.c
index 16f06624d..528d02b20 100644
--- a/src/revwalk.c
+++ b/src/revwalk.c
@@ -186,7 +186,7 @@ static int push_glob(git_revwalk *walk, const char *glob, int hide)
data.hide = hide;
if (git_reference_foreach_glob(
- walk->repo, git_buf_cstr(&buf), GIT_REF_LISTALL, push_glob_cb, &data) < 0)
+ walk->repo, git_buf_cstr(&buf), push_glob_cb, &data) < 0)
goto on_error;
regfree(&preg);
diff --git a/src/tag.c b/src/tag.c
index a4f2e2581..f81956de7 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -427,7 +427,7 @@ int git_tag_foreach(git_repository *repo, git_tag_foreach_cb cb, void *cb_data)
data.cb_data = cb_data;
data.repo = repo;
- return git_reference_foreach(repo, GIT_REF_OID, &tags_cb, &data);
+ return git_reference_foreach(repo, &tags_cb, &data);
}
typedef struct {
diff --git a/src/transports/local.c b/src/transports/local.c
index 8b4d50c14..bd3bf93bf 100644
--- a/src/transports/local.c
+++ b/src/transports/local.c
@@ -124,7 +124,7 @@ static int store_refs(transport_local *t)
assert(t);
- if (git_reference_list(&ref_names, t->repo, GIT_REF_LISTALL) < 0 ||
+ if (git_reference_list(&ref_names, t->repo) < 0 ||
git_vector_init(&t->refs, ref_names.count, NULL) < 0)
goto on_error;
diff --git a/src/transports/smart_protocol.c b/src/transports/smart_protocol.c
index 765b914b7..09bef1ae3 100644
--- a/src/transports/smart_protocol.c
+++ b/src/transports/smart_protocol.c
@@ -193,7 +193,7 @@ static int fetch_setup_walk(git_revwalk **out, git_repository *repo)
unsigned int i;
git_reference *ref;
- if (git_reference_list(&refs, repo, GIT_REF_LISTALL) < 0)
+ if (git_reference_list(&refs, repo) < 0)
return -1;
if (git_revwalk_new(&walk, repo) < 0)
diff --git a/tests-clar/network/fetchlocal.c b/tests-clar/network/fetchlocal.c
index bcf298cde..09335b3df 100644
--- a/tests-clar/network/fetchlocal.c
+++ b/tests-clar/network/fetchlocal.c
@@ -34,7 +34,7 @@ void test_network_fetchlocal__complete(void)
cl_git_pass(git_remote_download(origin, transfer_cb, &callcount));
cl_git_pass(git_remote_update_tips(origin));
- cl_git_pass(git_reference_list(&refnames, repo, GIT_REF_LISTALL));
+ cl_git_pass(git_reference_list(&refnames, repo));
cl_assert_equal_i(19, (int)refnames.count);
cl_assert(callcount > 0);
@@ -58,7 +58,7 @@ void test_network_fetchlocal__partial(void)
const char *url;
cl_set_cleanup(&cleanup_sandbox, NULL);
- cl_git_pass(git_reference_list(&refnames, repo, GIT_REF_LISTALL));
+ cl_git_pass(git_reference_list(&refnames, repo));
cl_assert_equal_i(1, (int)refnames.count);
url = cl_git_fixture_url("testrepo.git");
@@ -69,7 +69,7 @@ void test_network_fetchlocal__partial(void)
git_strarray_free(&refnames);
- cl_git_pass(git_reference_list(&refnames, repo, GIT_REF_LISTALL));
+ cl_git_pass(git_reference_list(&refnames, repo));
cl_assert_equal_i(20, (int)refnames.count); /* 18 remote + 1 local */
cl_assert(callcount > 0);
diff --git a/tests-clar/refdb/inmemory.c b/tests-clar/refdb/inmemory.c
index 243b5bb37..d2594cd6d 100644
--- a/tests-clar/refdb/inmemory.c
+++ b/tests-clar/refdb/inmemory.c
@@ -163,7 +163,7 @@ void test_refdb_inmemory__foreach(void)
cl_git_pass(git_oid_fromstr(&oid3, "763d71aadf09a7951596c9746c024e7eece7c7af"));
cl_git_pass(git_reference_create(&write3, repo, GIT_REFS_HEADS_DIR "test3", &oid3, 0));
- cl_git_pass(git_reference_foreach(repo, GIT_REF_LISTALL, foreach_test, &i));
+ cl_git_pass(git_reference_foreach(repo,foreach_test, &i));
cl_assert_equal_i(3, (int)i);
git_reference_free(write1);
@@ -210,7 +210,7 @@ void test_refdb_inmemory__delete(void)
git_reference_delete(write3);
git_reference_free(write3);
- cl_git_pass(git_reference_foreach(repo, GIT_REF_LISTALL, delete_test, &i));
+ cl_git_pass(git_reference_foreach(repo, delete_test, &i));
cl_assert_equal_i(1, (int)i);
git_reference_free(write2);
diff --git a/tests-clar/refdb/testdb.c b/tests-clar/refdb/testdb.c
index 627254e44..961e18d44 100644
--- a/tests-clar/refdb/testdb.c
+++ b/tests-clar/refdb/testdb.c
@@ -112,33 +112,49 @@ static int refdb_test_backend__lookup(
return GIT_ENOTFOUND;
}
-static int refdb_test_backend__foreach(
- git_refdb_backend *_backend,
- unsigned int list_flags,
- git_reference_foreach_cb callback,
- void *payload)
-{
- refdb_test_backend *backend;
- refdb_test_entry *entry;
+typedef struct {
+ git_reference_iterator parent;
size_t i;
+} refdb_test_iter;
- assert(_backend);
- backend = (refdb_test_backend *)_backend;
+static int refdb_test_backend__iterator(git_reference_iterator **out, git_refdb_backend *_backend)
+{
+ refdb_test_iter *iter;
- git_vector_foreach(&backend->refs, i, entry) {
- if (entry->type == GIT_REF_OID && (list_flags & GIT_REF_OID) == 0)
- continue;
+ GIT_UNUSED(_backend);
- if (entry->type == GIT_REF_SYMBOLIC && (list_flags & GIT_REF_SYMBOLIC) == 0)
- continue;
+ iter = git__calloc(1, sizeof(refdb_test_iter));
+ GITERR_CHECK_ALLOC(iter);
- if (callback(entry->name, payload) != 0)
- return GIT_EUSER;
- }
+ iter->parent.backend = _backend;
+ iter->i = 0;
+
+ *out = (git_reference_iterator *) iter;
return 0;
}
+static int refdb_test_backend__next(const char **name, git_reference_iterator *_iter)
+{
+ refdb_test_entry *entry;
+ refdb_test_backend *backend = (refdb_test_backend *) _iter->backend;
+ refdb_test_iter *iter = (refdb_test_iter *) _iter;
+
+ entry = git_vector_get(&backend->refs, iter->i);
+ if (!entry)
+ return GIT_ITEROVER;
+
+ *name = entry->name;
+ iter->i++;
+
+ return 0;
+}
+
+static void refdb_test_backend__iterator_free(git_reference_iterator *iter)
+{
+ git__free(iter);
+}
+
static void refdb_test_entry_free(refdb_test_entry *entry)
{
if (entry->type == GIT_REF_SYMBOLIC)
@@ -200,7 +216,9 @@ int refdb_backend_test(
backend->parent.exists = &refdb_test_backend__exists;
backend->parent.lookup = &refdb_test_backend__lookup;
- backend->parent.foreach = &refdb_test_backend__foreach;
+ backend->parent.iterator = &refdb_test_backend__iterator;
+ backend->parent.next = &refdb_test_backend__next;
+ backend->parent.iterator_free = &refdb_test_backend__iterator_free;
backend->parent.write = &refdb_test_backend__write;
backend->parent.delete = &refdb_test_backend__delete;
backend->parent.free = &refdb_test_backend__free;
diff --git a/tests-clar/refs/foreachglob.c b/tests-clar/refs/foreachglob.c
index 4da1a15dd..2c458082f 100644
--- a/tests-clar/refs/foreachglob.c
+++ b/tests-clar/refs/foreachglob.c
@@ -37,11 +37,11 @@ static int count_cb(const char *reference_name, void *payload)
return 0;
}
-static void assert_retrieval(const char *glob, unsigned int flags, int expected_count)
+static void assert_retrieval(const char *glob, int expected_count)
{
int count = 0;
- cl_git_pass(git_reference_foreach_glob(repo, glob, flags, count_cb, &count));
+ cl_git_pass(git_reference_foreach_glob(repo, glob, count_cb, &count));
cl_assert_equal_i(expected_count, count);
}
@@ -49,17 +49,17 @@ static void assert_retrieval(const char *glob, unsigned int flags, int expected_
void test_refs_foreachglob__retrieve_all_refs(void)
{
/* 12 heads (including one packed head) + 1 note + 2 remotes + 7 tags */
- assert_retrieval("*", GIT_REF_LISTALL, 22);
+ assert_retrieval("*", 22);
}
void test_refs_foreachglob__retrieve_remote_branches(void)
{
- assert_retrieval("refs/remotes/*", GIT_REF_LISTALL, 2);
+ assert_retrieval("refs/remotes/*", 2);
}
void test_refs_foreachglob__retrieve_local_branches(void)
{
- assert_retrieval("refs/heads/*", GIT_REF_LISTALL, 12);
+ assert_retrieval("refs/heads/*", 12);
}
void test_refs_foreachglob__retrieve_partially_named_references(void)
@@ -69,7 +69,7 @@ void test_refs_foreachglob__retrieve_partially_named_references(void)
* refs/remotes/test/master, refs/tags/test
*/
- assert_retrieval("*test*", GIT_REF_LISTALL, 4);
+ assert_retrieval("*test*", 4);
}
@@ -89,7 +89,7 @@ void test_refs_foreachglob__can_cancel(void)
int count = 0;
cl_assert_equal_i(GIT_EUSER, git_reference_foreach_glob(
- repo, "*", GIT_REF_LISTALL, interrupt_cb, &count) );
+ repo, "*", interrupt_cb, &count) );
cl_assert_equal_i(11, count);
}
diff --git a/tests-clar/refs/iterator.c b/tests-clar/refs/iterator.c
new file mode 100644
index 000000000..d5555c657
--- /dev/null
+++ b/tests-clar/refs/iterator.c
@@ -0,0 +1,94 @@
+#include "clar_libgit2.h"
+#include "refs.h"
+#include "vector.h"
+
+static git_repository *repo;
+
+void test_refs_iterator__initialize(void)
+{
+ cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
+}
+
+void test_refs_iterator__cleanup(void)
+{
+ git_repository_free(repo);
+}
+
+static const char *refnames[] = {
+ "refs/heads/br2",
+ "refs/heads/cannot-fetch",
+ "refs/heads/chomped",
+ "refs/heads/haacked",
+ "refs/heads/master",
+ "refs/heads/not-good",
+ "refs/heads/packed",
+ "refs/heads/packed-test",
+ "refs/heads/subtrees",
+ "refs/heads/test",
+ "refs/heads/track-local",
+ "refs/heads/trailing",
+ "refs/notes/fanout",
+ "refs/remotes/test/master",
+ "refs/tags/annotated_tag_to_blob",
+ "refs/tags/e90810b",
+ "refs/tags/hard_tag",
+ "refs/tags/point_to_blob",
+ "refs/tags/taggerless",
+ "refs/tags/test",
+ "refs/tags/wrapped_tag",
+};
+
+void test_refs_iterator__list(void)
+{
+ git_reference_iterator *iter;
+ git_vector output;
+ char *refname;
+ int error;
+ size_t i;
+
+ cl_git_pass(git_vector_init(&output, 32, git__strcmp_cb));
+ cl_git_pass(git_reference_iterator_new(&iter, repo));
+
+ do {
+ const char *name;
+ error = git_reference_next(&name, iter);
+ cl_assert(error == 0 || error == GIT_ITEROVER);
+ if (error != GIT_ITEROVER) {
+ char *dup = git__strdup(name);
+ cl_assert(dup != NULL);
+ cl_git_pass(git_vector_insert(&output, dup));
+ }
+ } while (!error);
+
+ cl_assert_equal_i(output.length, ARRAY_SIZE(refnames));
+
+ git_vector_sort(&output);
+ git_vector_foreach(&output, i, refname) {
+ cl_assert_equal_s(refname, refnames[i]);
+ }
+
+ git_reference_iterator_free(iter);
+
+ git_vector_foreach(&output, i, refname) {
+ git__free(refname);
+ }
+ git_vector_free(&output);
+}
+
+void test_refs_iterator__empty(void)
+{
+ git_reference_iterator *iter;
+ git_odb *odb;
+ const char *name;
+ git_repository *empty;
+
+ cl_git_pass(git_odb_new(&odb));
+ cl_git_pass(git_repository_wrap_odb(&empty, odb));
+
+ cl_git_pass(git_reference_iterator_new(&iter, empty));
+ cl_assert_equal_i(GIT_ITEROVER, git_reference_next(&name, iter));
+
+ git_reference_iterator_free(iter);
+ git_odb_free(odb);
+ git_repository_free(empty);
+}
diff --git a/tests-clar/refs/list.c b/tests-clar/refs/list.c
index 3948b2b7a..c9c2af4a7 100644
--- a/tests-clar/refs/list.c
+++ b/tests-clar/refs/list.c
@@ -25,7 +25,7 @@ void test_refs_list__all(void)
// try to list all the references in our test repo
git_strarray ref_list;
- cl_git_pass(git_reference_list(&ref_list, g_repo, GIT_REF_LISTALL));
+ cl_git_pass(git_reference_list(&ref_list, g_repo));
/*{
unsigned short i;
@@ -41,17 +41,6 @@ void test_refs_list__all(void)
git_strarray_free(&ref_list);
}
-void test_refs_list__symbolic_only(void)
-{
- // try to list only the symbolic references
- git_strarray ref_list;
-
- cl_git_pass(git_reference_list(&ref_list, g_repo, GIT_REF_SYMBOLIC));
- cl_assert(ref_list.count == 0); /* no symrefs in the test repo */
-
- git_strarray_free(&ref_list);
-}
-
void test_refs_list__do_not_retrieve_references_which_name_end_with_a_lock_extension(void)
{
git_strarray ref_list;
@@ -61,7 +50,7 @@ void test_refs_list__do_not_retrieve_references_which_name_end_with_a_lock_exten
"./testrepo/.git/refs/heads/hanwen.lock",
"144344043ba4d4a405da03de3844aa829ae8be0e\n");
- cl_git_pass(git_reference_list(&ref_list, g_repo, GIT_REF_LISTALL));
+ cl_git_pass(git_reference_list(&ref_list, g_repo));
cl_assert_equal_i((int)ref_list.count, 13);
git_strarray_free(&ref_list);
diff --git a/tests-clar/refs/listall.c b/tests-clar/refs/listall.c
index 8f4c3746b..c696fbb2e 100644
--- a/tests-clar/refs/listall.c
+++ b/tests-clar/refs/listall.c
@@ -9,7 +9,7 @@ static void ensure_no_refname_starts_with_a_forward_slash(const char *path)
size_t i;
cl_git_pass(git_repository_open(&repo, path));
- cl_git_pass(git_reference_list(&ref_list, repo, GIT_REF_LISTALL));
+ cl_git_pass(git_reference_list(&ref_list, repo));
cl_assert(ref_list.count > 0);
@@ -38,7 +38,7 @@ void test_refs_listall__from_repository_opened_through_gitdir_path(void)
void test_refs_listall__from_repository_with_no_trailing_newline(void)
{
cl_git_pass(git_repository_open(&repo, cl_fixture("bad_tag.git")));
- cl_git_pass(git_reference_list(&ref_list, repo, GIT_REF_LISTALL));
+ cl_git_pass(git_reference_list(&ref_list, repo));
cl_assert(ref_list.count > 0);