@@ -398,6 +398,98 @@ static VALUE rb_git_repo_init_at(int argc, VALUE *argv, VALUE klass)
398
398
return rugged_repo_new (klass , repo );
399
399
}
400
400
401
+ static int apply_cb_result (int exception , VALUE result )
402
+ {
403
+ if (exception || result == Qnil ) {
404
+ return GIT_EAPPLYFAIL ;
405
+ } else {
406
+ if (RTEST (result )) {
407
+ return 0 ;
408
+ } else {
409
+ return 1 ;
410
+ }
411
+ }
412
+ }
413
+
414
+ static int apply_delta_cb (const git_diff_delta * delta , void * data )
415
+ {
416
+ struct rugged_apply_cb_payload * payload = data ;
417
+ VALUE args = rb_ary_new2 (2 );
418
+ VALUE result ;
419
+
420
+ if (NIL_P (payload -> delta_cb ))
421
+ return 0 ;
422
+
423
+ VALUE rb_delta = rugged_diff_delta_new (Qnil , delta );
424
+
425
+ rb_ary_push (args , payload -> delta_cb );
426
+ rb_ary_push (args , rb_delta );
427
+
428
+ result = rb_protect (rugged__block_yield_splat , args , & payload -> exception );
429
+
430
+ return apply_cb_result (payload -> exception , result );
431
+ }
432
+
433
+ static int apply_hunk_cb (const git_diff_hunk * hunk , void * data )
434
+ {
435
+ struct rugged_apply_cb_payload * payload = data ;
436
+ VALUE args = rb_ary_new2 (2 );
437
+ VALUE result ;
438
+
439
+ if (NIL_P (payload -> hunk_cb ))
440
+ return 0 ;
441
+
442
+ VALUE rb_hunk = rugged_diff_hunk_new (Qnil , 0 , hunk , 0 );
443
+
444
+ rb_ary_push (args , payload -> hunk_cb );
445
+ rb_ary_push (args , rb_hunk );
446
+
447
+ result = rb_protect (rugged__block_yield_splat , args , & payload -> exception );
448
+
449
+ return apply_cb_result (payload -> exception , result );
450
+ }
451
+
452
+ static void rugged_parse_apply_options (git_apply_options * opts , git_apply_location_t * location , VALUE rb_options , struct rugged_apply_cb_payload * payload )
453
+ {
454
+ if (!NIL_P (rb_options )) {
455
+ VALUE rb_value ;
456
+ Check_Type (rb_options , T_HASH );
457
+
458
+ rb_value = rb_hash_aref (rb_options , CSTR2SYM ("location" ));
459
+ if (!NIL_P (rb_value )) {
460
+ ID id_location ;
461
+
462
+ Check_Type (rb_value , T_SYMBOL );
463
+ id_location = SYM2ID (rb_value );
464
+
465
+ if (id_location == rb_intern ("both" )) {
466
+ * location = GIT_APPLY_LOCATION_BOTH ;
467
+ } else if (id_location == rb_intern ("index" )) {
468
+ * location = GIT_APPLY_LOCATION_INDEX ;
469
+ } else if (id_location == rb_intern ("workdir" )) {
470
+ * location = GIT_APPLY_LOCATION_WORKDIR ;
471
+ } else {
472
+ rb_raise (rb_eTypeError ,
473
+ "Invalid location. Expected `:both`, `:index`, or `:workdir`" );
474
+ }
475
+ }
476
+
477
+ opts -> payload = payload ;
478
+
479
+ payload -> delta_cb = rb_hash_aref (rb_options , CSTR2SYM ("delta_callback" ));
480
+ if (!NIL_P (payload -> delta_cb )) {
481
+ CALLABLE_OR_RAISE (payload -> delta_cb , "delta_callback" );
482
+ opts -> delta_cb = apply_delta_cb ;
483
+ }
484
+
485
+ payload -> hunk_cb = rb_hash_aref (rb_options , CSTR2SYM ("hunk_callback" ));
486
+ if (!NIL_P (payload -> hunk_cb )) {
487
+ CALLABLE_OR_RAISE (payload -> hunk_cb , "hunk_callback" );
488
+ opts -> hunk_cb = apply_hunk_cb ;
489
+ }
490
+ }
491
+ }
492
+
401
493
static void parse_clone_options (git_clone_options * ret , VALUE rb_options , struct rugged_remote_cb_payload * remote_payload )
402
494
{
403
495
VALUE val ;
@@ -875,14 +967,34 @@ static VALUE rb_git_repo_revert_commit(int argc, VALUE *argv, VALUE self)
875
967
* repo.apply(diff, options = {}) -> true or false
876
968
*
877
969
* Applies the given diff to the repository.
970
+ * The following options can be passed in the +options+ Hash:
971
+ *
972
+ * :location ::
973
+ * Whether to apply the changes to the workdir (default),
974
+ * the index, or both. Valid values: +:index+, +:workdir+, +:both+.
975
+ *
976
+ * :delta_callback ::
977
+ * While applying the patch, this callback will be executed per delta (file).
978
+ * The current +delta+ will be passed to the block. The block's return value
979
+ * determines further behavior. When the block evaluates to:
980
+ * - +true+: the hunk will be applied and the apply process will continue.
981
+ * - +false+: the hunk will be skipped, but the apply process continues.
982
+ * - +nil+: the hunk is not applied, and the apply process is aborted.
983
+ *
984
+ * :hunk_callback ::
985
+ * While applying the patch, this callback will be executed per hunk.
986
+ * The current +hunk+ will be passed to the block. The block's return value
987
+ * determines further behavior, as per :delta_callback.
988
+ *
878
989
*/
879
990
static VALUE rb_git_repo_apply (int argc , VALUE * argv , VALUE self )
880
991
{
881
992
VALUE rb_diff , rb_options ;
882
993
git_diff * diff ;
883
994
git_repository * repo ;
884
995
git_apply_options opts = GIT_APPLY_OPTIONS_INIT ;
885
- git_apply_location_t location = GIT_APPLY_LOCATION_BOTH ;
996
+ git_apply_location_t location = GIT_APPLY_LOCATION_WORKDIR ;
997
+ struct rugged_apply_cb_payload payload = { Qnil , Qnil , 0 };
886
998
int error ;
887
999
888
1000
rb_scan_args (argc , argv , "11" , & rb_diff , & rb_options );
@@ -893,7 +1005,7 @@ static VALUE rb_git_repo_apply(int argc, VALUE *argv, VALUE self)
893
1005
894
1006
if (!NIL_P (rb_options )) {
895
1007
Check_Type (rb_options , T_HASH );
896
- rugged_parse_apply_options (& opts , & location , rb_options );
1008
+ rugged_parse_apply_options (& opts , & location , rb_options , & payload );
897
1009
}
898
1010
899
1011
Data_Get_Struct (self , git_repository , repo );
@@ -2581,33 +2693,6 @@ static VALUE rb_git_repo_cherrypick_commit(int argc, VALUE *argv, VALUE self)
2581
2693
return rugged_index_new (rb_cRuggedIndex , self , index );
2582
2694
}
2583
2695
2584
- void rugged_parse_apply_options (git_apply_options * opts , git_apply_location_t * location , VALUE rb_options )
2585
- {
2586
- if (!NIL_P (rb_options )) {
2587
- VALUE rb_value ;
2588
- Check_Type (rb_options , T_HASH );
2589
-
2590
- rb_value = rb_hash_aref (rb_options , CSTR2SYM ("location" ));
2591
- if (!NIL_P (rb_value )) {
2592
- ID id_location ;
2593
-
2594
- Check_Type (rb_value , T_SYMBOL );
2595
- id_location = SYM2ID (rb_value );
2596
-
2597
- if (id_location == rb_intern ("both" )) {
2598
- * location = GIT_APPLY_LOCATION_BOTH ;
2599
- } else if (id_location == rb_intern ("index" )) {
2600
- * location = GIT_APPLY_LOCATION_INDEX ;
2601
- } else if (id_location == rb_intern ("workdir" )) {
2602
- * location = GIT_APPLY_LOCATION_WORKDIR ;
2603
- } else {
2604
- rb_raise (rb_eTypeError ,
2605
- "Invalid location. Expected `:both`, `:index`, or `:workdir`" );
2606
- }
2607
- }
2608
- }
2609
- }
2610
-
2611
2696
void Init_rugged_repo (void )
2612
2697
{
2613
2698
id_call = rb_intern ("call" );
0 commit comments