diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/branch.c | 57 | ||||
-rw-r--r-- | src/clone.c | 1 | ||||
-rw-r--r-- | src/refdb.c | 80 | ||||
-rw-r--r-- | src/refdb.h | 16 | ||||
-rw-r--r-- | src/refdb_fs.c | 172 | ||||
-rw-r--r-- | src/refs.c | 84 | ||||
-rw-r--r-- | src/remote.c | 33 | ||||
-rw-r--r-- | src/repository.c | 2 | ||||
-rw-r--r-- | src/revwalk.c | 2 | ||||
-rw-r--r-- | src/tag.c | 2 | ||||
-rw-r--r-- | src/transports/local.c | 2 | ||||
-rw-r--r-- | src/transports/smart_protocol.c | 2 |
12 files changed, 277 insertions, 176 deletions
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); @@ -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) |