Commit af33210b735b760debc03ce558ff62c3834f0a5b

Edward Thomson 2018-07-10T16:10:03

apply: introduce a delta callback Introduce a callback to the application options that allow callers to add a per-delta callback. The callback can return an error code to stop patch application, or can return a value to skip the application of a particular delta.

diff --git a/include/git2/apply.h b/include/git2/apply.h
index cdeb9ed..eb9cad4 100644
--- a/include/git2/apply.h
+++ b/include/git2/apply.h
@@ -22,6 +22,22 @@
 GIT_BEGIN_DECL
 
 /**
+ * When applying a patch, callback that will be made per delta (file).
+ *
+ * When the callback:
+ * - returns < 0, the apply process will be aborted.
+ * - returns > 0, the delta will not be applied, but the apply process
+ *      continues
+ * - returns 0, the delta is applied, and the apply process continues.
+ *
+ * @param delta The delta to be applied
+ * @param payload User-specified payload
+ */
+typedef int (*git_apply_delta_cb)(
+	const git_diff_delta *delta,
+	void *payload);
+
+/**
  * Apply options structure
  *
  * Initialize with `GIT_APPLY_OPTIONS_INIT`. Alternatively, you can
@@ -31,6 +47,9 @@ GIT_BEGIN_DECL
  */
 typedef struct {
 	unsigned int version;
+
+	git_apply_delta_cb delta_cb;
+	void *payload;
 } git_apply_options;
 
 #define GIT_APPLY_OPTIONS_VERSION 1
diff --git a/src/apply.c b/src/apply.c
index e6c2ae1..9534267 100644
--- a/src/apply.c
+++ b/src/apply.c
@@ -390,7 +390,8 @@ static int apply_one(
 	git_index *preimage,
 	git_index *postimage,
 	git_diff *diff,
-	size_t i)
+	size_t i,
+	const git_apply_options *opts)
 {
 	git_patch *patch = NULL;
 	git_buf pre_contents = GIT_BUF_INIT, post_contents = GIT_BUF_INIT;
@@ -406,6 +407,17 @@ static int apply_one(
 
 	delta = git_patch_get_delta(patch);
 
+	if (opts->delta_cb) {
+		error = opts->delta_cb(delta, opts->payload);
+
+		if (error) {
+			if (error > 0)
+				error = 0;
+
+			goto done;
+		}
+	}
+
 	if (delta->status != GIT_DELTA_ADDED) {
 		error = git_reader_read(&pre_contents, &pre_id,
 			preimage_reader, delta->old_file.path);
@@ -514,7 +526,7 @@ int git_apply_to_tree(
 	}
 
 	for (i = 0; i < git_diff_num_deltas(diff); i++) {
-		if ((error = apply_one(repo, pre_reader, NULL, postimage, diff, i)) < 0)
+		if ((error = apply_one(repo, pre_reader, NULL, postimage, diff, i, &opts)) < 0)
 			goto done;
 	}
 
@@ -700,7 +712,7 @@ int git_apply(
 		goto done;
 
 	for (i = 0; i < git_diff_num_deltas(diff); i++) {
-		if ((error = apply_one(repo, pre_reader, preimage, postimage, diff, i)) < 0)
+		if ((error = apply_one(repo, pre_reader, preimage, postimage, diff, i, &opts)) < 0)
 			goto done;
 	}