diff options
-rw-r--r-- | src/diff_file.c | 25 | ||||
-rw-r--r-- | tests/diff/workdir.c | 61 | ||||
-rw-r--r-- | tests/index/bypath.c | 29 |
3 files changed, 115 insertions, 0 deletions
diff --git a/src/diff_file.c b/src/diff_file.c index c60362865..ecc34cf55 100644 --- a/src/diff_file.c +++ b/src/diff_file.c @@ -259,10 +259,35 @@ static int diff_file_content_load_blob( return error; } +static int diff_file_content_load_workdir_symlink_fake( + git_diff_file_content *fc, git_buf *path) +{ + git_buf target = GIT_BUF_INIT; + int error; + + if ((error = git_futils_readbuffer(&target, path->ptr)) < 0) + return error; + + fc->map.len = git_buf_len(&target); + fc->map.data = git_buf_detach(&target); + fc->flags |= GIT_DIFF_FLAG__FREE_DATA; + + git_buf_free(&target); + return error; +} + static int diff_file_content_load_workdir_symlink( git_diff_file_content *fc, git_buf *path) { ssize_t alloc_len, read_len; + int symlink_supported, error; + + if ((error = git_repository__cvar( + &symlink_supported, fc->repo, GIT_CVAR_SYMLINKS)) < 0) + return -1; + + if (!symlink_supported) + return diff_file_content_load_workdir_symlink_fake(fc, path); /* link path on disk could be UTF-16, so prepare a buffer that is * big enough to handle some UTF-8 data expansion diff --git a/tests/diff/workdir.c b/tests/diff/workdir.c index dac32453b..4c782339d 100644 --- a/tests/diff/workdir.c +++ b/tests/diff/workdir.c @@ -2097,3 +2097,64 @@ void test_diff_workdir__to_index_pathlist(void) git_vector_free(&pathlist); } +void test_diff_workdir__symlink_changed_on_non_symlink_platform(void) +{ + git_tree *tree; + git_diff *diff; + diff_expects exp = {0}; + const git_diff_delta *delta; + const char *commit = "7fccd7"; + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_vector pathlist = GIT_VECTOR_INIT; + int symlinks; + + g_repo = cl_git_sandbox_init("unsymlinked.git"); + + cl_git_pass(git_repository__cvar(&symlinks, g_repo, GIT_CVAR_SYMLINKS)); + + if (symlinks) + cl_skip(); + + cl_git_pass(git_vector_insert(&pathlist, "include/Nu/Nu.h")); + + opts.pathspec.strings = (char **)pathlist.contents; + opts.pathspec.count = pathlist.length; + + cl_must_pass(p_mkdir("symlink", 0777)); + cl_git_pass(git_repository_set_workdir(g_repo, "symlink", false)); + + cl_assert((tree = resolve_commit_oid_to_tree(g_repo, commit)) != NULL); + + /* first, do the diff with the original contents */ + + cl_git_pass(git_futils_mkpath2file("symlink/include/Nu/Nu.h", 0755)); + cl_git_mkfile("symlink/include/Nu/Nu.h", "../../objc/Nu.h"); + + cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, tree, &opts)); + cl_assert_equal_i(0, git_diff_num_deltas(diff)); + git_diff_free(diff); + + /* now update the contents and expect a difference, but that the file + * mode has persisted as a symbolic link. + */ + + cl_git_rewritefile("symlink/include/Nu/Nu.h", "awesome content\n"); + + cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, tree, &opts)); + + cl_git_pass(git_diff_foreach( + diff, diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &exp)); + cl_assert_equal_i(1, exp.files); + + cl_assert_equal_i(1, git_diff_num_deltas(diff)); + delta = git_diff_get_delta(diff, 0); + cl_assert_equal_i(GIT_FILEMODE_LINK, delta->old_file.mode); + cl_assert_equal_i(GIT_FILEMODE_LINK, delta->new_file.mode); + + git_diff_free(diff); + + cl_git_pass(git_futils_rmdir_r("symlink", NULL, GIT_RMDIR_REMOVE_FILES)); + + git_tree_free(tree); + git_vector_free(&pathlist); +} diff --git a/tests/index/bypath.c b/tests/index/bypath.c index 0c10cfe4c..88a76178a 100644 --- a/tests/index/bypath.c +++ b/tests/index/bypath.c @@ -328,3 +328,32 @@ void test_index_bypath__add_honors_conflict_case(void) cl_assert((entry = git_index_get_bypath(g_idx, "README.txt", 0)) != NULL); cl_assert_equal_i(GIT_FILEMODE_BLOB_EXECUTABLE, entry->mode); } + +void test_index_bypath__add_honors_symlink(void) +{ + const git_index_entry *entry; + git_index_entry new_entry; + int symlinks; + + cl_git_pass(git_repository__cvar(&symlinks, g_repo, GIT_CVAR_SYMLINKS)); + + if (symlinks) + cl_skip(); + + cl_assert((entry = git_index_get_bypath(g_idx, "README.txt", 0)) != NULL); + + memcpy(&new_entry, entry, sizeof(git_index_entry)); + new_entry.path = "README.txt"; + new_entry.mode = GIT_FILEMODE_LINK; + + cl_git_pass(git_index_add(g_idx, &new_entry)); + cl_git_pass(git_index_write(g_idx)); + + cl_git_rewritefile("submod2/README.txt", "Modified but still a (fake) symlink"); + + cl_git_pass(git_index_add_bypath(g_idx, "README.txt")); + cl_git_pass(git_index_write(g_idx)); + + cl_assert((entry = git_index_get_bypath(g_idx, "README.txt", 0)) != NULL); + cl_assert_equal_i(GIT_FILEMODE_LINK, entry->mode); +} |