From 28abf3dbd27c232acd7dd17c6a642c793a3c80c9 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Thu, 20 Sep 2012 11:41:49 +0200 Subject: [PATCH 1/3] checkout: prefer mode_t type usage over int --- src/checkout.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/checkout.c b/src/checkout.c index b20bd57e8..730e8a499 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -35,7 +35,7 @@ struct checkout_diff_data static int buffer_to_file( git_buf *buffer, const char *path, - int dir_mode, + mode_t dir_mode, int file_open_flags, mode_t file_mode) { @@ -56,10 +56,11 @@ static int buffer_to_file( static int blob_content_to_file( git_blob *blob, const char *path, - unsigned int entry_filemode, + mode_t entry_filemode, git_checkout_opts *opts) { - int error, nb_filters = 0, file_mode = opts->file_mode; + int error, nb_filters = 0; + mode_t file_mode = opts->file_mode; bool dont_free_filtered = false; git_buf unfiltered = GIT_BUF_INIT, filtered = GIT_BUF_INIT; git_vector filters = GIT_VECTOR_INIT; @@ -127,7 +128,7 @@ static int checkout_blob( git_repository *repo, git_oid *blob_oid, const char *path, - unsigned int filemode, + mode_t filemode, bool can_symlink, git_checkout_opts *opts) { From 9ac8b113b18e04d4d6f0573e3a6c5e06c447dbf3 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Thu, 20 Sep 2012 14:06:49 +0200 Subject: [PATCH 2/3] Fix MSVC amd64 compilation warnings --- src/checkout.c | 2 +- src/diff_output.c | 4 ++-- src/transports/http.c | 2 +- src/win32/utf-conv.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/checkout.c b/src/checkout.c index 730e8a499..89f73549f 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -25,7 +25,7 @@ struct checkout_diff_data { git_buf *path; - int workdir_len; + size_t workdir_len; git_checkout_opts *checkout_opts; git_indexer_stats *stats; git_repository *owner; diff --git a/src/diff_output.c b/src/diff_output.c index 37cceff92..58a1a3567 100644 --- a/src/diff_output.c +++ b/src/diff_output.c @@ -1354,9 +1354,9 @@ int git_diff_iterator_num_lines_in_hunk(git_diff_iterator *iter) return error; if (iter->hunk_curr) - return iter->hunk_curr->line_count; + return (int)iter->hunk_curr->line_count; if (iter->hunk_head) - return iter->hunk_head->line_count; + return (int)iter->hunk_head->line_count; return 0; } diff --git a/src/transports/http.c b/src/transports/http.c index 456b85e3f..d5015f5af 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -166,7 +166,7 @@ static int send_request(transport_http *t, const char *service, void *data, ssiz } if (WinHttpSendRequest(t->request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, - data, content_length, content_length, 0) == FALSE) { + data, (DWORD)content_length, (DWORD)content_length, 0) == FALSE) { giterr_set(GITERR_OS, "Failed to send request"); goto on_error; } diff --git a/src/win32/utf-conv.c b/src/win32/utf-conv.c index 88a84141e..396af7cad 100644 --- a/src/win32/utf-conv.c +++ b/src/win32/utf-conv.c @@ -72,7 +72,7 @@ void git__utf8_to_16(wchar_t *dest, size_t length, const char *src) void git__utf8_to_16(wchar_t *dest, size_t length, const char *src) { - MultiByteToWideChar(CP_UTF8, 0, src, -1, dest, length); + MultiByteToWideChar(CP_UTF8, 0, src, -1, dest, (int)length); } void git__utf16_to_8(char *out, const wchar_t *input) From 9e592583fc5fcd7eec5d40d30e34870e6a029fef Mon Sep 17 00:00:00 2001 From: nulltoken Date: Wed, 19 Sep 2012 12:23:47 +0200 Subject: [PATCH 3/3] checkout: add notification callback for skipped files --- include/git2/checkout.h | 15 ++++++++ src/checkout.c | 26 ++++++++++--- tests-clar/checkout/index.c | 73 +++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 6 deletions(-) diff --git a/include/git2/checkout.h b/include/git2/checkout.h index 42d47003d..ef3badbe9 100644 --- a/include/git2/checkout.h +++ b/include/git2/checkout.h @@ -36,6 +36,21 @@ typedef struct git_checkout_opts { int file_mode; /* default is 0644 */ int file_open_flags; /* default is O_CREAT | O_TRUNC | O_WRONLY */ + /* Optional callback to notify the consumer of files that + * haven't be checked out because a modified version of them + * exist in the working directory. + * + * When provided, this callback will be invoked when the flag + * GIT_CHECKOUT_OVERWRITE_MODIFIED isn't part of the checkout strategy. + */ + int (* skipped_notify_cb)( + const char *skipped_file, + const git_oid *blob_oid, + int file_mode, + void *payload); + + void *notify_payload; + /* when not NULL, arrays of fnmatch pattern specifying * which paths should be taken into account */ diff --git a/src/checkout.c b/src/checkout.c index 89f73549f..ea5e79abd 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -155,6 +155,7 @@ static int checkout_diff_fn( { struct checkout_diff_data *data; int error = -1; + git_checkout_opts *opts; data = (struct checkout_diff_data *)cb_data; @@ -164,9 +165,11 @@ static int checkout_diff_fn( if (git_buf_joinpath(data->path, git_buf_cstr(data->path), delta->new_file.path) < 0) return -1; + opts = data->checkout_opts; + switch (delta->status) { case GIT_DELTA_UNTRACKED: - if (!(data->checkout_opts->checkout_strategy & GIT_CHECKOUT_REMOVE_UNTRACKED)) + if (!(opts->checkout_strategy & GIT_CHECKOUT_REMOVE_UNTRACKED)) return 0; if (!git__suffixcmp(delta->new_file.path, "/")) @@ -176,8 +179,20 @@ static int checkout_diff_fn( break; case GIT_DELTA_MODIFIED: - if (!(data->checkout_opts->checkout_strategy & GIT_CHECKOUT_OVERWRITE_MODIFIED)) + if (!(opts->checkout_strategy & GIT_CHECKOUT_OVERWRITE_MODIFIED)) { + + if ((opts->skipped_notify_cb != NULL) + && (opts->skipped_notify_cb( + delta->new_file.path, + &delta->old_file.oid, + delta->old_file.mode, + opts->notify_payload))) { + giterr_clear(); + return GIT_EUSER; + } + return 0; + } if (checkout_blob( data->owner, @@ -185,13 +200,13 @@ static int checkout_diff_fn( git_buf_cstr(data->path), delta->old_file.mode, data->can_symlink, - data->checkout_opts) < 0) + opts) < 0) goto cleanup; break; case GIT_DELTA_DELETED: - if (!(data->checkout_opts->checkout_strategy & GIT_CHECKOUT_CREATE_MISSING)) + if (!(opts->checkout_strategy & GIT_CHECKOUT_CREATE_MISSING)) return 0; if (checkout_blob( @@ -200,7 +215,7 @@ static int checkout_diff_fn( git_buf_cstr(data->path), delta->old_file.mode, data->can_symlink, - data->checkout_opts) < 0) + opts) < 0) goto cleanup; break; @@ -378,4 +393,3 @@ int git_checkout_head( return error; } - diff --git a/tests-clar/checkout/index.c b/tests-clar/checkout/index.c index d1c59e38c..f017a0fe2 100644 --- a/tests-clar/checkout/index.c +++ b/tests-clar/checkout/index.c @@ -287,3 +287,76 @@ void test_checkout_index__options_open_flags(void) test_file_contents("./testrepo/new.txt", "hi\nmy new file\n"); } + +struct notify_data { + const char *file; + const char *sha; +}; + +static int notify_cb( + const char *skipped_file, + const git_oid *blob_oid, + int file_mode, + void *payload) +{ + struct notify_data *expectations = (struct notify_data *)payload; + + GIT_UNUSED(file_mode); + + cl_assert_equal_s(expectations->file, skipped_file); + cl_assert_equal_i(0, git_oid_streq(blob_oid, expectations->sha)); + + return 0; +} + +void test_checkout_index__can_notify_of_skipped_files(void) +{ + struct notify_data data; + + cl_git_mkfile("./testrepo/new.txt", "This isn't what's stored!"); + + /* + * $ git ls-tree HEAD + * 100644 blob a8233120f6ad708f843d861ce2b7228ec4e3dec6 README + * 100644 blob 3697d64be941a53d4ae8f6a271e4e3fa56b022cc branch_file.txt + * 100644 blob a71586c1dfe8a71c6cbf6c129f404c5642ff31bd new.txt + */ + data.file = "new.txt"; + data.sha = "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd"; + + g_opts.checkout_strategy = GIT_CHECKOUT_CREATE_MISSING; + g_opts.skipped_notify_cb = notify_cb; + g_opts.notify_payload = &data; + + cl_git_pass(git_checkout_index(g_repo, &g_opts, NULL)); +} + +static int dont_notify_cb( + const char *skipped_file, + const git_oid *blob_oid, + int file_mode, + void *payload) +{ + GIT_UNUSED(skipped_file); + GIT_UNUSED(blob_oid); + GIT_UNUSED(file_mode); + GIT_UNUSED(payload); + + cl_assert(false); + + return 0; +} + +void test_checkout_index__wont_notify_of_expected_line_ending_changes(void) +{ + cl_git_pass(p_unlink("./testrepo/.gitattributes")); + set_core_autocrlf_to(true); + + cl_git_mkfile("./testrepo/new.txt", "my new file\r\n"); + + g_opts.checkout_strategy = GIT_CHECKOUT_CREATE_MISSING; + g_opts.skipped_notify_cb = dont_notify_cb; + g_opts.notify_payload = NULL; + + cl_git_pass(git_checkout_index(g_repo, &g_opts, NULL)); +}