Commit 4ea3eebf by Edward Thomson

stash_apply: provide progress callbacks

parent 19c80a6f
......@@ -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
......
......@@ -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)
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);
......
......@@ -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));
}
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