@@ -749,7 +749,7 @@ static int check_cert_push_options(const struct string_list *push_options)
749749 return retval ;
750750}
751751
752- static void prepare_push_cert_sha1 (struct child_process * proc )
752+ static void prepare_push_cert_sha1 (struct run_hooks_opt * opt )
753753{
754754 static int already_done ;
755755
@@ -775,23 +775,23 @@ static void prepare_push_cert_sha1(struct child_process *proc)
775775 nonce_status = check_nonce (sigcheck .payload );
776776 }
777777 if (!is_null_oid (& push_cert_oid )) {
778- strvec_pushf (& proc -> env , "GIT_PUSH_CERT=%s" ,
778+ strvec_pushf (& opt -> env , "GIT_PUSH_CERT=%s" ,
779779 oid_to_hex (& push_cert_oid ));
780- strvec_pushf (& proc -> env , "GIT_PUSH_CERT_SIGNER=%s" ,
780+ strvec_pushf (& opt -> env , "GIT_PUSH_CERT_SIGNER=%s" ,
781781 sigcheck .signer ? sigcheck .signer : "" );
782- strvec_pushf (& proc -> env , "GIT_PUSH_CERT_KEY=%s" ,
782+ strvec_pushf (& opt -> env , "GIT_PUSH_CERT_KEY=%s" ,
783783 sigcheck .key ? sigcheck .key : "" );
784- strvec_pushf (& proc -> env , "GIT_PUSH_CERT_STATUS=%c" ,
784+ strvec_pushf (& opt -> env , "GIT_PUSH_CERT_STATUS=%c" ,
785785 sigcheck .result );
786786 if (push_cert_nonce ) {
787- strvec_pushf (& proc -> env ,
787+ strvec_pushf (& opt -> env ,
788788 "GIT_PUSH_CERT_NONCE=%s" ,
789789 push_cert_nonce );
790- strvec_pushf (& proc -> env ,
790+ strvec_pushf (& opt -> env ,
791791 "GIT_PUSH_CERT_NONCE_STATUS=%s" ,
792792 nonce_status );
793793 if (nonce_status == NONCE_SLOP )
794- strvec_pushf (& proc -> env ,
794+ strvec_pushf (& opt -> env ,
795795 "GIT_PUSH_CERT_NONCE_SLOP=%ld" ,
796796 nonce_stamp_slop );
797797 }
@@ -803,167 +803,139 @@ struct receive_hook_feed_state {
803803 struct ref_push_report * report ;
804804 int skip_broken ;
805805 struct strbuf buf ;
806- const struct string_list * push_options ;
807806};
808807
809- typedef int (* feed_fn )(void * , const char * * , size_t * );
810- static int run_and_feed_hook (const char * hook_name , feed_fn feed ,
811- struct receive_hook_feed_state * feed_state )
808+ static int feed_receive_hook_cb (int hook_stdin_fd , void * pp_cb , void * pp_task_cb UNUSED )
812809{
813- struct child_process proc = CHILD_PROCESS_INIT ;
814- struct async muxer ;
815- int code ;
816- const char * hook_path = find_hook ( the_repository , hook_name ) ;
810+ struct hook_cb_data * hook_cb = pp_cb ;
811+ struct receive_hook_feed_state * state = hook_cb -> options -> feed_pipe_cb_data ;
812+ struct command * cmd = state -> cmd ;
813+ unsigned int lines_batch_size = 500 ;
817814
818- if (!hook_path )
819- return 0 ;
815+ strbuf_reset (& state -> buf );
820816
821- strvec_push (& proc .args , hook_path );
822- proc .in = -1 ;
823- proc .stdout_to_stderr = 1 ;
824- proc .trace2_hook_name = hook_name ;
825-
826- if (feed_state -> push_options ) {
827- size_t i ;
828- for (i = 0 ; i < feed_state -> push_options -> nr ; i ++ )
829- strvec_pushf (& proc .env ,
830- "GIT_PUSH_OPTION_%" PRIuMAX "=%s" ,
831- (uintmax_t )i ,
832- feed_state -> push_options -> items [i ].string );
833- strvec_pushf (& proc .env , "GIT_PUSH_OPTION_COUNT=%" PRIuMAX "" ,
834- (uintmax_t )feed_state -> push_options -> nr );
835- } else
836- strvec_pushf (& proc .env , "GIT_PUSH_OPTION_COUNT" );
817+ /* batch lines to avoid going through run-command's poll loop for each line */
818+ for (unsigned int i = 0 ; i < lines_batch_size ; i ++ ) {
819+ while (cmd &&
820+ state -> skip_broken && (cmd -> error_string || cmd -> did_not_exist ))
821+ cmd = cmd -> next ;
837822
838- if (tmp_objdir )
839- strvec_pushv ( & proc . env , tmp_objdir_env ( tmp_objdir ));
823+ if (! cmd )
824+ break ; /* no more commands left */
840825
841- if (use_sideband ) {
842- memset (& muxer , 0 , sizeof (muxer ));
843- muxer .proc = copy_to_sideband ;
844- muxer .in = -1 ;
845- code = start_async (& muxer );
846- if (code )
847- return code ;
848- proc .err = muxer .in ;
849- }
826+ if (!state -> report )
827+ state -> report = cmd -> report ;
850828
851- prepare_push_cert_sha1 (& proc );
829+ if (state -> report ) {
830+ struct object_id * old_oid ;
831+ struct object_id * new_oid ;
832+ const char * ref_name ;
852833
853- code = start_command (& proc );
854- if (code ) {
855- if (use_sideband )
856- finish_async (& muxer );
857- return code ;
858- }
834+ old_oid = state -> report -> old_oid ? state -> report -> old_oid : & cmd -> old_oid ;
835+ new_oid = state -> report -> new_oid ? state -> report -> new_oid : & cmd -> new_oid ;
836+ ref_name = state -> report -> ref_name ? state -> report -> ref_name : cmd -> ref_name ;
859837
860- sigchain_push (SIGPIPE , SIG_IGN );
838+ strbuf_addf (& state -> buf , "%s %s %s\n" ,
839+ oid_to_hex (old_oid ), oid_to_hex (new_oid ),
840+ ref_name );
861841
862- while (1 ) {
863- const char * buf ;
864- size_t n ;
865- if (feed (feed_state , & buf , & n ))
866- break ;
867- if (write_in_full (proc .in , buf , n ) < 0 )
868- break ;
842+ state -> report = state -> report -> next ;
843+ if (!state -> report )
844+ cmd = cmd -> next ;
845+ } else {
846+ strbuf_addf (& state -> buf , "%s %s %s\n" ,
847+ oid_to_hex (& cmd -> old_oid ), oid_to_hex (& cmd -> new_oid ),
848+ cmd -> ref_name );
849+ cmd = cmd -> next ;
850+ }
869851 }
870- close (proc .in );
871- if (use_sideband )
872- finish_async (& muxer );
873852
874- sigchain_pop ( SIGPIPE ) ;
853+ state -> cmd = cmd ;
875854
876- return finish_command (& proc );
855+ if (state -> buf .len > 0 ) {
856+ int ret = write_in_full (hook_stdin_fd , state -> buf .buf , state -> buf .len );
857+ if (ret < 0 ) {
858+ if (errno == EPIPE )
859+ return 1 ; /* child closed pipe */
860+ return ret ;
861+ }
862+ }
863+
864+ return state -> cmd ? 0 : 1 ; /* 0 = more to come, 1 = EOF */
877865}
878866
879- static int feed_receive_hook ( void * state_ , const char * * bufp , size_t * sizep )
867+ static void hook_output_to_sideband ( struct strbuf * output , void * cb_data UNUSED )
880868{
881- struct receive_hook_feed_state * state = state_ ;
882- struct command * cmd = state -> cmd ;
883-
884- while (cmd &&
885- state -> skip_broken && (cmd -> error_string || cmd -> did_not_exist ))
886- cmd = cmd -> next ;
887- if (!cmd )
888- return -1 ; /* EOF */
889- if (!bufp )
890- return 0 ; /* OK, can feed something. */
891- strbuf_reset (& state -> buf );
892- if (!state -> report )
893- state -> report = cmd -> report ;
894- if (state -> report ) {
895- struct object_id * old_oid ;
896- struct object_id * new_oid ;
897- const char * ref_name ;
898-
899- old_oid = state -> report -> old_oid ? state -> report -> old_oid : & cmd -> old_oid ;
900- new_oid = state -> report -> new_oid ? state -> report -> new_oid : & cmd -> new_oid ;
901- ref_name = state -> report -> ref_name ? state -> report -> ref_name : cmd -> ref_name ;
902- strbuf_addf (& state -> buf , "%s %s %s\n" ,
903- oid_to_hex (old_oid ), oid_to_hex (new_oid ),
904- ref_name );
905- state -> report = state -> report -> next ;
906- if (!state -> report )
907- state -> cmd = cmd -> next ;
908- } else {
909- strbuf_addf (& state -> buf , "%s %s %s\n" ,
910- oid_to_hex (& cmd -> old_oid ), oid_to_hex (& cmd -> new_oid ),
911- cmd -> ref_name );
912- state -> cmd = cmd -> next ;
913- }
914- if (bufp ) {
915- * bufp = state -> buf .buf ;
916- * sizep = state -> buf .len ;
917- }
918- return 0 ;
869+ if (output && output -> len )
870+ send_sideband (1 , 2 , output -> buf , output -> len , use_sideband );
919871}
920872
921873static int run_receive_hook (struct command * commands ,
922874 const char * hook_name ,
923875 int skip_broken ,
924876 const struct string_list * push_options )
925877{
926- struct receive_hook_feed_state state ;
927- int status ;
928-
929- strbuf_init (& state .buf , 0 );
930- state .cmd = commands ;
931- state .skip_broken = skip_broken ;
932- state .report = NULL ;
933- if (feed_receive_hook (& state , NULL , NULL ))
878+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT ;
879+ struct command * iter = commands ;
880+ struct receive_hook_feed_state * feed_state ;
881+ int ret ;
882+
883+ /* if there are no valid commands, don't invoke the hook at all. */
884+ while (iter && skip_broken && (iter -> error_string || iter -> did_not_exist ))
885+ iter = iter -> next ;
886+ if (!iter )
934887 return 0 ;
935- state .cmd = commands ;
936- state .push_options = push_options ;
937- status = run_and_feed_hook (hook_name , feed_receive_hook , & state );
938- strbuf_release (& state .buf );
939- return status ;
888+
889+ if (push_options ) {
890+ int i ;
891+ for (i = 0 ; i < push_options -> nr ; i ++ )
892+ strvec_pushf (& opt .env , "GIT_PUSH_OPTION_%d=%s" , i ,
893+ push_options -> items [i ].string );
894+ strvec_pushf (& opt .env , "GIT_PUSH_OPTION_COUNT=%" PRIuMAX "" ,
895+ (uintmax_t )push_options -> nr );
896+ } else
897+ strvec_push (& opt .env , "GIT_PUSH_OPTION_COUNT" );
898+
899+ if (tmp_objdir )
900+ strvec_pushv (& opt .env , tmp_objdir_env (tmp_objdir ));
901+
902+ prepare_push_cert_sha1 (& opt );
903+
904+ /* set up sideband printer */
905+ if (use_sideband )
906+ opt .consume_output = hook_output_to_sideband ;
907+
908+ /* set up stdin callback */
909+ feed_state = xmalloc (sizeof (struct receive_hook_feed_state ));
910+ feed_state -> cmd = commands ;
911+ feed_state -> skip_broken = skip_broken ;
912+ feed_state -> report = NULL ;
913+ strbuf_init (& feed_state -> buf , 0 );
914+ opt .feed_pipe_cb_data = feed_state ;
915+ opt .feed_pipe = feed_receive_hook_cb ;
916+
917+ ret = run_hooks_opt (the_repository , hook_name , & opt );
918+
919+ strbuf_release (& feed_state -> buf );
920+ FREE_AND_NULL (opt .feed_pipe_cb_data );
921+
922+ return ret ;
940923}
941924
942925static int run_update_hook (struct command * cmd )
943926{
944- struct child_process proc = CHILD_PROCESS_INIT ;
945- int code ;
946- const char * hook_path = find_hook (the_repository , "update" );
947-
948- if (!hook_path )
949- return 0 ;
950-
951- strvec_push (& proc .args , hook_path );
952- strvec_push (& proc .args , cmd -> ref_name );
953- strvec_push (& proc .args , oid_to_hex (& cmd -> old_oid ));
954- strvec_push (& proc .args , oid_to_hex (& cmd -> new_oid ));
927+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT ;
955928
956- proc .no_stdin = 1 ;
957- proc .stdout_to_stderr = 1 ;
958- proc .err = use_sideband ? -1 : 0 ;
959- proc .trace2_hook_name = "update" ;
929+ strvec_pushl (& opt .args ,
930+ cmd -> ref_name ,
931+ oid_to_hex (& cmd -> old_oid ),
932+ oid_to_hex (& cmd -> new_oid ),
933+ NULL );
960934
961- code = start_command (& proc );
962- if (code )
963- return code ;
964935 if (use_sideband )
965- copy_to_sideband (proc .err , -1 , NULL );
966- return finish_command (& proc );
936+ opt .consume_output = hook_output_to_sideband ;
937+
938+ return run_hooks_opt (the_repository , "update" , & opt );
967939}
968940
969941static struct command * find_command_by_refname (struct command * list ,
@@ -1640,33 +1612,20 @@ static const char *update(struct command *cmd, struct shallow_info *si)
16401612static void run_update_post_hook (struct command * commands )
16411613{
16421614 struct command * cmd ;
1643- struct child_process proc = CHILD_PROCESS_INIT ;
1644- const char * hook ;
1645-
1646- hook = find_hook (the_repository , "post-update" );
1647- if (!hook )
1648- return ;
1615+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT ;
16491616
16501617 for (cmd = commands ; cmd ; cmd = cmd -> next ) {
16511618 if (cmd -> error_string || cmd -> did_not_exist )
16521619 continue ;
1653- if (!proc .args .nr )
1654- strvec_push (& proc .args , hook );
1655- strvec_push (& proc .args , cmd -> ref_name );
1620+ strvec_push (& opt .args , cmd -> ref_name );
16561621 }
1657- if (!proc .args .nr )
1622+ if (!opt .args .nr )
16581623 return ;
16591624
1660- proc .no_stdin = 1 ;
1661- proc .stdout_to_stderr = 1 ;
1662- proc .err = use_sideband ? -1 : 0 ;
1663- proc .trace2_hook_name = "post-update" ;
1625+ if (use_sideband )
1626+ opt .consume_output = hook_output_to_sideband ;
16641627
1665- if (!start_command (& proc )) {
1666- if (use_sideband )
1667- copy_to_sideband (proc .err , -1 , NULL );
1668- finish_command (& proc );
1669- }
1628+ run_hooks_opt (the_repository , "post-update" , & opt );
16701629}
16711630
16721631static void check_aliased_update_internal (struct command * cmd ,
0 commit comments