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:
authorEdward Thomson <ethomson@microsoft.com>2013-05-11 13:42:49 +0400
committerEdward Thomson <ethomson@microsoft.com>2013-05-11 13:42:49 +0400
commitb6cc559a78a073f2aadd179fe40c09be7318c898 (patch)
treec40a7806c16eb133794427aa2e1ca25e86ce1d74 /src/refdb_fs.c
parent4a65aead2ce2003902f4b54b331af33af7340b58 (diff)
parentc58cac12c24fbb127cf1928bec20decb007a75e8 (diff)
Merge pull request #1385 from carlosmn/refs-iter
Introduce a refs iterator
Diffstat (limited to 'src/refdb_fs.c')
-rw-r--r--src/refdb_fs.c172
1 files changed, 105 insertions, 67 deletions
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;