From ff0ddfa4bbec2e27491c822cf6b882c54d8675c8 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Wed, 17 Apr 2013 15:56:31 -0700 Subject: Add filesystem iterator variant This adds a new variant iterator that is a raw filesystem iterator for scanning directories from a root. There is still more work to do to blend this with the working directory iterator. --- src/iterator.c | 301 +++++++++++++++++++++++++++++++++++++++++++++ src/iterator.h | 11 ++ tests-clar/repo/iterator.c | 44 +++++++ 3 files changed, 356 insertions(+) diff --git a/src/iterator.c b/src/iterator.c index 5b5ed9525..dd8a6133d 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -833,6 +833,307 @@ int git_iterator_for_index( } +typedef struct fs_iterator_frame fs_iterator_frame; +struct fs_iterator_frame { + fs_iterator_frame *next; + git_vector entries; + size_t index; +}; + +typedef struct { + git_iterator base; + git_iterator_callbacks cb; + fs_iterator_frame *stack; + git_index_entry entry; + git_buf path; + size_t root_len; + int depth; +} fs_iterator; + +#define FS_MAX_DEPTH 100 + +static fs_iterator_frame *fs_iterator__alloc_frame(fs_iterator *fi) +{ + fs_iterator_frame *ff = git__calloc(1, sizeof(fs_iterator_frame)); + git_vector_cmp entry_compare = CASESELECT( + iterator__ignore_case(fi), + git_path_with_stat_cmp_icase, git_path_with_stat_cmp); + + if (ff && git_vector_init(&ff->entries, 0, entry_compare) < 0) { + git__free(ff); + ff = NULL; + } + + return ff; +} + +static void fs_iterator__free_frame(fs_iterator_frame *ff) +{ + size_t i; + git_path_with_stat *path; + + git_vector_foreach(&ff->entries, i, path) + git__free(path); + git_vector_free(&ff->entries); + git__free(ff); +} + +static int fs_iterator__update_entry(fs_iterator *fi); + +static int fs_iterator__entry_cmp(const void *i, const void *item) +{ + const fs_iterator *fi = (const fs_iterator *)i; + const git_path_with_stat *ps = item; + return fi->base.prefixcomp(fi->base.start, ps->path); +} + +static void fs_iterator__seek_frame_start( + fs_iterator *fi, fs_iterator_frame *ff) +{ + if (!ff) + return; + + if (fi->base.start) + git_vector_bsearch2( + &ff->index, &ff->entries, fs_iterator__entry_cmp, fi); + else + ff->index = 0; +} + +static int fs_iterator__expand_dir(fs_iterator *fi) +{ + int error; + fs_iterator_frame *ff; + + ff = fs_iterator__alloc_frame(fi); + GITERR_CHECK_ALLOC(ff); + + error = git_path_dirload_with_stat( + fi->path.ptr, fi->root_len, iterator__ignore_case(fi), + fi->base.start, fi->base.end, &ff->entries); + + if (error < 0 || ff->entries.length == 0) { + fs_iterator__free_frame(ff); + return GIT_ENOTFOUND; + } + + if (++(fi->depth) > FS_MAX_DEPTH) { + giterr_set(GITERR_REPOSITORY, + "Directory nesting is too deep (%d)", fi->depth); + fs_iterator__free_frame(ff); + return -1; + } + + fs_iterator__seek_frame_start(fi, ff); + + ff->next = fi->stack; + fi->stack = ff; + + return fs_iterator__update_entry(fi); +} + +static int fs_iterator__current( + const git_index_entry **entry, git_iterator *self) +{ + fs_iterator *fi = (fs_iterator *)self; + if (entry) + *entry = (fi->entry.path == NULL) ? NULL : &fi->entry; + return 0; +} + +static int fs_iterator__at_end(git_iterator *self) +{ + return (((fs_iterator *)self)->entry.path == NULL); +} + +static int fs_iterator__advance_into( + const git_index_entry **entry, git_iterator *iter) +{ + int error = 0; + fs_iterator *fi = (fs_iterator *)iter; + + iterator__clear_entry(entry); + + /* Allow you to explicitly advance into a commit/submodule (as well as a + * tree) to avoid cases where an entry is mislabeled as a submodule in + * the working directory. The fs iterator will never have COMMMIT + * entries on it's own, but a wrapper might add them. + */ + if (fi->entry.path != NULL && + (fi->entry.mode == GIT_FILEMODE_TREE || + fi->entry.mode == GIT_FILEMODE_COMMIT)) + /* returns GIT_ENOTFOUND if the directory is empty */ + error = fs_iterator__expand_dir(fi); + + if (!error && entry) + error = fs_iterator__current(entry, iter); + + return error; +} + +static int fs_iterator__advance( + const git_index_entry **entry, git_iterator *self) +{ + int error = 0; + fs_iterator *fi = (fs_iterator *)self; + fs_iterator_frame *ff; + git_path_with_stat *next; + + /* given include_trees & autoexpand, we might have to go into a tree */ + if (iterator__do_autoexpand(fi) && + fi->entry.path != NULL && + fi->entry.mode == GIT_FILEMODE_TREE) + { + error = fs_iterator__advance_into(entry, self); + + /* continue silently past empty directories if autoexpanding */ + if (error != GIT_ENOTFOUND) + return error; + giterr_clear(); + error = 0; + } + + if (entry != NULL) + *entry = NULL; + + while (fi->entry.path != NULL) { + ff = fi->stack; + next = git_vector_get(&ff->entries, ++ff->index); + + if (next != NULL) + break; + + /* pop stack if anything is left to pop */ + if (!ff->next) { + memset(&fi->entry, 0, sizeof(fi->entry)); + return 0; + } + + fi->stack = ff->next; + fi->depth--; + fs_iterator__free_frame(ff); + } + + error = fs_iterator__update_entry(fi); + + if (!error && entry != NULL) + error = fs_iterator__current(entry, self); + + return error; +} + +static int fs_iterator__seek(git_iterator *self, const char *prefix) +{ + GIT_UNUSED(self); + GIT_UNUSED(prefix); + /* pop stack until matching prefix */ + /* find prefix item in current frame */ + /* push subdirectories as deep as possible while matching */ + return 0; +} + +static int fs_iterator__reset( + git_iterator *self, const char *start, const char *end) +{ + fs_iterator *fi = (fs_iterator *)self; + + while (fi->stack != NULL && fi->stack->next != NULL) { + fs_iterator_frame *ff = fi->stack; + fi->stack = ff->next; + fs_iterator__free_frame(ff); + } + fi->depth = 0; + + if (iterator__reset_range(self, start, end) < 0) + return -1; + + fs_iterator__seek_frame_start(fi, fi->stack); + + return fs_iterator__update_entry(fi); +} + +static void fs_iterator__free(git_iterator *self) +{ + fs_iterator *fi = (fs_iterator *)self; + + while (fi->stack != NULL) { + fs_iterator_frame *ff = fi->stack; + fi->stack = ff->next; + fs_iterator__free_frame(ff); + } + + git_buf_free(&fi->path); +} + +static int fs_iterator__update_entry(fs_iterator *fi) +{ + git_path_with_stat *ps = + git_vector_get(&fi->stack->entries, fi->stack->index); + + git_buf_truncate(&fi->path, fi->root_len); + memset(&fi->entry, 0, sizeof(fi->entry)); + + if (!ps) + return 0; + + if (git_buf_put(&fi->path, ps->path, ps->path_len) < 0) + return -1; + + if (iterator__past_end(fi, fi->path.ptr + fi->root_len)) + return 0; + + fi->entry.path = ps->path; + git_index_entry__init_from_stat(&fi->entry, &ps->st); + + /* need different mode here to keep directories during iteration */ + fi->entry.mode = git_futils_canonical_mode(ps->st.st_mode); + + /* if this isn't a tree, then we're done */ + if (fi->entry.mode != GIT_FILEMODE_TREE) + return 0; + + if (iterator__include_trees(fi)) + return 0; + + return fs_iterator__advance(NULL, (git_iterator *)fi); +} + +int git_iterator_for_filesystem( + git_iterator **out, + const char *root, + git_iterator_flag_t flags, + const char *start, + const char *end) +{ + int error; + fs_iterator *fi; + + ITERATOR_BASE_INIT(fi, fs, FS, NULL); + + if ((flags & GIT_ITERATOR_IGNORE_CASE) != 0) + fi->base.flags |= GIT_ITERATOR_IGNORE_CASE; + + if (git_buf_sets(&fi->path, root) < 0 || git_path_to_dir(&fi->path) < 0) { + git__free(fi); + return -1; + } + fi->root_len = fi->path.size; + + if ((error = fs_iterator__expand_dir(fi)) < 0) { + if (error != GIT_ENOTFOUND) + goto fail; + giterr_clear(); + } + + *out = (git_iterator *)fi; + return 0; + +fail: + git_iterator_free((git_iterator *)fi); + return error; +} + + #define WORKDIR_MAX_DEPTH 100 typedef struct workdir_iterator_frame workdir_iterator_frame; diff --git a/src/iterator.h b/src/iterator.h index 4a4e6a9d8..7998f7c6b 100644 --- a/src/iterator.h +++ b/src/iterator.h @@ -19,6 +19,7 @@ typedef enum { GIT_ITERATOR_TYPE_TREE = 1, GIT_ITERATOR_TYPE_INDEX = 2, GIT_ITERATOR_TYPE_WORKDIR = 3, + GIT_ITERATOR_TYPE_FS = 4, } git_iterator_type_t; typedef enum { @@ -88,6 +89,16 @@ extern int git_iterator_for_workdir( const char *start, const char *end); +/* for filesystem iterators, you have to explicitly pass in the ignore_case + * behavior that you desire + */ +extern int git_iterator_for_filesystem( + git_iterator **out, + const char *root, + git_iterator_flag_t flags, + const char *start, + const char *end); + extern void git_iterator_free(git_iterator *iter); /* Return a git_index_entry structure for the current value the iterator diff --git a/tests-clar/repo/iterator.c b/tests-clar/repo/iterator.c index 00c46d6b1..ef9bfc33d 100644 --- a/tests-clar/repo/iterator.c +++ b/tests-clar/repo/iterator.c @@ -808,3 +808,47 @@ void test_repo_iterator__workdir_depth(void) expect_iterator_items(iter, 337, NULL, 337, NULL); git_iterator_free(iter); } + +void test_repo_iterator__fs(void) +{ + git_iterator *i; + static const char *expect_subdir[] = { + "current_file", + "modified_file", + "new_file", + NULL, + }; + + g_repo = cl_git_sandbox_init("status"); + + cl_git_pass(git_iterator_for_filesystem( + &i, "status/subdir", 0, NULL, NULL)); + expect_iterator_items(i, 3, expect_subdir, 3, expect_subdir); + git_iterator_free(i); +} + +void test_repo_iterator__fs2(void) +{ + git_iterator *i; + static const char *expect_subdir[] = { + "heads/br2", + "heads/dir", + "heads/master", + "heads/packed-test", + "heads/subtrees", + "heads/test", + "tags/e90810b", + "tags/foo/bar", + "tags/foo/foo/bar", + "tags/point_to_blob", + "tags/test", + NULL, + }; + + g_repo = cl_git_sandbox_init("testrepo"); + + cl_git_pass(git_iterator_for_filesystem( + &i, "testrepo/.git/refs", 0, NULL, NULL)); + expect_iterator_items(i, 11, expect_subdir, 11, expect_subdir); + git_iterator_free(i); +} -- cgit v1.2.1 From 71f85226eb5c2ef9e8c8ddb1943fc7fc1e6615ff Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 18 Apr 2013 11:11:38 -0700 Subject: Make workdir iterator use filesystem iterator This adds some hooks into the filesystem iterator so that the workdir iterator can just become a wrapper around it. Then we remove most of the workdir iterator code and just have it augment the filesystem iterator with skipping .git entries, updating the ignore stack, and checking for submodules. --- src/iterator.c | 545 ++++++++++++++++----------------------------------------- 1 file changed, 154 insertions(+), 391 deletions(-) diff --git a/src/iterator.c b/src/iterator.c index dd8a6133d..6eee5a805 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -26,8 +26,6 @@ (GIT_ITERATOR_IGNORE_CASE | GIT_ITERATOR_DONT_IGNORE_CASE) #define ITERATOR_BASE_INIT(P,NAME_LC,NAME_UC,REPO) do { \ - (P) = git__calloc(1, sizeof(NAME_LC ## _iterator)); \ - GITERR_CHECK_ALLOC(P); \ (P)->base.type = GIT_ITERATOR_TYPE_ ## NAME_UC; \ (P)->base.cb = &(P)->cb; \ ITERATOR_SET_CB(P,NAME_LC); \ @@ -148,7 +146,8 @@ int git_iterator_for_nothing( const char *start, const char *end) { - empty_iterator *i; + empty_iterator *i = git__calloc(1, sizeof(empty_iterator)); + GITERR_CHECK_ALLOC(i); #define empty_iterator__current empty_iterator__noop #define empty_iterator__advance empty_iterator__noop @@ -581,6 +580,9 @@ int git_iterator_for_tree( if ((error = git_object_dup((git_object **)&tree, (git_object *)tree)) < 0) return error; + ti = git__calloc(1, sizeof(tree_iterator)); + GITERR_CHECK_ALLOC(ti); + ITERATOR_BASE_INIT(ti, tree, TREE, git_tree_owner(tree)); if ((error = iterator__update_ignore_case((git_iterator *)ti, flags)) < 0) @@ -810,7 +812,8 @@ int git_iterator_for_index( const char *start, const char *end) { - index_iterator *ii; + index_iterator *ii = git__calloc(1, sizeof(index_iterator)); + GITERR_CHECK_ALLOC(ii); ITERATOR_BASE_INIT(ii, index, INDEX, git_index_owner(index)); @@ -840,7 +843,8 @@ struct fs_iterator_frame { size_t index; }; -typedef struct { +typedef struct fs_iterator fs_iterator; +struct fs_iterator { git_iterator base; git_iterator_callbacks cb; fs_iterator_frame *stack; @@ -848,7 +852,11 @@ typedef struct { git_buf path; size_t root_len; int depth; -} fs_iterator; + + int (*frame_added)(fs_iterator *self); + int (*frame_removed)(fs_iterator *self); + int (*entry_updated)(fs_iterator *self); +}; #define FS_MAX_DEPTH 100 @@ -867,15 +875,31 @@ static fs_iterator_frame *fs_iterator__alloc_frame(fs_iterator *fi) return ff; } -static void fs_iterator__free_frame(fs_iterator_frame *ff) +static void fs_iterator__pop_frame( + fs_iterator *fi, fs_iterator_frame *ff, bool pop_last) { size_t i; git_path_with_stat *path; + fs_iterator_frame *ff_next = ff->next; + + if (fi && !ff_next && !pop_last) { + memset(&fi->entry, 0, sizeof(fi->entry)); + return; + } git_vector_foreach(&ff->entries, i, path) git__free(path); git_vector_free(&ff->entries); git__free(ff); + + if (!fi || fi->stack != ff) + return; + + fi->stack = ff_next; + fi->depth--; + + if (fi->frame_removed) + fi->frame_removed(fi); } static int fs_iterator__update_entry(fs_iterator *fi); @@ -913,14 +937,14 @@ static int fs_iterator__expand_dir(fs_iterator *fi) fi->base.start, fi->base.end, &ff->entries); if (error < 0 || ff->entries.length == 0) { - fs_iterator__free_frame(ff); + fs_iterator__pop_frame(NULL, ff, true); return GIT_ENOTFOUND; } if (++(fi->depth) > FS_MAX_DEPTH) { giterr_set(GITERR_REPOSITORY, "Directory nesting is too deep (%d)", fi->depth); - fs_iterator__free_frame(ff); + fs_iterator__pop_frame(NULL, ff, true); return -1; } @@ -929,6 +953,9 @@ static int fs_iterator__expand_dir(fs_iterator *fi) ff->next = fi->stack; fi->stack = ff; + if (fi->frame_added && (error = fi->frame_added(fi)) < 0) + return error; + return fs_iterator__update_entry(fi); } @@ -971,7 +998,7 @@ static int fs_iterator__advance_into( return error; } -static int fs_iterator__advance( +static int fs_iterator__advance_over( const git_index_entry **entry, git_iterator *self) { int error = 0; @@ -979,20 +1006,6 @@ static int fs_iterator__advance( fs_iterator_frame *ff; git_path_with_stat *next; - /* given include_trees & autoexpand, we might have to go into a tree */ - if (iterator__do_autoexpand(fi) && - fi->entry.path != NULL && - fi->entry.mode == GIT_FILEMODE_TREE) - { - error = fs_iterator__advance_into(entry, self); - - /* continue silently past empty directories if autoexpanding */ - if (error != GIT_ENOTFOUND) - return error; - giterr_clear(); - error = 0; - } - if (entry != NULL) *entry = NULL; @@ -1003,15 +1016,7 @@ static int fs_iterator__advance( if (next != NULL) break; - /* pop stack if anything is left to pop */ - if (!ff->next) { - memset(&fi->entry, 0, sizeof(fi->entry)); - return 0; - } - - fi->stack = ff->next; - fi->depth--; - fs_iterator__free_frame(ff); + fs_iterator__pop_frame(fi, ff, false); } error = fs_iterator__update_entry(fi); @@ -1022,6 +1027,26 @@ static int fs_iterator__advance( return error; } +static int fs_iterator__advance( + const git_index_entry **entry, git_iterator *self) +{ + fs_iterator *fi = (fs_iterator *)self; + + /* given include_trees & autoexpand, we might have to go into a tree */ + if (iterator__do_autoexpand(fi) && + fi->entry.path != NULL && + fi->entry.mode == GIT_FILEMODE_TREE) + { + int error = fs_iterator__advance_into(entry, self); + if (error != GIT_ENOTFOUND) + return error; + /* continue silently past empty directories if autoexpanding */ + giterr_clear(); + } + + return fs_iterator__advance_over(entry, self); +} + static int fs_iterator__seek(git_iterator *self, const char *prefix) { GIT_UNUSED(self); @@ -1037,11 +1062,8 @@ static int fs_iterator__reset( { fs_iterator *fi = (fs_iterator *)self; - while (fi->stack != NULL && fi->stack->next != NULL) { - fs_iterator_frame *ff = fi->stack; - fi->stack = ff->next; - fs_iterator__free_frame(ff); - } + while (fi->stack != NULL && fi->stack->next != NULL) + fs_iterator__pop_frame(fi, fi->stack, false); fi->depth = 0; if (iterator__reset_range(self, start, end) < 0) @@ -1056,11 +1078,8 @@ static void fs_iterator__free(git_iterator *self) { fs_iterator *fi = (fs_iterator *)self; - while (fi->stack != NULL) { - fs_iterator_frame *ff = fi->stack; - fi->stack = ff->next; - fs_iterator__free_frame(ff); - } + while (fi->stack != NULL) + fs_iterator__pop_frame(fi, fi->stack, true); git_buf_free(&fi->path); } @@ -1075,10 +1094,8 @@ static int fs_iterator__update_entry(fs_iterator *fi) if (!ps) return 0; - if (git_buf_put(&fi->path, ps->path, ps->path_len) < 0) return -1; - if (iterator__past_end(fi, fi->path.ptr + fi->root_len)) return 0; @@ -1088,389 +1105,141 @@ static int fs_iterator__update_entry(fs_iterator *fi) /* need different mode here to keep directories during iteration */ fi->entry.mode = git_futils_canonical_mode(ps->st.st_mode); - /* if this isn't a tree, then we're done */ - if (fi->entry.mode != GIT_FILEMODE_TREE) - return 0; + /* allow wrapper to check/update the entry (can force skip) */ + if (fi->entry_updated && + fi->entry_updated(fi) == GIT_ENOTFOUND) + return fs_iterator__advance_over(NULL, (git_iterator *)fi); - if (iterator__include_trees(fi)) - return 0; + /* if this is a tree and trees aren't included, then skip */ + if (fi->entry.mode == GIT_FILEMODE_TREE && !iterator__include_trees(fi)) + return git_iterator_advance(NULL, (git_iterator *)fi); - return fs_iterator__advance(NULL, (git_iterator *)fi); + return 0; } -int git_iterator_for_filesystem( - git_iterator **out, - const char *root, - git_iterator_flag_t flags, - const char *start, - const char *end) +static int fs_iterator__initialize( + git_iterator **out, fs_iterator *fi, const char *root) { int error; - fs_iterator *fi; - - ITERATOR_BASE_INIT(fi, fs, FS, NULL); - - if ((flags & GIT_ITERATOR_IGNORE_CASE) != 0) - fi->base.flags |= GIT_ITERATOR_IGNORE_CASE; if (git_buf_sets(&fi->path, root) < 0 || git_path_to_dir(&fi->path) < 0) { git__free(fi); return -1; } + fi->root_len = fi->path.size; - if ((error = fs_iterator__expand_dir(fi)) < 0) { - if (error != GIT_ENOTFOUND) - goto fail; + if ((error = fs_iterator__expand_dir(fi)) == GIT_ENOTFOUND) { giterr_clear(); + error = 0; + } + if (error) { + git_iterator_free((git_iterator *)fi); + fi = NULL; } *out = (git_iterator *)fi; - return 0; - -fail: - git_iterator_free((git_iterator *)fi); return error; } +int git_iterator_for_filesystem( + git_iterator **out, + const char *root, + git_iterator_flag_t flags, + const char *start, + const char *end) +{ + fs_iterator *fi = git__calloc(1, sizeof(fs_iterator)); + GITERR_CHECK_ALLOC(fi); -#define WORKDIR_MAX_DEPTH 100 + ITERATOR_BASE_INIT(fi, fs, FS, NULL); + + if ((flags & GIT_ITERATOR_IGNORE_CASE) != 0) + fi->base.flags |= GIT_ITERATOR_IGNORE_CASE; + + return fs_iterator__initialize(out, fi, root); +} -typedef struct workdir_iterator_frame workdir_iterator_frame; -struct workdir_iterator_frame { - workdir_iterator_frame *next; - git_vector entries; - size_t index; -}; typedef struct { - git_iterator base; - git_iterator_callbacks cb; - workdir_iterator_frame *stack; + fs_iterator fi; git_ignores ignores; - git_index_entry entry; - git_buf path; - size_t root_len; int is_ignored; - int depth; } workdir_iterator; -GIT_INLINE(bool) path_is_dotgit(const git_path_with_stat *ps) +GIT_INLINE(bool) workdir_path_is_dotgit(const git_buf *path) { - if (!ps) - return false; - else { - const char *path = ps->path; - size_t len = ps->path_len; - - if (len < 4) - return false; - if (path[len - 1] == '/') - len--; - if (tolower(path[len - 1]) != 't' || - tolower(path[len - 2]) != 'i' || - tolower(path[len - 3]) != 'g' || - tolower(path[len - 4]) != '.') - return false; - return (len == 4 || path[len - 5] == '/'); - } -} - -static workdir_iterator_frame *workdir_iterator__alloc_frame( - workdir_iterator *wi) -{ - workdir_iterator_frame *wf = git__calloc(1, sizeof(workdir_iterator_frame)); - git_vector_cmp entry_compare = CASESELECT( - iterator__ignore_case(wi), - git_path_with_stat_cmp_icase, git_path_with_stat_cmp); - - if (wf == NULL) - return NULL; - - if (git_vector_init(&wf->entries, 0, entry_compare) != 0) { - git__free(wf); - return NULL; - } - - return wf; -} - -static void workdir_iterator__free_frame(workdir_iterator_frame *wf) -{ - unsigned int i; - git_path_with_stat *path; - - git_vector_foreach(&wf->entries, i, path) - git__free(path); - git_vector_free(&wf->entries); - git__free(wf); -} + size_t len; -static int workdir_iterator__update_entry(workdir_iterator *wi); - -static int workdir_iterator__entry_cmp(const void *i, const void *item) -{ - const workdir_iterator *wi = (const workdir_iterator *)i; - const git_path_with_stat *ps = item; - return wi->base.prefixcomp(wi->base.start, ps->path); -} + if (!path || (len = path->size) < 4) + return false; -static void workdir_iterator__seek_frame_start( - workdir_iterator *wi, workdir_iterator_frame *wf) -{ - if (!wf) - return; + if (path->ptr[len - 1] == '/') + len--; - if (wi->base.start) - git_vector_bsearch2( - &wf->index, &wf->entries, workdir_iterator__entry_cmp, wi); - else - wf->index = 0; + if (tolower(path->ptr[len - 1]) != 't' || + tolower(path->ptr[len - 2]) != 'i' || + tolower(path->ptr[len - 3]) != 'g' || + tolower(path->ptr[len - 4]) != '.') + return false; - if (path_is_dotgit(git_vector_get(&wf->entries, wf->index))) - wf->index++; + return (len == 4 || path->ptr[len - 5] == '/'); } -static int workdir_iterator__expand_dir(workdir_iterator *wi) +static int workdir_iterator__frame_added(fs_iterator *fi) { - int error; - workdir_iterator_frame *wf; - - wf = workdir_iterator__alloc_frame(wi); - GITERR_CHECK_ALLOC(wf); - - error = git_path_dirload_with_stat( - wi->path.ptr, wi->root_len, iterator__ignore_case(wi), - wi->base.start, wi->base.end, &wf->entries); - - if (error < 0 || wf->entries.length == 0) { - workdir_iterator__free_frame(wf); - return GIT_ENOTFOUND; - } - - if (++(wi->depth) > WORKDIR_MAX_DEPTH) { - giterr_set(GITERR_REPOSITORY, - "Working directory is too deep (%d)", wi->depth); - workdir_iterator__free_frame(wf); - return -1; - } - - workdir_iterator__seek_frame_start(wi, wf); - /* only push new ignores if this is not top level directory */ - if (wi->stack != NULL) { - ssize_t slash_pos = git_buf_rfind_next(&wi->path, '/'); - (void)git_ignore__push_dir(&wi->ignores, &wi->path.ptr[slash_pos + 1]); - } - - wf->next = wi->stack; - wi->stack = wf; + if (fi->stack->next != NULL) { + workdir_iterator *wi = (workdir_iterator *)fi; + ssize_t slash_pos = git_buf_rfind_next(&fi->path, '/'); - return workdir_iterator__update_entry(wi); -} + (void)git_ignore__push_dir(&wi->ignores, &fi->path.ptr[slash_pos + 1]); + } -static int workdir_iterator__current( - const git_index_entry **entry, git_iterator *self) -{ - workdir_iterator *wi = (workdir_iterator *)self; - if (entry) - *entry = (wi->entry.path == NULL) ? NULL : &wi->entry; return 0; } -static int workdir_iterator__at_end(git_iterator *self) +static int workdir_iterator__frame_removed(fs_iterator *fi) { - return (((workdir_iterator *)self)->entry.path == NULL); + workdir_iterator *wi = (workdir_iterator *)fi; + git_ignore__pop_dir(&wi->ignores); + return 0; } -static int workdir_iterator__advance_into( - const git_index_entry **entry, git_iterator *iter) +static int workdir_iterator__entry_updated(fs_iterator *fi) { int error = 0; - workdir_iterator *wi = (workdir_iterator *)iter; - - iterator__clear_entry(entry); - - /* workdir iterator will allow you to explicitly advance into a - * commit/submodule (as well as a tree) to avoid some cases where an - * entry is mislabeled as a submodule in the working directory - */ - if (wi->entry.path != NULL && - (wi->entry.mode == GIT_FILEMODE_TREE || - wi->entry.mode == GIT_FILEMODE_COMMIT)) - /* returns GIT_ENOTFOUND if the directory is empty */ - error = workdir_iterator__expand_dir(wi); + workdir_iterator *wi = (workdir_iterator *)fi; - if (!error && entry) - error = workdir_iterator__current(entry, iter); - - return error; -} + /* skip over .git entries */ + if (workdir_path_is_dotgit(&fi->path)) + return GIT_ENOTFOUND; -static int workdir_iterator__advance( - const git_index_entry **entry, git_iterator *self) -{ - int error = 0; - workdir_iterator *wi = (workdir_iterator *)self; - workdir_iterator_frame *wf; - git_path_with_stat *next; + /* reset is_ignored since we haven't checked yet */ + wi->is_ignored = -1; - /* given include_trees & autoexpand, we might have to go into a tree */ - if (iterator__do_autoexpand(wi) && - wi->entry.path != NULL && - wi->entry.mode == GIT_FILEMODE_TREE) - { - error = workdir_iterator__advance_into(entry, self); + /* check if apparent tree entries are actually submodules */ + if (fi->entry.mode != GIT_FILEMODE_TREE) + return 0; - /* continue silently past empty directories if autoexpanding */ - if (error != GIT_ENOTFOUND) - return error; + error = git_submodule_lookup(NULL, fi->base.repo, fi->entry.path); + if (error < 0) giterr_clear(); - error = 0; - } - - if (entry != NULL) - *entry = NULL; - while (wi->entry.path != NULL) { - wf = wi->stack; - next = git_vector_get(&wf->entries, ++wf->index); - - if (next != NULL) { - /* match git's behavior of ignoring anything named ".git" */ - if (path_is_dotgit(next)) - continue; - /* else found a good entry */ - break; - } - - /* pop stack if anything is left to pop */ - if (!wf->next) { - memset(&wi->entry, 0, sizeof(wi->entry)); - return 0; - } - - wi->stack = wf->next; - wi->depth--; - workdir_iterator__free_frame(wf); - git_ignore__pop_dir(&wi->ignores); + /* mark submodule (or any dir with .git) as GITLINK and remove slash */ + if (!error || error == GIT_EEXISTS) { + fi->entry.mode = S_IFGITLINK; + fi->entry.path[strlen(fi->entry.path) - 1] = '\0'; } - error = workdir_iterator__update_entry(wi); - - if (!error && entry != NULL) - error = workdir_iterator__current(entry, self); - - return error; -} - -static int workdir_iterator__seek(git_iterator *self, const char *prefix) -{ - GIT_UNUSED(self); - GIT_UNUSED(prefix); - /* pop stack until matching prefix */ - /* find prefix item in current frame */ - /* push subdirectories as deep as possible while matching */ return 0; } -static int workdir_iterator__reset( - git_iterator *self, const char *start, const char *end) -{ - workdir_iterator *wi = (workdir_iterator *)self; - - while (wi->stack != NULL && wi->stack->next != NULL) { - workdir_iterator_frame *wf = wi->stack; - wi->stack = wf->next; - workdir_iterator__free_frame(wf); - git_ignore__pop_dir(&wi->ignores); - } - wi->depth = 0; - - if (iterator__reset_range(self, start, end) < 0) - return -1; - - workdir_iterator__seek_frame_start(wi, wi->stack); - - return workdir_iterator__update_entry(wi); -} - static void workdir_iterator__free(git_iterator *self) { workdir_iterator *wi = (workdir_iterator *)self; - - while (wi->stack != NULL) { - workdir_iterator_frame *wf = wi->stack; - wi->stack = wf->next; - workdir_iterator__free_frame(wf); - } - + fs_iterator__free(self); git_ignore__free(&wi->ignores); - git_buf_free(&wi->path); -} - -static int workdir_iterator__update_entry(workdir_iterator *wi) -{ - int error = 0; - git_path_with_stat *ps = - git_vector_get(&wi->stack->entries, wi->stack->index); - - git_buf_truncate(&wi->path, wi->root_len); - memset(&wi->entry, 0, sizeof(wi->entry)); - - if (!ps) - return 0; - - /* skip over .git entries */ - if (path_is_dotgit(ps)) - return workdir_iterator__advance(NULL, (git_iterator *)wi); - - if (git_buf_put(&wi->path, ps->path, ps->path_len) < 0) - return -1; - - if (iterator__past_end(wi, wi->path.ptr + wi->root_len)) - return 0; - - wi->entry.path = ps->path; - - wi->is_ignored = -1; - - git_index_entry__init_from_stat(&wi->entry, &ps->st); - - /* need different mode here to keep directories during iteration */ - wi->entry.mode = git_futils_canonical_mode(ps->st.st_mode); - - /* if this is a file type we don't handle, treat as ignored */ - if (wi->entry.mode == 0) { - wi->is_ignored = 1; - return 0; - } - - /* if this isn't a tree, then we're done */ - if (wi->entry.mode != GIT_FILEMODE_TREE) - return 0; - - /* detect submodules */ - error = git_submodule_lookup(NULL, wi->base.repo, wi->entry.path); - if (error == GIT_ENOTFOUND) - giterr_clear(); - - if (error == GIT_EEXISTS) /* if contains .git, treat as untracked submod */ - error = 0; - - /* if submodule, mark as GITLINK and remove trailing slash */ - if (!error) { - size_t len = strlen(wi->entry.path); - assert(wi->entry.path[len - 1] == '/'); - wi->entry.path[len - 1] = '\0'; - wi->entry.mode = S_IFGITLINK; - return 0; - } - - if (iterator__include_trees(wi)) - return 0; - - return workdir_iterator__advance(NULL, (git_iterator *)wi); } int git_iterator_for_workdir( @@ -1481,7 +1250,8 @@ int git_iterator_for_workdir( const char *end) { int error; - workdir_iterator *wi; + workdir_iterator *wi = git__calloc(1, sizeof(workdir_iterator)); + GITERR_CHECK_ALLOC(wi); assert(iter && repo); @@ -1489,32 +1259,24 @@ int git_iterator_for_workdir( repo, "scan working directory")) < 0) return error; - ITERATOR_BASE_INIT(wi, workdir, WORKDIR, repo); + /* initialize as an fs iterator then do overrides */ + ITERATOR_BASE_INIT((&wi->fi), fs, FS, repo); - if ((error = iterator__update_ignore_case((git_iterator *)wi, flags)) < 0) - goto fail; + wi->fi.base.type = GIT_ITERATOR_TYPE_WORKDIR; + wi->fi.cb.free = workdir_iterator__free; + wi->fi.frame_added = workdir_iterator__frame_added; + wi->fi.frame_removed = workdir_iterator__frame_removed; + wi->fi.entry_updated = workdir_iterator__entry_updated; - if (git_buf_sets(&wi->path, git_repository_workdir(repo)) < 0 || - git_path_to_dir(&wi->path) < 0 || - git_ignore__for_path(repo, "", &wi->ignores) < 0) + if ((error = iterator__update_ignore_case((git_iterator *)wi, flags)) < 0 || + (error = git_ignore__for_path(repo, "", &wi->ignores)) < 0) { - git__free(wi); - return -1; - } - wi->root_len = wi->path.size; - - if ((error = workdir_iterator__expand_dir(wi)) < 0) { - if (error != GIT_ENOTFOUND) - goto fail; - giterr_clear(); + git_iterator_free((git_iterator *)wi); + return error; } - *iter = (git_iterator *)wi; - return 0; - -fail: - git_iterator_free((git_iterator *)wi); - return error; + return fs_iterator__initialize( + iter, (fs_iterator *)wi, git_repository_workdir(repo)); } @@ -1616,7 +1378,8 @@ bool git_iterator_current_is_ignored(git_iterator *iter) if (wi->is_ignored != -1) return (bool)(wi->is_ignored != 0); - if (git_ignore__lookup(&wi->ignores, wi->entry.path, &wi->is_ignored) < 0) + if (git_ignore__lookup( + &wi->ignores, wi->fi.entry.path, &wi->is_ignored) < 0) wi->is_ignored = true; return (bool)wi->is_ignored; @@ -1641,10 +1404,10 @@ int git_iterator_current_workdir_path(git_buf **path, git_iterator *iter) { workdir_iterator *wi = (workdir_iterator *)iter; - if (iter->type != GIT_ITERATOR_TYPE_WORKDIR || !wi->entry.path) + if (iter->type != GIT_ITERATOR_TYPE_WORKDIR || !wi->fi.entry.path) *path = NULL; else - *path = &wi->path; + *path = &wi->fi.path; return 0; } -- cgit v1.2.1 From fc57471a0c1834143ae6b18e65c1484c5c04e7e3 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 18 Apr 2013 14:13:53 -0700 Subject: More filesystem iterator cleanup Renamed the callback functions and made some minor rearrangements to clean up the flow of some code. --- src/iterator.c | 83 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/src/iterator.c b/src/iterator.c index 6eee5a805..a72f97eca 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -853,9 +853,9 @@ struct fs_iterator { size_t root_len; int depth; - int (*frame_added)(fs_iterator *self); - int (*frame_removed)(fs_iterator *self); - int (*entry_updated)(fs_iterator *self); + int (*enter_dir_cb)(fs_iterator *self); + int (*leave_dir_cb)(fs_iterator *self); + int (*update_entry_cb)(fs_iterator *self); }; #define FS_MAX_DEPTH 100 @@ -875,31 +875,34 @@ static fs_iterator_frame *fs_iterator__alloc_frame(fs_iterator *fi) return ff; } -static void fs_iterator__pop_frame( - fs_iterator *fi, fs_iterator_frame *ff, bool pop_last) +static void fs_iterator__free_frame(fs_iterator_frame *ff) { size_t i; git_path_with_stat *path; - fs_iterator_frame *ff_next = ff->next; - - if (fi && !ff_next && !pop_last) { - memset(&fi->entry, 0, sizeof(fi->entry)); - return; - } git_vector_foreach(&ff->entries, i, path) git__free(path); git_vector_free(&ff->entries); git__free(ff); +} - if (!fi || fi->stack != ff) - return; +static void fs_iterator__pop_frame( + fs_iterator *fi, fs_iterator_frame *ff, bool pop_last) +{ + if (fi && fi->stack == ff) { + if (!ff->next && !pop_last) { + memset(&fi->entry, 0, sizeof(fi->entry)); + return; + } + + if (fi->leave_dir_cb) + (void)fi->leave_dir_cb(fi); - fi->stack = ff_next; - fi->depth--; + fi->stack = ff->next; + fi->depth--; + } - if (fi->frame_removed) - fi->frame_removed(fi); + fs_iterator__free_frame(ff); } static int fs_iterator__update_entry(fs_iterator *fi); @@ -929,6 +932,12 @@ static int fs_iterator__expand_dir(fs_iterator *fi) int error; fs_iterator_frame *ff; + if (fi->depth > FS_MAX_DEPTH) { + giterr_set(GITERR_REPOSITORY, + "Directory nesting is too deep (%d)", fi->depth); + return -1; + } + ff = fs_iterator__alloc_frame(fi); GITERR_CHECK_ALLOC(ff); @@ -937,23 +946,17 @@ static int fs_iterator__expand_dir(fs_iterator *fi) fi->base.start, fi->base.end, &ff->entries); if (error < 0 || ff->entries.length == 0) { - fs_iterator__pop_frame(NULL, ff, true); + fs_iterator__free_frame(ff); return GIT_ENOTFOUND; } - if (++(fi->depth) > FS_MAX_DEPTH) { - giterr_set(GITERR_REPOSITORY, - "Directory nesting is too deep (%d)", fi->depth); - fs_iterator__pop_frame(NULL, ff, true); - return -1; - } - fs_iterator__seek_frame_start(fi, ff); ff->next = fi->stack; fi->stack = ff; + fi->depth++; - if (fi->frame_added && (error = fi->frame_added(fi)) < 0) + if (fi->enter_dir_cb && (error = fi->enter_dir_cb(fi)) < 0) return error; return fs_iterator__update_entry(fi); @@ -1106,8 +1109,8 @@ static int fs_iterator__update_entry(fs_iterator *fi) fi->entry.mode = git_futils_canonical_mode(ps->st.st_mode); /* allow wrapper to check/update the entry (can force skip) */ - if (fi->entry_updated && - fi->entry_updated(fi) == GIT_ENOTFOUND) + if (fi->update_entry_cb && + fi->update_entry_cb(fi) == GIT_ENOTFOUND) return fs_iterator__advance_over(NULL, (git_iterator *)fi); /* if this is a tree and trees aren't included, then skip */ @@ -1126,7 +1129,6 @@ static int fs_iterator__initialize( git__free(fi); return -1; } - fi->root_len = fi->path.size; if ((error = fs_iterator__expand_dir(fi)) == GIT_ENOTFOUND) { @@ -1186,7 +1188,7 @@ GIT_INLINE(bool) workdir_path_is_dotgit(const git_buf *path) return (len == 4 || path->ptr[len - 5] == '/'); } -static int workdir_iterator__frame_added(fs_iterator *fi) +static int workdir_iterator__enter_dir(fs_iterator *fi) { /* only push new ignores if this is not top level directory */ if (fi->stack->next != NULL) { @@ -1199,14 +1201,14 @@ static int workdir_iterator__frame_added(fs_iterator *fi) return 0; } -static int workdir_iterator__frame_removed(fs_iterator *fi) +static int workdir_iterator__leave_dir(fs_iterator *fi) { workdir_iterator *wi = (workdir_iterator *)fi; git_ignore__pop_dir(&wi->ignores); return 0; } -static int workdir_iterator__entry_updated(fs_iterator *fi) +static int workdir_iterator__update_entry(fs_iterator *fi) { int error = 0; workdir_iterator *wi = (workdir_iterator *)fi; @@ -1243,7 +1245,7 @@ static void workdir_iterator__free(git_iterator *self) } int git_iterator_for_workdir( - git_iterator **iter, + git_iterator **out, git_repository *repo, git_iterator_flag_t flags, const char *start, @@ -1253,7 +1255,7 @@ int git_iterator_for_workdir( workdir_iterator *wi = git__calloc(1, sizeof(workdir_iterator)); GITERR_CHECK_ALLOC(wi); - assert(iter && repo); + assert(out && repo); if ((error = git_repository__ensure_not_bare( repo, "scan working directory")) < 0) @@ -1262,11 +1264,11 @@ int git_iterator_for_workdir( /* initialize as an fs iterator then do overrides */ ITERATOR_BASE_INIT((&wi->fi), fs, FS, repo); - wi->fi.base.type = GIT_ITERATOR_TYPE_WORKDIR; - wi->fi.cb.free = workdir_iterator__free; - wi->fi.frame_added = workdir_iterator__frame_added; - wi->fi.frame_removed = workdir_iterator__frame_removed; - wi->fi.entry_updated = workdir_iterator__entry_updated; + wi->fi.base.type = GIT_ITERATOR_TYPE_WORKDIR; + wi->fi.cb.free = workdir_iterator__free; + wi->fi.enter_dir_cb = workdir_iterator__enter_dir; + wi->fi.leave_dir_cb = workdir_iterator__leave_dir; + wi->fi.update_entry_cb = workdir_iterator__update_entry; if ((error = iterator__update_ignore_case((git_iterator *)wi, flags)) < 0 || (error = git_ignore__for_path(repo, "", &wi->ignores)) < 0) @@ -1275,8 +1277,7 @@ int git_iterator_for_workdir( return error; } - return fs_iterator__initialize( - iter, (fs_iterator *)wi, git_repository_workdir(repo)); + return fs_iterator__initialize(out, &wi->fi, git_repository_workdir(repo)); } -- cgit v1.2.1 From 627d590819efa7f43b605ce1a22278c0c6b42516 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 18 Apr 2013 14:14:22 -0700 Subject: More filesystem iterator tests Refactors the helper function that builds a directory hierarchy and then made use of it to try more variations on filesystem iterator tests. --- tests-clar/repo/iterator.c | 134 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 103 insertions(+), 31 deletions(-) diff --git a/tests-clar/repo/iterator.c b/tests-clar/repo/iterator.c index ef9bfc33d..2e53c48d7 100644 --- a/tests-clar/repo/iterator.c +++ b/tests-clar/repo/iterator.c @@ -755,47 +755,52 @@ void test_repo_iterator__workdir_icase(void) git_iterator_free(i); } -void test_repo_iterator__workdir_depth(void) +static void build_workdir_tree(const char *root, int dirs, int subs) { int i, j; - git_iterator *iter; - char buf[64]; - - g_repo = cl_git_sandbox_init("icase"); - - for (i = 0; i < 10; ++i) { - p_snprintf(buf, sizeof(buf), "icase/dir%02d", i); - cl_git_pass(git_futils_mkdir(buf, NULL, 0775, GIT_MKDIR_PATH)); + char buf[64], sub[64]; + for (i = 0; i < dirs; ++i) { if (i % 2 == 0) { - p_snprintf(buf, sizeof(buf), "icase/dir%02d/file", i); + p_snprintf(buf, sizeof(buf), "%s/dir%02d", root, i); + cl_git_pass(git_futils_mkdir(buf, NULL, 0775, GIT_MKDIR_PATH)); + + p_snprintf(buf, sizeof(buf), "%s/dir%02d/file", root, i); cl_git_mkfile(buf, buf); + buf[strlen(buf) - 5] = '\0'; + } else { + p_snprintf(buf, sizeof(buf), "%s/DIR%02d", root, i); + cl_git_pass(git_futils_mkdir(buf, NULL, 0775, GIT_MKDIR_PATH)); } - for (j = 0; j < 10; ++j) { - p_snprintf(buf, sizeof(buf), "icase/dir%02d/sub%02d", i, j); - cl_git_pass(git_futils_mkdir(buf, NULL, 0775, GIT_MKDIR_PATH)); + for (j = 0; j < subs; ++j) { + switch (j % 4) { + case 0: p_snprintf(sub, sizeof(sub), "%s/sub%02d", buf, j); break; + case 1: p_snprintf(sub, sizeof(sub), "%s/sUB%02d", buf, j); break; + case 2: p_snprintf(sub, sizeof(sub), "%s/Sub%02d", buf, j); break; + case 3: p_snprintf(sub, sizeof(sub), "%s/SUB%02d", buf, j); break; + } + cl_git_pass(git_futils_mkdir(sub, NULL, 0775, GIT_MKDIR_PATH)); if (j % 2 == 0) { - p_snprintf( - buf, sizeof(buf), "icase/dir%02d/sub%02d/file", i, j); - cl_git_mkfile(buf, buf); + size_t sublen = strlen(sub); + memcpy(&sub[sublen], "/file", sizeof("/file")); + cl_git_mkfile(sub, sub); + sub[sublen] = '\0'; } } } +} - for (i = 1; i < 3; ++i) { - for (j = 0; j < 50; ++j) { - p_snprintf(buf, sizeof(buf), "icase/dir%02d/sub01/moar%02d", i, j); - cl_git_pass(git_futils_mkdir(buf, NULL, 0775, GIT_MKDIR_PATH)); +void test_repo_iterator__workdir_depth(void) +{ + git_iterator *iter; - if (j % 2 == 0) { - p_snprintf(buf, sizeof(buf), - "icase/dir%02d/sub01/moar%02d/file", i, j); - cl_git_mkfile(buf, buf); - } - } - } + g_repo = cl_git_sandbox_init("icase"); + + build_workdir_tree("icase", 10, 10); + build_workdir_tree("icase/dir01/Sub01", 50, 0); + build_workdir_tree("icase/DIR02/Sub01", 50, 0); /* auto expand with no tree entries */ cl_git_pass(git_iterator_for_workdir(&iter, g_repo, 0, NULL, NULL)); @@ -812,8 +817,42 @@ void test_repo_iterator__workdir_depth(void) void test_repo_iterator__fs(void) { git_iterator *i; - static const char *expect_subdir[] = { + static const char *expect_base[] = { + "DIR01/Sub02/file", + "DIR01/sub00/file", "current_file", + "dir00/Sub02/file", + "dir00/file", + "dir00/sub00/file", + "modified_file", + "new_file", + NULL, + }; + static const char *expect_trees[] = { + "DIR01/", + "DIR01/SUB03/", + "DIR01/Sub02/", + "DIR01/Sub02/file", + "DIR01/sUB01/", + "DIR01/sub00/", + "DIR01/sub00/file", + "current_file", + "dir00/", + "dir00/SUB03/", + "dir00/Sub02/", + "dir00/Sub02/file", + "dir00/file", + "dir00/sUB01/", + "dir00/sub00/", + "dir00/sub00/file", + "modified_file", + "new_file", + NULL, + }; + static const char *expect_noauto[] = { + "DIR01/", + "current_file", + "dir00/", "modified_file", "new_file", NULL, @@ -821,16 +860,49 @@ void test_repo_iterator__fs(void) g_repo = cl_git_sandbox_init("status"); + build_workdir_tree("status/subdir", 2, 4); + cl_git_pass(git_iterator_for_filesystem( &i, "status/subdir", 0, NULL, NULL)); - expect_iterator_items(i, 3, expect_subdir, 3, expect_subdir); + expect_iterator_items(i, 8, expect_base, 8, expect_base); + git_iterator_free(i); + + cl_git_pass(git_iterator_for_filesystem( + &i, "status/subdir", GIT_ITERATOR_INCLUDE_TREES, NULL, NULL)); + expect_iterator_items(i, 18, expect_trees, 18, expect_trees); + git_iterator_free(i); + + cl_git_pass(git_iterator_for_filesystem( + &i, "status/subdir", GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL)); + expect_iterator_items(i, 5, expect_noauto, 18, expect_trees); + git_iterator_free(i); + + git__tsort((void **)expect_base, 8, (git__tsort_cmp)git__strcasecmp); + git__tsort((void **)expect_trees, 18, (git__tsort_cmp)git__strcasecmp); + git__tsort((void **)expect_noauto, 5, (git__tsort_cmp)git__strcasecmp); + + cl_git_pass(git_iterator_for_filesystem( + &i, "status/subdir", GIT_ITERATOR_IGNORE_CASE, NULL, NULL)); + expect_iterator_items(i, 8, expect_base, 8, expect_base); + git_iterator_free(i); + + cl_git_pass(git_iterator_for_filesystem( + &i, "status/subdir", GIT_ITERATOR_IGNORE_CASE | + GIT_ITERATOR_INCLUDE_TREES, NULL, NULL)); + expect_iterator_items(i, 18, expect_trees, 18, expect_trees); + git_iterator_free(i); + + cl_git_pass(git_iterator_for_filesystem( + &i, "status/subdir", GIT_ITERATOR_IGNORE_CASE | + GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL)); + expect_iterator_items(i, 5, expect_noauto, 18, expect_trees); git_iterator_free(i); } void test_repo_iterator__fs2(void) { git_iterator *i; - static const char *expect_subdir[] = { + static const char *expect_base[] = { "heads/br2", "heads/dir", "heads/master", @@ -849,6 +921,6 @@ void test_repo_iterator__fs2(void) cl_git_pass(git_iterator_for_filesystem( &i, "testrepo/.git/refs", 0, NULL, NULL)); - expect_iterator_items(i, 11, expect_subdir, 11, expect_subdir); + expect_iterator_items(i, 11, expect_base, 11, expect_base); git_iterator_free(i); } -- cgit v1.2.1 From 2aee1aa4165583cf77815df404d87818d53b72dc Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 18 Apr 2013 14:35:13 -0700 Subject: Fix uninitialized var warnings --- src/index.c | 2 +- src/revparse.c | 2 +- tests-clar/repo/iterator.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/index.c b/src/index.c index 6290ec4e8..2afd28158 100644 --- a/src/index.c +++ b/src/index.c @@ -1345,7 +1345,7 @@ static size_t read_extension(git_index *index, const char *buffer, size_t buffer static int parse_index(git_index *index, const char *buffer, size_t buffer_size) { unsigned int i; - struct index_header header; + struct index_header header = { 0 }; git_oid checksum_calculated, checksum_expected; #define seek_forward(_increase) { \ diff --git a/src/revparse.c b/src/revparse.c index 74635ed04..8a22a04f3 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -16,7 +16,7 @@ static int disambiguate_refname(git_reference **out, git_repository *repo, const char *refname) { - int error, i; + int error = 0, i; bool fallbackmode = true; git_reference *ref; git_buf refnamebuf = GIT_BUF_INIT, name = GIT_BUF_INIT; diff --git a/tests-clar/repo/iterator.c b/tests-clar/repo/iterator.c index 2e53c48d7..9118dd17e 100644 --- a/tests-clar/repo/iterator.c +++ b/tests-clar/repo/iterator.c @@ -422,7 +422,7 @@ static void build_test_tree( git_treebuilder *builder; const char *scan = fmt, *next; char type, delimiter; - git_filemode_t mode; + git_filemode_t mode = GIT_FILEMODE_BLOB; git_buf name = GIT_BUF_INIT; va_list arglist; -- cgit v1.2.1 From 9ea29c8f1dd155cf62fc6c87edaeb9984da72f72 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 18 Apr 2013 14:41:16 -0700 Subject: Fix fs iterator test on case sensitive fs --- tests-clar/repo/iterator.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests-clar/repo/iterator.c b/tests-clar/repo/iterator.c index 9118dd17e..ab460735c 100644 --- a/tests-clar/repo/iterator.c +++ b/tests-clar/repo/iterator.c @@ -799,8 +799,8 @@ void test_repo_iterator__workdir_depth(void) g_repo = cl_git_sandbox_init("icase"); build_workdir_tree("icase", 10, 10); - build_workdir_tree("icase/dir01/Sub01", 50, 0); - build_workdir_tree("icase/DIR02/Sub01", 50, 0); + build_workdir_tree("icase/DIR01/sUB01", 50, 0); + build_workdir_tree("icase/dir02/sUB01", 50, 0); /* auto expand with no tree entries */ cl_git_pass(git_iterator_for_workdir(&iter, g_repo, 0, NULL, NULL)); -- cgit v1.2.1 From 38fd8121a2a87cc0da405b50f4439ca6578dcff5 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 18 Apr 2013 14:48:20 -0700 Subject: Fix win64 warnings --- src/branch.c | 2 +- tests-clar/refdb/inmemory.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/branch.c b/src/branch.c index e7088790e..956286b74 100644 --- a/src/branch.c +++ b/src/branch.c @@ -377,7 +377,7 @@ int git_branch_remote_name(char *buffer, size_t buffer_len, git_repository *repo if (buffer) git_buf_copy_cstr(buffer, buffer_len, &buf); - ret = git_buf_len(&buf) + 1; + ret = (int)git_buf_len(&buf) + 1; git_buf_free(&buf); return ret; diff --git a/tests-clar/refdb/inmemory.c b/tests-clar/refdb/inmemory.c index 2cccd8eb2..ca721e977 100644 --- a/tests-clar/refdb/inmemory.c +++ b/tests-clar/refdb/inmemory.c @@ -160,7 +160,7 @@ void test_refdb_inmemory__foreach(void) cl_git_pass(git_reference_create(&write3, repo, GIT_REFS_HEADS_DIR "test3", &oid3, 0)); cl_git_pass(git_reference_foreach(repo, GIT_REF_LISTALL, foreach_test, &i)); - cl_assert_equal_i(i, 3); + cl_assert_equal_i(3, (int)i); git_reference_free(write1); git_reference_free(write2); @@ -207,7 +207,7 @@ void test_refdb_inmemory__delete(void) git_reference_free(write3); cl_git_pass(git_reference_foreach(repo, GIT_REF_LISTALL, delete_test, &i)); - cl_assert_equal_i(i, 1); + cl_assert_equal_i(1, (int)i); git_reference_free(write2); } -- cgit v1.2.1 From 1af80a676613882b3e04e82874c6e7c8c14b5f49 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 18 Apr 2013 16:13:52 -0700 Subject: Fix workdir iterator leak When attempting to create a workdir iterator for a bare repo, don't leak the iterator structure. --- src/iterator.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/iterator.c b/src/iterator.c index a72f97eca..ff08c1ce0 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -1252,16 +1252,14 @@ int git_iterator_for_workdir( const char *end) { int error; - workdir_iterator *wi = git__calloc(1, sizeof(workdir_iterator)); - GITERR_CHECK_ALLOC(wi); - - assert(out && repo); + workdir_iterator *wi; - if ((error = git_repository__ensure_not_bare( - repo, "scan working directory")) < 0) - return error; + if (git_repository__ensure_not_bare(repo, "scan working directory") < 0) + return GIT_EBAREREPO; /* initialize as an fs iterator then do overrides */ + wi = git__calloc(1, sizeof(workdir_iterator)); + GITERR_CHECK_ALLOC(wi); ITERATOR_BASE_INIT((&wi->fi), fs, FS, repo); wi->fi.base.type = GIT_ITERATOR_TYPE_WORKDIR; -- cgit v1.2.1 From 743048f1e9d9c853ffac80093a4814a1ac7d9c62 Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Fri, 19 Apr 2013 10:29:50 -0700 Subject: Fix some minor issues --- README.md | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index fdddc5ca1..a2a18765a 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ release its source code. * Archives: * Website: * API documentation: +* IRC: #libgit2 on irc.freenode.net. What It Can Do ================================== @@ -155,15 +156,7 @@ we can add it to the list. How Can I Contribute? ================================== -Fork libgit2/libgit2 on GitHub, add your improvement, push it to a branch -in your fork named for the topic, send a pull request. If you change the -API or make other large changes, make a note of it in docs/rel-notes/ in a -file named after the next release. - -You can also file bugs or feature requests under the libgit2 project on -GitHub, or join us on the mailing list by sending an email to: - -libgit2@librelist.com +Check the [contribution guidelines](CONTRIBUTING.md). License -- cgit v1.2.1 From 4a38143c93dc705bc40109e3f79d7fac722d44d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Fri, 19 Apr 2013 23:55:37 +0200 Subject: remote: specify what values direction can mean in git_remote_connect() This fixes #1487 --- include/git2/remote.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/git2/remote.h b/include/git2/remote.h index 6f36a3999..9494a8b01 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -184,7 +184,8 @@ GIT_EXTERN(const git_refspec *) git_remote_pushspec(const git_remote *remote); * starts up a specific binary which can only do the one or the other. * * @param remote the remote to connect to - * @param direction whether you want to receive or send data + * @param direction GIT_DIRECTION_FETCH if you want to fetch or + * GIT_DIRECTION_PUSH if you want to push * @return 0 or an error code */ GIT_EXTERN(int) git_remote_connect(git_remote *remote, git_direction direction); -- cgit v1.2.1 From 4e4eab52f7c5062ea21ea278a38e48700e753883 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 19 Apr 2013 18:19:53 -0500 Subject: alloc doesn't take a refdb; git_refdb_free nicely in the tests --- include/git2/refdb.h | 2 -- include/git2/refdb_backend.h | 3 +-- src/refdb.c | 15 +++++++++++++-- src/refdb_fs.c | 11 ++++------- src/refs.c | 25 ++++++++++++------------- tests-clar/refdb/inmemory.c | 5 +++-- tests-clar/refdb/testdb.c | 11 ++--------- tests-clar/refs/delete.c | 1 + tests-clar/refs/pack.c | 1 + tests-clar/refs/rename.c | 1 + 10 files changed, 38 insertions(+), 37 deletions(-) diff --git a/include/git2/refdb.h b/include/git2/refdb.h index 76b8fda0d..0e3ec5eaf 100644 --- a/include/git2/refdb.h +++ b/include/git2/refdb.h @@ -32,13 +32,11 @@ GIT_BEGIN_DECL * @return the created git_reference or NULL on error */ GIT_EXTERN(git_reference *) git_reference__alloc( - git_refdb *refdb, const char *name, const git_oid *oid, const git_oid *peel); GIT_EXTERN(git_reference *) git_reference__alloc_symbolic( - git_refdb *refdb, const char *name, const char *target); diff --git a/include/git2/refdb_backend.h b/include/git2/refdb_backend.h index bf33817d6..20eb6a9dd 100644 --- a/include/git2/refdb_backend.h +++ b/include/git2/refdb_backend.h @@ -101,8 +101,7 @@ struct git_refdb_backend { */ GIT_EXTERN(int) git_refdb_backend_fs( struct git_refdb_backend **backend_out, - git_repository *repo, - git_refdb *refdb); + git_repository *repo); GIT_END_DECL diff --git a/src/refdb.c b/src/refdb.c index d9b73c6e7..2a0fd702c 100644 --- a/src/refdb.c +++ b/src/refdb.c @@ -45,7 +45,7 @@ int git_refdb_open(git_refdb **out, git_repository *repo) return -1; /* Add the default (filesystem) backend */ - if (git_refdb_backend_fs(&dir, repo, db) < 0) { + if (git_refdb_backend_fs(&dir, repo) < 0) { git_refdb_free(db); return -1; } @@ -111,9 +111,20 @@ int git_refdb_exists(int *exists, git_refdb *refdb, const char *ref_name) int git_refdb_lookup(git_reference **out, git_refdb *db, const char *ref_name) { + git_reference *ref; + int error; + assert(db && db->backend && ref_name); - return db->backend->lookup(out, db->backend, ref_name); + *out = NULL; + + if ((error = db->backend->lookup(&ref, db->backend, ref_name)) == 0) + { + ref->db = db; + *out = ref; + } + + return error; } int git_refdb_foreach( diff --git a/src/refdb_fs.c b/src/refdb_fs.c index 784749fd3..56b2b6a99 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -42,7 +42,6 @@ typedef struct refdb_fs_backend { git_repository *repo; const char *path; - git_refdb *refdb; git_refcache refcache; } refdb_fs_backend; @@ -430,12 +429,12 @@ static int loose_lookup( goto done; } - *out = git_reference__alloc_symbolic(backend->refdb, ref_name, target); + *out = git_reference__alloc_symbolic(ref_name, target); } else { if ((error = loose_parse_oid(&oid, &ref_file)) < 0) goto done; - *out = git_reference__alloc(backend->refdb, ref_name, &oid, NULL); + *out = git_reference__alloc(ref_name, &oid, NULL); } if (*out == NULL) @@ -484,7 +483,7 @@ static int packed_lookup( if ((error = packed_map_entry(&entry, &pos, backend, ref_name)) < 0) return error; - if ((*out = git_reference__alloc(backend->refdb, ref_name, + if ((*out = git_reference__alloc(ref_name, &entry->oid, &entry->peel)) == NULL) return -1; @@ -999,8 +998,7 @@ static void refdb_fs_backend__free(git_refdb_backend *_backend) int git_refdb_backend_fs( git_refdb_backend **backend_out, - git_repository *repository, - git_refdb *refdb) + git_repository *repository) { refdb_fs_backend *backend; @@ -1009,7 +1007,6 @@ int git_refdb_backend_fs( backend->repo = repository; backend->path = repository->path_repository; - backend->refdb = refdb; backend->parent.exists = &refdb_fs_backend__exists; backend->parent.lookup = &refdb_fs_backend__lookup; diff --git a/src/refs.c b/src/refs.c index 29d1c4fa9..5b5812aae 100644 --- a/src/refs.c +++ b/src/refs.c @@ -31,7 +31,7 @@ enum { GIT_PACKREF_WAS_LOOSE = 2 }; -static git_reference *alloc_ref(git_refdb *refdb, const char *name) +static git_reference *alloc_ref(const char *name) { git_reference *ref; size_t namelen = strlen(name); @@ -39,22 +39,20 @@ static git_reference *alloc_ref(git_refdb *refdb, const char *name) if ((ref = git__calloc(1, sizeof(git_reference) + namelen + 1)) == NULL) return NULL; - ref->db = refdb; memcpy(ref->name, name, namelen + 1); return ref; } git_reference *git_reference__alloc_symbolic( - git_refdb *refdb, const char *name, const char *target) { git_reference *ref; - assert(refdb && name && target); + assert(name && target); - ref = alloc_ref(refdb, name); + ref = alloc_ref(name); if (!ref) return NULL; @@ -69,16 +67,15 @@ git_reference *git_reference__alloc_symbolic( } git_reference *git_reference__alloc( - git_refdb *refdb, const char *name, const git_oid *oid, const git_oid *peel) { git_reference *ref; - assert(refdb && name && oid); + assert(name && oid); - ref = alloc_ref(refdb, name); + ref = alloc_ref(name); if (!ref) return NULL; @@ -368,12 +365,13 @@ static int reference__create( if (oid != NULL) { assert(symbolic == NULL); - ref = git_reference__alloc(refdb, name, oid, NULL); + ref = git_reference__alloc(name, oid, NULL); } else { - ref = git_reference__alloc_symbolic(refdb, name, symbolic); + ref = git_reference__alloc_symbolic(name, symbolic); } GITERR_CHECK_ALLOC(ref); + ref->db = refdb; if ((error = git_refdb_write(refdb, ref)) < 0) { git_reference_free(ref); @@ -490,10 +488,9 @@ int git_reference_rename( * Create the new reference. */ if (ref->type == GIT_REF_OID) { - result = git_reference__alloc(ref->db, new_name, - &ref->target.oid, &ref->peel); + result = git_reference__alloc(new_name, &ref->target.oid, &ref->peel); } else if (ref->type == GIT_REF_SYMBOLIC) { - result = git_reference__alloc_symbolic(ref->db, new_name, ref->target.symbolic); + result = git_reference__alloc_symbolic(new_name, ref->target.symbolic); } else { assert(0); } @@ -501,6 +498,8 @@ int git_reference_rename( if (result == NULL) return -1; + result->db = ref->db; + /* Check if we have to update HEAD. */ if ((error = git_branch_is_head(ref)) < 0) goto on_error; diff --git a/tests-clar/refdb/inmemory.c b/tests-clar/refdb/inmemory.c index ca721e977..ea76172cf 100644 --- a/tests-clar/refdb/inmemory.c +++ b/tests-clar/refdb/inmemory.c @@ -6,7 +6,6 @@ #define TEST_REPO_PATH "testrepo" static git_repository *repo; -static git_refdb *refdb; static git_refdb_backend *refdb_backend; int unlink_ref(void *payload, git_buf *file) @@ -52,6 +51,8 @@ int ref_file_foreach(git_repository *repo, int (* cb)(void *payload, git_buf *fi void test_refdb_inmemory__initialize(void) { + git_refdb *refdb; + git_buf repo_refs_dir = GIT_BUF_INIT; repo = cl_git_sandbox_init(TEST_REPO_PATH); @@ -60,10 +61,10 @@ void test_refdb_inmemory__initialize(void) 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) diff --git a/tests-clar/refdb/testdb.c b/tests-clar/refdb/testdb.c index e60f6790e..4bca39878 100644 --- a/tests-clar/refdb/testdb.c +++ b/tests-clar/refdb/testdb.c @@ -10,7 +10,6 @@ typedef struct refdb_test_backend { git_refdb_backend parent; git_repository *repo; - git_refdb *refdb; git_vector refs; } refdb_test_backend; @@ -100,10 +99,10 @@ static int refdb_test_backend__lookup( if (strcmp(entry->name, ref_name) == 0) { if (entry->type == GIT_REF_OID) { - *out = git_reference__alloc(backend->refdb, ref_name, + *out = git_reference__alloc(ref_name, &entry->target.oid, NULL); } else if (entry->type == GIT_REF_SYMBOLIC) { - *out = git_reference__alloc_symbolic(backend->refdb, ref_name, + *out = git_reference__alloc_symbolic(ref_name, entry->target.symbolic); } @@ -195,11 +194,6 @@ int refdb_backend_test( git_repository *repo) { refdb_test_backend *backend; - git_refdb *refdb; - int error = 0; - - if ((error = git_repository_refdb(&refdb, repo)) < 0) - return error; backend = git__calloc(1, sizeof(refdb_test_backend)); GITERR_CHECK_ALLOC(backend); @@ -207,7 +201,6 @@ int refdb_backend_test( git_vector_init(&backend->refs, 0, ref_name_cmp); backend->repo = repo; - backend->refdb = refdb; backend->parent.exists = &refdb_test_backend__exists; backend->parent.lookup = &refdb_test_backend__lookup; diff --git a/tests-clar/refs/delete.c b/tests-clar/refs/delete.c index ac517d869..053f41229 100644 --- a/tests-clar/refs/delete.c +++ b/tests-clar/refs/delete.c @@ -88,4 +88,5 @@ void test_refs_delete__packed_only(void) /* This should pass */ cl_git_pass(git_reference_delete(ref)); git_reference_free(ref); + git_refdb_free(refdb); } diff --git a/tests-clar/refs/pack.c b/tests-clar/refs/pack.c index 973abae30..412c4c5fd 100644 --- a/tests-clar/refs/pack.c +++ b/tests-clar/refs/pack.c @@ -25,6 +25,7 @@ static void packall(void) cl_git_pass(git_repository_refdb(&refdb, g_repo)); cl_git_pass(git_refdb_compress(refdb)); + git_refdb_free(refdb); } void test_refs_pack__empty(void) diff --git a/tests-clar/refs/rename.c b/tests-clar/refs/rename.c index e39abeb05..5ab84c48e 100644 --- a/tests-clar/refs/rename.c +++ b/tests-clar/refs/rename.c @@ -284,6 +284,7 @@ void test_refs_rename__overwrite(void) git_reference_free(ref_one); git_reference_free(ref_one_new); git_reference_free(ref_two); + git_refdb_free(refdb); } -- cgit v1.2.1 From 8f24e65ff6f7573bc6778f5bbea7119fc9b7b626 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sat, 20 Apr 2013 16:20:21 +0200 Subject: Plug a couple of leaks --- tests-clar/stash/drop.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests-clar/stash/drop.c b/tests-clar/stash/drop.c index 12f922630..60b3c72e0 100644 --- a/tests-clar/stash/drop.c +++ b/tests-clar/stash/drop.c @@ -146,6 +146,8 @@ void retrieve_top_stash_id(git_oid *out) cl_git_pass(git_reference_name_to_id(out, repo, GIT_REFS_STASH_FILE)); cl_assert_equal_i(true, git_oid_cmp(out, git_object_id(top_stash)) == 0); + + git_object_free(top_stash); } void test_stash_drop__dropping_the_top_stash_updates_the_stash_reference(void) @@ -165,4 +167,6 @@ void test_stash_drop__dropping_the_top_stash_updates_the_stash_reference(void) retrieve_top_stash_id(&oid); cl_git_pass(git_oid_cmp(&oid, git_object_id(next_top_stash))); + + git_object_free(next_top_stash); } -- cgit v1.2.1 From 6b24688758b721afece65702475f76d225d096be Mon Sep 17 00:00:00 2001 From: nulltoken Date: Sun, 21 Apr 2013 08:59:04 +0200 Subject: mailmap: Coalesce some identities --- .mailmap | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.mailmap b/.mailmap index a8b171908..3f5a087ea 100644 --- a/.mailmap +++ b/.mailmap @@ -5,3 +5,14 @@ Ben Straub Ben Straub Ben Straub Ben Straub Carlos Martín Nieto Carlos Martín Nieto +nulltoken +Scott J. Goldman +Martin Woodward +Peter Drahoš +Adam Roben +Adam Roben +Xavier L. +Xavier L. +Sascha Cunz +Authmillenon +Authmillenon -- cgit v1.2.1 From 83041c711cd7d9fccb7a1327e642ce33f0705370 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Fri, 19 Apr 2013 11:52:04 -0700 Subject: Move git_config_backend to include/git2/sys Moving backend implementor objects into include/git2/sys so the APIs can be isolated from the ones that normal libgit2 users would be likely to use. --- include/git2/config.h | 52 ++------------------------------- include/git2/sys/config.h | 70 +++++++++++++++++++++++++++++++++++++++++++++ src/config.c | 1 + src/config_file.c | 1 + src/submodule.c | 1 + tests-clar/config/backend.c | 1 + 6 files changed, 76 insertions(+), 50 deletions(-) create mode 100644 include/git2/sys/config.h diff --git a/include/git2/config.h b/include/git2/config.h index 19d4cb78d..5a2f956fd 100644 --- a/include/git2/config.h +++ b/include/git2/config.h @@ -43,29 +43,6 @@ typedef struct { typedef int (*git_config_foreach_cb)(const git_config_entry *, void *); - -/** - * Generic backend that implements the interface to - * access a configuration file - */ -struct git_config_backend { - unsigned int version; - struct git_config *cfg; - - /* Open means open the file/database and parse if necessary */ - int (*open)(struct git_config_backend *, unsigned int level); - int (*get)(const struct git_config_backend *, const char *key, const git_config_entry **entry); - int (*get_multivar)(struct git_config_backend *, const char *key, const char *regexp, git_config_foreach_cb callback, void *payload); - int (*set)(struct git_config_backend *, const char *key, const char *value); - int (*set_multivar)(git_config_backend *cfg, const char *name, const char *regexp, const char *value); - int (*del)(struct git_config_backend *, const char *key); - int (*foreach)(struct git_config_backend *, const char *, git_config_foreach_cb callback, void *payload); - int (*refresh)(struct git_config_backend *); - void (*free)(struct git_config_backend *); -}; -#define GIT_CONFIG_BACKEND_VERSION 1 -#define GIT_CONFIG_BACKEND_INIT {GIT_CONFIG_BACKEND_VERSION} - typedef enum { GIT_CVAR_FALSE = 0, GIT_CVAR_TRUE = 1, @@ -153,30 +130,6 @@ GIT_EXTERN(int) git_config_open_default(git_config **out); */ GIT_EXTERN(int) git_config_new(git_config **out); -/** - * Add a generic config file instance to an existing config - * - * Note that the configuration object will free the file - * automatically. - * - * Further queries on this config object will access each - * of the config file instances in order (instances with - * a higher priority level will be accessed first). - * - * @param cfg the configuration to add the file to - * @param file the configuration file (backend) to add - * @param level the priority level of the backend - * @param force if a config file already exists for the given - * priority level, replace it - * @return 0 on success, GIT_EEXISTS when adding more than one file - * for a given priority level (and force_replace set to 0), or error code - */ -GIT_EXTERN(int) git_config_add_backend( - git_config *cfg, - git_config_backend *file, - unsigned int level, - int force); - /** * Add an on-disk config file instance to an existing config * @@ -192,10 +145,9 @@ GIT_EXTERN(int) git_config_add_backend( * a higher priority level will be accessed first). * * @param cfg the configuration to add the file to - * @param path path to the configuration file (backend) to add + * @param path path to the configuration file to add * @param level the priority level of the backend - * @param force if a config file already exists for the given - * priority level, replace it + * @param force replace config file at the given priority level * @return 0 on success, GIT_EEXISTS when adding more than one file * for a given priority level (and force_replace set to 0), * GIT_ENOTFOUND when the file doesn't exist or error code diff --git a/include/git2/sys/config.h b/include/git2/sys/config.h new file mode 100644 index 000000000..c9039e96e --- /dev/null +++ b/include/git2/sys/config.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_git_sys_config_h__ +#define INCLUDE_git_sys_config_h__ + +#include "git2/common.h" +#include "git2/types.h" +#include "git2/config.h" + +/** + * @file git2/sys/config.h + * @brief Git config backend routines + * @ingroup Git + * @{ + */ +GIT_BEGIN_DECL + +/** + * Generic backend that implements the interface to + * access a configuration file + */ +struct git_config_backend { + unsigned int version; + struct git_config *cfg; + + /* Open means open the file/database and parse if necessary */ + int (*open)(struct git_config_backend *, unsigned int level); + int (*get)(const struct git_config_backend *, const char *key, const git_config_entry **entry); + int (*get_multivar)(struct git_config_backend *, const char *key, const char *regexp, git_config_foreach_cb callback, void *payload); + int (*set)(struct git_config_backend *, const char *key, const char *value); + int (*set_multivar)(git_config_backend *cfg, const char *name, const char *regexp, const char *value); + int (*del)(struct git_config_backend *, const char *key); + int (*foreach)(struct git_config_backend *, const char *, git_config_foreach_cb callback, void *payload); + int (*refresh)(struct git_config_backend *); + void (*free)(struct git_config_backend *); +}; +#define GIT_CONFIG_BACKEND_VERSION 1 +#define GIT_CONFIG_BACKEND_INIT {GIT_CONFIG_BACKEND_VERSION} + +/** + * Add a generic config file instance to an existing config + * + * Note that the configuration object will free the file + * automatically. + * + * Further queries on this config object will access each + * of the config file instances in order (instances with + * a higher priority level will be accessed first). + * + * @param cfg the configuration to add the file to + * @param file the configuration file (backend) to add + * @param level the priority level of the backend + * @param force if a config file already exists for the given + * priority level, replace it + * @return 0 on success, GIT_EEXISTS when adding more than one file + * for a given priority level (and force_replace set to 0), or error code + */ +GIT_EXTERN(int) git_config_add_backend( + git_config *cfg, + git_config_backend *file, + unsigned int level, + int force); + +/** @} */ +GIT_END_DECL +#endif diff --git a/src/config.c b/src/config.c index 5379b0ec5..1283522ca 100644 --- a/src/config.c +++ b/src/config.c @@ -9,6 +9,7 @@ #include "fileops.h" #include "config.h" #include "git2/config.h" +#include "git2/sys/config.h" #include "vector.h" #include "buf_text.h" #include "config_file.h" diff --git a/src/config_file.c b/src/config_file.c index 8b51ab21b..a4ff8bb94 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -12,6 +12,7 @@ #include "buffer.h" #include "buf_text.h" #include "git2/config.h" +#include "git2/sys/config.h" #include "git2/types.h" #include "strmap.h" diff --git a/src/submodule.c b/src/submodule.c index 2fdaf2f77..0a22e3b13 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -7,6 +7,7 @@ #include "common.h" #include "git2/config.h" +#include "git2/sys/config.h" #include "git2/types.h" #include "git2/repository.h" #include "git2/index.h" diff --git a/tests-clar/config/backend.c b/tests-clar/config/backend.c index 28502a8ba..3fd6eb114 100644 --- a/tests-clar/config/backend.c +++ b/tests-clar/config/backend.c @@ -1,4 +1,5 @@ #include "clar_libgit2.h" +#include "git2/sys/config.h" void test_config_backend__checks_version(void) { -- cgit v1.2.1 From 83cc70d9fec5f81d07f9fc4133c9515527efb9af Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Fri, 19 Apr 2013 12:48:33 -0700 Subject: Move odb_backend implementors stuff into git2/sys This moves some of the odb_backend stuff that is related to the internals of an odb_backend implementation into include/git2/sys. Some of the stuff related to streaming I left in include/git2 because it seemed like it would be reasonably needed by a normal user who wanted to stream objects into and out of the ODB. Also, I added APIs for traversing the list of backends so that some of the tests would not need to access ODB internals. --- include/git2/indexer.h | 22 +------ include/git2/odb.h | 97 ++++++++++++++++++------------- include/git2/odb_backend.h | 123 ++++++---------------------------------- include/git2/sys/config.h | 5 +- include/git2/sys/odb_backend.h | 86 ++++++++++++++++++++++++++++ include/git2/types.h | 20 +++++++ src/blob.c | 1 + src/odb.c | 22 +++++++ src/odb_loose.c | 2 +- src/odb_pack.c | 3 +- src/tag.c | 1 + src/transports/smart_protocol.c | 1 + tests-clar/object/raw/write.c | 3 +- tests-clar/odb/packed_one.c | 3 +- tests-clar/odb/sorting.c | 18 +++--- 15 files changed, 225 insertions(+), 182 deletions(-) create mode 100644 include/git2/sys/odb_backend.h diff --git a/include/git2/indexer.h b/include/git2/indexer.h index dfe6ae5aa..262dcd154 100644 --- a/include/git2/indexer.h +++ b/include/git2/indexer.h @@ -8,31 +8,11 @@ #define _INCLUDE_git_indexer_h__ #include "common.h" +#include "types.h" #include "oid.h" GIT_BEGIN_DECL -/** - * This is passed as the first argument to the callback to allow the - * user to see the progress. - */ -typedef struct git_transfer_progress { - unsigned int total_objects; - unsigned int indexed_objects; - unsigned int received_objects; - size_t received_bytes; -} git_transfer_progress; - - -/** - * Type for progress callbacks during indexing. Return a value less than zero - * to cancel the transfer. - * - * @param stats Structure containing information about the state of the transfer - * @param payload Payload provided by caller - */ -typedef int (*git_transfer_progress_callback)(const git_transfer_progress *stats, void *payload); - typedef struct git_indexer_stream git_indexer_stream; /** diff --git a/include/git2/odb.h b/include/git2/odb.h index 8fd1a95be..b64436c4d 100644 --- a/include/git2/odb.h +++ b/include/git2/odb.h @@ -10,8 +10,6 @@ #include "common.h" #include "types.h" #include "oid.h" -#include "odb_backend.h" -#include "indexer.h" /** * @file git2/odb.h @@ -22,6 +20,11 @@ */ GIT_BEGIN_DECL +/** + * Function type for callbacks from git_odb_foreach. + */ +typedef int (*git_odb_foreach_cb)(const git_oid *id, void *payload); + /** * Create a new object database with no backends. * @@ -52,42 +55,6 @@ GIT_EXTERN(int) git_odb_new(git_odb **out); */ GIT_EXTERN(int) git_odb_open(git_odb **out, const char *objects_dir); -/** - * Add a custom backend to an existing Object DB - * - * The backends are checked in relative ordering, based on the - * value of the `priority` parameter. - * - * Read for more information. - * - * @param odb database to add the backend to - * @param backend pointer to a git_odb_backend instance - * @param priority Value for ordering the backends queue - * @return 0 on success; error code otherwise - */ -GIT_EXTERN(int) git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int priority); - -/** - * Add a custom backend to an existing Object DB; this - * backend will work as an alternate. - * - * Alternate backends are always checked for objects *after* - * all the main backends have been exhausted. - * - * The backends are checked in relative ordering, based on the - * value of the `priority` parameter. - * - * Writing is disabled on alternate backends. - * - * Read for more information. - * - * @param odb database to add the backend to - * @param backend pointer to a git_odb_backend instance - * @param priority Value for ordering the backends queue - * @return 0 on success; error code otherwise - */ -GIT_EXTERN(int) git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, int priority); - /** * Add an on-disk alternate to an existing Object DB. * @@ -406,6 +373,60 @@ GIT_EXTERN(size_t) git_odb_object_size(git_odb_object *object); */ GIT_EXTERN(git_otype) git_odb_object_type(git_odb_object *object); +/** + * Add a custom backend to an existing Object DB + * + * The backends are checked in relative ordering, based on the + * value of the `priority` parameter. + * + * Read for more information. + * + * @param odb database to add the backend to + * @param backend pointer to a git_odb_backend instance + * @param priority Value for ordering the backends queue + * @return 0 on success; error code otherwise + */ +GIT_EXTERN(int) git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int priority); + +/** + * Add a custom backend to an existing Object DB; this + * backend will work as an alternate. + * + * Alternate backends are always checked for objects *after* + * all the main backends have been exhausted. + * + * The backends are checked in relative ordering, based on the + * value of the `priority` parameter. + * + * Writing is disabled on alternate backends. + * + * Read for more information. + * + * @param odb database to add the backend to + * @param backend pointer to a git_odb_backend instance + * @param priority Value for ordering the backends queue + * @return 0 on success; error code otherwise + */ +GIT_EXTERN(int) git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, int priority); + +/** + * Get the number of ODB backend objects + * + * @param odb object database + * @return number of backends in the ODB + */ +GIT_EXTERN(size_t) git_odb_num_backends(git_odb *odb); + +/** + * Lookup an ODB backend object by index + * + * @param out output pointer to ODB backend at pos + * @param odb object database + * @param pos index into object database backend list + * @return 0 on success; GIT_ENOTFOUND if pos is invalid; other errors < 0 + */ +GIT_EXTERN(int) git_odb_get_backend(git_odb_backend **out, git_odb *odb, size_t pos); + /** @} */ GIT_END_DECL #endif diff --git a/include/git2/odb_backend.h b/include/git2/odb_backend.h index dbc3981f6..d38005d15 100644 --- a/include/git2/odb_backend.h +++ b/include/git2/odb_backend.h @@ -7,106 +7,24 @@ #ifndef INCLUDE_git_odb_backend_h__ #define INCLUDE_git_odb_backend_h__ -#include "common.h" -#include "types.h" -#include "oid.h" -#include "indexer.h" +#include "git2/common.h" +#include "git2/types.h" /** * @file git2/backend.h * @brief Git custom backend functions - * @defgroup git_backend Git custom backend API + * @defgroup git_odb Git object database routines * @ingroup Git * @{ */ GIT_BEGIN_DECL -struct git_odb_stream; -struct git_odb_writepack; - -/** - * Function type for callbacks from git_odb_foreach. - */ -typedef int (*git_odb_foreach_cb)(const git_oid *id, void *payload); - /** - * An instance for a custom backend + * Constructors for in-box ODB backends. */ -struct git_odb_backend { - unsigned int version; - git_odb *odb; - - /* read and read_prefix each return to libgit2 a buffer which - * will be freed later. The buffer should be allocated using - * the function git_odb_backend_malloc to ensure that it can - * be safely freed later. */ - int (* read)( - void **, size_t *, git_otype *, - struct git_odb_backend *, - const git_oid *); - - /* To find a unique object given a prefix - * of its oid. - * The oid given must be so that the - * remaining (GIT_OID_HEXSZ - len)*4 bits - * are 0s. - */ - int (* read_prefix)( - git_oid *, - void **, size_t *, git_otype *, - struct git_odb_backend *, - const git_oid *, - size_t); - - int (* read_header)( - size_t *, git_otype *, - struct git_odb_backend *, - const git_oid *); - - /* The writer may assume that the object - * has already been hashed and is passed - * in the first parameter. - */ - int (* write)( - git_oid *, - struct git_odb_backend *, - const void *, - size_t, - git_otype); - - int (* writestream)( - struct git_odb_stream **, - struct git_odb_backend *, - size_t, - git_otype); - - int (* readstream)( - struct git_odb_stream **, - struct git_odb_backend *, - const git_oid *); - - int (* exists)( - struct git_odb_backend *, - const git_oid *); - - int (* refresh)(struct git_odb_backend *); - - int (* foreach)( - struct git_odb_backend *, - git_odb_foreach_cb cb, - void *payload); - - int (* writepack)( - struct git_odb_writepack **, - struct git_odb_backend *, - git_transfer_progress_callback progress_cb, - void *progress_payload); - - void (* free)(struct git_odb_backend *); -}; - -#define GIT_ODB_BACKEND_VERSION 1 -#define GIT_ODB_BACKEND_INIT {GIT_ODB_BACKEND_VERSION} +GIT_EXTERN(int) git_odb_backend_pack(git_odb_backend **out, const char *objects_dir); +GIT_EXTERN(int) git_odb_backend_loose(git_odb_backend **out, const char *objects_dir, int compression_level, int do_fsync); +GIT_EXTERN(int) git_odb_backend_one_pack(git_odb_backend **out, const char *index_file); /** Streaming mode */ enum { @@ -117,33 +35,24 @@ enum { /** A stream to read/write from a backend */ struct git_odb_stream { - struct git_odb_backend *backend; + git_odb_backend *backend; unsigned int mode; - int (*read)(struct git_odb_stream *stream, char *buffer, size_t len); - int (*write)(struct git_odb_stream *stream, const char *buffer, size_t len); - int (*finalize_write)(git_oid *oid_p, struct git_odb_stream *stream); - void (*free)(struct git_odb_stream *stream); + int (*read)(git_odb_stream *stream, char *buffer, size_t len); + int (*write)(git_odb_stream *stream, const char *buffer, size_t len); + int (*finalize_write)(git_oid *oid_p, git_odb_stream *stream); + void (*free)(git_odb_stream *stream); }; /** A stream to write a pack file to the ODB */ struct git_odb_writepack { - struct git_odb_backend *backend; + git_odb_backend *backend; - int (*add)(struct git_odb_writepack *writepack, const void *data, size_t size, git_transfer_progress *stats); - int (*commit)(struct git_odb_writepack *writepack, git_transfer_progress *stats); - void (*free)(struct git_odb_writepack *writepack); + int (*add)(git_odb_writepack *writepack, const void *data, size_t size, git_transfer_progress *stats); + int (*commit)(git_odb_writepack *writepack, git_transfer_progress *stats); + void (*free)(git_odb_writepack *writepack); }; -GIT_EXTERN(void *) git_odb_backend_malloc(git_odb_backend *backend, size_t len); - -/** - * Constructors for in-box ODB backends. - */ -GIT_EXTERN(int) git_odb_backend_pack(git_odb_backend **out, const char *objects_dir); -GIT_EXTERN(int) git_odb_backend_loose(git_odb_backend **out, const char *objects_dir, int compression_level, int do_fsync); -GIT_EXTERN(int) git_odb_backend_one_pack(git_odb_backend **out, const char *index_file); - GIT_END_DECL #endif diff --git a/include/git2/sys/config.h b/include/git2/sys/config.h index c9039e96e..1c9deba7c 100644 --- a/include/git2/sys/config.h +++ b/include/git2/sys/config.h @@ -4,8 +4,8 @@ * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ -#ifndef INCLUDE_git_sys_config_h__ -#define INCLUDE_git_sys_config_h__ +#ifndef INCLUDE_sys_git_config_backend_h__ +#define INCLUDE_sys_git_config_backend_h__ #include "git2/common.h" #include "git2/types.h" @@ -14,6 +14,7 @@ /** * @file git2/sys/config.h * @brief Git config backend routines + * @defgroup git_backend Git custom backend APIs * @ingroup Git * @{ */ diff --git a/include/git2/sys/odb_backend.h b/include/git2/sys/odb_backend.h new file mode 100644 index 000000000..3cd2734c0 --- /dev/null +++ b/include/git2/sys/odb_backend.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_sys_git_odb_backend_h__ +#define INCLUDE_sys_git_odb_backend_h__ + +#include "git2/common.h" +#include "git2/types.h" +#include "git2/oid.h" +#include "git2/odb.h" + +/** + * @file git2/sys/backend.h + * @brief Git custom backend implementors functions + * @defgroup git_backend Git custom backend APIs + * @ingroup Git + * @{ + */ +GIT_BEGIN_DECL + +/** + * An instance for a custom backend + */ +struct git_odb_backend { + unsigned int version; + git_odb *odb; + + /* read and read_prefix each return to libgit2 a buffer which + * will be freed later. The buffer should be allocated using + * the function git_odb_backend_malloc to ensure that it can + * be safely freed later. */ + int (* read)( + void **, size_t *, git_otype *, git_odb_backend *, const git_oid *); + + /* To find a unique object given a prefix + * of its oid. + * The oid given must be so that the + * remaining (GIT_OID_HEXSZ - len)*4 bits + * are 0s. + */ + int (* read_prefix)( + git_oid *, void **, size_t *, git_otype *, + git_odb_backend *, const git_oid *, size_t); + + int (* read_header)( + size_t *, git_otype *, git_odb_backend *, const git_oid *); + + /* The writer may assume that the object + * has already been hashed and is passed + * in the first parameter. + */ + int (* write)( + git_oid *, git_odb_backend *, const void *, size_t, git_otype); + + int (* writestream)( + git_odb_stream **, git_odb_backend *, size_t, git_otype); + + int (* readstream)( + git_odb_stream **, git_odb_backend *, const git_oid *); + + int (* exists)( + git_odb_backend *, const git_oid *); + + int (* refresh)(git_odb_backend *); + + int (* foreach)( + git_odb_backend *, git_odb_foreach_cb cb, void *payload); + + int (* writepack)( + git_odb_writepack **, git_odb_backend *, + git_transfer_progress_callback progress_cb, void *progress_payload); + + void (* free)(git_odb_backend *); +}; + +#define GIT_ODB_BACKEND_VERSION 1 +#define GIT_ODB_BACKEND_INIT {GIT_ODB_BACKEND_VERSION} + +GIT_EXTERN(void *) git_odb_backend_malloc(git_odb_backend *backend, size_t len); + +GIT_END_DECL + +#endif diff --git a/include/git2/types.h b/include/git2/types.h index bc15050ce..aca9ed927 100644 --- a/include/git2/types.h +++ b/include/git2/types.h @@ -196,6 +196,26 @@ typedef struct git_push git_push; typedef struct git_remote_head git_remote_head; typedef struct git_remote_callbacks git_remote_callbacks; +/** + * This is passed as the first argument to the callback to allow the + * user to see the progress. + */ +typedef struct git_transfer_progress { + unsigned int total_objects; + unsigned int indexed_objects; + unsigned int received_objects; + size_t received_bytes; +} git_transfer_progress; + +/** + * Type for progress callbacks during indexing. Return a value less than zero + * to cancel the transfer. + * + * @param stats Structure containing information about the state of the transfer + * @param payload Payload provided by caller + */ +typedef int (*git_transfer_progress_callback)(const git_transfer_progress *stats, void *payload); + /** @} */ GIT_END_DECL diff --git a/src/blob.c b/src/blob.c index c0514fc13..11e1f4d77 100644 --- a/src/blob.c +++ b/src/blob.c @@ -8,6 +8,7 @@ #include "git2/common.h" #include "git2/object.h" #include "git2/repository.h" +#include "git2/odb_backend.h" #include "common.h" #include "blob.h" diff --git a/src/odb.c b/src/odb.c index c98df247c..ecdaf7ac2 100644 --- a/src/odb.c +++ b/src/odb.c @@ -8,6 +8,7 @@ #include "common.h" #include #include "git2/object.h" +#include "git2/sys/odb_backend.h" #include "fileops.h" #include "hash.h" #include "odb.h" @@ -403,6 +404,27 @@ int git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, int priority) return add_backend_internal(odb, backend, priority, 1); } +size_t git_odb_num_backends(git_odb *odb) +{ + assert(odb); + return odb->backends.length; +} + +int git_odb_get_backend(git_odb_backend **out, git_odb *odb, size_t pos) +{ + backend_internal *internal; + + assert(odb && odb); + internal = git_vector_get(&odb->backends, pos); + + if (internal && internal->backend) { + *out = internal->backend; + return 0; + } + + return GIT_ENOTFOUND; +} + static int add_default_backends(git_odb *db, const char *objects_dir, int as_alternates, int alternate_depth) { git_odb_backend *loose, *packed; diff --git a/src/odb_loose.c b/src/odb_loose.c index 68083f7fd..e78172cf6 100644 --- a/src/odb_loose.c +++ b/src/odb_loose.c @@ -8,7 +8,7 @@ #include "common.h" #include #include "git2/object.h" -#include "git2/oid.h" +#include "git2/sys/odb_backend.h" #include "fileops.h" #include "hash.h" #include "odb.h" diff --git a/src/odb_pack.c b/src/odb_pack.c index 7240a4ac7..773e14974 100644 --- a/src/odb_pack.c +++ b/src/odb_pack.c @@ -8,7 +8,8 @@ #include "common.h" #include #include "git2/repository.h" -#include "git2/oid.h" +#include "git2/indexer.h" +#include "git2/sys/odb_backend.h" #include "fileops.h" #include "hash.h" #include "odb.h" diff --git a/src/tag.c b/src/tag.c index 735ba7e1d..c82decbe3 100644 --- a/src/tag.c +++ b/src/tag.c @@ -13,6 +13,7 @@ #include "git2/object.h" #include "git2/repository.h" #include "git2/signature.h" +#include "git2/odb_backend.h" void git_tag__free(git_tag *tag) { diff --git a/src/transports/smart_protocol.c b/src/transports/smart_protocol.c index 8acedeb49..90851980c 100644 --- a/src/transports/smart_protocol.c +++ b/src/transports/smart_protocol.c @@ -5,6 +5,7 @@ * a Linking Exception. For full terms see the included COPYING file. */ #include "git2.h" +#include "git2/odb_backend.h" #include "smart.h" #include "refs.h" diff --git a/tests-clar/object/raw/write.c b/tests-clar/object/raw/write.c index 1b28d0df7..60aa31f6a 100644 --- a/tests-clar/object/raw/write.c +++ b/tests-clar/object/raw/write.c @@ -1,5 +1,6 @@ - #include "clar_libgit2.h" +#include "git2/odb_backend.h" + #include "fileops.h" #include "odb.h" diff --git a/tests-clar/odb/packed_one.c b/tests-clar/odb/packed_one.c index e9d246c23..4f9bde9ed 100644 --- a/tests-clar/odb/packed_one.c +++ b/tests-clar/odb/packed_one.c @@ -1,5 +1,6 @@ #include "clar_libgit2.h" -#include "odb.h" +#include "git2/odb_backend.h" + #include "pack_data_one.h" #include "pack.h" diff --git a/tests-clar/odb/sorting.c b/tests-clar/odb/sorting.c index b4f9e44bc..147a160c8 100644 --- a/tests-clar/odb/sorting.c +++ b/tests-clar/odb/sorting.c @@ -1,13 +1,12 @@ #include "clar_libgit2.h" -#include "git2/odb_backend.h" -#include "odb.h" +#include "git2/sys/odb_backend.h" typedef struct { git_odb_backend base; - int position; + size_t position; } fake_backend; -static git_odb_backend *new_backend(int position) +static git_odb_backend *new_backend(size_t position) { fake_backend *b; @@ -22,14 +21,13 @@ static git_odb_backend *new_backend(int position) static void check_backend_sorting(git_odb *odb) { - unsigned int i; - - for (i = 0; i < odb->backends.length; ++i) { - fake_backend *internal = - *((fake_backend **)git_vector_get(&odb->backends, i)); + size_t i, max_i = git_odb_num_backends(odb); + fake_backend *internal; + for (i = 0; i < max_i; ++i) { + cl_git_pass(git_odb_get_backend((git_odb_backend **)&internal, odb, i)); cl_assert(internal != NULL); - cl_assert(internal->position == (int)i); + cl_assert_equal_sz(i, internal->position); } } -- cgit v1.2.1 From 7cc3c9202722c53bf46e5a8f8d0d7180423a7632 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Tue, 29 Jan 2013 07:48:36 -0600 Subject: Added git_repository_new function --- include/git2/repository.h | 8 ++++++++ src/repository.c | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/include/git2/repository.h b/include/git2/repository.h index ed837b359..f55ab798f 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -136,6 +136,14 @@ GIT_EXTERN(int) git_repository_open_ext( */ GIT_EXTERN(int) git_repository_open_bare(git_repository **out, const char *bare_path); +/** + * Create a new repository with neither backends nor config object + * + * Note that this is only useful if you wish to associate the repository + * with a non-filesystem-backed object database and config store. + */ +GIT_EXTERN(int) git_repository_new(git_repository **out); + /** * Free a previously allocated repository * diff --git a/src/repository.c b/src/repository.c index 64ab2f4db..72b5a079a 100644 --- a/src/repository.c +++ b/src/repository.c @@ -129,6 +129,12 @@ static git_repository *repository_alloc(void) return repo; } +int git_repository_new(git_repository **out) +{ + *out = repository_alloc(); + return 0; +} + static int load_config_data(git_repository *repo) { int is_bare; -- cgit v1.2.1 From 1384b688d0bb5cd784c453fffef69d27e3db44ca Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Fri, 19 Apr 2013 13:00:12 -0700 Subject: Move some low-level repo fns to include/git2/sys --- include/git2/repository.h | 70 ----------------------------- include/git2/sys/repository.h | 92 +++++++++++++++++++++++++++++++++++++++ src/repository.c | 1 + tests-clar/diff/patch.c | 2 + tests-clar/repo/setters.c | 2 + tests-clar/status/worktree_init.c | 6 ++- 6 files changed, 101 insertions(+), 72 deletions(-) create mode 100644 include/git2/sys/repository.h diff --git a/include/git2/repository.h b/include/git2/repository.h index f55ab798f..08024cd89 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -136,14 +136,6 @@ GIT_EXTERN(int) git_repository_open_ext( */ GIT_EXTERN(int) git_repository_open_bare(git_repository **out, const char *bare_path); -/** - * Create a new repository with neither backends nor config object - * - * Note that this is only useful if you wish to associate the repository - * with a non-filesystem-backed object database and config store. - */ -GIT_EXTERN(int) git_repository_new(git_repository **out); - /** * Free a previously allocated repository * @@ -408,21 +400,6 @@ GIT_EXTERN(int) git_repository_is_bare(git_repository *repo); */ GIT_EXTERN(int) git_repository_config(git_config **out, git_repository *repo); -/** - * Set the configuration file for this repository - * - * This configuration file will be used for all configuration - * queries involving this repository. - * - * The repository will keep a reference to the config file; - * the user must still free the config after setting it - * to the repository, or it will leak. - * - * @param repo A repository object - * @param config A Config object - */ -GIT_EXTERN(void) git_repository_set_config(git_repository *repo, git_config *config); - /** * Get the Object Database for this repository. * @@ -439,21 +416,6 @@ GIT_EXTERN(void) git_repository_set_config(git_repository *repo, git_config *con */ GIT_EXTERN(int) git_repository_odb(git_odb **out, git_repository *repo); -/** - * Set the Object Database for this repository - * - * The ODB will be used for all object-related operations - * involving this repository. - * - * The repository will keep a reference to the ODB; the user - * must still free the ODB object after setting it to the - * repository, or it will leak. - * - * @param repo A repository object - * @param odb An ODB object - */ -GIT_EXTERN(void) git_repository_set_odb(git_repository *repo, git_odb *odb); - /** * Get the Reference Database Backend for this repository. * @@ -470,23 +432,6 @@ GIT_EXTERN(void) git_repository_set_odb(git_repository *repo, git_odb *odb); */ GIT_EXTERN(int) git_repository_refdb(git_refdb **out, git_repository *repo); -/** - * Set the Reference Database Backend for this repository - * - * The refdb will be used for all reference related operations - * involving this repository. - * - * The repository will keep a reference to the refdb; the user - * must still free the refdb object after setting it to the - * repository, or it will leak. - * - * @param repo A repository object - * @param refdb An refdb object - */ -GIT_EXTERN(void) git_repository_set_refdb( - git_repository *repo, - git_refdb *refdb); - /** * Get the Index file for this repository. * @@ -503,21 +448,6 @@ GIT_EXTERN(void) git_repository_set_refdb( */ GIT_EXTERN(int) git_repository_index(git_index **out, git_repository *repo); -/** - * Set the index file for this repository - * - * This index will be used for all index-related operations - * involving this repository. - * - * The repository will keep a reference to the index file; - * the user must still free the index after setting it - * to the repository, or it will leak. - * - * @param repo A repository object - * @param index An index object - */ -GIT_EXTERN(void) git_repository_set_index(git_repository *repo, git_index *index); - /** * Retrieve git's prepared message * diff --git a/include/git2/sys/repository.h b/include/git2/sys/repository.h new file mode 100644 index 000000000..34bc17516 --- /dev/null +++ b/include/git2/sys/repository.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_sys_git_repository_h__ +#define INCLUDE_sys_git_repository_h__ + +/** + * @file git2/sys/repository.h + * @brief Git repository custom implementation routines + * @defgroup git_backend Git custom backend APIs + * @ingroup Git + * @{ + */ +GIT_BEGIN_DECL + +/** + * Create a new repository with neither backends nor config object + * + * Note that this is only useful if you wish to associate the repository + * with a non-filesystem-backed object database and config store. + * + * @param out The blank repository + * @return 0 on success, or an error code + */ +GIT_EXTERN(int) git_repository_new(git_repository **out); + +/** + * Set the configuration file for this repository + * + * This configuration file will be used for all configuration + * queries involving this repository. + * + * The repository will keep a reference to the config file; + * the user must still free the config after setting it + * to the repository, or it will leak. + * + * @param repo A repository object + * @param config A Config object + */ +GIT_EXTERN(void) git_repository_set_config(git_repository *repo, git_config *config); + +/** + * Set the Object Database for this repository + * + * The ODB will be used for all object-related operations + * involving this repository. + * + * The repository will keep a reference to the ODB; the user + * must still free the ODB object after setting it to the + * repository, or it will leak. + * + * @param repo A repository object + * @param odb An ODB object + */ +GIT_EXTERN(void) git_repository_set_odb(git_repository *repo, git_odb *odb); + +/** + * Set the Reference Database Backend for this repository + * + * The refdb will be used for all reference related operations + * involving this repository. + * + * The repository will keep a reference to the refdb; the user + * must still free the refdb object after setting it to the + * repository, or it will leak. + * + * @param repo A repository object + * @param refdb An refdb object + */ +GIT_EXTERN(void) git_repository_set_refdb(git_repository *repo, git_refdb *refdb); + +/** + * Set the index file for this repository + * + * This index will be used for all index-related operations + * involving this repository. + * + * The repository will keep a reference to the index file; + * the user must still free the index after setting it + * to the repository, or it will leak. + * + * @param repo A repository object + * @param index An index object + */ +GIT_EXTERN(void) git_repository_set_index(git_repository *repo, git_index *index); + +/** @} */ +GIT_END_DECL +#endif diff --git a/src/repository.c b/src/repository.c index 72b5a079a..a16f69da4 100644 --- a/src/repository.c +++ b/src/repository.c @@ -9,6 +9,7 @@ #include "git2/object.h" #include "git2/refdb.h" +#include "git2/sys/repository.h" #include "common.h" #include "repository.h" diff --git a/tests-clar/diff/patch.c b/tests-clar/diff/patch.c index 4d17da468..d41f3f12d 100644 --- a/tests-clar/diff/patch.c +++ b/tests-clar/diff/patch.c @@ -1,4 +1,6 @@ #include "clar_libgit2.h" +#include "git2/sys/repository.h" + #include "diff_helpers.h" #include "repository.h" #include "buf_text.h" diff --git a/tests-clar/repo/setters.c b/tests-clar/repo/setters.c index 7e482dee1..063d76c8d 100644 --- a/tests-clar/repo/setters.c +++ b/tests-clar/repo/setters.c @@ -1,4 +1,6 @@ #include "clar_libgit2.h" +#include "git2/sys/repository.h" + #include "buffer.h" #include "posix.h" #include "util.h" diff --git a/tests-clar/status/worktree_init.c b/tests-clar/status/worktree_init.c index b67107aec..296c27c86 100644 --- a/tests-clar/status/worktree_init.c +++ b/tests-clar/status/worktree_init.c @@ -1,4 +1,6 @@ #include "clar_libgit2.h" +#include "git2/sys/repository.h" + #include "fileops.h" #include "ignore.h" #include "status_helpers.h" @@ -321,10 +323,10 @@ void test_status_worktree_init__new_staged_file_must_handle_crlf(void) cl_set_cleanup(&cleanup_new_repo, "getting_started"); cl_git_pass(git_repository_init(&repo, "getting_started", 0)); - // Ensure that repo has core.autocrlf=true + /* Ensure that repo has core.autocrlf=true */ cl_repo_set_bool(repo, "core.autocrlf", true); - cl_git_mkfile("getting_started/testfile.txt", "content\r\n"); // Content with CRLF + cl_git_mkfile("getting_started/testfile.txt", "content\r\n"); /* Content with CRLF */ cl_git_pass(git_repository_index(&index, repo)); cl_git_pass(git_index_add_bypath(index, "testfile.txt")); -- cgit v1.2.1 From 9255039898bf4c625f678f390c8075c11d10cad0 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Tue, 29 Jan 2013 09:53:23 -0600 Subject: Added git_commit_create_oid --- include/git2/commit.h | 20 ++++++++++++++++++++ src/commit.c | 50 ++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/include/git2/commit.h b/include/git2/commit.h index 764053eaa..e7ef51816 100644 --- a/include/git2/commit.h +++ b/include/git2/commit.h @@ -287,6 +287,26 @@ GIT_EXTERN(int) git_commit_create_v( int parent_count, ...); +/** + * Create a new commit in the repository, as with `git_commit_create`, + * using `git_oid` instances as parameters instead of `git_object`. + * + * See documentation for `git_commit_create` for information about the + * parameters, as the meaning is identical excepting that `tree` and + * `parents` now take `git_oid`. + */ +GIT_EXTERN(int) git_commit_create_oid( + git_oid *oid, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_oid *tree, + int parent_count, + const git_oid *parents[]); + /** @} */ GIT_END_DECL #endif diff --git a/src/commit.c b/src/commit.c index c7b83ed43..e6bfd95ce 100644 --- a/src/commit.c +++ b/src/commit.c @@ -76,7 +76,7 @@ int git_commit_create_v( return res; } -int git_commit_create( +int git_commit_create_oid( git_oid *oid, git_repository *repo, const char *update_ref, @@ -84,22 +84,18 @@ int git_commit_create( const git_signature *committer, const char *message_encoding, const char *message, - const git_tree *tree, + const git_oid *tree, int parent_count, - const git_commit *parents[]) + const git_oid *parents[]) { git_buf commit = GIT_BUF_INIT; int i; git_odb *odb; - assert(git_object_owner((const git_object *)tree) == repo); - - git_oid__writebuf(&commit, "tree ", git_object_id((const git_object *)tree)); + git_oid__writebuf(&commit, "tree ", tree); - for (i = 0; i < parent_count; ++i) { - assert(git_object_owner((const git_object *)parents[i]) == repo); - git_oid__writebuf(&commit, "parent ", git_object_id((const git_object *)parents[i])); - } + for (i = 0; i < parent_count; ++i) + git_oid__writebuf(&commit, "parent ", parents[i]); git_signature__writebuf(&commit, "author ", author); git_signature__writebuf(&commit, "committer ", committer); @@ -131,6 +127,40 @@ on_error: return -1; } +int git_commit_create( + git_oid *oid, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_tree *tree, + int parent_count, + const git_commit *parents[]) +{ + int retval, i; + const git_oid **parent_oids; + + assert(git_object_owner((const git_object *)tree) == repo); + + parent_oids = git__malloc(parent_count * sizeof(git_oid *)); + GITERR_CHECK_ALLOC(parent_oids); + + for (i = 0; i < parent_count; ++i) { + assert(git_object_owner((const git_object *)parents[i]) == repo); + parent_oids[i] = git_object_id((const git_object *)parents[i]); + } + + retval = git_commit_create_oid(oid, repo, update_ref, author, committer, + message_encoding, message, + git_object_id((const git_object *)tree), + parent_count, parent_oids); + + git__free((void *)parent_oids); + return retval; +} + int git_commit__parse_buffer(git_commit *commit, const void *data, size_t len) { const char *buffer = data; -- cgit v1.2.1 From 9233b3de4ea264a8ae846c784acc70c505022d8b Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Fri, 19 Apr 2013 13:17:29 -0700 Subject: Move git_commit_create_from_oids into sys/commit.h Actually this renames git_commit_create_oid to git_commit_create_from_oids and moves the API declaration to include/git2/sys/commit.h since it is a dangerous API for general use (because it doesn't check that the OID list items actually refer to real objects). --- include/git2/commit.h | 108 ++++++++++++++++++---------------------------- include/git2/sys/commit.h | 45 +++++++++++++++++++ src/commit.c | 81 ++++++++++++++++++---------------- 3 files changed, 129 insertions(+), 105 deletions(-) create mode 100644 include/git2/sys/commit.h diff --git a/include/git2/commit.h b/include/git2/commit.h index e7ef51816..0f7601252 100644 --- a/include/git2/commit.h +++ b/include/git2/commit.h @@ -201,14 +201,12 @@ GIT_EXTERN(int) git_commit_nth_gen_ancestor( unsigned int n); /** - * Create a new commit in the repository using `git_object` - * instances as parameters. + * Create new commit in the repository from a list of `git_object` pointers * - * The message will not be cleaned up. This can be achieved - * through `git_message_prettify()`. + * The message will not be cleaned up automatically. You can do that with + * the `git_message_prettify()` function. * - * @param id Pointer where to store the OID of the - * newly created commit + * @param id Pointer in which to store the OID of the newly created commit * * @param repo Repository where to store the commit * @@ -219,93 +217,69 @@ GIT_EXTERN(int) git_commit_nth_gen_ancestor( * make it point to this commit. If the reference doesn't * exist yet, it will be created. * - * @param author Signature representing the author and the authory - * time of this commit + * @param author Signature with author and author time of commit * - * @param committer Signature representing the committer and the - * commit time of this commit + * @param committer Signature with committer and * commit time of commit * * @param message_encoding The encoding for the message in the - * commit, represented with a standard encoding name. - * E.g. "UTF-8". If NULL, no encoding header is written and - * UTF-8 is assumed. + * commit, represented with a standard encoding name. + * E.g. "UTF-8". If NULL, no encoding header is written and + * UTF-8 is assumed. * * @param message Full message for this commit * * @param tree An instance of a `git_tree` object that will - * be used as the tree for the commit. This tree object must - * also be owned by the given `repo`. + * be used as the tree for the commit. This tree object must + * also be owned by the given `repo`. * * @param parent_count Number of parents for this commit * * @param parents[] Array of `parent_count` pointers to `git_commit` - * objects that will be used as the parents for this commit. This - * array may be NULL if `parent_count` is 0 (root commit). All the - * given commits must be owned by the `repo`. + * objects that will be used as the parents for this commit. This + * array may be NULL if `parent_count` is 0 (root commit). All the + * given commits must be owned by the `repo`. * * @return 0 or an error code * The created commit will be written to the Object Database and * the given reference will be updated to point to it */ GIT_EXTERN(int) git_commit_create( - git_oid *id, - git_repository *repo, - const char *update_ref, - const git_signature *author, - const git_signature *committer, - const char *message_encoding, - const char *message, - const git_tree *tree, - int parent_count, - const git_commit *parents[]); + git_oid *id, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_tree *tree, + int parent_count, + const git_commit *parents[]); /** - * Create a new commit in the repository using a variable - * argument list. + * Create new commit in the repository using a variable argument list. * - * The message will be cleaned up from excess whitespace - * it will be made sure that the last line ends with a '\n'. + * The message will be cleaned up from excess whitespace and it will be made + * sure that the last line ends with a '\n'. * - * The parents for the commit are specified as a variable - * list of pointers to `const git_commit *`. Note that this - * is a convenience method which may not be safe to export - * for certain languages or compilers + * The parents for the commit are specified as a variable list of pointers + * to `const git_commit *`. Note that this is a convenience method which may + * not be safe to export for certain languages or compilers * - * All other parameters remain the same + * All other parameters remain the same at `git_commit_create()`. * * @see git_commit_create */ GIT_EXTERN(int) git_commit_create_v( - git_oid *id, - git_repository *repo, - const char *update_ref, - const git_signature *author, - const git_signature *committer, - const char *message_encoding, - const char *message, - const git_tree *tree, - int parent_count, - ...); - -/** - * Create a new commit in the repository, as with `git_commit_create`, - * using `git_oid` instances as parameters instead of `git_object`. - * - * See documentation for `git_commit_create` for information about the - * parameters, as the meaning is identical excepting that `tree` and - * `parents` now take `git_oid`. - */ -GIT_EXTERN(int) git_commit_create_oid( - git_oid *oid, - git_repository *repo, - const char *update_ref, - const git_signature *author, - const git_signature *committer, - const char *message_encoding, - const char *message, - const git_oid *tree, - int parent_count, - const git_oid *parents[]); + git_oid *id, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_tree *tree, + int parent_count, + ...); /** @} */ GIT_END_DECL diff --git a/include/git2/sys/commit.h b/include/git2/sys/commit.h new file mode 100644 index 000000000..096e028c5 --- /dev/null +++ b/include/git2/sys/commit.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_sys_git_commit_h__ +#define INCLUDE_sys_git_commit_h__ + +#include "git2/common.h" +#include "git2/types.h" +#include "git2/oid.h" + +/** + * @file git2/sys/commit.h + * @brief Low-level Git commit creation + * @defgroup git_backend Git custom backend APIs + * @ingroup Git + * @{ + */ +GIT_BEGIN_DECL + +/** + * Create new commit in the repository from a list of `git_oid` values + * + * See documentation for `git_commit_create()` for information about the + * parameters, as the meaning is identical excepting that `tree` and + * `parents` now take `git_oid`. This is a dangerous API in that the + * `parents` list of `git_oid`s in not checked for validity. + */ +GIT_EXTERN(int) git_commit_create_from_oids( + git_oid *oid, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_oid *tree, + int parent_count, + const git_oid *parents[]); + +/** @} */ +GIT_END_DECL +#endif diff --git a/src/commit.c b/src/commit.c index e6bfd95ce..dd416920d 100644 --- a/src/commit.c +++ b/src/commit.c @@ -9,6 +9,7 @@ #include "git2/object.h" #include "git2/repository.h" #include "git2/signature.h" +#include "git2/sys/commit.h" #include "common.h" #include "odb.h" @@ -44,16 +45,16 @@ void git_commit__free(git_commit *commit) } int git_commit_create_v( - git_oid *oid, - git_repository *repo, - const char *update_ref, - const git_signature *author, - const git_signature *committer, - const char *message_encoding, - const char *message, - const git_tree *tree, - int parent_count, - ...) + git_oid *oid, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_tree *tree, + int parent_count, + ...) { va_list ap; int i, res; @@ -76,22 +77,25 @@ int git_commit_create_v( return res; } -int git_commit_create_oid( - git_oid *oid, - git_repository *repo, - const char *update_ref, - const git_signature *author, - const git_signature *committer, - const char *message_encoding, - const char *message, - const git_oid *tree, - int parent_count, - const git_oid *parents[]) +int git_commit_create_from_oids( + git_oid *oid, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_oid *tree, + int parent_count, + const git_oid *parents[]) { git_buf commit = GIT_BUF_INIT; int i; git_odb *odb; + assert(oid && repo && tree && parent_count >= 0); + assert(git_object_owner((const git_object *)tree) == repo); + git_oid__writebuf(&commit, "tree ", tree); for (i = 0; i < parent_count; ++i) @@ -128,21 +132,21 @@ on_error: } int git_commit_create( - git_oid *oid, - git_repository *repo, - const char *update_ref, - const git_signature *author, - const git_signature *committer, - const char *message_encoding, - const char *message, - const git_tree *tree, - int parent_count, - const git_commit *parents[]) + git_oid *oid, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_tree *tree, + int parent_count, + const git_commit *parents[]) { - int retval, i; + int retval, i; const git_oid **parent_oids; - assert(git_object_owner((const git_object *)tree) == repo); + assert(parent_count >= 0); parent_oids = git__malloc(parent_count * sizeof(git_oid *)); GITERR_CHECK_ALLOC(parent_oids); @@ -152,13 +156,14 @@ int git_commit_create( parent_oids[i] = git_object_id((const git_object *)parents[i]); } - retval = git_commit_create_oid(oid, repo, update_ref, author, committer, - message_encoding, message, - git_object_id((const git_object *)tree), - parent_count, parent_oids); + retval = git_commit_create_from_oids( + oid, repo, update_ref, author, committer, + message_encoding, message, + git_object_id((const git_object *)tree), parent_count, parent_oids); git__free((void *)parent_oids); - return retval; + + return retval; } int git_commit__parse_buffer(git_commit *commit, const void *data, size_t len) -- cgit v1.2.1 From 4dcd87801972e1b880afa9cd0998842bae7af5b5 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Fri, 19 Apr 2013 17:17:44 -0700 Subject: Move refdb_backend to include/git2/sys This moves most of the refdb stuff over to the include/git2/sys directory, with some minor shifts in function organization. While I was making the necessary updates, I also removed the trailing whitespace in a few files that I modified just because I was there and it was bugging me. --- include/git2/refdb.h | 14 ----- include/git2/refdb_backend.h | 108 ----------------------------------- include/git2/sys/refdb_backend.h | 120 +++++++++++++++++++++++++++++++++++++++ src/refdb.c | 9 +-- src/refdb_fs.c | 30 +++++----- src/refs.c | 45 +++++++-------- src/util.h | 2 + tests-clar/refdb/inmemory.c | 62 ++++++++++---------- tests-clar/refdb/testdb.c | 48 +++++++--------- tests-clar/refdb/testdb.h | 5 ++ 10 files changed, 224 insertions(+), 219 deletions(-) delete mode 100644 include/git2/refdb_backend.h create mode 100644 include/git2/sys/refdb_backend.h diff --git a/include/git2/refdb.h b/include/git2/refdb.h index 0e3ec5eaf..9278b1116 100644 --- a/include/git2/refdb.h +++ b/include/git2/refdb.h @@ -81,20 +81,6 @@ GIT_EXTERN(int) git_refdb_compress(git_refdb *refdb); */ GIT_EXTERN(void) git_refdb_free(git_refdb *refdb); -/** - * Sets the custom backend to an existing reference DB - * - * Read for more information. - * - * @param refdb database to add the backend to - * @param backend pointer to a git_refdb_backend instance - * @param priority Value for ordering the backends queue - * @return 0 on success; error code otherwise - */ -GIT_EXTERN(int) git_refdb_set_backend( - git_refdb *refdb, - git_refdb_backend *backend); - /** @} */ GIT_END_DECL diff --git a/include/git2/refdb_backend.h b/include/git2/refdb_backend.h deleted file mode 100644 index 20eb6a9dd..000000000 --- a/include/git2/refdb_backend.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#ifndef INCLUDE_git_refdb_backend_h__ -#define INCLUDE_git_refdb_backend_h__ - -#include "common.h" -#include "types.h" -#include "oid.h" - -/** - * @file git2/refdb_backend.h - * @brief Git custom refs backend functions - * @defgroup git_refdb_backend Git custom refs backend API - * @ingroup Git - * @{ - */ -GIT_BEGIN_DECL - -/** An instance for a custom backend */ -struct git_refdb_backend { - unsigned int version; - - /** - * Queries the refdb backend to determine if the given ref_name - * exists. A refdb implementation must provide this function. - */ - int (*exists)( - int *exists, - struct git_refdb_backend *backend, - const char *ref_name); - - /** - * Queries the refdb backend for a given reference. A refdb - * implementation must provide this function. - */ - int (*lookup)( - git_reference **out, - struct git_refdb_backend *backend, - const char *ref_name); - - /** - * Enumerates each reference in the refdb. A refdb implementation must - * provide this function. - */ - int (*foreach)( - struct git_refdb_backend *backend, - unsigned int list_flags, - git_reference_foreach_cb callback, - void *payload); - - /** - * Enumerates each reference in the refdb that matches the given - * glob string. A refdb implementation may provide this function; - * if it is not provided, foreach will be used and the results filtered - * against the glob. - */ - int (*foreach_glob)( - struct git_refdb_backend *backend, - const char *glob, - unsigned int list_flags, - git_reference_foreach_cb callback, - void *payload); - - /** - * Writes the given reference to the refdb. A refdb implementation - * must provide this function. - */ - int (*write)(struct git_refdb_backend *backend, const git_reference *ref); - - /** - * Deletes the given reference from the refdb. A refdb implementation - * must provide this function. - */ - int (*delete)(struct git_refdb_backend *backend, const git_reference *ref); - - /** - * Suggests that the given refdb compress or optimize its references. - * This mechanism is implementation specific. (For on-disk reference - * databases, this may pack all loose references.) A refdb - * implementation may provide this function; if it is not provided, - * nothing will be done. - */ - int (*compress)(struct git_refdb_backend *backend); - - /** - * Frees any resources held by the refdb. A refdb implementation may - * provide this function; if it is not provided, nothing will be done. - */ - void (*free)(struct git_refdb_backend *backend); -}; - -#define GIT_ODB_BACKEND_VERSION 1 -#define GIT_ODB_BACKEND_INIT {GIT_ODB_BACKEND_VERSION} - -/** - * Constructors for default refdb backends. - */ -GIT_EXTERN(int) git_refdb_backend_fs( - struct git_refdb_backend **backend_out, - git_repository *repo); - -GIT_END_DECL - -#endif diff --git a/include/git2/sys/refdb_backend.h b/include/git2/sys/refdb_backend.h new file mode 100644 index 000000000..dcdf7bcb8 --- /dev/null +++ b/include/git2/sys/refdb_backend.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_git_refdb_backend_h__ +#define INCLUDE_git_refdb_backend_h__ + +#include "git2/common.h" +#include "git2/types.h" +#include "git2/oid.h" + +/** + * @file git2/refdb_backend.h + * @brief Git custom refs backend functions + * @defgroup git_refdb_backend Git custom refs backend API + * @ingroup Git + * @{ + */ +GIT_BEGIN_DECL + +/** An instance for a custom backend */ +struct git_refdb_backend { + unsigned int version; + + /** + * Queries the refdb backend to determine if the given ref_name + * exists. A refdb implementation must provide this function. + */ + int (*exists)( + int *exists, + struct git_refdb_backend *backend, + const char *ref_name); + + /** + * Queries the refdb backend for a given reference. A refdb + * implementation must provide this function. + */ + int (*lookup)( + git_reference **out, + struct git_refdb_backend *backend, + const char *ref_name); + + /** + * Enumerates each reference in the refdb. A refdb implementation must + * provide this function. + */ + int (*foreach)( + struct git_refdb_backend *backend, + unsigned int list_flags, + git_reference_foreach_cb callback, + void *payload); + + /** + * Enumerates each reference in the refdb that matches the given + * glob string. A refdb implementation may provide this function; + * if it is not provided, foreach will be used and the results filtered + * against the glob. + */ + int (*foreach_glob)( + struct git_refdb_backend *backend, + const char *glob, + unsigned int list_flags, + git_reference_foreach_cb callback, + void *payload); + + /** + * Writes the given reference to the refdb. A refdb implementation + * must provide this function. + */ + int (*write)(struct git_refdb_backend *backend, const git_reference *ref); + + /** + * Deletes the given reference from the refdb. A refdb implementation + * must provide this function. + */ + int (*delete)(struct git_refdb_backend *backend, const git_reference *ref); + + /** + * Suggests that the given refdb compress or optimize its references. + * This mechanism is implementation specific. (For on-disk reference + * databases, this may pack all loose references.) A refdb + * implementation may provide this function; if it is not provided, + * nothing will be done. + */ + int (*compress)(struct git_refdb_backend *backend); + + /** + * Frees any resources held by the refdb. A refdb implementation may + * provide this function; if it is not provided, nothing will be done. + */ + void (*free)(struct git_refdb_backend *backend); +}; + +#define GIT_ODB_BACKEND_VERSION 1 +#define GIT_ODB_BACKEND_INIT {GIT_ODB_BACKEND_VERSION} + +/** + * Constructors for default refdb backends. + */ +GIT_EXTERN(int) git_refdb_backend_fs( + struct git_refdb_backend **backend_out, + git_repository *repo); + +/** + * Sets the custom backend to an existing reference DB + * + * @param refdb database to add the backend to + * @param backend pointer to a git_refdb_backend instance + * @param priority Value for ordering the backends queue + * @return 0 on success; error code otherwise + */ +GIT_EXTERN(int) git_refdb_set_backend( + git_refdb *refdb, + git_refdb_backend *backend); + +GIT_END_DECL + +#endif diff --git a/src/refdb.c b/src/refdb.c index 2a0fd702c..0675be638 100644 --- a/src/refdb.c +++ b/src/refdb.c @@ -7,15 +7,16 @@ #include "common.h" #include "posix.h" + #include "git2/object.h" #include "git2/refs.h" #include "git2/refdb.h" +#include "git2/sys/refdb_backend.h" + #include "hash.h" #include "refdb.h" #include "refs.h" -#include "git2/refdb_backend.h" - int git_refdb_new(git_refdb **out, git_repository *repo) { git_refdb *db; @@ -74,11 +75,11 @@ int git_refdb_set_backend(git_refdb *db, git_refdb_backend *backend) int git_refdb_compress(git_refdb *db) { assert(db); - + if (db->backend->compress) { return db->backend->compress(db->backend); } - + return 0; } diff --git a/src/refdb_fs.c b/src/refdb_fs.c index 56b2b6a99..4d5d6006d 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include GIT__USE_STRMAP; @@ -61,7 +61,7 @@ static int reference_read( /* Determine the full path of the file */ if (git_buf_joinpath(&path, repo_path, ref_name) < 0) return -1; - + result = git_futils_readbuffer_updated(file_content, path.ptr, mtime, NULL, updated); git_buf_free(&path); @@ -174,7 +174,7 @@ static int packed_load(refdb_fs_backend *backend) ref_cache->packfile = git_strmap_alloc(); GITERR_CHECK_ALLOC(ref_cache->packfile); } - + result = reference_read(&packfile, &ref_cache->packfile_time, backend->path, GIT_PACKEDREFS_FILE, &updated); @@ -192,7 +192,7 @@ static int packed_load(refdb_fs_backend *backend) if (result < 0) return -1; - + if (!updated) return 0; @@ -433,7 +433,7 @@ static int loose_lookup( } else { if ((error = loose_parse_oid(&oid, &ref_file)) < 0) goto done; - + *out = git_reference__alloc(ref_name, &oid, NULL); } @@ -455,19 +455,19 @@ static int packed_map_entry( if (packed_load(backend) < 0) return -1; - + /* Look up on the packfile */ packfile_refs = backend->refcache.packfile; *pos = git_strmap_lookup_index(packfile_refs, ref_name); - + if (!git_strmap_valid_index(packfile_refs, *pos)) { giterr_set(GITERR_REFERENCE, "Reference '%s' not found", ref_name); return GIT_ENOTFOUND; } *entry = git_strmap_value_at(packfile_refs, *pos); - + return 0; } @@ -479,14 +479,14 @@ static int packed_lookup( struct packref *entry; khiter_t pos; int error = 0; - + if ((error = packed_map_entry(&entry, &pos, backend, ref_name)) < 0) return error; if ((*out = git_reference__alloc(ref_name, &entry->oid, &entry->peel)) == NULL) return -1; - + return 0; } @@ -582,7 +582,7 @@ static int refdb_fs_backend__foreach( git_buf refs_path = GIT_BUF_INIT; const char *ref_name; void *ref = NULL; - + GIT_UNUSED(ref); assert(_backend); @@ -590,7 +590,7 @@ static int refdb_fs_backend__foreach( if (packed_load(backend) < 0) return -1; - + /* list all the packed references first */ if (list_type & GIT_REF_OID) { git_strmap_foreach(backend->refcache.packfile, ref_name, ref, { @@ -924,7 +924,7 @@ static int refdb_fs_backend__delete( repo = backend->repo; /* If a loose reference exists, remove it from the filesystem */ - + if (git_buf_joinpath(&loose_path, repo->path_repository, ref->name) < 0) return -1; @@ -932,7 +932,7 @@ static int refdb_fs_backend__delete( error = p_unlink(loose_path.ptr); loose_deleted = 1; } - + git_buf_free(&loose_path); if (error != 0) @@ -946,7 +946,7 @@ static int refdb_fs_backend__delete( error = packed_write(backend); } - + if (pack_error == GIT_ENOTFOUND) error = loose_deleted ? 0 : GIT_ENOTFOUND; else diff --git a/src/refs.c b/src/refs.c index 5b5812aae..d9291e56f 100644 --- a/src/refs.c +++ b/src/refs.c @@ -19,7 +19,6 @@ #include #include #include -#include GIT__USE_STRMAP; @@ -255,10 +254,10 @@ int git_reference_lookup_resolved( max_nesting = MAX_NESTING_LEVEL; else if (max_nesting < 0) max_nesting = DEFAULT_NESTING_LEVEL; - + strncpy(scan_name, name, GIT_REFNAME_MAX); scan_type = GIT_REF_SYMBOLIC; - + if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0) return -1; @@ -276,7 +275,7 @@ int git_reference_lookup_resolved( if ((error = git_refdb_lookup(&ref, refdb, scan_name)) < 0) return error; - + scan_type = ref->type; } @@ -354,7 +353,7 @@ static int reference__create( git_refdb *refdb; git_reference *ref = NULL; int error = 0; - + if (ref_out) *ref_out = NULL; @@ -369,7 +368,7 @@ static int reference__create( } else { ref = git_reference__alloc_symbolic(name, symbolic); } - + GITERR_CHECK_ALLOC(ref); ref->db = refdb; @@ -377,7 +376,7 @@ static int reference__create( git_reference_free(ref); return error; } - + if (ref_out == NULL) git_reference_free(ref); else @@ -397,17 +396,17 @@ int git_reference_create( int error = 0; assert(repo && name && oid); - + /* Sanity check the reference being created - target must exist. */ if ((error = git_repository_odb__weakptr(&odb, repo)) < 0) return error; - + if (!git_odb_exists(odb, oid)) { giterr_set(GITERR_REFERENCE, "Target OID for the reference doesn't exist on the repository"); return -1; } - + return reference__create(ref_out, repo, name, oid, NULL, force); } @@ -422,7 +421,7 @@ int git_reference_symbolic_create( int error = 0; assert(repo && name && target); - + if ((error = git_reference__normalize_name_lax( normalized, sizeof(normalized), target)) < 0) return error; @@ -436,7 +435,7 @@ int git_reference_set_target( const git_oid *id) { assert(out && ref && id); - + if (ref->type != GIT_REF_OID) { giterr_set(GITERR_REFERENCE, "Cannot set OID on symbolic reference"); return -1; @@ -451,13 +450,13 @@ int git_reference_symbolic_set_target( const char *target) { assert(out && ref && target); - + if (ref->type != GIT_REF_SYMBOLIC) { giterr_set(GITERR_REFERENCE, "Cannot set symbolic target on a direct reference"); return -1; } - + return git_reference_symbolic_create(out, ref->db->repo, ref->name, target, 1); } @@ -473,7 +472,7 @@ int git_reference_rename( git_reference *result = NULL; int error = 0; int reference_has_log; - + *out = NULL; normalization_flags = ref->type == GIT_REF_SYMBOLIC ? @@ -488,7 +487,7 @@ int git_reference_rename( * Create the new reference. */ if (ref->type == GIT_REF_OID) { - result = git_reference__alloc(new_name, &ref->target.oid, &ref->peel); + result = git_reference__alloc(new_name, &ref->target.oid, &ref->peel); } else if (ref->type == GIT_REF_SYMBOLIC) { result = git_reference__alloc_symbolic(new_name, ref->target.symbolic); } else { @@ -509,11 +508,11 @@ int git_reference_rename( /* Now delete the old ref and save the new one. */ if ((error = git_refdb_delete(ref->db, ref)) < 0) goto on_error; - + /* Save the new reference. */ if ((error = git_refdb_write(ref->db, result)) < 0) goto rollback; - + /* Update HEAD it was poiting to the reference being renamed. */ if (should_head_be_updated && (error = git_repository_set_head(ref->db->repo, new_name)) < 0) { giterr_set(GITERR_REFERENCE, "Failed to update HEAD after renaming reference"); @@ -547,7 +546,7 @@ int git_reference_resolve(git_reference **ref_out, const git_reference *ref) switch (git_reference_type(ref)) { case GIT_REF_OID: return git_reference_lookup(ref_out, ref->db->repo, ref->name); - + case GIT_REF_SYMBOLIC: return git_reference_lookup_resolved(ref_out, ref->db->repo, ref->target.symbolic, -1); @@ -846,7 +845,7 @@ static int reference__update_terminal( if (nesting > MAX_NESTING_LEVEL) return GIT_ENOTFOUND; - + error = git_reference_lookup(&ref, repo, ref_name); /* If we haven't found the reference at all, create a new reference. */ @@ -854,10 +853,10 @@ static int reference__update_terminal( giterr_clear(); return git_reference_create(NULL, repo, ref_name, oid, 0); } - + if (error < 0) return error; - + /* If the ref is a symbolic reference, follow its target. */ if (git_reference_type(ref) == GIT_REF_SYMBOLIC) { error = reference__update_terminal(repo, git_reference_symbolic_target(ref), oid, @@ -867,7 +866,7 @@ static int reference__update_terminal( git_reference_free(ref); error = git_reference_create(NULL, repo, ref_name, oid, 1); } - + return error; } diff --git a/src/util.h b/src/util.h index c0f271997..af3ef0b46 100644 --- a/src/util.h +++ b/src/util.h @@ -7,6 +7,8 @@ #ifndef INCLUDE_util_h__ #define INCLUDE_util_h__ +#include "common.h" + #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) #define bitsizeof(x) (CHAR_BIT * sizeof(x)) #define MSB(x, bits) ((x) & (~0ULL << (bitsizeof(x) - (bits)))) diff --git a/tests-clar/refdb/inmemory.c b/tests-clar/refdb/inmemory.c index ea76172cf..2c76d4192 100644 --- a/tests-clar/refdb/inmemory.c +++ b/tests-clar/refdb/inmemory.c @@ -1,12 +1,15 @@ #include "clar_libgit2.h" -#include "refdb.h" -#include "repository.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; -static git_refdb_backend *refdb_backend; int unlink_ref(void *payload, git_buf *file) { @@ -26,7 +29,7 @@ int ref_file_foreach(git_repository *repo, int (* cb)(void *payload, git_buf *fi 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"); @@ -38,7 +41,7 @@ int ref_file_foreach(git_repository *repo, int (* cb)(void *payload, git_buf *fi 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) @@ -51,16 +54,17 @@ int ref_file_foreach(git_repository *repo, int (* cb)(void *payload, git_buf *fi void test_refdb_inmemory__initialize(void) { - git_refdb *refdb; - 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)); - + git_refdb_free(refdb); + ref_file_foreach(repo, unlink_ref); git_buf_free(&repo_refs_dir); @@ -76,10 +80,10 @@ 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); @@ -89,10 +93,10 @@ 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)); @@ -139,7 +143,7 @@ int foreach_test(const char *ref_name, void *payload) cl_assert(git_oid_cmp(&expected, git_reference_target(ref)) == 0); ++(*i); - + git_reference_free(ref); return 0; @@ -150,19 +154,19 @@ 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, GIT_REF_LISTALL, foreach_test, &i)); cl_assert_equal_i(3, (int)i); - + git_reference_free(write1); git_reference_free(write2); git_reference_free(write3); @@ -175,14 +179,14 @@ int delete_test(const char *ref_name, void *payload) size_t *i = payload; cl_git_pass(git_reference_lookup(&ref, repo, ref_name)); - - cl_git_pass(git_oid_fromstr(&expected, "e90810b8df3e80c413d903f631643c716887138d")); + + 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; } @@ -191,22 +195,22 @@ 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, GIT_REF_LISTALL, delete_test, &i)); cl_assert_equal_i(1, (int)i); diff --git a/tests-clar/refdb/testdb.c b/tests-clar/refdb/testdb.c index 4bca39878..627254e44 100644 --- a/tests-clar/refdb/testdb.c +++ b/tests-clar/refdb/testdb.c @@ -1,14 +1,10 @@ -#include "common.h" #include "vector.h" #include "util.h" -#include -#include -#include -#include +#include "testdb.h" typedef struct refdb_test_backend { git_refdb_backend parent; - + git_repository *repo; git_vector refs; } refdb_test_backend; @@ -16,7 +12,7 @@ typedef struct refdb_test_backend { typedef struct refdb_test_entry { char *name; git_ref_t type; - + union { git_oid oid; char *symbolic; @@ -37,19 +33,19 @@ static int refdb_test_backend__exists( 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; } @@ -59,18 +55,18 @@ static int refdb_test_backend__write( { 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 { @@ -79,7 +75,7 @@ static int refdb_test_backend__write( } git_vector_insert(&backend->refs, entry); - + return 0; } @@ -94,7 +90,7 @@ static int refdb_test_backend__lookup( assert(_backend); backend = (refdb_test_backend *)_backend; - + git_vector_foreach(&backend->refs, i, entry) { if (strcmp(entry->name, ref_name) == 0) { @@ -108,7 +104,7 @@ static int refdb_test_backend__lookup( if (*out == NULL) return -1; - + return 0; } } @@ -125,21 +121,21 @@ static int refdb_test_backend__foreach( 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 (entry->type == GIT_REF_OID && (list_flags & GIT_REF_OID) == 0) continue; - + if (entry->type == GIT_REF_SYMBOLIC && (list_flags & GIT_REF_SYMBOLIC) == 0) continue; - + if (callback(entry->name, payload) != 0) return GIT_EUSER; } - + return 0; } @@ -147,7 +143,7 @@ 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); } @@ -178,14 +174,14 @@ 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_vector_free(&backend->refs); git__free(backend); } @@ -197,7 +193,7 @@ int refdb_backend_test( backend = git__calloc(1, sizeof(refdb_test_backend)); GITERR_CHECK_ALLOC(backend); - + git_vector_init(&backend->refs, 0, ref_name_cmp); backend->repo = repo; diff --git a/tests-clar/refdb/testdb.h b/tests-clar/refdb/testdb.h index e38abd967..49d1cb1d0 100644 --- a/tests-clar/refdb/testdb.h +++ b/tests-clar/refdb/testdb.h @@ -1,3 +1,8 @@ +#include +#include +#include +#include + int refdb_backend_test( git_refdb_backend **backend_out, git_repository *repo); -- cgit v1.2.1 From 21ca045100337bcb2905a20a72d42721d18871f9 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Sun, 21 Apr 2013 12:52:17 -0700 Subject: Move git_reference__alloc to include/git2/sys Create a new include/git2/sys/refs.h and move the reference alloc functions there. Also fix some documentation issues and some minor code cleanups. --- include/git2/refdb.h | 19 ------------------- include/git2/sys/refdb_backend.h | 36 +++++++++++++++++++++++------------- include/git2/sys/refs.h | 38 ++++++++++++++++++++++++++++++++++++++ src/refdb.c | 28 ++++++++++++---------------- src/refdb.h | 2 +- src/refdb_fs.c | 1 + src/refs.c | 4 ++-- tests-clar/refdb/inmemory.c | 1 - tests-clar/refdb/testdb.h | 1 + 9 files changed, 78 insertions(+), 52 deletions(-) create mode 100644 include/git2/sys/refs.h diff --git a/include/git2/refdb.h b/include/git2/refdb.h index 9278b1116..a315876ae 100644 --- a/include/git2/refdb.h +++ b/include/git2/refdb.h @@ -21,25 +21,6 @@ */ GIT_BEGIN_DECL -/** - * Create a new reference. Either an oid or a symbolic target must be - * specified. - * - * @param refdb the reference database to associate with this reference - * @param name the reference name - * @param oid the object id for a direct reference - * @param symbolic the target for a symbolic reference - * @return the created git_reference or NULL on error - */ -GIT_EXTERN(git_reference *) git_reference__alloc( - const char *name, - const git_oid *oid, - const git_oid *peel); - -GIT_EXTERN(git_reference *) git_reference__alloc_symbolic( - const char *name, - const char *target); - /** * Create a new reference database with no backends. * diff --git a/include/git2/sys/refdb_backend.h b/include/git2/sys/refdb_backend.h index dcdf7bcb8..d5f599fec 100644 --- a/include/git2/sys/refdb_backend.h +++ b/include/git2/sys/refdb_backend.h @@ -4,8 +4,8 @@ * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ -#ifndef INCLUDE_git_refdb_backend_h__ -#define INCLUDE_git_refdb_backend_h__ +#ifndef INCLUDE_sys_git_refdb_backend_h__ +#define INCLUDE_sys_git_refdb_backend_h__ #include "git2/common.h" #include "git2/types.h" @@ -30,7 +30,7 @@ struct git_refdb_backend { */ int (*exists)( int *exists, - struct git_refdb_backend *backend, + git_refdb_backend *backend, const char *ref_name); /** @@ -39,7 +39,7 @@ struct git_refdb_backend { */ int (*lookup)( git_reference **out, - struct git_refdb_backend *backend, + git_refdb_backend *backend, const char *ref_name); /** @@ -47,7 +47,7 @@ struct git_refdb_backend { * provide this function. */ int (*foreach)( - struct git_refdb_backend *backend, + git_refdb_backend *backend, unsigned int list_flags, git_reference_foreach_cb callback, void *payload); @@ -59,7 +59,7 @@ struct git_refdb_backend { * against the glob. */ int (*foreach_glob)( - struct git_refdb_backend *backend, + git_refdb_backend *backend, const char *glob, unsigned int list_flags, git_reference_foreach_cb callback, @@ -69,13 +69,13 @@ struct git_refdb_backend { * Writes the given reference to the refdb. A refdb implementation * must provide this function. */ - int (*write)(struct git_refdb_backend *backend, const git_reference *ref); + int (*write)(git_refdb_backend *backend, const git_reference *ref); /** * Deletes the given reference from the refdb. A refdb implementation * must provide this function. */ - int (*delete)(struct git_refdb_backend *backend, const git_reference *ref); + int (*delete)(git_refdb_backend *backend, const git_reference *ref); /** * Suggests that the given refdb compress or optimize its references. @@ -84,31 +84,41 @@ struct git_refdb_backend { * implementation may provide this function; if it is not provided, * nothing will be done. */ - int (*compress)(struct git_refdb_backend *backend); + int (*compress)(git_refdb_backend *backend); /** * Frees any resources held by the refdb. A refdb implementation may * provide this function; if it is not provided, nothing will be done. */ - void (*free)(struct git_refdb_backend *backend); + void (*free)(git_refdb_backend *backend); }; #define GIT_ODB_BACKEND_VERSION 1 #define GIT_ODB_BACKEND_INIT {GIT_ODB_BACKEND_VERSION} /** - * Constructors for default refdb backends. + * Constructors for default filesystem-based refdb backend + * + * Under normal usage, this is called for you when the repository is + * opened / created, but you can use this to explicitly construct a + * filesystem refdb backend for a repository. + * + * @param backend_out Output pointer to the git_refdb_backend object + * @param repo Git repository to access + * @return 0 on success, <0 error code on failure */ GIT_EXTERN(int) git_refdb_backend_fs( - struct git_refdb_backend **backend_out, + git_refdb_backend **backend_out, git_repository *repo); /** * Sets the custom backend to an existing reference DB * + * The `git_refdb` will take ownership of the `git_refdb_backend` so you + * should NOT free it after calling this function. + * * @param refdb database to add the backend to * @param backend pointer to a git_refdb_backend instance - * @param priority Value for ordering the backends queue * @return 0 on success; error code otherwise */ GIT_EXTERN(int) git_refdb_set_backend( diff --git a/include/git2/sys/refs.h b/include/git2/sys/refs.h new file mode 100644 index 000000000..85963258c --- /dev/null +++ b/include/git2/sys/refs.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_sys_git_refdb_h__ +#define INCLUDE_sys_git_refdb_h__ + +#include "git2/common.h" +#include "git2/types.h" +#include "git2/oid.h" + +/** + * Create a new direct reference from an OID. + * + * @param name the reference name + * @param oid the object id for a direct reference + * @param symbolic the target for a symbolic reference + * @return the created git_reference or NULL on error + */ +GIT_EXTERN(git_reference *) git_reference__alloc( + const char *name, + const git_oid *oid, + const git_oid *peel); + +/** + * Create a new symbolic reference. + * + * @param name the reference name + * @param symbolic the target for a symbolic reference + * @return the created git_reference or NULL on error + */ +GIT_EXTERN(git_reference *) git_reference__alloc_symbolic( + const char *name, + const char *target); + +#endif diff --git a/src/refdb.c b/src/refdb.c index 0675be638..33a1934d1 100644 --- a/src/refdb.c +++ b/src/refdb.c @@ -58,15 +58,19 @@ int git_refdb_open(git_refdb **out, git_repository *repo) return 0; } -int git_refdb_set_backend(git_refdb *db, git_refdb_backend *backend) +static void refdb_free_backend(git_refdb *db) { if (db->backend) { - if(db->backend->free) + if (db->backend->free) db->backend->free(db->backend); else git__free(db->backend); } +} +int git_refdb_set_backend(git_refdb *db, git_refdb_backend *backend) +{ + refdb_free_backend(db); db->backend = backend; return 0; @@ -76,22 +80,15 @@ int git_refdb_compress(git_refdb *db) { assert(db); - if (db->backend->compress) { + if (db->backend->compress) return db->backend->compress(db->backend); - } return 0; } static void refdb_free(git_refdb *db) { - if (db->backend) { - if(db->backend->free) - db->backend->free(db->backend); - else - git__free(db->backend); - } - + refdb_free_backend(db); git__free(db); } @@ -115,14 +112,13 @@ int git_refdb_lookup(git_reference **out, git_refdb *db, const char *ref_name) git_reference *ref; int error; - assert(db && db->backend && ref_name); - - *out = NULL; + assert(db && db->backend && out && ref_name); - if ((error = db->backend->lookup(&ref, db->backend, ref_name)) == 0) - { + if (!(error = db->backend->lookup(&ref, db->backend, ref_name))) { ref->db = db; *out = ref; + } else { + *out = NULL; } return error; diff --git a/src/refdb.h b/src/refdb.h index 0969711b9..047113ac8 100644 --- a/src/refdb.h +++ b/src/refdb.h @@ -41,6 +41,6 @@ int git_refdb_foreach_glob( int git_refdb_write(git_refdb *refdb, const git_reference *ref); -int git_refdb_delete(struct git_refdb *refdb, const git_reference *ref); +int git_refdb_delete(git_refdb *refdb, const git_reference *ref); #endif diff --git a/src/refdb_fs.c b/src/refdb_fs.c index 4d5d6006d..443871005 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -19,6 +19,7 @@ #include #include #include +#include GIT__USE_STRMAP; diff --git a/src/refs.c b/src/refs.c index d9291e56f..9c6684a5a 100644 --- a/src/refs.c +++ b/src/refs.c @@ -19,6 +19,7 @@ #include #include #include +#include GIT__USE_STRMAP; @@ -44,8 +45,7 @@ static git_reference *alloc_ref(const char *name) } git_reference *git_reference__alloc_symbolic( - const char *name, - const char *target) + const char *name, const char *target) { git_reference *ref; diff --git a/tests-clar/refdb/inmemory.c b/tests-clar/refdb/inmemory.c index 2c76d4192..243b5bb37 100644 --- a/tests-clar/refdb/inmemory.c +++ b/tests-clar/refdb/inmemory.c @@ -63,7 +63,6 @@ void test_refdb_inmemory__initialize(void) 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)); - git_refdb_free(refdb); ref_file_foreach(repo, unlink_ref); diff --git a/tests-clar/refdb/testdb.h b/tests-clar/refdb/testdb.h index 49d1cb1d0..a0d1bbc48 100644 --- a/tests-clar/refdb/testdb.h +++ b/tests-clar/refdb/testdb.h @@ -1,6 +1,7 @@ #include #include #include +#include #include int refdb_backend_test( -- cgit v1.2.1 From 0d4a5b13afc6c516212b194b238ab08d3362a041 Mon Sep 17 00:00:00 2001 From: Jasper Lievisse Adriaanse Date: Mon, 22 Apr 2013 00:13:35 +0200 Subject: Add missing prototype for p_realpath(). --- src/unix/posix.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/unix/posix.h b/src/unix/posix.h index f4886c5d1..9c9f837b9 100644 --- a/src/unix/posix.h +++ b/src/unix/posix.h @@ -21,6 +21,8 @@ /* The OpenBSD realpath function behaves differently */ #if !defined(__OpenBSD__) # define p_realpath(p, po) realpath(p, po) +#else +char *p_realpath(const char *, char *); #endif #define p_vsnprintf(b, c, f, a) vsnprintf(b, c, f, a) -- cgit v1.2.1