summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@microsoft.com>2015-05-01 18:34:38 -0400
committerEdward Thomson <ethomson@microsoft.com>2015-05-11 14:12:42 -0400
commit4ea3eebf4b53274b885f749f543101f6633c665e (patch)
tree527861b4c15a3780418dc9ffa11b828a2af7f2da
parent19c80a6fd1cfc0300e3a99f72fb8056431ba521e (diff)
downloadlibgit2-4ea3eebf4b53274b885f749f543101f6633c665e.tar.gz
stash_apply: provide progress callbacks
-rw-r--r--include/git2/stash.h38
-rw-r--r--src/stash.c26
-rw-r--r--tests/stash/apply.c45
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));
+}