Commit 0cb24616 by Russell Belfer

Merge pull request #942 from nulltoken/topic/checkout-notify-skipped

checkout: add notification callback for skipped files
parents 73f6da66 9e592583
...@@ -36,6 +36,21 @@ typedef struct git_checkout_opts { ...@@ -36,6 +36,21 @@ typedef struct git_checkout_opts {
int file_mode; /* default is 0644 */ int file_mode; /* default is 0644 */
int file_open_flags; /* default is O_CREAT | O_TRUNC | O_WRONLY */ 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 /* when not NULL, arrays of fnmatch pattern specifying
* which paths should be taken into account * which paths should be taken into account
*/ */
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
struct checkout_diff_data struct checkout_diff_data
{ {
git_buf *path; git_buf *path;
int workdir_len; size_t workdir_len;
git_checkout_opts *checkout_opts; git_checkout_opts *checkout_opts;
git_indexer_stats *stats; git_indexer_stats *stats;
git_repository *owner; git_repository *owner;
...@@ -35,7 +35,7 @@ struct checkout_diff_data ...@@ -35,7 +35,7 @@ struct checkout_diff_data
static int buffer_to_file( static int buffer_to_file(
git_buf *buffer, git_buf *buffer,
const char *path, const char *path,
int dir_mode, mode_t dir_mode,
int file_open_flags, int file_open_flags,
mode_t file_mode) mode_t file_mode)
{ {
...@@ -56,10 +56,11 @@ static int buffer_to_file( ...@@ -56,10 +56,11 @@ static int buffer_to_file(
static int blob_content_to_file( static int blob_content_to_file(
git_blob *blob, git_blob *blob,
const char *path, const char *path,
unsigned int entry_filemode, mode_t entry_filemode,
git_checkout_opts *opts) 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; bool dont_free_filtered = false;
git_buf unfiltered = GIT_BUF_INIT, filtered = GIT_BUF_INIT; git_buf unfiltered = GIT_BUF_INIT, filtered = GIT_BUF_INIT;
git_vector filters = GIT_VECTOR_INIT; git_vector filters = GIT_VECTOR_INIT;
...@@ -127,7 +128,7 @@ static int checkout_blob( ...@@ -127,7 +128,7 @@ static int checkout_blob(
git_repository *repo, git_repository *repo,
git_oid *blob_oid, git_oid *blob_oid,
const char *path, const char *path,
unsigned int filemode, mode_t filemode,
bool can_symlink, bool can_symlink,
git_checkout_opts *opts) git_checkout_opts *opts)
{ {
...@@ -154,6 +155,7 @@ static int checkout_diff_fn( ...@@ -154,6 +155,7 @@ static int checkout_diff_fn(
{ {
struct checkout_diff_data *data; struct checkout_diff_data *data;
int error = -1; int error = -1;
git_checkout_opts *opts;
data = (struct checkout_diff_data *)cb_data; data = (struct checkout_diff_data *)cb_data;
...@@ -163,9 +165,11 @@ static int checkout_diff_fn( ...@@ -163,9 +165,11 @@ static int checkout_diff_fn(
if (git_buf_joinpath(data->path, git_buf_cstr(data->path), delta->new_file.path) < 0) if (git_buf_joinpath(data->path, git_buf_cstr(data->path), delta->new_file.path) < 0)
return -1; return -1;
opts = data->checkout_opts;
switch (delta->status) { switch (delta->status) {
case GIT_DELTA_UNTRACKED: case GIT_DELTA_UNTRACKED:
if (!(data->checkout_opts->checkout_strategy & GIT_CHECKOUT_REMOVE_UNTRACKED)) if (!(opts->checkout_strategy & GIT_CHECKOUT_REMOVE_UNTRACKED))
return 0; return 0;
if (!git__suffixcmp(delta->new_file.path, "/")) if (!git__suffixcmp(delta->new_file.path, "/"))
...@@ -175,8 +179,20 @@ static int checkout_diff_fn( ...@@ -175,8 +179,20 @@ static int checkout_diff_fn(
break; break;
case GIT_DELTA_MODIFIED: 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; return 0;
}
if (checkout_blob( if (checkout_blob(
data->owner, data->owner,
...@@ -184,13 +200,13 @@ static int checkout_diff_fn( ...@@ -184,13 +200,13 @@ static int checkout_diff_fn(
git_buf_cstr(data->path), git_buf_cstr(data->path),
delta->old_file.mode, delta->old_file.mode,
data->can_symlink, data->can_symlink,
data->checkout_opts) < 0) opts) < 0)
goto cleanup; goto cleanup;
break; break;
case GIT_DELTA_DELETED: case GIT_DELTA_DELETED:
if (!(data->checkout_opts->checkout_strategy & GIT_CHECKOUT_CREATE_MISSING)) if (!(opts->checkout_strategy & GIT_CHECKOUT_CREATE_MISSING))
return 0; return 0;
if (checkout_blob( if (checkout_blob(
...@@ -199,7 +215,7 @@ static int checkout_diff_fn( ...@@ -199,7 +215,7 @@ static int checkout_diff_fn(
git_buf_cstr(data->path), git_buf_cstr(data->path),
delta->old_file.mode, delta->old_file.mode,
data->can_symlink, data->can_symlink,
data->checkout_opts) < 0) opts) < 0)
goto cleanup; goto cleanup;
break; break;
...@@ -377,4 +393,3 @@ int git_checkout_head( ...@@ -377,4 +393,3 @@ int git_checkout_head(
return error; return error;
} }
...@@ -1354,9 +1354,9 @@ int git_diff_iterator_num_lines_in_hunk(git_diff_iterator *iter) ...@@ -1354,9 +1354,9 @@ int git_diff_iterator_num_lines_in_hunk(git_diff_iterator *iter)
return error; return error;
if (iter->hunk_curr) if (iter->hunk_curr)
return iter->hunk_curr->line_count; return (int)iter->hunk_curr->line_count;
if (iter->hunk_head) if (iter->hunk_head)
return iter->hunk_head->line_count; return (int)iter->hunk_head->line_count;
return 0; return 0;
} }
......
...@@ -166,7 +166,7 @@ static int send_request(transport_http *t, const char *service, void *data, ssiz ...@@ -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, 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"); giterr_set(GITERR_OS, "Failed to send request");
goto on_error; goto on_error;
} }
......
...@@ -72,7 +72,7 @@ void git__utf8_to_16(wchar_t *dest, size_t length, const char *src) ...@@ -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) 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) void git__utf16_to_8(char *out, const wchar_t *input)
......
...@@ -287,3 +287,76 @@ void test_checkout_index__options_open_flags(void) ...@@ -287,3 +287,76 @@ void test_checkout_index__options_open_flags(void)
test_file_contents("./testrepo/new.txt", "hi\nmy new file\n"); 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));
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment