From 4ea3eebf4b53274b885f749f543101f6633c665e Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 1 May 2015 18:34:38 -0400 Subject: [PATCH] stash_apply: provide progress callbacks --- include/git2/stash.h | 38 +++++++++++++++++++++++++++++++++++++ src/stash.c | 26 ++++++++++++++++++++++--- tests/stash/apply.c | 45 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 3 deletions(-) diff --git a/include/git2/stash.h b/include/git2/stash.h index 1f773dcb0..526db0ba2 100644 --- a/include/git2/stash.h +++ b/include/git2/stash.h @@ -80,6 +80,40 @@ typedef enum { GIT_STASH_APPLY_REINSTATE_INDEX = (1 << 0), } git_stash_apply_flags; +typedef enum { + GIT_STASH_APPLY_PROGRESS_NONE = 0, + + /** Loading the stashed data from the object database. */ + GIT_STASH_APPLY_PROGRESS_LOADING_STASH, + + /** The stored index is being analyzed. */ + GIT_STASH_APPLY_PROGRESS_ANALYZE_INDEX, + + /** The modified files are being analyzed. */ + GIT_STASH_APPLY_PROGRESS_ANALYZE_MODIFIED, + + /** The untracked and ignored files are being analyzed. */ + GIT_STASH_APPLY_PROGRESS_ANALYZE_UNTRACKED, + + /** The untracked files are being written to disk. */ + GIT_STASH_APPLY_PROGRESS_CHECKOUT_UNTRACKED, + + /** The modified files are being written to disk. */ + GIT_STASH_APPLY_PROGRESS_CHECKOUT_MODIFIED, + + /** The stash was applied successfully. */ + GIT_STASH_APPLY_PROGRESS_DONE, +} git_stash_apply_progress_t; + +/** + * Stash application progress notification function. + * Return 0 to continue processing, or a negative value to + * abort the stash application. + */ +typedef int (*git_stash_apply_progress_cb)( + git_stash_apply_progress_t progress, + void *payload); + /** Stash application options structure. * * Initialize with the `GIT_STASH_APPLY_OPTIONS_INIT` macro to set @@ -95,6 +129,10 @@ typedef struct git_stash_apply_options { /** Options to use when writing files to the working directory. */ git_checkout_options checkout_options; + + /** Optional callback to notify the consumer of application progress. */ + git_stash_apply_progress_cb progress_cb; + void *progress_payload; } git_stash_apply_options; #define GIT_STASH_APPLY_OPTIONS_VERSION 1 diff --git a/src/stash.c b/src/stash.c index dade06f94..71ab7b945 100644 --- a/src/stash.c +++ b/src/stash.c @@ -701,6 +701,11 @@ int git_stash_apply_init_options(git_stash_apply_options *opts, unsigned int ver return 0; } +#define NOTIFY_PROGRESS(opts, progress_type) \ + if ((opts).progress_cb && \ + (error = (opts).progress_cb((progress_type), (opts).progress_payload))) \ + return (error < 0) ? error : -1; + int git_stash_apply( git_repository *repo, size_t index, @@ -725,6 +730,8 @@ int git_stash_apply( normalize_apply_options(&opts, given_opts); checkout_strategy = opts.checkout_options.checkout_strategy; + NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_LOADING_STASH); + /* Retrieve commit corresponding to the given stash */ if ((error = retrieve_stash_commit(&stash_commit, repo, index)) < 0) goto cleanup; @@ -739,6 +746,8 @@ int git_stash_apply( if ((error = git_repository_index(&repo_index, repo)) < 0) goto cleanup; + NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_ANALYZE_INDEX); + /* Restore index if required */ if ((opts.flags & GIT_STASH_APPLY_REINSTATE_INDEX) && git_oid_cmp(git_tree_id(stash_parent_tree), git_tree_id(index_tree))) { @@ -753,19 +762,26 @@ int git_stash_apply( } } + NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_ANALYZE_MODIFIED); + /* Restore modified files in workdir */ if ((error = merge_index_and_tree( &modified_index, repo, stash_parent_tree, repo_index, stash_tree)) < 0) goto cleanup; /* If applicable, restore untracked / ignored files in workdir */ - if (untracked_tree && - (error = merge_index_and_tree(&untracked_index, repo, NULL, repo_index, untracked_tree)) < 0) - goto cleanup; + if (untracked_tree) { + NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_ANALYZE_UNTRACKED); + + if ((error = merge_index_and_tree(&untracked_index, repo, NULL, repo_index, untracked_tree)) < 0) + goto cleanup; + } if (untracked_index) { opts.checkout_options.checkout_strategy |= GIT_CHECKOUT_DONT_UPDATE_INDEX; + NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_CHECKOUT_UNTRACKED); + if ((error = git_checkout_index(repo, untracked_index, &opts.checkout_options)) < 0) goto cleanup; @@ -787,6 +803,8 @@ int git_stash_apply( */ opts.checkout_options.baseline_index = repo_index; + NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_CHECKOUT_MODIFIED); + if ((error = git_checkout_index(repo, modified_index, &opts.checkout_options)) < 0) goto cleanup; @@ -795,6 +813,8 @@ int git_stash_apply( goto cleanup; } + NOTIFY_PROGRESS(opts, GIT_STASH_APPLY_PROGRESS_DONE); + cleanup: git_index_free(untracked_index); git_index_free(modified_index); diff --git a/tests/stash/apply.c b/tests/stash/apply.c index de330e9d3..213945e9b 100644 --- a/tests/stash/apply.c +++ b/tests/stash/apply.c @@ -286,3 +286,48 @@ void test_stash_apply__executes_notify_cb(void) cl_assert_equal_b(true, seen_paths.who); cl_assert_equal_b(true, seen_paths.when); } + +int progress_cb( + git_stash_apply_progress_t progress, + void *payload) +{ + git_stash_apply_progress_t *p = (git_stash_apply_progress_t *)payload; + + cl_assert_equal_i((*p)+1, progress); + + *p = progress; + + return 0; +} + +void test_stash_apply__calls_progress_cb(void) +{ + git_stash_apply_options opts = GIT_STASH_APPLY_OPTIONS_INIT; + git_stash_apply_progress_t progress = GIT_STASH_APPLY_PROGRESS_NONE; + + opts.progress_cb = progress_cb; + opts.progress_payload = &progress; + + cl_git_pass(git_stash_apply(repo, 0, &opts)); + cl_assert_equal_i(progress, GIT_STASH_APPLY_PROGRESS_DONE); +} + +int aborting_progress_cb( + git_stash_apply_progress_t progress, + void *payload) +{ + if (progress == GIT_STASH_APPLY_PROGRESS_ANALYZE_MODIFIED) + return -44; + + return 0; +} + +void test_stash_apply__progress_cb_can_abort(void) +{ + git_stash_apply_options opts = GIT_STASH_APPLY_OPTIONS_INIT; + git_stash_apply_progress_t progress = GIT_STASH_APPLY_PROGRESS_NONE; + + opts.progress_cb = aborting_progress_cb; + + cl_git_fail_with(-44, git_stash_apply(repo, 0, &opts)); +}