@@ -748,7 +748,7 @@ static int check_cert_push_options(const struct string_list *push_options)
748748 return retval ;
749749}
750750
751- static void prepare_push_cert_sha1 (struct child_process * proc )
751+ static void prepare_push_cert_sha1 (struct run_hooks_opt * opt )
752752{
753753 static int already_done ;
754754
@@ -774,195 +774,191 @@ static void prepare_push_cert_sha1(struct child_process *proc)
774774 nonce_status = check_nonce (sigcheck .payload );
775775 }
776776 if (!is_null_oid (& push_cert_oid )) {
777- strvec_pushf (& proc -> env , "GIT_PUSH_CERT=%s" ,
777+ strvec_pushf (& opt -> env , "GIT_PUSH_CERT=%s" ,
778778 oid_to_hex (& push_cert_oid ));
779- strvec_pushf (& proc -> env , "GIT_PUSH_CERT_SIGNER=%s" ,
779+ strvec_pushf (& opt -> env , "GIT_PUSH_CERT_SIGNER=%s" ,
780780 sigcheck .signer ? sigcheck .signer : "" );
781- strvec_pushf (& proc -> env , "GIT_PUSH_CERT_KEY=%s" ,
781+ strvec_pushf (& opt -> env , "GIT_PUSH_CERT_KEY=%s" ,
782782 sigcheck .key ? sigcheck .key : "" );
783- strvec_pushf (& proc -> env , "GIT_PUSH_CERT_STATUS=%c" ,
783+ strvec_pushf (& opt -> env , "GIT_PUSH_CERT_STATUS=%c" ,
784784 sigcheck .result );
785785 if (push_cert_nonce ) {
786- strvec_pushf (& proc -> env ,
786+ strvec_pushf (& opt -> env ,
787787 "GIT_PUSH_CERT_NONCE=%s" ,
788788 push_cert_nonce );
789- strvec_pushf (& proc -> env ,
789+ strvec_pushf (& opt -> env ,
790790 "GIT_PUSH_CERT_NONCE_STATUS=%s" ,
791791 nonce_status );
792792 if (nonce_status == NONCE_SLOP )
793- strvec_pushf (& proc -> env ,
793+ strvec_pushf (& opt -> env ,
794794 "GIT_PUSH_CERT_NONCE_SLOP=%ld" ,
795795 nonce_stamp_slop );
796796 }
797797 }
798798}
799799
800+ struct receive_hook_feed_context {
801+ struct command * cmd ;
802+ int skip_broken ;
803+ };
804+
800805struct receive_hook_feed_state {
801806 struct command * cmd ;
802807 struct ref_push_report * report ;
803808 int skip_broken ;
804809 struct strbuf buf ;
805- const struct string_list * push_options ;
806810};
807811
808- typedef int (* feed_fn )(void * , const char * * , size_t * );
809- static int run_and_feed_hook (const char * hook_name , feed_fn feed ,
810- struct receive_hook_feed_state * feed_state )
812+ static int feed_receive_hook (int hook_stdin_fd , struct receive_hook_feed_state * state , int lines_batch_size )
811813{
812- struct child_process proc = CHILD_PROCESS_INIT ;
813- struct async muxer ;
814- int code ;
815- const char * hook_path = find_hook (the_repository , hook_name );
814+ struct command * cmd = state -> cmd ;
816815
817- if (!hook_path )
818- return 0 ;
816+ strbuf_reset (& state -> buf );
819817
820- strvec_push (& proc .args , hook_path );
821- proc .in = -1 ;
822- proc .stdout_to_stderr = 1 ;
823- proc .trace2_hook_name = hook_name ;
824-
825- if (feed_state -> push_options ) {
826- size_t i ;
827- for (i = 0 ; i < feed_state -> push_options -> nr ; i ++ )
828- strvec_pushf (& proc .env ,
829- "GIT_PUSH_OPTION_%" PRIuMAX "=%s" ,
830- (uintmax_t )i ,
831- feed_state -> push_options -> items [i ].string );
832- strvec_pushf (& proc .env , "GIT_PUSH_OPTION_COUNT=%" PRIuMAX "" ,
833- (uintmax_t )feed_state -> push_options -> nr );
834- } else
835- strvec_pushf (& proc .env , "GIT_PUSH_OPTION_COUNT" );
818+ /* batch lines to avoid going through run-command's ppoll for each line */
819+ for (int i = 0 ; i < lines_batch_size ; i ++ ) {
820+ while (cmd &&
821+ state -> skip_broken && (cmd -> error_string || cmd -> did_not_exist ))
822+ cmd = cmd -> next ;
836823
837- if (tmp_objdir )
838- strvec_pushv ( & proc . env , tmp_objdir_env ( tmp_objdir ));
824+ if (! cmd )
825+ break ; /* no more commands left */
839826
840- if (use_sideband ) {
841- memset (& muxer , 0 , sizeof (muxer ));
842- muxer .proc = copy_to_sideband ;
843- muxer .in = -1 ;
844- code = start_async (& muxer );
845- if (code )
846- return code ;
847- proc .err = muxer .in ;
848- }
827+ if (!state -> report )
828+ state -> report = cmd -> report ;
849829
850- prepare_push_cert_sha1 (& proc );
830+ if (state -> report ) {
831+ struct object_id * old_oid ;
832+ struct object_id * new_oid ;
833+ const char * ref_name ;
851834
852- code = start_command (& proc );
853- if (code ) {
854- if (use_sideband )
855- finish_async (& muxer );
856- return code ;
857- }
835+ old_oid = state -> report -> old_oid ? state -> report -> old_oid : & cmd -> old_oid ;
836+ new_oid = state -> report -> new_oid ? state -> report -> new_oid : & cmd -> new_oid ;
837+ ref_name = state -> report -> ref_name ? state -> report -> ref_name : cmd -> ref_name ;
858838
859- sigchain_push (SIGPIPE , SIG_IGN );
839+ strbuf_addf (& state -> buf , "%s %s %s\n" ,
840+ oid_to_hex (old_oid ), oid_to_hex (new_oid ),
841+ ref_name );
860842
861- while (1 ) {
862- const char * buf ;
863- size_t n ;
864- if (feed (feed_state , & buf , & n ))
865- break ;
866- if (write_in_full (proc .in , buf , n ) < 0 )
867- break ;
843+ state -> report = state -> report -> next ;
844+ if (!state -> report )
845+ cmd = cmd -> next ;
846+ } else {
847+ strbuf_addf (& state -> buf , "%s %s %s\n" ,
848+ oid_to_hex (& cmd -> old_oid ), oid_to_hex (& cmd -> new_oid ),
849+ cmd -> ref_name );
850+ cmd = cmd -> next ;
851+ }
868852 }
869- close (proc .in );
870- if (use_sideband )
871- finish_async (& muxer );
872853
873- sigchain_pop ( SIGPIPE ) ;
854+ state -> cmd = cmd ;
874855
875- return finish_command (& proc );
856+ if (state -> buf .len > 0 ) {
857+ int ret = write_in_full (hook_stdin_fd , state -> buf .buf , state -> buf .len );
858+ if (ret < 0 ) {
859+ if (errno == EPIPE )
860+ return 1 ; /* child closed pipe */
861+ return ret ;
862+ }
863+ }
864+
865+ return state -> cmd ? 0 : 1 ; /* 0 = more to come, 1 = EOF */
876866}
877867
878- static int feed_receive_hook ( void * state_ , const char * * bufp , size_t * sizep )
868+ static int feed_receive_hook_cb ( int hook_stdin_fd , void * pp_cb , void * pp_task_cb UNUSED )
879869{
880- struct receive_hook_feed_state * state = state_ ;
881- struct command * cmd = state -> cmd ;
870+ struct hook_cb_data * hook_cb = pp_cb ;
871+ struct receive_hook_feed_state * feed_state = hook_cb -> options -> feed_pipe_cb_data ;
882872
883- while (cmd &&
884- state -> skip_broken && (cmd -> error_string || cmd -> did_not_exist ))
885- cmd = cmd -> next ;
886- if (!cmd )
887- return -1 ; /* EOF */
888- if (!bufp )
889- return 0 ; /* OK, can feed something. */
890- strbuf_reset (& state -> buf );
891- if (!state -> report )
892- state -> report = cmd -> report ;
893- if (state -> report ) {
894- struct object_id * old_oid ;
895- struct object_id * new_oid ;
896- const char * ref_name ;
897-
898- old_oid = state -> report -> old_oid ? state -> report -> old_oid : & cmd -> old_oid ;
899- new_oid = state -> report -> new_oid ? state -> report -> new_oid : & cmd -> new_oid ;
900- ref_name = state -> report -> ref_name ? state -> report -> ref_name : cmd -> ref_name ;
901- strbuf_addf (& state -> buf , "%s %s %s\n" ,
902- oid_to_hex (old_oid ), oid_to_hex (new_oid ),
903- ref_name );
904- state -> report = state -> report -> next ;
905- if (!state -> report )
906- state -> cmd = cmd -> next ;
907- } else {
908- strbuf_addf (& state -> buf , "%s %s %s\n" ,
909- oid_to_hex (& cmd -> old_oid ), oid_to_hex (& cmd -> new_oid ),
910- cmd -> ref_name );
911- state -> cmd = cmd -> next ;
912- }
913- if (bufp ) {
914- * bufp = state -> buf .buf ;
915- * sizep = state -> buf .len ;
873+ /* first-time setup */
874+ if (!hook_cb -> options -> feed_pipe_cb_data ) {
875+ struct receive_hook_feed_context * ctx = hook_cb -> options -> feed_pipe_ctx ;
876+ if (!ctx )
877+ BUG ("run_hooks_opt.feed_pipe_ctx required for receive hook" );
878+
879+ hook_cb -> options -> feed_pipe_cb_data = xmalloc (sizeof (struct receive_hook_feed_state ));
880+ feed_state = hook_cb -> options -> feed_pipe_cb_data ;
881+ strbuf_init (& feed_state -> buf , 0 );
882+ feed_state -> cmd = ctx -> cmd ;
883+ feed_state -> skip_broken = ctx -> skip_broken ;
884+ feed_state -> report = NULL ;
916885 }
917- return 0 ;
886+
887+ /* batch 500 lines at once to avoid going through the run-command ppoll loop too often */
888+ if (feed_receive_hook (hook_stdin_fd , feed_state , 500 ) == 0 )
889+ return 0 ; /* still have more data to feed */
890+
891+ strbuf_release (& feed_state -> buf );
892+
893+ if (hook_cb -> options -> feed_pipe_cb_data )
894+ FREE_AND_NULL (hook_cb -> options -> feed_pipe_cb_data );
895+
896+ return 1 ; /* done feeding, run-command can close pipe */
897+ }
898+
899+ static void hook_output_to_sideband (struct strbuf * output , void * cb_data UNUSED )
900+ {
901+ if (output && output -> len )
902+ send_sideband (1 , 2 , output -> buf , output -> len , use_sideband );
918903}
919904
920905static int run_receive_hook (struct command * commands ,
921906 const char * hook_name ,
922907 int skip_broken ,
923908 const struct string_list * push_options )
924909{
925- struct receive_hook_feed_state state ;
926- int status ;
910+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT ;
911+ struct receive_hook_feed_context ctx ;
912+ struct command * iter = commands ;
927913
928- strbuf_init (& state .buf , 0 );
929- state .cmd = commands ;
930- state .skip_broken = skip_broken ;
931- state .report = NULL ;
932- if (feed_receive_hook (& state , NULL , NULL ))
914+ /* if there are no valid commands, don't invoke the hook at all. */
915+ while (iter && skip_broken && (iter -> error_string || iter -> did_not_exist ))
916+ iter = iter -> next ;
917+ if (!iter )
933918 return 0 ;
934- state .cmd = commands ;
935- state .push_options = push_options ;
936- status = run_and_feed_hook (hook_name , feed_receive_hook , & state );
937- strbuf_release (& state .buf );
938- return status ;
919+
920+ if (push_options ) {
921+ int i ;
922+ for (i = 0 ; i < push_options -> nr ; i ++ )
923+ strvec_pushf (& opt .env , "GIT_PUSH_OPTION_%d=%s" , i ,
924+ push_options -> items [i ].string );
925+ strvec_pushf (& opt .env , "GIT_PUSH_OPTION_COUNT=%" PRIuMAX "" ,
926+ (uintmax_t )push_options -> nr );
927+ } else
928+ strvec_push (& opt .env , "GIT_PUSH_OPTION_COUNT" );
929+
930+ if (tmp_objdir )
931+ strvec_pushv (& opt .env , tmp_objdir_env (tmp_objdir ));
932+
933+ prepare_push_cert_sha1 (& opt );
934+
935+ /* set up sideband printer */
936+ if (use_sideband )
937+ opt .consume_sideband = hook_output_to_sideband ;
938+
939+ /* set up stdin callback */
940+ ctx .cmd = commands ;
941+ ctx .skip_broken = skip_broken ;
942+ opt .feed_pipe = feed_receive_hook_cb ;
943+ opt .feed_pipe_ctx = & ctx ;
944+
945+ return run_hooks_opt (the_repository , hook_name , & opt );
939946}
940947
941948static int run_update_hook (struct command * cmd )
942949{
943- struct child_process proc = CHILD_PROCESS_INIT ;
944- int code ;
945- const char * hook_path = find_hook (the_repository , "update" );
946-
947- if (!hook_path )
948- return 0 ;
949-
950- strvec_push (& proc .args , hook_path );
951- strvec_push (& proc .args , cmd -> ref_name );
952- strvec_push (& proc .args , oid_to_hex (& cmd -> old_oid ));
953- strvec_push (& proc .args , oid_to_hex (& cmd -> new_oid ));
950+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT ;
954951
955- proc .no_stdin = 1 ;
956- proc .stdout_to_stderr = 1 ;
957- proc .err = use_sideband ? -1 : 0 ;
958- proc .trace2_hook_name = "update" ;
952+ strvec_pushl (& opt .args ,
953+ cmd -> ref_name ,
954+ oid_to_hex (& cmd -> old_oid ),
955+ oid_to_hex (& cmd -> new_oid ),
956+ NULL );
959957
960- code = start_command (& proc );
961- if (code )
962- return code ;
963958 if (use_sideband )
964- copy_to_sideband (proc .err , -1 , NULL );
965- return finish_command (& proc );
959+ opt .consume_sideband = hook_output_to_sideband ;
960+
961+ return run_hooks_opt (the_repository , "update" , & opt );
966962}
967963
968964static struct command * find_command_by_refname (struct command * list ,
@@ -1639,33 +1635,20 @@ static const char *update(struct command *cmd, struct shallow_info *si)
16391635static void run_update_post_hook (struct command * commands )
16401636{
16411637 struct command * cmd ;
1642- struct child_process proc = CHILD_PROCESS_INIT ;
1643- const char * hook ;
1644-
1645- hook = find_hook (the_repository , "post-update" );
1646- if (!hook )
1647- return ;
1638+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT ;
16481639
16491640 for (cmd = commands ; cmd ; cmd = cmd -> next ) {
16501641 if (cmd -> error_string || cmd -> did_not_exist )
16511642 continue ;
1652- if (!proc .args .nr )
1653- strvec_push (& proc .args , hook );
1654- strvec_push (& proc .args , cmd -> ref_name );
1643+ strvec_push (& opt .args , cmd -> ref_name );
16551644 }
1656- if (!proc .args .nr )
1645+ if (!opt .args .nr )
16571646 return ;
16581647
1659- proc .no_stdin = 1 ;
1660- proc .stdout_to_stderr = 1 ;
1661- proc .err = use_sideband ? -1 : 0 ;
1662- proc .trace2_hook_name = "post-update" ;
1648+ if (use_sideband )
1649+ opt .consume_sideband = hook_output_to_sideband ;
16631650
1664- if (!start_command (& proc )) {
1665- if (use_sideband )
1666- copy_to_sideband (proc .err , -1 , NULL );
1667- finish_command (& proc );
1668- }
1651+ run_hooks_opt (the_repository , "post-update" , & opt );
16691652}
16701653
16711654static void check_aliased_update_internal (struct command * cmd ,
0 commit comments