diff options
| author | Edward Thomson <ethomson@microsoft.com> | 2013-05-21 11:05:21 -0500 |
|---|---|---|
| committer | Russell Belfer <rb@github.com> | 2013-06-17 10:03:14 -0700 |
| commit | 1ee2ef87ec4c2c63b7c89849eb9daad9e46e6fe7 (patch) | |
| tree | d10293ba11d1ed7cb54df329b75d293bf8c3e9aa /src/status.c | |
| parent | 09c2f91c150a4862c9189d9e08d0dc111d4d706c (diff) | |
| download | libgit2-1ee2ef87ec4c2c63b7c89849eb9daad9e46e6fe7.tar.gz | |
status access by index, providing more details to callers
Diffstat (limited to 'src/status.c')
| -rw-r--r-- | src/status.c | 232 |
1 files changed, 166 insertions, 66 deletions
diff --git a/src/status.c b/src/status.c index 712e0d515..33e67efac 100644 --- a/src/status.c +++ b/src/status.c @@ -11,6 +11,7 @@ #include "hash.h" #include "vector.h" #include "tree.h" +#include "status.h" #include "git2/status.h" #include "repository.h" #include "ignore.h" @@ -77,71 +78,105 @@ static unsigned int workdir_delta2status(git_delta_t workdir_status) return st; } -typedef struct { - git_status_cb cb; - void *payload; - const git_status_options *opts; -} status_user_callback; +static bool status_is_included( + git_status_list *statuslist, + git_diff_delta *head2idx, + git_diff_delta *idx2wd) +{ + /* if excluding submodules and this is a submodule everywhere */ + if ((statuslist->opts.flags & GIT_STATUS_OPT_EXCLUDE_SUBMODULES) != 0) { + bool in_tree = (head2idx && head2idx->status != GIT_DELTA_ADDED); + bool in_index = (head2idx && head2idx->status != GIT_DELTA_DELETED); + bool in_wd = (idx2wd && idx2wd->status != GIT_DELTA_DELETED); + + if ((!in_tree || head2idx->old_file.mode == GIT_FILEMODE_COMMIT) && + (!in_index || head2idx->new_file.mode == GIT_FILEMODE_COMMIT) && + (!in_wd || idx2wd->new_file.mode == GIT_FILEMODE_COMMIT)) + return 0; + } -static int status_invoke_cb( - git_diff_delta *h2i, git_diff_delta *i2w, void *payload) + return 1; +} + +static git_status_t status_compute( + git_diff_delta *head2idx, + git_diff_delta *idx2wd) { - status_user_callback *usercb = payload; - const char *path = NULL; - unsigned int status = 0; + git_status_t status = 0; - if (i2w) { - path = i2w->old_file.path; - status |= workdir_delta2status(i2w->status); - } - if (h2i) { - path = h2i->old_file.path; - status |= index_delta2status(h2i->status); - } + if (head2idx) + status |= index_delta2status(head2idx->status); - /* if excluding submodules and this is a submodule everywhere */ - if (usercb->opts && - (usercb->opts->flags & GIT_STATUS_OPT_EXCLUDE_SUBMODULES) != 0) - { - bool in_tree = (h2i && h2i->status != GIT_DELTA_ADDED); - bool in_index = (h2i && h2i->status != GIT_DELTA_DELETED); - bool in_wd = (i2w && i2w->status != GIT_DELTA_DELETED); + if (idx2wd) + status |= workdir_delta2status(idx2wd->status); - if ((!in_tree || h2i->old_file.mode == GIT_FILEMODE_COMMIT) && - (!in_index || h2i->new_file.mode == GIT_FILEMODE_COMMIT) && - (!in_wd || i2w->new_file.mode == GIT_FILEMODE_COMMIT)) - return 0; - } + return status; +} + +static int status_collect( + git_diff_delta *head2idx, + git_diff_delta *idx2wd, + void *payload) +{ + git_status_list *statuslist = payload; + git_status_entry *status_entry; + + if (!status_is_included(statuslist, head2idx, idx2wd)) + return 0; + + status_entry = git__malloc(sizeof(git_status_entry)); + GITERR_CHECK_ALLOC(status_entry); + + status_entry->status = status_compute(head2idx, idx2wd); + status_entry->head_to_index = head2idx; + status_entry->index_to_workdir = idx2wd; + + git_vector_insert(&statuslist->paired, status_entry); - return usercb->cb(path, status, usercb->payload); + return 0; } -int git_status_foreach_ext( +git_status_list *git_status_list_alloc(void) +{ + git_status_list *statuslist = NULL; + + if ((statuslist = git__calloc(1, sizeof(git_status_list))) == NULL || + git_vector_init(&statuslist->paired, 0, NULL) < 0) + return NULL; + + return statuslist; +} + +int git_status_list_new( + git_status_list **out, git_repository *repo, - const git_status_options *opts, - git_status_cb cb, - void *payload) + const git_status_options *opts) { - int err = 0; + git_status_list *statuslist = NULL; git_diff_options diffopt = GIT_DIFF_OPTIONS_INIT; - git_diff_list *head2idx = NULL, *idx2wd = NULL; git_tree *head = NULL; git_status_show_t show = opts ? opts->show : GIT_STATUS_SHOW_INDEX_AND_WORKDIR; - status_user_callback usercb; + int error = 0; assert(show <= GIT_STATUS_SHOW_INDEX_THEN_WORKDIR); + *out = NULL; + GITERR_CHECK_VERSION(opts, GIT_STATUS_OPTIONS_VERSION, "git_status_options"); - if (show != GIT_STATUS_SHOW_INDEX_ONLY && - (err = git_repository__ensure_not_bare(repo, "status")) < 0) - return err; + if ((error = git_repository__ensure_not_bare(repo, "status")) < 0) + return error; /* if there is no HEAD, that's okay - we'll make an empty iterator */ - if (((err = git_repository_head_tree(&head, repo)) < 0) && - !(err == GIT_ENOTFOUND || err == GIT_EORPHANEDHEAD)) - return err; + if (((error = git_repository_head_tree(&head, repo)) < 0) && + !(error == GIT_ENOTFOUND || error == GIT_EORPHANEDHEAD)) + return error; + + statuslist = git_status_list_alloc(); + GITERR_CHECK_ALLOC(statuslist); + + memcpy(&statuslist->opts, opts, sizeof(git_status_options)); memcpy(&diffopt.pathspec, &opts->pathspec, sizeof(diffopt.pathspec)); @@ -163,41 +198,106 @@ int git_status_foreach_ext( diffopt.flags = diffopt.flags | GIT_DIFF_IGNORE_SUBMODULES; if (show != GIT_STATUS_SHOW_WORKDIR_ONLY) { - err = git_diff_tree_to_index(&head2idx, repo, head, NULL, &diffopt); - if (err < 0) - goto cleanup; + error = git_diff_tree_to_index(&statuslist->head2idx, repo, head, NULL, &diffopt); + + if (error < 0) + goto on_error; } if (show != GIT_STATUS_SHOW_INDEX_ONLY) { - err = git_diff_index_to_workdir(&idx2wd, repo, NULL, &diffopt); - if (err < 0) - goto cleanup; - } + error = git_diff_index_to_workdir(&statuslist->idx2wd, repo, NULL, &diffopt); - usercb.cb = cb; - usercb.payload = payload; - usercb.opts = opts; + if (error < 0) + goto on_error; + } if (show == GIT_STATUS_SHOW_INDEX_THEN_WORKDIR) { - if ((err = git_diff__paired_foreach( - head2idx, NULL, status_invoke_cb, &usercb)) < 0) - goto cleanup; + if ((error = git_diff__paired_foreach(statuslist->head2idx, NULL, status_collect, statuslist)) < 0) + goto on_error; - git_diff_list_free(head2idx); - head2idx = NULL; + git_diff_list_free(statuslist->head2idx); + statuslist->head2idx = NULL; } - err = git_diff__paired_foreach(head2idx, idx2wd, status_invoke_cb, &usercb); + if ((error = git_diff__paired_foreach(statuslist->head2idx, statuslist->idx2wd, status_collect, statuslist)) < 0) + goto on_error; + + *out = statuslist; + goto done; + +on_error: + git_status_list_free(statuslist); -cleanup: +done: git_tree_free(head); - git_diff_list_free(head2idx); - git_diff_list_free(idx2wd); - if (err == GIT_EUSER) - giterr_clear(); + return error; +} + +size_t git_status_list_entrycount(git_status_list *statuslist) +{ + assert(statuslist); + + return statuslist->paired.length; +} + +const git_status_entry *git_status_byindex( + git_status_list *statuslist, + size_t i) +{ + assert(statuslist); + + return git_vector_get(&statuslist->paired, i); +} + +void git_status_list_free(git_status_list *statuslist) +{ + git_status_entry *status_entry; + size_t i; + + if (statuslist == NULL) + return; + + git_diff_list_free(statuslist->head2idx); + git_diff_list_free(statuslist->idx2wd); + + git_vector_foreach(&statuslist->paired, i, status_entry) + git__free(status_entry); - return err; + git_vector_free(&statuslist->paired); + + git__free(statuslist); +} + +int git_status_foreach_ext( + git_repository *repo, + const git_status_options *opts, + git_status_cb cb, + void *payload) +{ + git_status_list *statuslist; + const git_status_entry *status_entry; + size_t i; + int error = 0; + + if ((error = git_status_list_new(&statuslist, repo, opts)) < 0) + return error; + + git_vector_foreach(&statuslist->paired, i, status_entry) { + const char *path = status_entry->head_to_index ? + status_entry->head_to_index->old_file.path : + status_entry->index_to_workdir->old_file.path; + + if (cb(path, status_entry->status, payload) != 0) { + error = GIT_EUSER; + giterr_clear(); + break; + } + } + + git_status_list_free(statuslist); + + return error; } int git_status_foreach( |
