Merge branch 'pr/3147'
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6ade3e3..0b2e433 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,11 @@ v0.23 + 1
the opportunity for concurrent operations and not committing any
changes until the unlock.
+* `git_diff_options` added a new callback `progress_cb` to report on the
+ progress of the diff as files are being compared. The documentation of
+ the existing callback `notify_cb` was updated to reflect that it only
+ gets called when new deltas are added to the diff.
+
### API removals
### Breaking API changes
@@ -36,6 +41,9 @@ v0.23 + 1
it existed in the index. This does not affect the higher-level
`git_index_add_bypath` or `git_index_add_frombuffer` functions.
+* The `notify_payload` field of `git_diff_options` was renamed to `payload`
+ to reflect that it's also the payload for the new progress callback.
+
v0.23
------
diff --git a/include/git2/diff.h b/include/git2/diff.h
index a0f6db3..cbffdb4 100644
--- a/include/git2/diff.h
+++ b/include/git2/diff.h
@@ -351,6 +351,22 @@ typedef int (*git_diff_notify_cb)(
void *payload);
/**
+ * Diff progress callback.
+ *
+ * Called before each file comparison.
+ *
+ * @param diff_so_far The diff being generated.
+ * @param old_path The path to the old file or NULL.
+ * @param new_path The path to the new file or NULL.
+ * @return Non-zero to abort the diff.
+ */
+typedef int (*git_diff_progress_cb)(
+ const git_diff *diff_so_far,
+ const char *old_path,
+ const char *new_path,
+ void *payload);
+
+/**
* Structure describing options about how the diff should be executed.
*
* Setting all values of the structure to zero will yield the default
@@ -370,8 +386,10 @@ typedef int (*git_diff_notify_cb)(
* - `max_size` is a file size (in bytes) above which a blob will be marked
* as binary automatically; pass a negative value to disable.
* - `notify_cb` is an optional callback function, notifying the consumer of
- * which files are being examined as the diff is generated
- * - `notify_payload` is the payload data to pass to the `notify_cb` function
+ * changes to the diff as new deltas are added.
+ * - `progress_cb` is an optional callback function, notifying the consumer of
+ * which files are being examined as the diff is generated.
+ * - `payload` is the payload to pass to the callback functions.
* - `ignore_submodules` overrides the submodule ignore setting for all
* submodules in the diff.
*/
@@ -383,8 +401,9 @@ typedef struct {
git_submodule_ignore_t ignore_submodules; /**< submodule ignore rule */
git_strarray pathspec; /**< defaults to include all paths */
- git_diff_notify_cb notify_cb;
- void *notify_payload;
+ git_diff_notify_cb notify_cb;
+ git_diff_progress_cb progress_cb;
+ void *payload;
/* options controlling how to diff text is generated */
@@ -403,7 +422,7 @@ typedef struct {
* `git_diff_options_init` programmatic initialization.
*/
#define GIT_DIFF_OPTIONS_INIT \
- {GIT_DIFF_OPTIONS_VERSION, 0, GIT_SUBMODULE_IGNORE_UNSPECIFIED, {NULL,0}, NULL, NULL, 3}
+ {GIT_DIFF_OPTIONS_VERSION, 0, GIT_SUBMODULE_IGNORE_UNSPECIFIED, {NULL,0}, NULL, NULL, NULL, 3}
/**
* Initializes a `git_diff_options` with default values. Equivalent to
diff --git a/src/diff.c b/src/diff.c
index b5e9b6c..c236235 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -56,7 +56,7 @@ static int diff_insert_delta(
if (diff->opts.notify_cb) {
error = diff->opts.notify_cb(
- diff, delta, matched_pathspec, diff->opts.notify_payload);
+ diff, delta, matched_pathspec, diff->opts.payload);
if (error) {
git__free(delta);
@@ -1260,7 +1260,18 @@ int git_diff__from_iterators(
/* run iterators building diffs */
while (!error && (info.oitem || info.nitem)) {
- int cmp = info.oitem ?
+ int cmp;
+
+ /* report progress */
+ if (opts && opts->progress_cb) {
+ if ((error = opts->progress_cb(diff,
+ info.oitem ? info.oitem->path : NULL,
+ info.nitem ? info.nitem->path : NULL,
+ opts->payload)))
+ break;
+ }
+
+ cmp = info.oitem ?
(info.nitem ? diff->entrycomp(info.oitem, info.nitem) : -1) : 1;
/* create DELETED records for old items not matched in new */
diff --git a/tests/diff/notify.c b/tests/diff/notify.c
index 6ef4af5..74abbc9 100644
--- a/tests/diff/notify.c
+++ b/tests/diff/notify.c
@@ -55,7 +55,7 @@ static void test_notify(
opts.pathspec.strings = searched_pathspecs;
opts.pathspec.count = pathspecs_count;
- opts.notify_payload = expected_matched_pathspecs;
+ opts.payload = expected_matched_pathspecs;
memset(&exp, 0, sizeof(exp));
cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
@@ -228,3 +228,30 @@ void test_diff_notify__notify_cb_can_be_used_as_filtering_function(void)
git_diff_free(diff);
}
+
+static int progress_abort_diff(
+ const git_diff *diff_so_far,
+ const char *old_path,
+ const char *new_path,
+ void *payload)
+{
+ GIT_UNUSED(old_path);
+ GIT_UNUSED(new_path);
+ GIT_UNUSED(payload);
+
+ return -42;
+}
+
+void test_diff_notify__progress_cb_can_abort_diff(void)
+{
+ git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
+ git_diff *diff = NULL;
+
+ g_repo = cl_git_sandbox_init("status");
+
+ opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED;
+ opts.progress_cb = progress_abort_diff;
+
+ cl_git_fail_with(
+ git_diff_index_to_workdir(&diff, g_repo, NULL, &opts), -42);
+}
diff --git a/tests/diff/tree.c b/tests/diff/tree.c
index 2bc9e6a..e4b2a8b 100644
--- a/tests/diff/tree.c
+++ b/tests/diff/tree.c
@@ -90,7 +90,7 @@ void test_diff_tree__0(void)
#define DIFF_OPTS(FLAGS, CTXT) \
{GIT_DIFF_OPTIONS_VERSION, (FLAGS), GIT_SUBMODULE_IGNORE_UNSPECIFIED, \
- {NULL,0}, NULL, NULL, (CTXT), 1}
+ {NULL,0}, NULL, NULL, NULL, (CTXT), 1}
void test_diff_tree__options(void)
{