summaryrefslogtreecommitdiff
path: root/src/status.c
diff options
context:
space:
mode:
authorRussell Belfer <arrbee@arrbee.com>2012-03-16 15:56:01 -0700
committerRussell Belfer <arrbee@arrbee.com>2012-03-16 15:56:01 -0700
commit0d0fa7c3681e4ef3d0452666a9bc97d4b08391c9 (patch)
tree5e03e03bf9dc2f6125f4fb450cd3239d882b824f /src/status.c
parent4cfe2ab60b1e26554b2bf753b06f538cb3475bd0 (diff)
downloadlibgit2-0d0fa7c3681e4ef3d0452666a9bc97d4b08391c9.tar.gz
Convert attr, ignore, mwindow, status to new errors
Also cleaned up some previously converted code that still had little things to polish.
Diffstat (limited to 'src/status.c')
-rw-r--r--src/status.c350
1 files changed, 134 insertions, 216 deletions
diff --git a/src/status.c b/src/status.c
index 6315d6355..2221db3d9 100644
--- a/src/status.c
+++ b/src/status.c
@@ -76,15 +76,17 @@ static int status_entry_update_from_workdir(struct status_entry *e, const char*
{
struct stat filest;
- if (p_stat(full_path, &filest) < GIT_SUCCESS)
- return git__throw(GIT_EOSERR, "Failed to determine status of file '%s'. Can't read file", full_path);
+ 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 GIT_SUCCESS;
+ return 0;
}
static int status_entry_update_flags(struct status_entry *e)
@@ -115,7 +117,7 @@ static int status_entry_update_flags(struct status_entry *e)
else if (git_oid_cmp(&e->index_oid, &e->wt_oid) != 0)
e->status_flags |= GIT_STATUS_WT_MODIFIED;
- return GIT_SUCCESS;
+ return 0;
}
static int status_entry_is_ignorable(struct status_entry *e)
@@ -126,14 +128,17 @@ static int status_entry_is_ignorable(struct status_entry *e)
static int status_entry_update_ignore(struct status_entry *e, git_ignores *ignores, const char *path)
{
- int error, ignored;
+ int ignored;
- if ((error = git_ignore__lookup(ignores, path, &ignored)) == GIT_SUCCESS &&
- ignored)
+ if (git_ignore__lookup(ignores, path, &ignored) < 0)
+ 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 error;
+ return 0;
}
struct status_st {
@@ -156,33 +161,28 @@ static int retrieve_head_tree(git_tree **tree_out, git_repository *repo)
git_reference *resolved_head_ref;
git_commit *head_commit = NULL;
git_tree *tree;
- int error = GIT_SUCCESS;
+ int error = 0;
*tree_out = NULL;
- error = git_repository_head(&resolved_head_ref, repo);
- /*
- * We assume that a situation where HEAD exists but can not be resolved is valid.
- * A new repository fits this description for instance.
- */
- if (error == GIT_ENOTFOUND)
- return GIT_SUCCESS;
- if (error < GIT_SUCCESS)
- return git__rethrow(error, "HEAD can't be resolved");
+ if ((error = git_repository_head(&resolved_head_ref, repo)) < 0) {
+ /* Assume that a situation where HEAD exists but can not be resolved
+ * is valid. A new repository fits this description for instance.
+ */
+ if (error == GIT_ENOTFOUND)
+ return 0;
+ return error;
+ }
- if ((error = git_commit_lookup(&head_commit, repo, git_reference_oid(resolved_head_ref))) < GIT_SUCCESS)
- return git__rethrow(error, "The tip of HEAD can't be retrieved");
+ if ((error = git_commit_lookup(
+ &head_commit, repo, git_reference_oid(resolved_head_ref))) < 0)
+ return error;
git_reference_free(resolved_head_ref);
- if ((error = git_commit_tree(&tree, head_commit)) < GIT_SUCCESS) {
- error = git__rethrow(error, "The tree of HEAD can't be retrieved");
- goto exit;
- }
-
- *tree_out = tree;
+ if ((error = git_commit_tree(&tree, head_commit)) == 0)
+ *tree_out = tree;
-exit:
git_commit_free(head_commit);
return error;
}
@@ -231,7 +231,8 @@ static int process_folder(
break;
default:
- return git__throw(GIT_EINVALIDTYPE, "Unexpected tree entry type");
+ giterr_set(GITERR_REPOSITORY, "Unexpected tree entry type");
+ return -1;
}
}
@@ -240,7 +241,7 @@ static int process_folder(
git_ignores ignores, *old_ignores;
if ((error = git_ignore__for_path(st->repo,
- full_path->ptr + st->workdir_path_len, &ignores)) == GIT_SUCCESS)
+ full_path->ptr + st->workdir_path_len, &ignores)) == 0)
{
old_ignores = st->ignores;
st->ignores = &ignores;
@@ -267,17 +268,17 @@ static int process_folder(
static int store_if_changed(struct status_st *st, struct status_entry *e)
{
- int error;
- if ((error = status_entry_update_flags(e)) < GIT_SUCCESS)
- return git__throw(error, "Failed to process the file '%s'. It doesn't exist in the workdir, in the HEAD nor in the index", e->path);
+ int error = status_entry_update_flags(e);
+ if (error < 0)
+ return error;
if (status_entry_is_ignorable(e) &&
- (error = status_entry_update_ignore(e, st->ignores, e->path)) < GIT_SUCCESS)
+ (error = status_entry_update_ignore(e, st->ignores, e->path)) < 0)
return error;
if (e->status_flags == GIT_STATUS_CURRENT) {
git__free(e);
- return GIT_SUCCESS;
+ return 0;
}
return git_vector_insert(st->vector, e);
@@ -293,7 +294,7 @@ static int determine_status(
enum path_type path_type)
{
struct status_entry *e;
- int error = GIT_SUCCESS;
+ int error = 0;
git_otype tree_entry_type = GIT_OBJ_BAD;
if (tree_entry != NULL)
@@ -317,10 +318,9 @@ static int determine_status(
st->index_position++;
}
- if (in_workdir)
- if ((error = status_entry_update_from_workdir(
- e, full_path->ptr)) < GIT_SUCCESS)
- return error; /* The callee has already set the error message */
+ if (in_workdir &&
+ (error = status_entry_update_from_workdir(e, full_path->ptr)) < 0)
+ return error; /* The callee has already set the error message */
return store_if_changed(st, e);
}
@@ -337,7 +337,7 @@ static int determine_status(
st->tree_position++;
if (in_index)
st->index_position++;
- return GIT_SUCCESS;
+ return 0;
}
static int path_type_from(git_buf *full_path, int is_dir)
@@ -354,7 +354,8 @@ static int path_type_from(git_buf *full_path, int is_dir)
return GIT_STATUS_PATH_FOLDER;
}
-static const char *status_path(const char *first, const char *second, const char *third)
+static const char *status_path(
+ const char *first, const char *second, const char *third)
{
/* At least one of them can not be NULL */
assert(first != NULL || second != NULL || third != NULL);
@@ -399,10 +400,11 @@ static int dirent_cb(void *state, git_buf *a)
path_type = path_type_from(a, st->is_dir);
if (path_type == GIT_STATUS_PATH_IGNORE)
- return GIT_SUCCESS; /* Let's skip the ".git" directory */
+ return 0; /* Let's skip the ".git" directory */
a_name = (path_type != GIT_STATUS_PATH_NULL) ? a->ptr + st->workdir_path_len : NULL;
+ /* Loop over head tree and index up to and including this workdir file */
while (1) {
if (st->tree == NULL)
m = NULL;
@@ -412,7 +414,7 @@ static int dirent_cb(void *state, git_buf *a)
entry = git_index_get(st->index, st->index_position);
if ((m == NULL) && (a == NULL) && (entry == NULL))
- return GIT_SUCCESS;
+ return 0;
if (m != NULL) {
git_buf_truncate(&st->head_tree_relative_path,
@@ -424,7 +426,7 @@ static int dirent_cb(void *state, git_buf *a)
git_path_to_dir(&st->head_tree_relative_path);
if (git_buf_oom(&st->head_tree_relative_path))
- return GIT_ENOMEM;
+ return -1;
m_name = st->head_tree_relative_path.ptr;
} else
@@ -441,11 +443,11 @@ static int dirent_cb(void *state, git_buf *a)
pi = ((cmpmi >= 0) && (cmpai >= 0)) ? i_name : NULL;
if ((error = determine_status(st, pm != NULL, pi != NULL, pa != NULL,
- m, entry, a, status_path(pm, pi, pa), path_type)) < GIT_SUCCESS)
- return git__rethrow(error, "An error occured while determining the status of '%s'", a->ptr);
+ m, entry, a, status_path(pm, pi, pa), path_type)) < 0)
+ return error;
if ((pa != NULL) || (path_type == GIT_STATUS_PATH_FOLDER))
- return GIT_SUCCESS;
+ return 0;
}
}
@@ -469,27 +471,27 @@ int git_status_foreach(
git_index *index = NULL;
git_buf temp_path = GIT_BUF_INIT;
struct status_st dirent_st = {0};
- int error = GIT_SUCCESS;
+ int error = 0;
unsigned int i;
git_tree *tree;
struct status_entry *e;
const char *workdir;
- if ((workdir = git_repository_workdir(repo)) == NULL)
- return git__throw(GIT_ERROR,
- "Cannot retrieve status on a bare repository");
+ assert(repo);
- if ((error = git_repository_index__weakptr(&index, repo)) < GIT_SUCCESS) {
- return git__rethrow(error,
- "Failed to determine statuses. Index can't be opened");
+ if ((workdir = git_repository_workdir(repo)) == NULL ||
+ !git_path_isdir(workdir))
+ {
+ giterr_set(GITERR_OS, "Cannot get status - invalid working directory");
+ return GIT_ENOTFOUND;
}
- if ((error = retrieve_head_tree(&tree, repo)) < GIT_SUCCESS) {
- error = git__rethrow(error, "Failed to determine statuses");
- goto exit;
- }
+ if ((error = git_repository_index__weakptr(&index, repo)) < 0 ||
+ (error = retrieve_head_tree(&tree, repo)) < 0)
+ return error;
- git_vector_init(&entries, DEFAULT_SIZE, status_cmp);
+ if ((error = git_vector_init(&entries, DEFAULT_SIZE, status_cmp)) < 0)
+ goto exit;
dirent_st.repo = repo;
dirent_st.vector = &entries;
@@ -503,42 +505,21 @@ int git_status_foreach(
dirent_st.index_position = 0;
dirent_st.is_dir = 1;
- if (git_path_isdir(workdir) == false) {
- error = git__throw(GIT_EINVALIDPATH,
- "Failed to determine status of file '%s'. "
- "The given path doesn't lead to a folder", workdir);
- goto exit;
- }
-
git_buf_sets(&temp_path, workdir);
- error = git_ignore__for_path(repo, "", dirent_st.ignores);
- if (error < GIT_SUCCESS)
+ if ((error = git_ignore__for_path(repo, "", dirent_st.ignores)) < 0)
goto exit;
- error = alphasorted_futils_direach(
- &temp_path, dirent_cb, &dirent_st);
-
- if (error < GIT_SUCCESS)
- error = git__rethrow(error,
- "Failed to determine statuses. "
- "An error occured while processing the working directory");
+ error = alphasorted_futils_direach(&temp_path, dirent_cb, &dirent_st);
- if ((error == GIT_SUCCESS) &&
- ((error = dirent_cb(&dirent_st, NULL)) < GIT_SUCCESS))
- error = git__rethrow(error,
- "Failed to determine statuses. "
- "An error occured while post-processing the HEAD tree and the index");
+ if (!error)
+ error = dirent_cb(&dirent_st, NULL);
for (i = 0; i < entries.length; ++i) {
e = (struct status_entry *)git_vector_get(&entries, i);
- if (error == GIT_SUCCESS) {
+ if (!error)
error = callback(e->path, e->status_flags, payload);
- if (error < GIT_SUCCESS)
- error = git__rethrow(error,
- "Failed to determine statuses. User callback failed");
- }
git__free(e);
}
@@ -557,222 +538,159 @@ static int recurse_tree_entry(git_tree *tree, struct status_entry *e, const char
char *dir_sep;
const git_tree_entry *tree_entry;
git_tree *subtree;
- int error = GIT_SUCCESS;
+ int error;
dir_sep = strchr(path, '/');
if (!dir_sep) {
- tree_entry = git_tree_entry_byname(tree, path);
- if (tree_entry == NULL)
- return GIT_SUCCESS; /* The leaf doesn't exist in the tree*/
-
- status_entry_update_from_tree_entry(e, tree_entry);
- return GIT_SUCCESS;
+ 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';
- tree_entry = git_tree_entry_byname(tree, path);
- if (tree_entry == NULL)
- return GIT_SUCCESS; /* The subtree doesn't exist in the tree*/
+ if ((tree_entry = git_tree_entry_byname(tree, path)) == NULL)
+ return 0; /* The subtree doesn't exist in the tree*/
*dir_sep = '/';
/* Retreive subtree */
- if ((error = git_tree_lookup(&subtree, tree->object.repo, &tree_entry->oid)) < GIT_SUCCESS)
- return git__throw(GIT_EOBJCORRUPTED, "Can't find tree object '%s'", tree_entry->filename);
+ 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);
+ }
- error = recurse_tree_entry(subtree, e, dir_sep+1);
- git_tree_free(subtree);
return error;
}
-int git_status_file(unsigned int *status_flags, git_repository *repo, const char *path)
+int git_status_file(
+ 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 = GIT_SUCCESS;
+ int error = 0;
git_tree *tree = NULL;
const char *workdir;
assert(status_flags && repo && path);
- if ((workdir = git_repository_workdir(repo)) == NULL)
- return git__throw(GIT_ERROR,
- "Cannot retrieve status on a bare repository");
+ if ((workdir = git_repository_workdir(repo)) == NULL) {
+ giterr_set(GITERR_OS, "Cannot get file status from bare repo");
+ return GIT_ENOTFOUND;
+ }
- if ((error = git_buf_joinpath(&temp_path, workdir, path)) < GIT_SUCCESS)
- return git__rethrow(error,
- "Failed to determine status of file '%s'", path);
+ if (git_buf_joinpath(&temp_path, workdir, path) < 0)
+ return -1;
- if (git_path_isdir(temp_path.ptr) == true) {
+ if (git_path_isdir(temp_path.ptr)) {
+ giterr_set(GITERR_OS, "Cannot get file status for directory '%s'", temp_path.ptr);
git_buf_free(&temp_path);
- return git__throw(GIT_EINVALIDPATH,
- "Failed to determine status of file '%s'. "
- "Given path leads to a folder, not a file", path);
+ return GIT_ENOTFOUND;
}
e = status_entry_new(NULL, path);
- if (e == NULL) {
- git_buf_free(&temp_path);
- return GIT_ENOMEM;
- }
+ GITERR_CHECK_ALLOC(e);
/* Find file in Workdir */
- if (git_path_exists(temp_path.ptr) == true) {
- if ((error = status_entry_update_from_workdir(e, temp_path.ptr)) < GIT_SUCCESS)
- goto cleanup; /* The callee has already set the error message */
- }
+ 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)) < GIT_SUCCESS) {
- git__rethrow(error,
- "Failed to determine status of file '%s'."
- "Index can't be opened", path);
+ if ((error = git_repository_index__weakptr(&index, repo)) < 0)
goto cleanup;
- }
-
status_entry_update_from_index(e, index);
- if ((error = retrieve_head_tree(&tree, repo)) < GIT_SUCCESS) {
- git__rethrow(error,
- "Failed to determine status of file '%s'", path);
+ /* Try to find file in HEAD */
+ if ((error = retrieve_head_tree(&tree, repo)) < 0)
goto cleanup;
- }
- /* If the repository is not empty, try and locate the file in HEAD */
if (tree != NULL) {
- if ((error = git_buf_sets(&temp_path, path)) < GIT_SUCCESS) {
- git__rethrow(error,
- "Failed to determine status of file '%s'", path);
- goto cleanup;
- }
-
- error = recurse_tree_entry(tree, e, temp_path.ptr);
- if (error < GIT_SUCCESS) {
- git__rethrow(error,
- "Failed to determine status of file '%s'. "
- "An error occured while processing the tree", path);
+ 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)) < GIT_SUCCESS) {
- git__throw(error, "Nonexistent file");
- goto cleanup;
- }
+ if ((error = status_entry_update_flags(e)) < 0)
+ giterr_set(GITERR_OS, "Cannot find file '%s' to determine status", path);
- if (status_entry_is_ignorable(e)) {
+ if (!error && status_entry_is_ignorable(e)) {
git_ignores ignores;
- if ((error = git_ignore__for_path(repo, path, &ignores)) == GIT_SUCCESS)
+ if ((error = git_ignore__for_path(repo, path, &ignores)) == 0)
error = status_entry_update_ignore(e, &ignores, path);
git_ignore__free(&ignores);
-
- if (error < GIT_SUCCESS)
- goto cleanup;
}
- *status_flags = e->status_flags;
+ if (!error)
+ *status_flags = e->status_flags;
cleanup:
git_buf_free(&temp_path);
git_tree_free(tree);
git__free(e);
+
return error;
}
/*
* git_path_direach is not supposed to return entries in an ordered manner.
- * alphasorted_futils_direach wraps git_path_direach and invokes the callback
- * function by passing it alphabeticcally sorted paths parameters.
+ * alphasorted_futils_direach wraps git_path_dirload and invokes the
+ * callback function by passing it alphabetically sorted path parameters.
*
*/
-
-static char *alphasorted_dirent_info_new(const git_buf *path)
-{
- char *di = git__malloc(path->size + 2);
- if (!di)
- return di;
-
- git_buf_copy_cstr(di, path->size + 1, path);
-
- if (git_path_isdir(path->ptr) == true) {
- /*
- * Append a forward slash to the name to force folders
- * to be ordered in a similar way than in a tree
- *
- * The file "subdir" should appear before the file "subdir.txt"
- * The folder "subdir" should appear after the file "subdir.txt"
- */
- di[path->size] = '/';
- di[path->size + 1] = '\0';
- }
-
- return di;
-}
-
-static int alphasorted_dirent_cb(void *state, git_buf *full_path)
-{
- char *entry;
- git_vector *entry_names;
-
- entry_names = (git_vector *)state;
- entry = alphasorted_dirent_info_new(full_path);
-
- if (entry == NULL)
- return GIT_ENOMEM;
-
- if (git_vector_insert(entry_names, entry) < GIT_SUCCESS) {
- git__free(entry);
- return GIT_ENOMEM;
- }
-
- return GIT_SUCCESS;
-}
-
static int alphasorted_futils_direach(
git_buf *path,
int (*fn)(void *, git_buf *),
void *arg)
{
+ int error;
char *entry;
git_vector entry_names;
unsigned int idx;
- int error = GIT_SUCCESS;
- git_buf entry_path = GIT_BUF_INIT;
- if (git_vector_init(&entry_names, 16, git__strcmp_cb) < GIT_SUCCESS)
- return GIT_ENOMEM;
+ if (git_vector_init(&entry_names, 16, git__strcmp_cb) < 0)
+ return -1;
- error = git_path_direach(path, alphasorted_dirent_cb, &entry_names);
+ if ((error = git_path_dirload(path->ptr, 0, 1, &entry_names)) < 0)
+ return error;
- git_vector_sort(&entry_names);
+ git_vector_foreach(&entry_names, idx, entry) {
+ size_t entry_len = strlen(entry);
+ if (git_path_isdir(entry)) {
+ /* dirload allocated 1 extra byte so there is space for slash */
+ entry[entry_len++] = '/';
+ entry[entry_len] = '\0';
+ }
+ }
- for (idx = 0; idx < entry_names.length; ++idx) {
- entry = (char *)git_vector_get(&entry_names, idx);
+ git_vector_sort(&entry_names);
- /* We have to walk the entire vector even if there was an error,
- * in order to free up memory, but we stop making callbacks after
- * an error.
+ git_vector_foreach(&entry_names, idx, entry) {
+ /* Walk the entire vector even if there is an error, in order to
+ * free up memory, but stop making callbacks after an error.
*/
- if (error == GIT_SUCCESS)
- error = git_buf_sets(&entry_path, entry);
+ if (!error) {
+ git_buf entry_path = GIT_BUF_INIT;
+ git_buf_attach(&entry_path, entry, 0);
- if (error == GIT_SUCCESS) {
((struct status_st *)arg)->is_dir =
- (entry[entry_path.size - 1] == '/');
+ (entry_path.ptr[entry_path.size - 1] == '/');
+
error = fn(arg, &entry_path);
}
git__free(entry);
}
- git_buf_free(&entry_path);
git_vector_free(&entry_names);
+
return error;
}
@@ -782,11 +700,11 @@ int git_status_should_ignore(git_repository *repo, const char *path, int *ignore
int error;
git_ignores ignores;
- if ((error = git_ignore__for_path(repo, path, &ignores)) == GIT_SUCCESS)
- error = git_ignore__lookup(&ignores, path, ignored);
+ if (git_ignore__for_path(repo, path, &ignores) < 0)
+ return -1;
+ error = git_ignore__lookup(&ignores, path, ignored);
git_ignore__free(&ignores);
-
return error;
}