summaryrefslogtreecommitdiff
path: root/src/status.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/status.c')
-rw-r--r--src/status.c252
1 files changed, 39 insertions, 213 deletions
diff --git a/src/status.c b/src/status.c
index 1c5609cd8..e9ad3cfe4 100644
--- a/src/status.c
+++ b/src/status.c
@@ -70,7 +70,7 @@ static unsigned int workdir_delta2status(git_delta_t workdir_status)
int git_status_foreach_ext(
git_repository *repo,
- git_status_options *opts,
+ const git_status_options *opts,
int (*cb)(const char *, unsigned int, void *),
void *cbdata)
{
@@ -163,245 +163,71 @@ int git_status_foreach(
return git_status_foreach_ext(repo, &opts, callback, payload);
}
-
-/*
- * the old stuff
- */
-
-struct status_entry {
- git_index_time mtime;
-
- git_oid head_oid;
- git_oid index_oid;
- git_oid wt_oid;
-
- unsigned int status_flags;
-
- char path[GIT_FLEX_ARRAY]; /* more */
+struct status_file_info {
+ unsigned int count;
+ unsigned int status;
+ char *expected;
};
-static struct status_entry *status_entry_new(git_vector *entries, const char *path)
-{
- struct status_entry *e = git__calloc(sizeof(*e) + strlen(path) + 1, 1);
- if (e == NULL)
- return NULL;
-
- if (entries != NULL)
- git_vector_insert(entries, e);
-
- strcpy(e->path, path);
-
- return e;
-}
-
-GIT_INLINE(void) status_entry_update_from_tree_entry(struct status_entry *e, const git_tree_entry *tree_entry)
-{
- assert(e && tree_entry);
-
- git_oid_cpy(&e->head_oid, &tree_entry->oid);
-}
-
-GIT_INLINE(void) status_entry_update_from_index_entry(struct status_entry *e, const git_index_entry *index_entry)
-{
- assert(e && index_entry);
-
- git_oid_cpy(&e->index_oid, &index_entry->oid);
- e->mtime = index_entry->mtime;
-}
-
-static void status_entry_update_from_index(struct status_entry *e, git_index *index)
-{
- int idx;
- git_index_entry *index_entry;
-
- assert(e && index);
-
- idx = git_index_find(index, e->path);
- if (idx < 0)
- return;
-
- index_entry = git_index_get(index, idx);
-
- status_entry_update_from_index_entry(e, index_entry);
-}
-
-static int status_entry_update_from_workdir(struct status_entry *e, const char* full_path)
-{
- struct stat filest;
-
- if (p_stat(full_path, &filest) < 0) {
- giterr_set(GITERR_OS, "Cannot access file '%s'", full_path);
- return GIT_ENOTFOUND;
- }
-
- if (e->mtime.seconds == (git_time_t)filest.st_mtime)
- git_oid_cpy(&e->wt_oid, &e->index_oid);
- else
- git_odb_hashfile(&e->wt_oid, full_path, GIT_OBJ_BLOB);
-
- return 0;
-}
-
-static int status_entry_update_flags(struct status_entry *e)
-{
- git_oid zero;
- int head_zero, index_zero, wt_zero;
-
- memset(&zero, 0x0, sizeof(git_oid));
-
- head_zero = git_oid_cmp(&zero, &e->head_oid);
- index_zero = git_oid_cmp(&zero, &e->index_oid);
- wt_zero = git_oid_cmp(&zero, &e->wt_oid);
-
- if (head_zero == 0 && index_zero == 0 && wt_zero == 0)
- return GIT_ENOTFOUND;
-
- if (head_zero == 0 && index_zero != 0)
- e->status_flags |= GIT_STATUS_INDEX_NEW;
- else if (index_zero == 0 && head_zero != 0)
- e->status_flags |= GIT_STATUS_INDEX_DELETED;
- else if (git_oid_cmp(&e->head_oid, &e->index_oid) != 0)
- e->status_flags |= GIT_STATUS_INDEX_MODIFIED;
-
- if (index_zero == 0 && wt_zero != 0)
- e->status_flags |= GIT_STATUS_WT_NEW;
- else if (wt_zero == 0 && index_zero != 0)
- e->status_flags |= GIT_STATUS_WT_DELETED;
- else if (git_oid_cmp(&e->index_oid, &e->wt_oid) != 0)
- e->status_flags |= GIT_STATUS_WT_MODIFIED;
-
- return 0;
-}
-
-static int status_entry_is_ignorable(struct status_entry *e)
+static int get_one_status(const char *path, unsigned int status, void *data)
{
- /* don't ignore files that exist in head or index already */
- return (e->status_flags == GIT_STATUS_WT_NEW);
-}
+ struct status_file_info *sfi = data;
-static int status_entry_update_ignore(struct status_entry *e, git_ignores *ignores, const char *path)
-{
- int ignored;
+ sfi->count++;
+ sfi->status = status;
- if (git_ignore__lookup(ignores, path, &ignored) < 0)
+ if (sfi->count > 1 || strcmp(sfi->expected, path) != 0) {
+ giterr_set(GITERR_INVALID,
+ "Ambiguous path '%s' given to git_status_file", sfi->expected);
return -1;
-
- if (ignored)
- /* toggle off WT_NEW and on IGNORED */
- e->status_flags =
- (e->status_flags & ~GIT_STATUS_WT_NEW) | GIT_STATUS_IGNORED;
-
- return 0;
-}
-
-static int recurse_tree_entry(git_tree *tree, struct status_entry *e, const char *path)
-{
- char *dir_sep;
- const git_tree_entry *tree_entry;
- git_tree *subtree;
- int error;
-
- dir_sep = strchr(path, '/');
- if (!dir_sep) {
- if ((tree_entry = git_tree_entry_byname(tree, path)) != NULL)
- /* The leaf exists in the tree*/
- status_entry_update_from_tree_entry(e, tree_entry);
- return 0;
- }
-
- /* Retrieve subtree name */
- *dir_sep = '\0';
-
- if ((tree_entry = git_tree_entry_byname(tree, path)) == NULL)
- return 0; /* The subtree doesn't exist in the tree*/
-
- *dir_sep = '/';
-
- /* Retreive subtree */
- error = git_tree_lookup(&subtree, tree->object.repo, &tree_entry->oid);
- if (!error) {
- error = recurse_tree_entry(subtree, e, dir_sep+1);
- git_tree_free(subtree);
}
- return error;
+ return 0;
}
int git_status_file(
- unsigned int *status_flags, git_repository *repo, const char *path)
+ unsigned int *status_flags,
+ git_repository *repo,
+ const char *path)
{
- struct status_entry *e;
- git_index *index = NULL;
- git_buf temp_path = GIT_BUF_INIT;
- int error = 0;
- git_tree *tree = NULL;
- const char *workdir;
+ int error;
+ git_status_options opts;
+ struct status_file_info sfi;
assert(status_flags && repo && path);
- if ((workdir = git_repository_workdir(repo)) == NULL) {
- giterr_set(GITERR_INVALID, "Cannot get file status from bare repo");
+ memset(&sfi, 0, sizeof(sfi));
+ if ((sfi.expected = git__strdup(path)) == NULL)
return -1;
- }
-
- if (git_buf_joinpath(&temp_path, workdir, path) < 0)
- return -1;
-
- if (git_path_isdir(temp_path.ptr)) {
- giterr_set(GITERR_INVALID, "Cannot get file status for directory '%s'", temp_path.ptr);
- git_buf_free(&temp_path);
- return -1;
- }
-
- e = status_entry_new(NULL, path);
- GITERR_CHECK_ALLOC(e);
-
- /* Find file in Workdir */
- if (git_path_exists(temp_path.ptr) == true &&
- (error = status_entry_update_from_workdir(e, temp_path.ptr)) < 0)
- goto cleanup;
-
- /* Find file in Index */
- if ((error = git_repository_index__weakptr(&index, repo)) < 0)
- goto cleanup;
- status_entry_update_from_index(e, index);
- /* Try to find file in HEAD */
- if ((error = git_repository_head_tree(&tree, repo)) < 0)
- goto cleanup;
-
- if (tree != NULL) {
- if ((error = git_buf_sets(&temp_path, path)) < 0 ||
- (error = recurse_tree_entry(tree, e, temp_path.ptr)) < 0)
- goto cleanup;
- }
-
- /* Determine status */
- if ((error = status_entry_update_flags(e)) < 0)
- giterr_set(GITERR_OS, "Cannot find file '%s' to determine status", path);
-
- if (!error && status_entry_is_ignorable(e)) {
- git_ignores ignores;
+ memset(&opts, 0, sizeof(opts));
+ opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
+ opts.flags = GIT_STATUS_OPT_INCLUDE_IGNORED |
+ GIT_STATUS_OPT_INCLUDE_UNTRACKED |
+ GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS |
+ GIT_STATUS_OPT_INCLUDE_UNMODIFIED;
+ opts.pathspec.count = 1;
+ opts.pathspec.strings = &sfi.expected;
- if ((error = git_ignore__for_path(repo, path, &ignores)) == 0)
- error = status_entry_update_ignore(e, &ignores, path);
+ error = git_status_foreach_ext(repo, &opts, get_one_status, &sfi);
- git_ignore__free(&ignores);
+ if (!error && !sfi.count) {
+ giterr_set(GITERR_INVALID,
+ "Attempt to get status of nonexistent file '%s'", path);
+ error = GIT_ENOTFOUND;
}
- if (!error)
- *status_flags = e->status_flags;
+ *status_flags = sfi.status;
-cleanup:
- git_buf_free(&temp_path);
- git_tree_free(tree);
- git__free(e);
+ git__free(sfi.expected);
return error;
}
int git_status_should_ignore(
- int *ignored, git_repository *repo, const char *path)
+ int *ignored,
+ git_repository *repo,
+ const char *path)
{
int error;
git_ignores ignores;