diff options
-rw-r--r-- | src/diff.c | 12 | ||||
-rw-r--r-- | src/repository.c | 35 | ||||
-rw-r--r-- | src/userdiff.h | 16 | ||||
-rw-r--r-- | tests/repo/state.c | 18 | ||||
-rw-r--r-- | tests/status/submodules.c | 93 |
5 files changed, 149 insertions, 25 deletions
diff --git a/src/diff.c b/src/diff.c index 484273f4a..e62f45c22 100644 --- a/src/diff.c +++ b/src/diff.c @@ -876,7 +876,7 @@ static int handle_unmatched_new_item( DIFF_FLAG_IS_SET(diff, GIT_DIFF_RECURSE_IGNORED_DIRS)); /* do not advance into directories that contain a .git file */ - if (recurse_into_dir) { + if (recurse_into_dir && !contains_oitem) { git_buf *full = NULL; if (git_iterator_current_workdir_path(&full, info->new_iter) < 0) return -1; @@ -969,6 +969,16 @@ static int handle_unmatched_new_item( if (git_submodule_lookup(NULL, info->repo, nitem->path) != 0) { giterr_clear(); delta_type = GIT_DELTA_IGNORED; + + /* if this contains a tracked item, treat as normal TREE */ + if (contains_oitem) { + error = git_iterator_advance_into(&info->nitem, info->new_iter); + if (error != GIT_ENOTFOUND) + return error; + + giterr_clear(); + return git_iterator_advance(&info->nitem, info->new_iter); + } } } diff --git a/src/repository.c b/src/repository.c index 49d1bc63e..6b2705bfa 100644 --- a/src/repository.c +++ b/src/repository.c @@ -1955,24 +1955,32 @@ int git_repository_state(git_repository *repo) return state; } -int git_repository__cleanup_files(git_repository *repo, const char *files[], size_t files_len) +int git_repository__cleanup_files( + git_repository *repo, const char *files[], size_t files_len) { - git_buf path = GIT_BUF_INIT; + git_buf buf = GIT_BUF_INIT; size_t i; - int error = 0; + int error; - for (i = 0; i < files_len; ++i) { - git_buf_clear(&path); + for (error = 0, i = 0; !error && i < files_len; ++i) { + const char *path; - if ((error = git_buf_joinpath(&path, repo->path_repository, files[i])) < 0 || - (git_path_isfile(git_buf_cstr(&path)) && - (error = p_unlink(git_buf_cstr(&path))) < 0)) - goto done; - } + if (git_buf_joinpath(&buf, repo->path_repository, files[i]) < 0) + return -1; -done: - git_buf_free(&path); + path = git_buf_cstr(&buf); + + if (git_path_isfile(path)) { + error = p_unlink(path); + } else if (git_path_isdir(path)) { + error = git_futils_rmdir_r(path, NULL, + GIT_RMDIR_REMOVE_FILES | GIT_RMDIR_REMOVE_BLOCKERS); + } + + git_buf_clear(&buf); + } + git_buf_free(&buf); return error; } @@ -1982,6 +1990,9 @@ static const char *state_files[] = { GIT_MERGE_MSG_FILE, GIT_REVERT_HEAD_FILE, GIT_CHERRY_PICK_HEAD_FILE, + GIT_BISECT_LOG_FILE, + GIT_REBASE_MERGE_DIR, + GIT_REBASE_APPLY_DIR, }; int git_repository_state_cleanup(git_repository *repo) diff --git a/src/userdiff.h b/src/userdiff.h index 7eb095246..523f2f8d4 100644 --- a/src/userdiff.h +++ b/src/userdiff.h @@ -45,13 +45,13 @@ typedef struct { static git_diff_driver_definition builtin_defs[] = { IPATTERN("ada", - "!^(.*[ \t])?(is new|renames|is separate)([ \t].*)?$\n" + "!^(.*[ \t])?(is[ \t]+new|renames|is[ \t]+separate)([ \t].*)?$\n" "!^[ \t]*with[ \t].*$\n" "^[ \t]*((procedure|function)[ \t]+.*)$\n" "^[ \t]*((package|protected|task)[ \t]+.*)$", /* -- */ "[a-zA-Z][a-zA-Z0-9_]*" - "|[0-9][-+0-9#_.eE]" + "|[-+]?[0-9][0-9#_.aAbBcCdDeEfF]*([eE][+-]?[0-9_]+)?" "|=>|\\.\\.|\\*\\*|:=|/=|>=|<=|<<|>>|<>"), IPATTERN("fortran", @@ -159,15 +159,13 @@ PATTERNS("tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$", PATTERNS("cpp", /* Jump targets or access declarations */ - "!^[ \t]*[A-Za-z_][A-Za-z_0-9]*:.*$\n" - /* C/++ functions/methods at top level */ - "^([A-Za-z_][A-Za-z_0-9]*([ \t*]+[A-Za-z_][A-Za-z_0-9]*([ \t]*::[ \t]*[^[:space:]]+)?){1,}[ \t]*\\([^;]*)$\n" - /* compound type at top level */ - "^((struct|class|enum)[^;]*)$", + "!^[ \t]*[A-Za-z_][A-Za-z_0-9]*:[[:space:]]*($|/[/*])\n" + /* functions/methods, variables, and compounds at top level */ + "^((::[[:space:]]*)?[A-Za-z_].*)$", /* -- */ "[a-zA-Z_][a-zA-Z0-9_]*" - "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?" - "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->"), + "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lLuU]*" + "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->\\*?|\\.\\*"), PATTERNS("csharp", /* Keywords */ diff --git a/tests/repo/state.c b/tests/repo/state.c index 5e7227205..2d6c780ee 100644 --- a/tests/repo/state.c +++ b/tests/repo/state.c @@ -45,52 +45,70 @@ void test_repo_state__merge(void) { setup_simple_state(GIT_MERGE_HEAD_FILE); assert_repo_state(GIT_REPOSITORY_STATE_MERGE); + cl_git_pass(git_repository_state_cleanup(_repo)); + assert_repo_state(GIT_REPOSITORY_STATE_NONE); } void test_repo_state__revert(void) { setup_simple_state(GIT_REVERT_HEAD_FILE); assert_repo_state(GIT_REPOSITORY_STATE_REVERT); + cl_git_pass(git_repository_state_cleanup(_repo)); + assert_repo_state(GIT_REPOSITORY_STATE_NONE); } void test_repo_state__cherry_pick(void) { setup_simple_state(GIT_CHERRY_PICK_HEAD_FILE); assert_repo_state(GIT_REPOSITORY_STATE_CHERRY_PICK); + cl_git_pass(git_repository_state_cleanup(_repo)); + assert_repo_state(GIT_REPOSITORY_STATE_NONE); } void test_repo_state__bisect(void) { setup_simple_state(GIT_BISECT_LOG_FILE); assert_repo_state(GIT_REPOSITORY_STATE_BISECT); + cl_git_pass(git_repository_state_cleanup(_repo)); + assert_repo_state(GIT_REPOSITORY_STATE_NONE); } void test_repo_state__rebase_interactive(void) { setup_simple_state(GIT_REBASE_MERGE_INTERACTIVE_FILE); assert_repo_state(GIT_REPOSITORY_STATE_REBASE_INTERACTIVE); + cl_git_pass(git_repository_state_cleanup(_repo)); + assert_repo_state(GIT_REPOSITORY_STATE_NONE); } void test_repo_state__rebase_merge(void) { setup_simple_state(GIT_REBASE_MERGE_DIR "whatever"); assert_repo_state(GIT_REPOSITORY_STATE_REBASE_MERGE); + cl_git_pass(git_repository_state_cleanup(_repo)); + assert_repo_state(GIT_REPOSITORY_STATE_NONE); } void test_repo_state__rebase(void) { setup_simple_state(GIT_REBASE_APPLY_REBASING_FILE); assert_repo_state(GIT_REPOSITORY_STATE_REBASE); + cl_git_pass(git_repository_state_cleanup(_repo)); + assert_repo_state(GIT_REPOSITORY_STATE_NONE); } void test_repo_state__apply_mailbox(void) { setup_simple_state(GIT_REBASE_APPLY_APPLYING_FILE); assert_repo_state(GIT_REPOSITORY_STATE_APPLY_MAILBOX); + cl_git_pass(git_repository_state_cleanup(_repo)); + assert_repo_state(GIT_REPOSITORY_STATE_NONE); } void test_repo_state__apply_mailbox_or_rebase(void) { setup_simple_state(GIT_REBASE_APPLY_DIR "whatever"); assert_repo_state(GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE); + cl_git_pass(git_repository_state_cleanup(_repo)); + assert_repo_state(GIT_REPOSITORY_STATE_NONE); } diff --git a/tests/status/submodules.c b/tests/status/submodules.c index 6d0d63a5f..63cf73f36 100644 --- a/tests/status/submodules.c +++ b/tests/status/submodules.c @@ -1,7 +1,5 @@ #include "clar_libgit2.h" -#include "buffer.h" -#include "path.h" -#include "posix.h" +#include "fileops.h" #include "status_helpers.h" #include "../submodule/submodule_helpers.h" @@ -389,3 +387,92 @@ void test_status_submodules__contained_untracked_repo(void) g_repo, &opts, cb_status__match, &counts)); cl_assert_equal_i(5, counts.entry_count); } + +void test_status_submodules__broken_stuff_that_git_allows(void) +{ + git_status_options opts = GIT_STATUS_OPTIONS_INIT; + status_entry_counts counts; + git_repository *contained; + static const char *expected_files_with_broken[] = { + ".gitmodules", + "added", + "broken/tracked", + "deleted", + "ignored", + "modified", + "untracked" + }; + static unsigned int expected_status_with_broken[] = { + GIT_STATUS_WT_MODIFIED, + GIT_STATUS_INDEX_NEW, + GIT_STATUS_INDEX_NEW, + GIT_STATUS_INDEX_DELETED, + GIT_STATUS_IGNORED, + GIT_STATUS_WT_MODIFIED, + GIT_STATUS_WT_NEW, + }; + + g_repo = setup_fixture_submodules(); + + opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | + GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS | + GIT_STATUS_OPT_INCLUDE_IGNORED; + + /* make a directory and stick a tracked item into the index */ + { + git_index *idx; + cl_must_pass(p_mkdir("submodules/broken", 0777)); + cl_git_mkfile("submodules/broken/tracked", "tracked content"); + cl_git_pass(git_repository_index(&idx, g_repo)); + cl_git_pass(git_index_add_bypath(idx, "broken/tracked")); + cl_git_pass(git_index_write(idx)); + git_index_free(idx); + } + + status_counts_init( + counts, expected_files_with_broken, expected_status_with_broken); + cl_git_pass(git_status_foreach_ext( + g_repo, &opts, cb_status__match, &counts)); + cl_assert_equal_i(7, counts.entry_count); + + /* directory with tracked items that looks a little bit like a repo */ + + cl_must_pass(p_mkdir("submodules/broken/.git", 0777)); + cl_must_pass(p_mkdir("submodules/broken/.git/info", 0777)); + cl_git_mkfile("submodules/broken/.git/info/exclude", "# bogus"); + + status_counts_init( + counts, expected_files_with_broken, expected_status_with_broken); + cl_git_pass(git_status_foreach_ext( + g_repo, &opts, cb_status__match, &counts)); + cl_assert_equal_i(7, counts.entry_count); + + /* directory with tracked items that is a repo */ + + cl_git_pass(git_futils_rmdir_r( + "submodules/broken/.git", NULL, GIT_RMDIR_REMOVE_FILES)); + cl_git_pass(git_repository_init(&contained, "submodules/broken", false)); + git_repository_free(contained); + + status_counts_init( + counts, expected_files_with_broken, expected_status_with_broken); + cl_git_pass(git_status_foreach_ext( + g_repo, &opts, cb_status__match, &counts)); + cl_assert_equal_i(7, counts.entry_count); + + /* directory with tracked items that claims to be a submodule but is not */ + + cl_git_pass(git_futils_rmdir_r( + "submodules/broken/.git", NULL, GIT_RMDIR_REMOVE_FILES)); + cl_git_append2file("submodules/.gitmodules", + "\n[submodule \"broken\"]\n" + "\tpath = broken\n" + "\turl = https://github.com/not/used\n\n"); + + status_counts_init( + counts, expected_files_with_broken, expected_status_with_broken); + cl_git_pass(git_status_foreach_ext( + g_repo, &opts, cb_status__match, &counts)); + cl_assert_equal_i(7, counts.entry_count); +} + |