@@ -561,6 +561,48 @@ static int copy_to_sideband(int in, int out UNUSED, void *arg UNUSED)
561561 return 0 ;
562562}
563563
564+ /*
565+ * Start an async thread which redirects hook stderr over the sideband.
566+ * The original stderr fd is saved to `saved_stderr` and STDERR_FILENO is
567+ * redirected to the async's input pipe.
568+ */
569+ static void prepare_sideband_async (struct async * sideband_async , int * saved_stderr , int * started )
570+ {
571+ * started = 0 ;
572+
573+ if (!use_sideband )
574+ return ;
575+
576+ memset (sideband_async , 0 , sizeof (* sideband_async ));
577+ sideband_async -> proc = copy_to_sideband ;
578+ sideband_async -> in = -1 ;
579+
580+ if (!start_async (sideband_async )) {
581+ * started = 1 ;
582+ * saved_stderr = dup (STDERR_FILENO );
583+ if (* saved_stderr >= 0 )
584+ dup2 (sideband_async -> in , STDERR_FILENO );
585+ close (sideband_async -> in );
586+ }
587+ }
588+
589+ /*
590+ * Restore the original stderr and wait for the async sideband thread to finish.
591+ */
592+ static void finish_sideband_async (struct async * sideband_async , int saved_stderr , int started )
593+ {
594+ if (!use_sideband )
595+ return ;
596+
597+ if (saved_stderr >= 0 ) {
598+ dup2 (saved_stderr , STDERR_FILENO );
599+ close (saved_stderr );
600+ }
601+
602+ if (started )
603+ finish_async (sideband_async );
604+ }
605+
564606static void hmac_hash (unsigned char * out ,
565607 const char * key_in , size_t key_len ,
566608 const char * text , size_t text_len )
@@ -749,7 +791,7 @@ static int check_cert_push_options(const struct string_list *push_options)
749791 return retval ;
750792}
751793
752- static void prepare_push_cert_sha1 (struct child_process * proc )
794+ static void prepare_push_cert_sha1 (struct run_hooks_opt * opt )
753795{
754796 static int already_done ;
755797
@@ -775,23 +817,23 @@ static void prepare_push_cert_sha1(struct child_process *proc)
775817 nonce_status = check_nonce (sigcheck .payload );
776818 }
777819 if (!is_null_oid (& push_cert_oid )) {
778- strvec_pushf (& proc -> env , "GIT_PUSH_CERT=%s" ,
820+ strvec_pushf (& opt -> env , "GIT_PUSH_CERT=%s" ,
779821 oid_to_hex (& push_cert_oid ));
780- strvec_pushf (& proc -> env , "GIT_PUSH_CERT_SIGNER=%s" ,
822+ strvec_pushf (& opt -> env , "GIT_PUSH_CERT_SIGNER=%s" ,
781823 sigcheck .signer ? sigcheck .signer : "" );
782- strvec_pushf (& proc -> env , "GIT_PUSH_CERT_KEY=%s" ,
824+ strvec_pushf (& opt -> env , "GIT_PUSH_CERT_KEY=%s" ,
783825 sigcheck .key ? sigcheck .key : "" );
784- strvec_pushf (& proc -> env , "GIT_PUSH_CERT_STATUS=%c" ,
826+ strvec_pushf (& opt -> env , "GIT_PUSH_CERT_STATUS=%c" ,
785827 sigcheck .result );
786828 if (push_cert_nonce ) {
787- strvec_pushf (& proc -> env ,
829+ strvec_pushf (& opt -> env ,
788830 "GIT_PUSH_CERT_NONCE=%s" ,
789831 push_cert_nonce );
790- strvec_pushf (& proc -> env ,
832+ strvec_pushf (& opt -> env ,
791833 "GIT_PUSH_CERT_NONCE_STATUS=%s" ,
792834 nonce_status );
793835 if (nonce_status == NONCE_SLOP )
794- strvec_pushf (& proc -> env ,
836+ strvec_pushf (& opt -> env ,
795837 "GIT_PUSH_CERT_NONCE_SLOP=%ld" ,
796838 nonce_stamp_slop );
797839 }
@@ -803,94 +845,25 @@ struct receive_hook_feed_state {
803845 struct ref_push_report * report ;
804846 int skip_broken ;
805847 struct strbuf buf ;
806- const struct string_list * push_options ;
807848};
808849
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 )
850+ static int feed_receive_hook_cb (int hook_stdin_fd , void * pp_cb UNUSED , void * pp_task_cb )
812851{
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 );
817-
818- if (!hook_path )
819- return 0 ;
820-
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" );
837-
838- if (tmp_objdir )
839- strvec_pushv (& proc .env , tmp_objdir_env (tmp_objdir ));
840-
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- }
850-
851- prepare_push_cert_sha1 (& proc );
852-
853- code = start_command (& proc );
854- if (code ) {
855- if (use_sideband )
856- finish_async (& muxer );
857- return code ;
858- }
859-
860- sigchain_push (SIGPIPE , SIG_IGN );
861-
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 ;
869- }
870- close (proc .in );
871- if (use_sideband )
872- finish_async (& muxer );
873-
874- sigchain_pop (SIGPIPE );
875-
876- return finish_command (& proc );
877- }
878-
879- static int feed_receive_hook (void * state_ , const char * * bufp , size_t * sizep )
880- {
881- struct receive_hook_feed_state * state = state_ ;
852+ struct receive_hook_feed_state * state = pp_task_cb ;
882853 struct command * cmd = state -> cmd ;
883854
855+ strbuf_reset (& state -> buf );
856+
884857 while (cmd &&
885858 state -> skip_broken && (cmd -> error_string || cmd -> did_not_exist ))
886859 cmd = cmd -> next ;
860+
887861 if (!cmd )
888- return -1 ; /* EOF */
889- if (!bufp )
890- return 0 ; /* OK, can feed something. */
891- strbuf_reset (& state -> buf );
862+ return 1 ; /* no more commands left */
863+
892864 if (!state -> report )
893865 state -> report = cmd -> report ;
866+
894867 if (state -> report ) {
895868 struct object_id * old_oid ;
896869 struct object_id * new_oid ;
@@ -899,71 +872,115 @@ static int feed_receive_hook(void *state_, const char **bufp, size_t *sizep)
899872 old_oid = state -> report -> old_oid ? state -> report -> old_oid : & cmd -> old_oid ;
900873 new_oid = state -> report -> new_oid ? state -> report -> new_oid : & cmd -> new_oid ;
901874 ref_name = state -> report -> ref_name ? state -> report -> ref_name : cmd -> ref_name ;
875+
902876 strbuf_addf (& state -> buf , "%s %s %s\n" ,
903877 oid_to_hex (old_oid ), oid_to_hex (new_oid ),
904878 ref_name );
879+
905880 state -> report = state -> report -> next ;
906881 if (!state -> report )
907- state -> cmd = cmd -> next ;
882+ cmd = cmd -> next ;
908883 } else {
909884 strbuf_addf (& state -> buf , "%s %s %s\n" ,
910885 oid_to_hex (& cmd -> old_oid ), oid_to_hex (& cmd -> new_oid ),
911886 cmd -> ref_name );
912- state -> cmd = cmd -> next ;
887+ cmd = cmd -> next ;
913888 }
914- if (bufp ) {
915- * bufp = state -> buf .buf ;
916- * sizep = state -> buf .len ;
889+
890+ state -> cmd = cmd ;
891+
892+ if (state -> buf .len > 0 ) {
893+ int ret = write_in_full (hook_stdin_fd , state -> buf .buf , state -> buf .len );
894+ if (ret < 0 ) {
895+ if (errno == EPIPE )
896+ return 1 ; /* child closed pipe */
897+ return ret ;
898+ }
917899 }
918- return 0 ;
900+
901+ return state -> cmd ? 0 : 1 ; /* 0 = more to come, 1 = EOF */
919902}
920903
921904static int run_receive_hook (struct command * commands ,
922905 const char * hook_name ,
923906 int skip_broken ,
924907 const struct string_list * push_options )
925908{
926- struct receive_hook_feed_state state ;
927- int status ;
909+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT ;
910+ struct command * iter = commands ;
911+ struct receive_hook_feed_state feed_state ;
912+ struct async sideband_async ;
913+ int sideband_async_started = 0 ;
914+ int saved_stderr = -1 ;
915+ int ret ;
916+
917+ if (!hook_exists (the_repository , hook_name ))
918+ return 0 ;
928919
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 ))
920+ /* if there are no valid commands, don't invoke the hook at all. */
921+ while (iter && skip_broken && (iter -> error_string || iter -> did_not_exist ))
922+ iter = iter -> next ;
923+ if (!iter )
934924 return 0 ;
935- state .cmd = commands ;
936- state .push_options = push_options ;
937- status = run_and_feed_hook (
C307
hook_name , feed_receive_hook , & state );
938- strbuf_release (& state .buf );
939- return status ;
925+
926+ if (push_options ) {
927+ for (int i = 0 ; i < push_options -> nr ; i ++ )
928+ strvec_pushf (& opt .env , "GIT_PUSH_OPTION_%d=%s" , i ,
929+ push_options -> items [i ].string );
930+ strvec_pushf (& opt .env , "GIT_PUSH_OPTION_COUNT=%" PRIuMAX "" ,
931+ (uintmax_t )push_options -> nr );
932+ } else {
933+ strvec_push (& opt .env , "GIT_PUSH_OPTION_COUNT" );
934+ }
935+
936+ if (tmp_objdir )
937+ strvec_pushv (& opt .env , tmp_objdir_env (tmp_objdir ));
938+
939+ prepare_push_cert_sha1 (& opt );
940+
941+ prepare_sideband_async (& sideband_async , & saved_stderr , & sideband_async_started );
942+
943+ /* set up stdin callback */
944+ feed_state .cmd = commands ;
945+ feed_state .skip_broken = skip_broken ;
946+ feed_state .report = NULL ;
947+ strbuf_init (& feed_state .buf , 0 );
948+ opt .feed_pipe_cb_data = & feed_state ;
949+ opt .feed_pipe = feed_receive_hook_cb ;
950+
951+ ret = run_hooks_opt (the_repository , hook_name , & opt );
952+
953+ strbuf_release (& feed_state .buf );
954+ finish_sideband_async (& sideband_async , saved_stderr , sideband_async_started );
955+
956+ return ret ;
940957}
941958
942959static int run_update_hook (struct command * cmd )
943960{
944- struct child_process proc = CHILD_PROCESS_INIT ;
961+ static const char hook_name [] = "update" ;
962+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT ;
963+ struct async sideband_async ;
964+ int sideband_async_started = 0 ;
965+ int saved_stderr = -1 ;
945966 int code ;
946- const char * hook_path = find_hook(the_repository , "update" );
947967
948- if (!hook_path )
968+ if (!hook_exists ( the_repository , hook_name ) )
949969 return 0 ;
950970
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 ));
971+ strvec_pushl (& opt .args ,
972+ cmd -> ref_name ,
973+ oid_to_hex (& cmd -> old_oid ),
974+ oid_to_hex (& cmd -> new_oid ),
975+ NULL );
955976
956- proc .no_stdin = 1 ;
957- proc .stdout_to_stderr = 1 ;
958- proc .err = use_sideband ? -1 : 0 ;
959- proc .trace2_hook_name = "update" ;
977+ prepare_sideband_async (& sideband_async , & saved_stderr , & sideband_async_started );
960978
961- code = start_command (& proc );
962- if (code )
963- return code ;
964- if (use_sideband )
965- copy_to_sideband (proc .err , -1 , NULL );
966- return finish_command (& proc );
979+ code = run_hooks_opt (the_repository , hook_name , & opt );
980+
981+ finish_sideband_async (& sideband_async , saved_stderr , sideband_async_started );
982+
983+ return code ;
967984}
968985
969986static struct command * find_command_by_refname (struct command * list ,
@@ -1639,34 +1656,29 @@ static const char *update(struct command *cmd, struct shallow_info *si)
16391656
16401657static void run_update_post_hook (struct command * commands )
16411658{
1659+ static const char hook_name [] = "post-update" ;
1660+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT ;
1661+ struct async sideband_async ;
16421662 struct command * cmd ;
1643- struct child_process proc = CHILD_PROCESS_INIT ;
1644- const char * hook ;
1663+ int sideband_async_started = 0 ;
1664+ int saved_stderr = -1 ;
16451665
1646- hook = find_hook (the_repository , "post-update" );
1647- if (!hook )
1666+ if (!hook_exists (the_repository , hook_name ))
16481667 return ;
16491668
16501669 for (cmd = commands ; cmd ; cmd = cmd -> next ) {
16511670 if (cmd -> error_string || cmd -> did_not_exist )
16521671 continue ;
1653- if (!proc .args .nr )
1654- strvec_push (& proc .args , hook );
1655- strvec_push (& proc .args , cmd -> ref_name );
1672+ strvec_push (& opt .args , cmd -> ref_name );
16561673 }
1657- if (!proc .args .nr )
1674+ if (!opt .args .nr )
16581675 return ;
16591676
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" ;
1677+ prepare_sideband_async (& sideband_async , & saved_stderr , & sideband_async_started );
16641678
1665- if (!start_command (& proc )) {
1666- if (use_sideband )
1667- copy_to_sideband (proc .err , -1 , NULL );
1668- finish_command (& proc );
1669- }
1679+ run_hooks_opt (the_repository , hook_name , & opt );
1680+
1681+ finish_sideband_async (& sideband_async , saved_stderr , sideband_async_started );
16701682}
16711683
16721684static void check_aliased_update_internal (struct command * cmd ,
0 commit comments