Commit 947fad4f by Vicent Martí

Merge pull request #1624 from libgit2/vmg/full-ref-iterator

Breaking RefDB changes
parents 9d9fff3c efd5a4e1
...@@ -257,11 +257,6 @@ GIT_EXTERN(int) git_reference_set_target( ...@@ -257,11 +257,6 @@ GIT_EXTERN(int) git_reference_set_target(
* The new name will be checked for validity. * The new name will be checked for validity.
* See `git_reference_create_symbolic()` for rules about valid names. * See `git_reference_create_symbolic()` for rules about valid names.
* *
* On success, the given git_reference will be deleted from disk and a
* new `git_reference` will be returned.
*
* The reference will be immediately renamed in-memory and on disk.
*
* If the `force` flag is not enabled, and there's already * If the `force` flag is not enabled, and there's already
* a reference with the given name, the renaming will fail. * a reference with the given name, the renaming will fail.
* *
...@@ -277,7 +272,7 @@ GIT_EXTERN(int) git_reference_set_target( ...@@ -277,7 +272,7 @@ GIT_EXTERN(int) git_reference_set_target(
* *
*/ */
GIT_EXTERN(int) git_reference_rename( GIT_EXTERN(int) git_reference_rename(
git_reference **out, git_reference **new_ref,
git_reference *ref, git_reference *ref,
const char *new_name, const char *new_name,
int force); int force);
...@@ -308,7 +303,8 @@ GIT_EXTERN(int) git_reference_delete(git_reference *ref); ...@@ -308,7 +303,8 @@ GIT_EXTERN(int) git_reference_delete(git_reference *ref);
*/ */
GIT_EXTERN(int) git_reference_list(git_strarray *array, git_repository *repo); GIT_EXTERN(int) git_reference_list(git_strarray *array, git_repository *repo);
typedef int (*git_reference_foreach_cb)(const char *refname, void *payload); typedef int (*git_reference_foreach_cb)(git_reference *reference, void *payload);
typedef int (*git_reference_foreach_name_cb)(const char *name, void *payload);
/** /**
* Perform a callback on each reference in the repository. * Perform a callback on each reference in the repository.
...@@ -328,6 +324,11 @@ GIT_EXTERN(int) git_reference_foreach( ...@@ -328,6 +324,11 @@ GIT_EXTERN(int) git_reference_foreach(
git_reference_foreach_cb callback, git_reference_foreach_cb callback,
void *payload); void *payload);
GIT_EXTERN(int) git_reference_foreach_name(
git_repository *repo,
git_reference_foreach_name_cb callback,
void *payload);
/** /**
* Free the given reference. * Free the given reference.
* *
...@@ -351,7 +352,9 @@ GIT_EXTERN(int) git_reference_cmp(git_reference *ref1, git_reference *ref2); ...@@ -351,7 +352,9 @@ GIT_EXTERN(int) git_reference_cmp(git_reference *ref1, git_reference *ref2);
* @param repo the repository * @param repo the repository
* @return 0 or an error code * @return 0 or an error code
*/ */
GIT_EXTERN(int) git_reference_iterator_new(git_reference_iterator **out, git_repository *repo); GIT_EXTERN(int) git_reference_iterator_new(
git_reference_iterator **out,
git_repository *repo);
/** /**
* Create an iterator for the repo's references that match the * Create an iterator for the repo's references that match the
...@@ -362,16 +365,21 @@ GIT_EXTERN(int) git_reference_iterator_new(git_reference_iterator **out, git_rep ...@@ -362,16 +365,21 @@ GIT_EXTERN(int) git_reference_iterator_new(git_reference_iterator **out, git_rep
* @param glob the glob to match against the reference names * @param glob the glob to match against the reference names
* @return 0 or an error code * @return 0 or an error code
*/ */
GIT_EXTERN(int) git_reference_iterator_glob_new(git_reference_iterator **out, git_repository *repo, const char *glob); GIT_EXTERN(int) git_reference_iterator_glob_new(
git_reference_iterator **out,
git_repository *repo,
const char *glob);
/** /**
* Get the next reference name * Get the next reference
* *
* @param out pointer in which to store the string * @param out pointer in which to store the reference
* @param iter the iterator * @param iter the iterator
* @param 0, GIT_ITEROVER if there are no more; or an error code * @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); GIT_EXTERN(int) git_reference_next(git_reference **out, git_reference_iterator *iter);
GIT_EXTERN(int) git_reference_next_name(const char **out, git_reference_iterator *iter);
/** /**
* Free the iterator and its associated resources * Free the iterator and its associated resources
...@@ -401,7 +409,7 @@ GIT_EXTERN(void) git_reference_iterator_free(git_reference_iterator *iter); ...@@ -401,7 +409,7 @@ GIT_EXTERN(void) git_reference_iterator_free(git_reference_iterator *iter);
GIT_EXTERN(int) git_reference_foreach_glob( GIT_EXTERN(int) git_reference_foreach_glob(
git_repository *repo, git_repository *repo,
const char *glob, const char *glob,
git_reference_foreach_cb callback, git_reference_foreach_name_cb callback,
void *payload); void *payload);
/** /**
......
...@@ -33,8 +33,27 @@ GIT_BEGIN_DECL ...@@ -33,8 +33,27 @@ GIT_BEGIN_DECL
* and assign `iter->parent.backend` to your `git_refdb_backend`. * and assign `iter->parent.backend` to your `git_refdb_backend`.
*/ */
struct git_reference_iterator { struct git_reference_iterator {
git_refdb_backend *backend; git_refdb *db;
char *glob;
/**
* Return the current reference and advance the iterator.
*/
int (*next)(
git_reference **ref,
git_reference_iterator *iter);
/**
* Return the name of the current reference and advance the iterator
*/
int (*next_name)(
const char **ref_name,
git_reference_iterator *iter);
/**
* Free the iterator
*/
void (*free)(
git_reference_iterator *iter);
}; };
/** An instance for a custom backend */ /** An instance for a custom backend */
...@@ -66,46 +85,25 @@ struct git_refdb_backend { ...@@ -66,46 +85,25 @@ struct git_refdb_backend {
*/ */
int (*iterator)( int (*iterator)(
git_reference_iterator **iter, git_reference_iterator **iter,
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, struct git_refdb_backend *backend,
const char *glob); 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 * Writes the given reference to the refdb. A refdb implementation
* must provide this function. * must provide this function.
*/ */
int (*write)(git_refdb_backend *backend, const git_reference *ref); int (*write)(git_refdb_backend *backend,
const git_reference *ref, int force);
int (*rename)(
git_reference **out, git_refdb_backend *backend,
const char *old_name, const char *new_name, int force);
/** /**
* Deletes the given reference from the refdb. A refdb implementation * Deletes the given reference from the refdb. A refdb implementation
* must provide this function. * must provide this function.
*/ */
int (*delete)(git_refdb_backend *backend, const git_reference *ref); int (*delete)(git_refdb_backend *backend, const char *ref_name);
/** /**
* Suggests that the given refdb compress or optimize its references. * Suggests that the given refdb compress or optimize its references.
......
...@@ -131,28 +131,32 @@ int git_branch_foreach( ...@@ -131,28 +131,32 @@ int git_branch_foreach(
void *payload) void *payload)
{ {
git_reference_iterator *iter; git_reference_iterator *iter;
const char *name; git_reference *ref;
int error; int error;
if (git_reference_iterator_new(&iter, repo) < 0) if (git_reference_iterator_new(&iter, repo) < 0)
return -1; return -1;
while ((error = git_reference_next(&name, iter)) == 0) { while ((error = git_reference_next(&ref, iter)) == 0) {
if (list_flags & GIT_BRANCH_LOCAL && if (list_flags & GIT_BRANCH_LOCAL &&
git__prefixcmp(name, GIT_REFS_HEADS_DIR) == 0) { git__prefixcmp(ref->name, GIT_REFS_HEADS_DIR) == 0) {
if (callback(name + strlen(GIT_REFS_HEADS_DIR), GIT_BRANCH_LOCAL, payload)) { if (callback(ref->name + strlen(GIT_REFS_HEADS_DIR),
GIT_BRANCH_LOCAL, payload)) {
error = GIT_EUSER; error = GIT_EUSER;
break; break;
} }
} }
if (list_flags & GIT_BRANCH_REMOTE && if (list_flags & GIT_BRANCH_REMOTE &&
git__prefixcmp(name, GIT_REFS_REMOTES_DIR) == 0) { git__prefixcmp(ref->name, GIT_REFS_REMOTES_DIR) == 0) {
if (callback(name + strlen(GIT_REFS_REMOTES_DIR), GIT_BRANCH_REMOTE, payload)) { if (callback(ref->name + strlen(GIT_REFS_REMOTES_DIR),
GIT_BRANCH_REMOTE, payload)) {
error = GIT_EUSER; error = GIT_EUSER;
break; break;
} }
} }
git_reference_free(ref);
} }
if (error == GIT_ITEROVER) if (error == GIT_ITEROVER)
...@@ -160,7 +164,6 @@ int git_branch_foreach( ...@@ -160,7 +164,6 @@ int git_branch_foreach(
git_reference_iterator_free(iter); git_reference_iterator_free(iter);
return error; return error;
} }
int git_branch_move( int git_branch_move(
...@@ -179,18 +182,21 @@ int git_branch_move( ...@@ -179,18 +182,21 @@ int git_branch_move(
if (!git_reference_is_branch(branch)) if (!git_reference_is_branch(branch))
return not_a_local_branch(git_reference_name(branch)); return not_a_local_branch(git_reference_name(branch));
if ((error = git_buf_joinpath(&new_reference_name, GIT_REFS_HEADS_DIR, new_branch_name)) < 0 || error = git_buf_joinpath(&new_reference_name, GIT_REFS_HEADS_DIR, new_branch_name);
(error = git_buf_printf(&old_config_section, "branch.%s", git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR))) < 0 || if (error < 0)
(error = git_buf_printf(&new_config_section, "branch.%s", new_branch_name)) < 0)
goto done; goto done;
git_buf_printf(&old_config_section,
"branch.%s", git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR));
git_buf_printf(&new_config_section, "branch.%s", new_branch_name);
if ((error = git_config_rename_section(git_reference_owner(branch), if ((error = git_config_rename_section(git_reference_owner(branch),
git_buf_cstr(&old_config_section), git_buf_cstr(&old_config_section),
git_buf_cstr(&new_config_section))) < 0) git_buf_cstr(&new_config_section))) < 0)
goto done; goto done;
if ((error = git_reference_rename(out, branch, git_buf_cstr(&new_reference_name), force)) < 0) error = git_reference_rename(out, branch, git_buf_cstr(&new_reference_name), force);
goto done;
done: done:
git_buf_free(&new_reference_name); git_buf_free(&new_reference_name);
......
...@@ -495,12 +495,9 @@ static int checkout_action( ...@@ -495,12 +495,9 @@ static int checkout_action(
if (cmp == 0) { if (cmp == 0) {
if (wd->mode == GIT_FILEMODE_TREE) { if (wd->mode == GIT_FILEMODE_TREE) {
/* case 2 - entry prefixed by workdir tree */ /* case 2 - entry prefixed by workdir tree */
if ((error = git_iterator_advance_into(&wd, workdir)) < 0) { error = git_iterator_advance_into_or_over(&wd, workdir);
if (error != GIT_ENOTFOUND || if (error && error != GIT_ITEROVER)
git_iterator_advance(&wd, workdir) < 0) goto fail;
goto fail;
}
*wditem_ptr = wd; *wditem_ptr = wd;
continue; continue;
} }
...@@ -515,8 +512,10 @@ static int checkout_action( ...@@ -515,8 +512,10 @@ static int checkout_action(
} }
/* case 1 - handle wd item (if it matches pathspec) */ /* case 1 - handle wd item (if it matches pathspec) */
if (checkout_action_wd_only(data, workdir, wd, pathspec) < 0 || if (checkout_action_wd_only(data, workdir, wd, pathspec) < 0)
git_iterator_advance(&wd, workdir) < 0) goto fail;
if ((error = git_iterator_advance(&wd, workdir)) < 0 &&
error != GIT_ITEROVER)
goto fail; goto fail;
*wditem_ptr = wd; *wditem_ptr = wd;
...@@ -539,8 +538,9 @@ static int checkout_action( ...@@ -539,8 +538,9 @@ static int checkout_action(
if (delta->status == GIT_DELTA_TYPECHANGE) { if (delta->status == GIT_DELTA_TYPECHANGE) {
if (delta->old_file.mode == GIT_FILEMODE_TREE) { if (delta->old_file.mode == GIT_FILEMODE_TREE) {
act = checkout_action_with_wd(data, delta, wd); act = checkout_action_with_wd(data, delta, wd);
if (git_iterator_advance_into(&wd, workdir) < 0) if ((error = git_iterator_advance_into(&wd, workdir)) < 0 &&
wd = NULL; error != GIT_ENOTFOUND)
goto fail;
*wditem_ptr = wd; *wditem_ptr = wd;
return act; return act;
} }
...@@ -550,8 +550,9 @@ static int checkout_action( ...@@ -550,8 +550,9 @@ static int checkout_action(
delta->old_file.mode == GIT_FILEMODE_COMMIT) delta->old_file.mode == GIT_FILEMODE_COMMIT)
{ {
act = checkout_action_with_wd(data, delta, wd); act = checkout_action_with_wd(data, delta, wd);
if (git_iterator_advance(&wd, workdir) < 0) if ((error = git_iterator_advance(&wd, workdir)) < 0 &&
wd = NULL; error != GIT_ITEROVER)
goto fail;
*wditem_ptr = wd; *wditem_ptr = wd;
return act; return act;
} }
...@@ -582,6 +583,9 @@ static int checkout_remaining_wd_items( ...@@ -582,6 +583,9 @@ static int checkout_remaining_wd_items(
error = git_iterator_advance(&wd, workdir); error = git_iterator_advance(&wd, workdir);
} }
if (error == GIT_ITEROVER)
error = 0;
return error; return error;
} }
...@@ -603,7 +607,8 @@ static int checkout_get_actions( ...@@ -603,7 +607,8 @@ static int checkout_get_actions(
git_pathspec_init(&pathspec, &data->opts.paths, &pathpool) < 0) git_pathspec_init(&pathspec, &data->opts.paths, &pathpool) < 0)
return -1; return -1;
if ((error = git_iterator_current(&wditem, workdir)) < 0) if ((error = git_iterator_current(&wditem, workdir)) < 0 &&
error != GIT_ITEROVER)
goto fail; goto fail;
deltas = &data->diff->deltas; deltas = &data->diff->deltas;
......
...@@ -241,7 +241,7 @@ static int update_head_to_remote(git_repository *repo, git_remote *remote) ...@@ -241,7 +241,7 @@ static int update_head_to_remote(git_repository *repo, git_remote *remote)
} }
/* Not master. Check all the other refs. */ /* Not master. Check all the other refs. */
if (git_reference_foreach( if (git_reference_foreach_name(
repo, repo,
reference_matches_remote_head, reference_matches_remote_head,
&head_info) < 0) &head_info) < 0)
......
...@@ -796,6 +796,9 @@ static int diff_scan_inside_untracked_dir( ...@@ -796,6 +796,9 @@ static int diff_scan_inside_untracked_dir(
done: done:
git_buf_free(&base); git_buf_free(&base);
if (error == GIT_ITEROVER)
error = 0;
return error; return error;
} }
...@@ -981,8 +984,11 @@ static int handle_matched_item( ...@@ -981,8 +984,11 @@ static int handle_matched_item(
{ {
int error = 0; int error = 0;
if (!(error = maybe_modified(diff, info)) && if ((error = maybe_modified(diff, info)) < 0)
!(error = git_iterator_advance(&info->oitem, info->old_iter))) return error;
if (!(error = git_iterator_advance(&info->oitem, info->old_iter)) ||
error == GIT_ITEROVER)
error = git_iterator_advance(&info->nitem, info->new_iter); error = git_iterator_advance(&info->nitem, info->new_iter);
return error; return error;
...@@ -1011,15 +1017,22 @@ int git_diff__from_iterators( ...@@ -1011,15 +1017,22 @@ int git_diff__from_iterators(
/* make iterators have matching icase behavior */ /* make iterators have matching icase behavior */
if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE)) { if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE)) {
if (!(error = git_iterator_set_ignore_case(old_iter, true))) if ((error = git_iterator_set_ignore_case(old_iter, true)) < 0 ||
error = git_iterator_set_ignore_case(new_iter, true); (error = git_iterator_set_ignore_case(new_iter, true)) < 0)
goto cleanup;
} }
/* finish initialization */ /* finish initialization */
if (!error && if ((error = diff_list_apply_options(diff, opts)) < 0)
!(error = diff_list_apply_options(diff, opts)) && goto cleanup;
!(error = git_iterator_current(&info.oitem, old_iter)))
error = git_iterator_current(&info.nitem, new_iter); if ((error = git_iterator_current(&info.oitem, old_iter)) < 0 &&
error != GIT_ITEROVER)
goto cleanup;
if ((error = git_iterator_current(&info.nitem, new_iter)) < 0 &&
error != GIT_ITEROVER)
goto cleanup;
error = 0;
/* run iterators building diffs */ /* run iterators building diffs */
while (!error && (info.oitem || info.nitem)) { while (!error && (info.oitem || info.nitem)) {
...@@ -1041,8 +1054,13 @@ int git_diff__from_iterators( ...@@ -1041,8 +1054,13 @@ int git_diff__from_iterators(
*/ */
else else
error = handle_matched_item(diff, &info); error = handle_matched_item(diff, &info);
/* because we are iterating over two lists, ignore ITEROVER */
if (error == GIT_ITEROVER)
error = 0;
} }
cleanup:
if (!error) if (!error)
*diff_ptr = diff; *diff_ptr = diff;
else else
......
...@@ -142,9 +142,9 @@ GIT_INLINE(int) git_iterator_advance( ...@@ -142,9 +142,9 @@ GIT_INLINE(int) git_iterator_advance(
* *
* If the current item is not a tree, this is a no-op. * If the current item is not a tree, this is a no-op.
* *
* For working directory iterators only, a tree (i.e. directory) can be * For filesystem and working directory iterators, a tree (i.e. directory)
* empty. In that case, this function returns GIT_ENOTFOUND and does not * can be empty. In that case, this function returns GIT_ENOTFOUND and
* advance. That can't happen for tree and index iterators. * does not advance. That can't happen for tree and index iterators.
*/ */
GIT_INLINE(int) git_iterator_advance_into( GIT_INLINE(int) git_iterator_advance_into(
const git_index_entry **entry, git_iterator *iter) const git_index_entry **entry, git_iterator *iter)
...@@ -152,18 +152,50 @@ GIT_INLINE(int) git_iterator_advance_into( ...@@ -152,18 +152,50 @@ GIT_INLINE(int) git_iterator_advance_into(
return iter->cb->advance_into(entry, iter); return iter->cb->advance_into(entry, iter);
} }
/**
* Advance into a tree or skip over it if it is empty.
*
* Because `git_iterator_advance_into` may return GIT_ENOTFOUND if the
* directory is empty (only with filesystem and working directory
* iterators) and a common response is to just call `git_iterator_advance`
* when that happens, this bundles the two into a single simple call.
*/
GIT_INLINE(int) git_iterator_advance_into_or_over(
const git_index_entry **entry, git_iterator *iter)
{
int error = iter->cb->advance_into(entry, iter);
if (error == GIT_ENOTFOUND) {
giterr_clear();
error = iter->cb->advance(entry, iter);
}
return error;
}
/* Seek is currently unimplemented */
GIT_INLINE(int) git_iterator_seek( GIT_INLINE(int) git_iterator_seek(
git_iterator *iter, const char *prefix) git_iterator *iter, const char *prefix)
{ {
return iter->cb->seek(iter, prefix); return iter->cb->seek(iter, prefix);
} }
/**
* Go back to the start of the iteration.
*
* This resets the iterator to the start of the iteration. It also allows
* you to reset the `start` and `end` pathname boundaries of the iteration
* when doing so.
*/
GIT_INLINE(int) git_iterator_reset( GIT_INLINE(int) git_iterator_reset(
git_iterator *iter, const char *start, const char *end) git_iterator *iter, const char *start, const char *end)
{ {
return iter->cb->reset(iter, start, end); return iter->cb->reset(iter, start, end);
} }
/**
* Check if the iterator is at the end
*
* @return 0 if not at end, >0 if at end
*/
GIT_INLINE(int) git_iterator_at_end(git_iterator *iter) GIT_INLINE(int) git_iterator_at_end(git_iterator *iter)
{ {
return iter->cb->at_end(iter); return iter->cb->at_end(iter);
......
...@@ -1259,7 +1259,8 @@ int git_merge_diff_list__find_differences( ...@@ -1259,7 +1259,8 @@ int git_merge_diff_list__find_differences(
/* Set up the iterators */ /* Set up the iterators */
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
if ((error = git_iterator_current(&items[i], iterators[i])) < 0) error = git_iterator_current(&items[i], iterators[i]);
if (error < 0 && error != GIT_ITEROVER)
goto done; goto done;
} }
...@@ -1313,11 +1314,16 @@ int git_merge_diff_list__find_differences( ...@@ -1313,11 +1314,16 @@ int git_merge_diff_list__find_differences(
error = merge_index_insert_conflict(diff_list, &df_data, cur_items); error = merge_index_insert_conflict(diff_list, &df_data, cur_items);
else else
error = merge_index_insert_unmodified(diff_list, cur_items); error = merge_index_insert_unmodified(diff_list, cur_items);
if (error < 0)
goto done;
/* Advance each iterator that participated */ /* Advance each iterator that participated */
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
if (cur_items[i] != NULL && if (cur_items[i] == NULL)
(error = git_iterator_advance(&items[i], iterators[i])) < 0) continue;
error = git_iterator_advance(&items[i], iterators[i]);
if (error < 0 && error != GIT_ITEROVER)
goto done; goto done;
} }
} }
...@@ -1326,6 +1332,9 @@ done: ...@@ -1326,6 +1332,9 @@ done:
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
git_iterator_free(iterators[i]); git_iterator_free(iterators[i]);
if (error == GIT_ITEROVER)
error = 0;
return error; return error;
} }
......
...@@ -647,18 +647,12 @@ int git_note_next( ...@@ -647,18 +647,12 @@ int git_note_next(
const git_index_entry *item; const git_index_entry *item;
if ((error = git_iterator_current(&item, it)) < 0) if ((error = git_iterator_current(&item, it)) < 0)
goto exit; return error;
if (item != NULL) { git_oid_cpy(note_id, &item->oid);
git_oid_cpy(note_id, &item->oid);
error = process_entry_path(item->path, annotated_id);
if (error >= 0) if (!(error = process_entry_path(item->path, annotated_id)))
error = git_iterator_advance(NULL, it); git_iterator_advance(NULL, it);
} else {
error = GIT_ITEROVER;
}
exit:
return error; return error;
} }
...@@ -86,7 +86,7 @@ int git_refdb_compress(git_refdb *db) ...@@ -86,7 +86,7 @@ int git_refdb_compress(git_refdb *db)
return 0; return 0;
} }
static void refdb_free(git_refdb *db) void git_refdb__free(git_refdb *db)
{ {
refdb_free_backend(db); refdb_free_backend(db);
git__free(db); git__free(db);
...@@ -97,7 +97,7 @@ void git_refdb_free(git_refdb *db) ...@@ -97,7 +97,7 @@ void git_refdb_free(git_refdb *db)
if (db == NULL) if (db == NULL)
return; return;
GIT_REFCOUNT_DEC(db, refdb_free); GIT_REFCOUNT_DEC(db, git_refdb__free);
} }
int git_refdb_exists(int *exists, git_refdb *refdb, const char *ref_name) int git_refdb_exists(int *exists, git_refdb *refdb, const char *ref_name)
...@@ -114,90 +114,91 @@ int git_refdb_lookup(git_reference **out, git_refdb *db, const char *ref_name) ...@@ -114,90 +114,91 @@ int git_refdb_lookup(git_reference **out, git_refdb *db, const char *ref_name)
assert(db && db->backend && out && ref_name); assert(db && db->backend && out && ref_name);
if (!(error = db->backend->lookup(&ref, db->backend, ref_name))) { error = db->backend->lookup(&ref, db->backend, ref_name);
ref->db = db; if (error < 0)
*out = ref; return error;
} else {
*out = NULL; GIT_REFCOUNT_INC(db);
} ref->db = db;
return error; *out = ref;
return 0;
} }
int git_refdb_iterator(git_reference_iterator **out, git_refdb *db) int git_refdb_iterator(git_reference_iterator **out, git_refdb *db, const char *glob)
{ {
if (!db->backend || !db->backend->iterator) { if (!db->backend || !db->backend->iterator) {
giterr_set(GITERR_REFERENCE, "This backend doesn't support iterators"); giterr_set(GITERR_REFERENCE, "This backend doesn't support iterators");
return -1; return -1;
} }
if (db->backend->iterator(out, db->backend) < 0) if (db->backend->iterator(out, db->backend, glob) < 0)
return -1; return -1;
GIT_REFCOUNT_INC(db);
(*out)->db = db;
return 0; return 0;
} }
int git_refdb_iterator_glob(git_reference_iterator **out, git_refdb *db, const char *glob) int git_refdb_iterator_next(git_reference **out, git_reference_iterator *iter)
{ {
if (!db->backend) { int error;
giterr_set(GITERR_REFERENCE, "There are no backends loaded");
return -1;
}
if (db->backend->iterator_glob) if ((error = iter->next(out, iter)) < 0)
return db->backend->iterator_glob(out, db->backend, glob); return error;
/* If the backend doesn't support glob-filtering themselves, we have to do it */ GIT_REFCOUNT_INC(iter->db);
if (db->backend->iterator(out, db->backend) < 0) (*out)->db = iter->db;
return -1;
(*out)->glob = git__strdup(glob);
if (!(*out)->glob) {
db->backend->iterator_free(*out);
return -1;
}
return 0; return 0;
} }
int git_refdb_next(const char **out, git_reference_iterator *iter) int git_refdb_iterator_next_name(const char **out, git_reference_iterator *iter)
{ {
int error; return iter->next_name(out, iter);
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) void git_refdb_iterator_free(git_reference_iterator *iter)
{ {
git__free(iter->glob); GIT_REFCOUNT_DEC(iter->db, git_refdb__free);
iter->backend->iterator_free(iter); iter->free(iter);
} }
struct glob_cb_data { int git_refdb_write(git_refdb *db, git_reference *ref, int force)
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); assert(db && db->backend);
return db->backend->write(db->backend, ref); GIT_REFCOUNT_INC(db);
ref->db = db;
return db->backend->write(db->backend, ref, force);
} }
int git_refdb_delete(struct git_refdb *db, const git_reference *ref) int git_refdb_rename(
git_reference **out,
git_refdb *db,
const char *old_name,
const char *new_name,
int force)
{ {
int error;
assert(db && db->backend); assert(db && db->backend);
error = db->backend->rename(out, db->backend, old_name, new_name, force);
if (error < 0)
return error;
return db->backend->delete(db->backend, ref); if (out) {
GIT_REFCOUNT_INC(db);
(*out)->db = db;
}
return 0;
}
int git_refdb_delete(struct git_refdb *db, const char *ref_name)
{
assert(db && db->backend);
return db->backend->delete(db->backend, ref_name);
} }
...@@ -16,6 +16,8 @@ struct git_refdb { ...@@ -16,6 +16,8 @@ struct git_refdb {
git_refdb_backend *backend; git_refdb_backend *backend;
}; };
void git_refdb__free(git_refdb *db);
int git_refdb_exists( int git_refdb_exists(
int *exists, int *exists,
git_refdb *refdb, git_refdb *refdb,
...@@ -26,13 +28,19 @@ int git_refdb_lookup( ...@@ -26,13 +28,19 @@ int git_refdb_lookup(
git_refdb *refdb, git_refdb *refdb,
const char *ref_name); const char *ref_name);
int git_refdb_iterator(git_reference_iterator **out, git_refdb *db); int git_refdb_rename(
int git_refdb_iterator_glob(git_reference_iterator **out, git_refdb *db, const char *glob); git_reference **out,
int git_refdb_next(const char **out, git_reference_iterator *iter); git_refdb *db,
const char *old_name,
const char *new_name,
int force);
int git_refdb_iterator(git_reference_iterator **out, git_refdb *db, const char *glob);
int git_refdb_iterator_next(git_reference **out, git_reference_iterator *iter);
int git_refdb_iterator_next_name(const char **out, git_reference_iterator *iter);
void git_refdb_iterator_free(git_reference_iterator *iter); void git_refdb_iterator_free(git_reference_iterator *iter);
int git_refdb_write(git_refdb *refdb, const git_reference *ref); int git_refdb_write(git_refdb *refdb, git_reference *ref, int force);
int git_refdb_delete(git_refdb *refdb, const char *ref_name);
int git_refdb_delete(git_refdb *refdb, const git_reference *ref);
#endif #endif
...@@ -1233,31 +1233,23 @@ static int update_branch_remote_config_entry( ...@@ -1233,31 +1233,23 @@ static int update_branch_remote_config_entry(
} }
static int rename_one_remote_reference( static int rename_one_remote_reference(
git_repository *repo, git_reference *reference,
const char *reference_name,
const char *old_remote_name, const char *old_remote_name,
const char *new_remote_name) const char *new_remote_name)
{ {
int error = -1; int error = -1;
git_buf new_name = GIT_BUF_INIT; git_buf new_name = GIT_BUF_INIT;
git_reference *reference = NULL;
git_reference *newref = NULL;
if (git_buf_printf( if (git_buf_printf(
&new_name, &new_name,
GIT_REFS_REMOTES_DIR "%s%s", GIT_REFS_REMOTES_DIR "%s%s",
new_remote_name, new_remote_name,
reference_name + strlen(GIT_REFS_REMOTES_DIR) + strlen(old_remote_name)) < 0) reference->name + strlen(GIT_REFS_REMOTES_DIR) + strlen(old_remote_name)) < 0)
return -1; return -1;
if (git_reference_lookup(&reference, repo, reference_name) < 0) error = git_reference_rename(NULL, reference, git_buf_cstr(&new_name), 0);
goto cleanup;
error = git_reference_rename(&newref, reference, git_buf_cstr(&new_name), 0);
git_reference_free(reference); git_reference_free(reference);
cleanup:
git_reference_free(newref);
git_buf_free(&new_name); git_buf_free(&new_name);
return error; return error;
} }
...@@ -1267,46 +1259,28 @@ static int rename_remote_references( ...@@ -1267,46 +1259,28 @@ static int rename_remote_references(
const char *old_name, const char *old_name,
const char *new_name) const char *new_name)
{ {
git_vector refnames;
int error = -1; int error = -1;
unsigned int i; git_reference *ref;
char *name;
const char *refname;
git_reference_iterator *iter; git_reference_iterator *iter;
if (git_vector_init(&refnames, 8, NULL) < 0)
return -1;
if (git_reference_iterator_new(&iter, repo) < 0) if (git_reference_iterator_new(&iter, repo) < 0)
goto cleanup; return -1;
while ((error = git_reference_next(&refname, iter)) == 0) { while ((error = git_reference_next(&ref, iter)) == 0) {
if (git__prefixcmp(refname, GIT_REFS_REMOTES_DIR)) if (git__prefixcmp(ref->name, GIT_REFS_REMOTES_DIR))
continue; continue;
if ((error = git_vector_insert(&refnames, git__strdup(refname))) < 0) if ((error = rename_one_remote_reference(ref, old_name, new_name)) < 0) {
break; git_reference_iterator_free(iter);
return error;
}
} }
git_reference_iterator_free(iter); git_reference_iterator_free(iter);
if (error == GIT_ITEROVER)
error = 0;
else
goto cleanup;
git_vector_foreach(&refnames, i, name) { if (error == GIT_ITEROVER)
if ((error = rename_one_remote_reference(repo, name, old_name, new_name)) < 0) return 0;
goto cleanup;
}
error = 0;
cleanup:
git_vector_foreach(&refnames, i, name) {
git__free(name);
}
git_vector_free(&refnames);
return error; return error;
} }
......
...@@ -1473,12 +1473,14 @@ static int at_least_one_cb(const char *refname, void *payload) ...@@ -1473,12 +1473,14 @@ static int at_least_one_cb(const char *refname, void *payload)
static int repo_contains_no_reference(git_repository *repo) static int repo_contains_no_reference(git_repository *repo)
{ {
int error = git_reference_foreach(repo, at_least_one_cb, NULL); int error = git_reference_foreach_name(repo, &at_least_one_cb, NULL);
if (error == GIT_EUSER) if (error == GIT_EUSER)
return 0; return 0;
if (!error) if (!error)
return 1; return 1;
return error; return error;
} }
......
...@@ -1143,9 +1143,7 @@ static int load_submodule_config_from_index( ...@@ -1143,9 +1143,7 @@ static int load_submodule_config_from_index(
(error = git_iterator_for_index(&i, index, 0, NULL, NULL)) < 0) (error = git_iterator_for_index(&i, index, 0, NULL, NULL)) < 0)
return error; return error;
error = git_iterator_current(&entry, i); while (!(error = git_iterator_advance(&entry, i))) {
while (!error && entry != NULL) {
if (S_ISGITLINK(entry->mode)) { if (S_ISGITLINK(entry->mode)) {
error = submodule_load_from_index(repo, entry); error = submodule_load_from_index(repo, entry);
...@@ -1158,10 +1156,11 @@ static int load_submodule_config_from_index( ...@@ -1158,10 +1156,11 @@ static int load_submodule_config_from_index(
if (strcmp(entry->path, GIT_MODULES_FILE) == 0) if (strcmp(entry->path, GIT_MODULES_FILE) == 0)
git_oid_cpy(gitmodules_oid, &entry->oid); git_oid_cpy(gitmodules_oid, &entry->oid);
} }
error = git_iterator_advance(&entry, i);
} }
if (error == GIT_ITEROVER)
error = 0;
git_iterator_free(i); git_iterator_free(i);
return error; return error;
...@@ -1183,9 +1182,7 @@ static int load_submodule_config_from_head( ...@@ -1183,9 +1182,7 @@ static int load_submodule_config_from_head(
return error; return error;
} }
error = git_iterator_current(&entry, i); while (!(error = git_iterator_advance(&entry, i))) {
while (!error && entry != NULL) {
if (S_ISGITLINK(entry->mode)) { if (S_ISGITLINK(entry->mode)) {
error = submodule_load_from_head(repo, entry->path, &entry->oid); error = submodule_load_from_head(repo, entry->path, &entry->oid);
...@@ -1199,10 +1196,11 @@ static int load_submodule_config_from_head( ...@@ -1199,10 +1196,11 @@ static int load_submodule_config_from_head(
git_oid_iszero(gitmodules_oid)) git_oid_iszero(gitmodules_oid))
git_oid_cpy(gitmodules_oid, &entry->oid); git_oid_cpy(gitmodules_oid, &entry->oid);
} }
error = git_iterator_advance(&entry, i);
} }
if (error == GIT_ITEROVER)
error = 0;
git_iterator_free(i); git_iterator_free(i);
git_tree_free(head); git_tree_free(head);
......
...@@ -440,7 +440,7 @@ int git_tag_foreach(git_repository *repo, git_tag_foreach_cb cb, void *cb_data) ...@@ -440,7 +440,7 @@ int git_tag_foreach(git_repository *repo, git_tag_foreach_cb cb, void *cb_data)
data.cb_data = cb_data; data.cb_data = cb_data;
data.repo = repo; data.repo = repo;
return git_reference_foreach(repo, &tags_cb, &data); return git_reference_foreach_name(repo, &tags_cb, &data);
} }
typedef struct { typedef struct {
......
...@@ -31,7 +31,7 @@ static void tree_iterator_test( ...@@ -31,7 +31,7 @@ static void tree_iterator_test(
git_tree *t; git_tree *t;
git_iterator *i; git_iterator *i;
const git_index_entry *entry; const git_index_entry *entry;
int count = 0, count_post_reset = 0; int error, count = 0, count_post_reset = 0;
git_repository *repo = cl_git_sandbox_init(sandbox); git_repository *repo = cl_git_sandbox_init(sandbox);
cl_assert(t = resolve_commit_oid_to_tree(repo, treeish)); cl_assert(t = resolve_commit_oid_to_tree(repo, treeish));
...@@ -39,29 +39,30 @@ static void tree_iterator_test( ...@@ -39,29 +39,30 @@ static void tree_iterator_test(
&i, t, GIT_ITERATOR_DONT_IGNORE_CASE, start, end)); &i, t, GIT_ITERATOR_DONT_IGNORE_CASE, start, end));
/* test loop */ /* test loop */
cl_git_pass(git_iterator_current(&entry, i)); while (!(error = git_iterator_advance(&entry, i))) {
while (entry != NULL) { cl_assert(entry);
if (expected_values != NULL) if (expected_values != NULL)
cl_assert_equal_s(expected_values[count], entry->path); cl_assert_equal_s(expected_values[count], entry->path);
count++; count++;
cl_git_pass(git_iterator_advance(&entry, i));
} }
cl_assert_equal_i(GIT_ITEROVER, error);
cl_assert(!entry);
cl_assert_equal_i(expected_count, count);
/* test reset */ /* test reset */
cl_git_pass(git_iterator_reset(i, NULL, NULL)); cl_git_pass(git_iterator_reset(i, NULL, NULL));
cl_git_pass(git_iterator_current(&entry, i));
while (entry != NULL) { while (!(error = git_iterator_advance(&entry, i))) {
cl_assert(entry);
if (expected_values != NULL) if (expected_values != NULL)
cl_assert_equal_s(expected_values[count_post_reset], entry->path); cl_assert_equal_s(expected_values[count_post_reset], entry->path);
count_post_reset++; count_post_reset++;
cl_git_pass(git_iterator_advance(&entry, i));
} }
cl_assert_equal_i(GIT_ITEROVER, error);
git_iterator_free(i); cl_assert(!entry);
cl_assert_equal_i(expected_count, count);
cl_assert_equal_i(count, count_post_reset); cl_assert_equal_i(count, count_post_reset);
git_iterator_free(i);
git_tree_free(t); git_tree_free(t);
} }
...@@ -298,7 +299,7 @@ void test_diff_iterator__tree_special_functions(void) ...@@ -298,7 +299,7 @@ void test_diff_iterator__tree_special_functions(void)
git_iterator *i; git_iterator *i;
const git_index_entry *entry; const git_index_entry *entry;
git_repository *repo = cl_git_sandbox_init("attr"); git_repository *repo = cl_git_sandbox_init("attr");
int cases = 0; int error, cases = 0;
const char *rootoid = "ce39a97a7fb1fa90bcf5e711249c1e507476ae0e"; const char *rootoid = "ce39a97a7fb1fa90bcf5e711249c1e507476ae0e";
t = resolve_commit_oid_to_tree( t = resolve_commit_oid_to_tree(
...@@ -307,9 +308,10 @@ void test_diff_iterator__tree_special_functions(void) ...@@ -307,9 +308,10 @@ void test_diff_iterator__tree_special_functions(void)
cl_git_pass(git_iterator_for_tree( cl_git_pass(git_iterator_for_tree(
&i, t, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)); &i, t, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL));
cl_git_pass(git_iterator_current(&entry, i));
while (entry != NULL) { while (!(error = git_iterator_advance(&entry, i))) {
cl_assert(entry);
if (strcmp(entry->path, "sub/file") == 0) { if (strcmp(entry->path, "sub/file") == 0) {
cases++; cases++;
check_tree_entry( check_tree_entry(
...@@ -338,11 +340,11 @@ void test_diff_iterator__tree_special_functions(void) ...@@ -338,11 +340,11 @@ void test_diff_iterator__tree_special_functions(void)
"2929de282ce999e95183aedac6451d3384559c4b", "2929de282ce999e95183aedac6451d3384559c4b",
rootoid, NULL); rootoid, NULL);
} }
cl_git_pass(git_iterator_advance(&entry, i));
} }
cl_assert_equal_i(GIT_ITEROVER, error);
cl_assert(!entry);
cl_assert_equal_i(4, cases); cl_assert_equal_i(4, cases);
git_iterator_free(i); git_iterator_free(i);
git_tree_free(t); git_tree_free(t);
} }
...@@ -360,14 +362,15 @@ static void index_iterator_test( ...@@ -360,14 +362,15 @@ static void index_iterator_test(
git_index *index; git_index *index;
git_iterator *i; git_iterator *i;
const git_index_entry *entry; const git_index_entry *entry;
int count = 0; int error, count = 0;
git_repository *repo = cl_git_sandbox_init(sandbox); git_repository *repo = cl_git_sandbox_init(sandbox);
cl_git_pass(git_repository_index(&index, repo)); cl_git_pass(git_repository_index(&index, repo));
cl_git_pass(git_iterator_for_index(&i, index, 0, start, end)); cl_git_pass(git_iterator_for_index(&i, index, 0, start, end));
cl_git_pass(git_iterator_current(&entry, i));
while (entry != NULL) { while (!(error = git_iterator_advance(&entry, i))) {
cl_assert(entry);
if (expected_names != NULL) if (expected_names != NULL)
cl_assert_equal_s(expected_names[count], entry->path); cl_assert_equal_s(expected_names[count], entry->path);
...@@ -378,13 +381,14 @@ static void index_iterator_test( ...@@ -378,13 +381,14 @@ static void index_iterator_test(
} }
count++; count++;
cl_git_pass(git_iterator_advance(&entry, i));
} }
cl_assert_equal_i(GIT_ITEROVER, error);
cl_assert(!entry);
cl_assert_equal_i(expected_count, count);
git_iterator_free(i); git_iterator_free(i);
git_index_free(index); git_index_free(index);
cl_assert_equal_i(expected_count, count);
} }
static const char *expected_index_0[] = { static const char *expected_index_0[] = {
...@@ -535,12 +539,15 @@ static void workdir_iterator_test( ...@@ -535,12 +539,15 @@ static void workdir_iterator_test(
{ {
git_iterator *i; git_iterator *i;
const git_index_entry *entry; const git_index_entry *entry;
int count = 0, count_all = 0, count_all_post_reset = 0; int error, count = 0, count_all = 0, count_all_post_reset = 0;
git_repository *repo = cl_git_sandbox_init(sandbox); git_repository *repo = cl_git_sandbox_init(sandbox);
cl_git_pass(git_iterator_for_workdir( cl_git_pass(git_iterator_for_workdir(
&i, repo, GIT_ITERATOR_DONT_AUTOEXPAND, start, end)); &i, repo, GIT_ITERATOR_DONT_AUTOEXPAND, start, end));
cl_git_pass(git_iterator_current(&entry, i));
error = git_iterator_current(&entry, i);
cl_assert((error == 0 && entry != NULL) ||
(error == GIT_ITEROVER && entry == NULL));
while (entry != NULL) { while (entry != NULL) {
int ignored = git_iterator_current_is_ignored(i); int ignored = git_iterator_current_is_ignored(i);
...@@ -560,29 +567,39 @@ static void workdir_iterator_test( ...@@ -560,29 +567,39 @@ static void workdir_iterator_test(
count++; count++;
count_all++; count_all++;
cl_git_pass(git_iterator_advance(&entry, i)); error = git_iterator_advance(&entry, i);
cl_assert((error == 0 && entry != NULL) ||
(error == GIT_ITEROVER && entry == NULL));
} }
cl_assert_equal_i(expected_count, count);
cl_assert_equal_i(expected_count + expected_ignores, count_all);
cl_git_pass(git_iterator_reset(i, NULL, NULL)); cl_git_pass(git_iterator_reset(i, NULL, NULL));
cl_git_pass(git_iterator_current(&entry, i));
error = git_iterator_current(&entry, i);
cl_assert((error == 0 && entry != NULL) ||
(error == GIT_ITEROVER && entry == NULL));
while (entry != NULL) { while (entry != NULL) {
if (S_ISDIR(entry->mode)) { if (S_ISDIR(entry->mode)) {
cl_git_pass(git_iterator_advance_into(&entry, i)); cl_git_pass(git_iterator_advance_into(&entry, i));
continue; continue;
} }
if (expected_names != NULL) if (expected_names != NULL)
cl_assert_equal_s( cl_assert_equal_s(
expected_names[count_all_post_reset], entry->path); expected_names[count_all_post_reset], entry->path);
count_all_post_reset++; count_all_post_reset++;
cl_git_pass(git_iterator_advance(&entry, i));
}
git_iterator_free(i); error = git_iterator_advance(&entry, i);
cl_assert(error == 0 || error == GIT_ITEROVER);
}
cl_assert_equal_i(expected_count, count);
cl_assert_equal_i(expected_count + expected_ignores, count_all);
cl_assert_equal_i(count_all, count_all_post_reset); cl_assert_equal_i(count_all, count_all_post_reset);
git_iterator_free(i);
} }
void test_diff_iterator__workdir_0(void) void test_diff_iterator__workdir_0(void)
...@@ -752,8 +769,10 @@ void test_diff_iterator__workdir_builtin_ignores(void) ...@@ -752,8 +769,10 @@ void test_diff_iterator__workdir_builtin_ignores(void)
{ {
/* it is possible to advance "into" a submodule */ /* it is possible to advance "into" a submodule */
cl_git_pass(git_iterator_advance_into(&entry, i)); cl_git_pass(git_iterator_advance_into(&entry, i));
} else } else {
cl_git_pass(git_iterator_advance(&entry, i)); int error = git_iterator_advance(&entry, i);
cl_assert(!error || error == GIT_ITEROVER);
}
} }
cl_assert(expected[idx].path == NULL); cl_assert(expected[idx].path == NULL);
...@@ -766,7 +785,7 @@ static void check_wd_first_through_third_range( ...@@ -766,7 +785,7 @@ static void check_wd_first_through_third_range(
{ {
git_iterator *i; git_iterator *i;
const git_index_entry *entry; const git_index_entry *entry;
int idx; int error, idx;
static const char *expected[] = { "FIRST", "second", "THIRD", NULL }; static const char *expected[] = { "FIRST", "second", "THIRD", NULL };
cl_git_pass(git_iterator_for_workdir( cl_git_pass(git_iterator_for_workdir(
...@@ -776,7 +795,8 @@ static void check_wd_first_through_third_range( ...@@ -776,7 +795,8 @@ static void check_wd_first_through_third_range(
for (idx = 0; entry != NULL; ++idx) { for (idx = 0; entry != NULL; ++idx) {
cl_assert_equal_s(expected[idx], entry->path); cl_assert_equal_s(expected[idx], entry->path);
cl_git_pass(git_iterator_advance(&entry, i)); error = git_iterator_advance(&entry, i);
cl_assert(!error || error == GIT_ITEROVER);
} }
cl_assert(expected[idx] == NULL); cl_assert(expected[idx] == NULL);
...@@ -814,8 +834,7 @@ static void check_tree_range( ...@@ -814,8 +834,7 @@ static void check_tree_range(
{ {
git_tree *head; git_tree *head;
git_iterator *i; git_iterator *i;
const git_index_entry *entry; int error, count;
int count;
cl_git_pass(git_repository_head_tree(&head, repo)); cl_git_pass(git_repository_head_tree(&head, repo));
...@@ -824,13 +843,10 @@ static void check_tree_range( ...@@ -824,13 +843,10 @@ static void check_tree_range(
ignore_case ? GIT_ITERATOR_IGNORE_CASE : GIT_ITERATOR_DONT_IGNORE_CASE, ignore_case ? GIT_ITERATOR_IGNORE_CASE : GIT_ITERATOR_DONT_IGNORE_CASE,
start, end)); start, end));
cl_git_pass(git_iterator_current(&entry, i)); for (count = 0; !(error = git_iterator_advance(NULL, i)); ++count)
/* count em up */;
for (count = 0; entry != NULL; ) {
++count;
cl_git_pass(git_iterator_advance(&entry, i));
}
cl_assert_equal_i(GIT_ITEROVER, error);
cl_assert_equal_i(expected_count, count); cl_assert_equal_i(expected_count, count);
git_iterator_free(i); git_iterator_free(i);
...@@ -872,8 +888,7 @@ static void check_index_range( ...@@ -872,8 +888,7 @@ static void check_index_range(
{ {
git_index *index; git_index *index;
git_iterator *i; git_iterator *i;
const git_index_entry *entry; int error, count, caps;
int count, caps;
bool is_ignoring_case; bool is_ignoring_case;
cl_git_pass(git_repository_index(&index, repo)); cl_git_pass(git_repository_index(&index, repo));
...@@ -888,13 +903,10 @@ static void check_index_range( ...@@ -888,13 +903,10 @@ static void check_index_range(
cl_assert(git_iterator_ignore_case(i) == ignore_case); cl_assert(git_iterator_ignore_case(i) == ignore_case);
cl_git_pass(git_iterator_current(&entry, i)); for (count = 0; !(error = git_iterator_advance(NULL, i)); ++count)
/* count em up */;
for (count = 0; entry != NULL; ) {
++count;
cl_git_pass(git_iterator_advance(&entry, i));
}
cl_assert_equal_i(GIT_ITEROVER, error);
cl_assert_equal_i(expected_count, count); cl_assert_equal_i(expected_count, count);
git_iterator_free(i); git_iterator_free(i);
......
#include "clar_libgit2.h"
#include "buffer.h"
#include "posix.h"
#include "path.h"
#include "refs.h"
#include "testdb.h"
#define TEST_REPO_PATH "testrepo"
static git_repository *repo;
int unlink_ref(void *payload, git_buf *file)
{
GIT_UNUSED(payload);
return p_unlink(git_buf_cstr(file));
}
int empty(void *payload, git_buf *file)
{
GIT_UNUSED(payload);
GIT_UNUSED(file);
return -1;
}
int ref_file_foreach(git_repository *repo, int (* cb)(void *payload, git_buf *filename))
{
const char *repo_path;
git_buf repo_refs_dir = GIT_BUF_INIT;
int error = 0;
repo_path = git_repository_path(repo);
git_buf_joinpath(&repo_refs_dir, repo_path, "HEAD");
if (git_path_exists(git_buf_cstr(&repo_refs_dir)) &&
cb(NULL, &repo_refs_dir) < 0)
return -1;
git_buf_joinpath(&repo_refs_dir, repo_path, "refs");
git_buf_joinpath(&repo_refs_dir, git_buf_cstr(&repo_refs_dir), "heads");
if (git_path_direach(&repo_refs_dir, cb, NULL) != 0)
return -1;
git_buf_joinpath(&repo_refs_dir, repo_path, "packed-refs");
if (git_path_exists(git_buf_cstr(&repo_refs_dir)) &&
cb(NULL, &repo_refs_dir) < 0)
return -1;
git_buf_free(&repo_refs_dir);
return error;
}
void test_refdb_inmemory__initialize(void)
{
git_buf repo_refs_dir = GIT_BUF_INIT;
git_refdb *refdb;
git_refdb_backend *refdb_backend;
repo = cl_git_sandbox_init(TEST_REPO_PATH);
cl_git_pass(git_repository_refdb(&refdb, repo));
cl_git_pass(refdb_backend_test(&refdb_backend, repo));
cl_git_pass(git_refdb_set_backend(refdb, refdb_backend));
ref_file_foreach(repo, unlink_ref);
git_buf_free(&repo_refs_dir);
git_refdb_free(refdb);
}
void test_refdb_inmemory__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_refdb_inmemory__doesnt_write_ref_file(void)
{
git_reference *ref;
git_oid oid;
cl_git_pass(git_oid_fromstr(&oid, "c47800c7266a2be04c571c04d5a6614691ea99bd"));
cl_git_pass(git_reference_create(&ref, repo, GIT_REFS_HEADS_DIR "test1", &oid, 0));
ref_file_foreach(repo, empty);
git_reference_free(ref);
}
void test_refdb_inmemory__read(void)
{
git_reference *write1, *write2, *write3, *read1, *read2, *read3;
git_oid oid1, oid2, oid3;
cl_git_pass(git_oid_fromstr(&oid1, "c47800c7266a2be04c571c04d5a6614691ea99bd"));
cl_git_pass(git_reference_create(&write1, repo, GIT_REFS_HEADS_DIR "test1", &oid1, 0));
cl_git_pass(git_oid_fromstr(&oid2, "e90810b8df3e80c413d903f631643c716887138d"));
cl_git_pass(git_reference_create(&write2, repo, GIT_REFS_HEADS_DIR "test2", &oid2, 0));
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_lookup(&read1, repo, GIT_REFS_HEADS_DIR "test1"));
cl_assert(strcmp(git_reference_name(read1), git_reference_name(write1)) == 0);
cl_assert(git_oid_cmp(git_reference_target(read1), git_reference_target(write1)) == 0);
cl_git_pass(git_reference_lookup(&read2, repo, GIT_REFS_HEADS_DIR "test2"));
cl_assert(strcmp(git_reference_name(read2), git_reference_name(write2)) == 0);
cl_assert(git_oid_cmp(git_reference_target(read2), git_reference_target(write2)) == 0);
cl_git_pass(git_reference_lookup(&read3, repo, GIT_REFS_HEADS_DIR "test3"));
cl_assert(strcmp(git_reference_name(read3), git_reference_name(write3)) == 0);
cl_assert(git_oid_cmp(git_reference_target(read3), git_reference_target(write3)) == 0);
git_reference_free(write1);
git_reference_free(write2);
git_reference_free(write3);
git_reference_free(read1);
git_reference_free(read2);
git_reference_free(read3);
}
int foreach_test(const char *ref_name, void *payload)
{
git_reference *ref;
git_oid expected;
size_t *i = payload;
cl_git_pass(git_reference_lookup(&ref, repo, ref_name));
if (*i == 0)
cl_git_pass(git_oid_fromstr(&expected, "c47800c7266a2be04c571c04d5a6614691ea99bd"));
else if (*i == 1)
cl_git_pass(git_oid_fromstr(&expected, "e90810b8df3e80c413d903f631643c716887138d"));
else if (*i == 2)
cl_git_pass(git_oid_fromstr(&expected, "763d71aadf09a7951596c9746c024e7eece7c7af"));
cl_assert(git_oid_cmp(&expected, git_reference_target(ref)) == 0);
++(*i);
git_reference_free(ref);
return 0;
}
void test_refdb_inmemory__foreach(void)
{
git_reference *write1, *write2, *write3;
git_oid oid1, oid2, oid3;
size_t i = 0;
cl_git_pass(git_oid_fromstr(&oid1, "c47800c7266a2be04c571c04d5a6614691ea99bd"));
cl_git_pass(git_reference_create(&write1, repo, GIT_REFS_HEADS_DIR "test1", &oid1, 0));
cl_git_pass(git_oid_fromstr(&oid2, "e90810b8df3e80c413d903f631643c716887138d"));
cl_git_pass(git_reference_create(&write2, repo, GIT_REFS_HEADS_DIR "test2", &oid2, 0));
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,foreach_test, &i));
cl_assert_equal_i(3, (int)i);
git_reference_free(write1);
git_reference_free(write2);
git_reference_free(write3);
}
int delete_test(const char *ref_name, void *payload)
{
git_reference *ref;
git_oid expected;
size_t *i = payload;
cl_git_pass(git_reference_lookup(&ref, repo, ref_name));
cl_git_pass(git_oid_fromstr(&expected, "e90810b8df3e80c413d903f631643c716887138d"));
cl_assert(git_oid_cmp(&expected, git_reference_target(ref)) == 0);
++(*i);
git_reference_free(ref);
return 0;
}
void test_refdb_inmemory__delete(void)
{
git_reference *write1, *write2, *write3;
git_oid oid1, oid2, oid3;
size_t i = 0;
cl_git_pass(git_oid_fromstr(&oid1, "c47800c7266a2be04c571c04d5a6614691ea99bd"));
cl_git_pass(git_reference_create(&write1, repo, GIT_REFS_HEADS_DIR "test1", &oid1, 0));
cl_git_pass(git_oid_fromstr(&oid2, "e90810b8df3e80c413d903f631643c716887138d"));
cl_git_pass(git_reference_create(&write2, repo, GIT_REFS_HEADS_DIR "test2", &oid2, 0));
cl_git_pass(git_oid_fromstr(&oid3, "763d71aadf09a7951596c9746c024e7eece7c7af"));
cl_git_pass(git_reference_create(&write3, repo, GIT_REFS_HEADS_DIR "test3", &oid3, 0));
git_reference_delete(write1);
git_reference_free(write1);
git_reference_delete(write3);
git_reference_free(write3);
cl_git_pass(git_reference_foreach(repo, delete_test, &i));
cl_assert_equal_i(1, (int)i);
git_reference_free(write2);
}
#include "vector.h"
#include "util.h"
#include "testdb.h"
typedef struct refdb_test_backend {
git_refdb_backend parent;
git_repository *repo;
git_vector refs;
} refdb_test_backend;
typedef struct refdb_test_entry {
char *name;
git_ref_t type;
union {
git_oid oid;
char *symbolic;
} target;
} refdb_test_entry;
static int ref_name_cmp(const void *a, const void *b)
{
return strcmp(git_reference_name((git_reference *)a),
git_reference_name((git_reference *)b));
}
static int refdb_test_backend__exists(
int *exists,
git_refdb_backend *_backend,
const char *ref_name)
{
refdb_test_backend *backend;
refdb_test_entry *entry;
size_t i;
assert(_backend);
backend = (refdb_test_backend *)_backend;
*exists = 0;
git_vector_foreach(&backend->refs, i, entry) {
if (strcmp(entry->name, ref_name) == 0) {
*exists = 1;
break;
}
}
return 0;
}
static int refdb_test_backend__write(
git_refdb_backend *_backend,
const git_reference *ref)
{
refdb_test_backend *backend;
refdb_test_entry *entry;
assert(_backend);
backend = (refdb_test_backend *)_backend;
entry = git__calloc(1, sizeof(refdb_test_entry));
GITERR_CHECK_ALLOC(entry);
entry->name = git__strdup(git_reference_name(ref));
GITERR_CHECK_ALLOC(entry->name);
entry->type = git_reference_type(ref);
if (entry->type == GIT_REF_OID)
git_oid_cpy(&entry->target.oid, git_reference_target(ref));
else {
entry->target.symbolic = git__strdup(git_reference_symbolic_target(ref));
GITERR_CHECK_ALLOC(entry->target.symbolic);
}
git_vector_insert(&backend->refs, entry);
return 0;
}
static int refdb_test_backend__lookup(
git_reference **out,
git_refdb_backend *_backend,
const char *ref_name)
{
refdb_test_backend *backend;
refdb_test_entry *entry;
size_t i;
assert(_backend);
backend = (refdb_test_backend *)_backend;
git_vector_foreach(&backend->refs, i, entry) {
if (strcmp(entry->name, ref_name) == 0) {
if (entry->type == GIT_REF_OID) {
*out = git_reference__alloc(ref_name,
&entry->target.oid, NULL);
} else if (entry->type == GIT_REF_SYMBOLIC) {
*out = git_reference__alloc_symbolic(ref_name,
entry->target.symbolic);
}
if (*out == NULL)
return -1;
return 0;
}
}
return GIT_ENOTFOUND;
}
typedef struct {
git_reference_iterator parent;
size_t i;
} refdb_test_iter;
static int refdb_test_backend__iterator(git_reference_iterator **out, git_refdb_backend *_backend)
{
refdb_test_iter *iter;
GIT_UNUSED(_backend);
iter = git__calloc(1, sizeof(refdb_test_iter));
GITERR_CHECK_ALLOC(iter);
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)
git__free(entry->target.symbolic);
git__free(entry->name);
git__free(entry);
}
static int refdb_test_backend__delete(
git_refdb_backend *_backend,
const git_reference *ref)
{
refdb_test_backend *backend;
refdb_test_entry *entry;
size_t i;
assert(_backend);
backend = (refdb_test_backend *)_backend;
git_vector_foreach(&backend->refs, i, entry) {
if (strcmp(entry->name, git_reference_name(ref)) == 0) {
git_vector_remove(&backend->refs, i);
refdb_test_entry_free(entry);
}
}
return GIT_ENOTFOUND;
}
static void refdb_test_backend__free(git_refdb_backend *_backend)
{
refdb_test_backend *backend;
refdb_test_entry *entry;
size_t i;
assert(_backend);
backend = (refdb_test_backend *)_backend;
git_vector_foreach(&backend->refs, i, entry)
refdb_test_entry_free(entry);
git_vector_free(&backend->refs);
git__free(backend);
}
int refdb_backend_test(
git_refdb_backend **backend_out,
git_repository *repo)
{
refdb_test_backend *backend;
backend = git__calloc(1, sizeof(refdb_test_backend));
GITERR_CHECK_ALLOC(backend);
git_vector_init(&backend->refs, 0, ref_name_cmp);
backend->repo = repo;
backend->parent.exists = &refdb_test_backend__exists;
backend->parent.lookup = &refdb_test_backend__lookup;
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;
*backend_out = (git_refdb_backend *)backend;
return 0;
}
#include <git2/errors.h>
#include <git2/repository.h>
#include <git2/refdb.h>
#include <git2/sys/refs.h>
#include <git2/sys/refdb_backend.h>
int refdb_backend_test(
git_refdb_backend **backend_out,
git_repository *repo);
...@@ -38,40 +38,43 @@ static const char *refnames[] = { ...@@ -38,40 +38,43 @@ static const char *refnames[] = {
"refs/tags/wrapped_tag", "refs/tags/wrapped_tag",
}; };
static int refcmp_cb(const void *a, const void *b)
{
const git_reference *refa = (const git_reference *)a;
const git_reference *refb = (const git_reference *)b;
return strcmp(refa->name, refb->name);
}
void test_refs_iterator__list(void) void test_refs_iterator__list(void)
{ {
git_reference_iterator *iter; git_reference_iterator *iter;
git_vector output; git_vector output;
char *refname; git_reference *ref;
int error; int error;
size_t i; size_t i;
cl_git_pass(git_vector_init(&output, 32, git__strcmp_cb)); cl_git_pass(git_vector_init(&output, 32, &refcmp_cb));
cl_git_pass(git_reference_iterator_new(&iter, repo)); cl_git_pass(git_reference_iterator_new(&iter, repo));
do { do {
const char *name; error = git_reference_next(&ref, iter);
error = git_reference_next(&name, iter);
cl_assert(error == 0 || error == GIT_ITEROVER); cl_assert(error == 0 || error == GIT_ITEROVER);
if (error != GIT_ITEROVER) { if (error != GIT_ITEROVER) {
char *dup = git__strdup(name); cl_git_pass(git_vector_insert(&output, ref));
cl_assert(dup != NULL);
cl_git_pass(git_vector_insert(&output, dup));
} }
} while (!error); } while (!error);
git_reference_iterator_free(iter);
cl_assert_equal_i(output.length, ARRAY_SIZE(refnames)); cl_assert_equal_i(output.length, ARRAY_SIZE(refnames));
git_vector_sort(&output); 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_vector_foreach(&output, i, ref) {
git__free(refname); cl_assert_equal_s(ref->name, refnames[i]);
git_reference_free(ref);
} }
git_vector_free(&output); git_vector_free(&output);
} }
...@@ -79,14 +82,14 @@ void test_refs_iterator__empty(void) ...@@ -79,14 +82,14 @@ void test_refs_iterator__empty(void)
{ {
git_reference_iterator *iter; git_reference_iterator *iter;
git_odb *odb; git_odb *odb;
const char *name; git_reference *ref;
git_repository *empty; git_repository *empty;
cl_git_pass(git_odb_new(&odb)); cl_git_pass(git_odb_new(&odb));
cl_git_pass(git_repository_wrap_odb(&empty, odb)); cl_git_pass(git_repository_wrap_odb(&empty, odb));
cl_git_pass(git_reference_iterator_new(&iter, empty)); cl_git_pass(git_reference_iterator_new(&iter, empty));
cl_assert_equal_i(GIT_ITEROVER, git_reference_next(&name, iter)); cl_assert_equal_i(GIT_ITEROVER, git_reference_next(&ref, iter));
git_reference_iterator_free(iter); git_reference_iterator_free(iter);
git_odb_free(odb); git_odb_free(odb);
......
...@@ -31,12 +31,11 @@ static void expect_iterator_items( ...@@ -31,12 +31,11 @@ static void expect_iterator_items(
if (expected_flat < 0) { v = true; expected_flat = -expected_flat; } if (expected_flat < 0) { v = true; expected_flat = -expected_flat; }
if (expected_total < 0) { v = true; expected_total = -expected_total; } if (expected_total < 0) { v = true; expected_total = -expected_total; }
count = 0;
cl_git_pass(git_iterator_current(&entry, i));
if (v) fprintf(stderr, "== %s ==\n", no_trees ? "notrees" : "trees"); if (v) fprintf(stderr, "== %s ==\n", no_trees ? "notrees" : "trees");
while (entry != NULL) { count = 0;
while (!git_iterator_advance(&entry, i)) {
if (v) fprintf(stderr, " %s %07o\n", entry->path, (int)entry->mode); if (v) fprintf(stderr, " %s %07o\n", entry->path, (int)entry->mode);
if (no_trees) if (no_trees)
...@@ -54,8 +53,6 @@ static void expect_iterator_items( ...@@ -54,8 +53,6 @@ static void expect_iterator_items(
cl_assert(entry->mode != GIT_FILEMODE_TREE); cl_assert(entry->mode != GIT_FILEMODE_TREE);
} }
cl_git_pass(git_iterator_advance(&entry, i));
if (++count > expected_flat) if (++count > expected_flat)
break; break;
} }
...@@ -93,10 +90,14 @@ static void expect_iterator_items( ...@@ -93,10 +90,14 @@ static void expect_iterator_items(
/* could return NOTFOUND if directory is empty */ /* could return NOTFOUND if directory is empty */
cl_assert(!error || error == GIT_ENOTFOUND); cl_assert(!error || error == GIT_ENOTFOUND);
if (error == GIT_ENOTFOUND) if (error == GIT_ENOTFOUND) {
cl_git_pass(git_iterator_advance(&entry, i)); error = git_iterator_advance(&entry, i);
} else cl_assert(!error || error == GIT_ITEROVER);
cl_git_pass(git_iterator_advance(&entry, i)); }
} else {
error = git_iterator_advance(&entry, i);
cl_assert(!error || error == GIT_ITEROVER);
}
if (++count > expected_total) if (++count > expected_total)
break; break;
......
...@@ -370,12 +370,9 @@ void test_submodule_status__iterator(void) ...@@ -370,12 +370,9 @@ void test_submodule_status__iterator(void)
cl_git_pass(git_iterator_for_workdir(&iter, g_repo, cl_git_pass(git_iterator_for_workdir(&iter, g_repo,
GIT_ITERATOR_IGNORE_CASE | GIT_ITERATOR_INCLUDE_TREES, NULL, NULL)); GIT_ITERATOR_IGNORE_CASE | GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
cl_git_pass(git_iterator_current(&entry, iter));
for (i = 0; entry; ++i) { for (i = 0; !git_iterator_advance(&entry, iter); ++i)
cl_assert_equal_s(expected[i], entry->path); cl_assert_equal_s(expected[i], entry->path);
cl_git_pass(git_iterator_advance(&entry, iter));
}
git_iterator_free(iter); git_iterator_free(iter);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment