@@ -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,174 +775,175 @@ 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 }
798798 }
799799}
800800
801+ struct receive_hook_feed_context {
802+ struct command * cmd ;
803+ int skip_broken ;
804+ };
805+
801806struct receive_hook_feed_state {
802807 struct command * cmd ;
803808 struct ref_push_report * report ;
804809 int skip_broken ;
805810 struct strbuf buf ;
806- const struct string_list * push_options ;
807811};
808812
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 )
813+ static int feed_receive_hook (int hook_stdin_fd , struct receive_hook_feed_state * state , int lines_batch_size )
812814{
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 );
815+ struct command * cmd = state -> cmd ;
817816
818- if (!hook_path )
819- return 0 ;
817+ strbuf_reset (& state -> buf );
820818
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" );
819+ /* batch lines to avoid going through run-command's ppoll for each line */
820+ for (int i = 0 ; i < lines_batch_size ; i ++ ) {
821+ while (cmd &&
822+ state -> skip_broken && (cmd -> error_string || cmd -> did_not_exist ))
823+ cmd = cmd -> next ;
837824
838- if (tmp_objdir )
839- strvec_pushv ( & proc . env , tmp_objdir_env ( tmp_objdir ));
825+ if (! cmd )
826+ break ; /* no more commands left */
840827
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- }
828+ if (!state -> report )
829+ state -> report = cmd -> report ;
850830
851- prepare_push_cert_sha1 (& proc );
831+ if (state -> report ) {
832+ struct object_id * old_oid ;
833+ struct object_id * new_oid ;
834+ const char * ref_name ;
852835
853- code = start_command (& proc );
854- if (code ) {
855- if (use_sideband )
856- finish_async (& muxer );
857- return code ;
858- }
836+ old_oid = state -> report -> old_oid ? state -> report -> old_oid : & cmd -> old_oid ;
837+ new_oid = state -> report -> new_oid ? state -> report -> new_oid : & cmd -> new_oid ;
838+ ref_name = state -> report -> ref_name ? state -> report -> ref_name : cmd -> ref_name ;
859839
860- sigchain_push (SIGPIPE , SIG_IGN );
840+ strbuf_addf (& state -> buf , "%s %s %s\n" ,
841+ oid_to_hex (old_oid ), oid_to_hex (new_oid ),
842+ ref_name );
861843
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 ;
844+ state -> report = state -> report -> next ;
845+ if (!state -> report )
846+ cmd = cmd -> next ;
847+ } else {
848+ strbuf_addf (& state -> buf , "%s %s %s\n" ,
849+ oid_to_hex (& cmd -> old_oid ), oid_to_hex (& cmd -> new_oid ),
850+ cmd -> ref_name );
851+ cmd = cmd -> next ;
852+ }
869853 }
870- close (proc .in );
871- if (use_sideband )
872- finish_async (& muxer );
873854
874- sigchain_pop ( SIGPIPE ) ;
855+ state -> cmd = cmd ;
875856
876- return finish_command (& proc );
857+ if (state -> buf .len > 0 ) {
858+ int ret = write_in_full (hook_stdin_fd , state -> buf .buf , state -> buf .len );
859+ if (ret < 0 ) {
860+ if (errno == EPIPE )
861+ return 1 ; /* child closed pipe */
862+ return ret ;
863+ }
864+ }
865+
866+ return state -> cmd ? 0 : 1 ; /* 0 = more to come, 1 = EOF */
877867}
878868
879- static int feed_receive_hook ( void * state_ , const char * * bufp , size_t * sizep )
869+ static int feed_receive_hook_cb ( int hook_stdin_fd , void * pp_cb , void * pp_task_cb UNUSED )
880870{
881- struct receive_hook_feed_state * state = state_ ;
882- struct command * cmd = state -> cmd ;
871+ struct hook_cb_data * hook_cb = pp_cb ;
872+ struct receive_hook_feed_state * feed_state = hook_cb -> options -> feed_pipe_cb_data ;
883873
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 ;
874+ /* first-time setup */
875+ if (!hook_cb -> options -> feed_pipe_cb_data ) {
876+ struct receive_hook_feed_context * ctx = hook_cb -> options -> feed_pipe_ctx ;
877+ if (!ctx )
878+ BUG ("run_hooks_opt.feed_pipe_ctx required for receive hook" );
879+
880+ hook_cb -> options -> feed_pipe_cb_data = xmalloc (sizeof (struct receive_hook_feed_state ));
881+ feed_state = hook_cb -> options -> feed_pipe_cb_data ;
882+ strbuf_init (& feed_state -> buf , 0 );
883+ feed_state -> cmd = ctx -> cmd ;
884+ feed_state -> skip_broken = ctx -> skip_broken ;
885+ feed_state -> report = NULL ;
917886 }
918- return 0 ;
887+
888+ /* batch 500 lines at once to avoid going through the run-command ppoll loop too often */
889+ if (feed_receive_hook (hook_stdin_fd , feed_state , 500 ) == 0 )
890+ return 0 ; /* still have more data to feed */
891+
892+ strbuf_release (& feed_state -> buf );
893+
894+ if (hook_cb -> options -> feed_pipe_cb_data )
895+ FREE_AND_NULL (hook_cb -> options -> feed_pipe_cb_data );
896+
897+ return 1 ; /* done feeding, run-command can close pipe */
898+ }
899+
900+ static void hook_output_to_sideband (struct strbuf * output , void * cb_data UNUSED )
901+ {
902+ if (output && output -> len )
903+ send_sideband (1 , 2 , output -> buf , output -> len , use_sideband );
919904}
920905
921906static int run_receive_hook (struct command * commands ,
922907 const char * hook_name ,
923908 int skip_broken ,
924909 const struct string_list * push_options )
925910{
926- struct receive_hook_feed_state state ;
927- int status ;
911+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT ;
912+ struct receive_hook_feed_context ctx ;
913+ struct command * iter = commands ;
928914
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 ))
915+ /* if there are no valid commands, don't invoke the hook at all. */
916+ while (iter && skip_broken && (iter -> error_string || iter -> did_not_exist ))
917+ iter = iter -> next ;
918+ if (!iter )
934919 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 ;
940- }
941920
942- static void hook_output_to_sideband (struct strbuf * output , void * cb_data UNUSED )
943- {
944- if (output && output -> len )
945- send_sideband (1 , 2 , output -> buf , output -> len , use_sideband );
921+ if (push_options ) {
922+ int i ;
923+ for (i = 0 ; i < push_options -> nr ; i ++ )
924+ strvec_pushf (& opt .env , "GIT_PUSH_OPTION_%d=%s" , i ,
925+ push_options -> items [i ].string );
926+ strvec_pushf (& opt .env , "GIT_PUSH_OPTION_COUNT=%" PRIuMAX "" ,
927+ (uintmax_t )push_options -> nr );
928+ } else
929+ strvec_push (& opt .env , "GIT_PUSH_OPTION_COUNT" );
930+
931+ if (tmp_objdir )
932+ strvec_pushv (& opt .env , tmp_objdir_env (tmp_objdir ));
933+
934+ prepare_push_cert_sha1 (& opt );
935+
936+ /* set up sideband printer */
937+ if (use_sideband )
938+ opt .consume_sideband = hook_output_to_sideband ;
939+
940+ /* set up stdin callback */
941+ ctx .cmd = commands ;
942+ ctx .skip_broken = skip_broken ;
943+ opt .feed_pipe = feed_receive_hook_cb ;
944+ opt .feed_pipe_ctx = & ctx ;
945+
946+ return run_hooks_opt (the_repository , hook_name , & opt );
946947}
947948
948949static int run_update_hook (struct command * cmd )
0 commit comments