17
17
#include "shallow.h"
18
18
#include "trace.h"
19
19
#include "trace2.h"
20
+ #include "dir.h"
21
+ #include "hook.h"
20
22
21
23
#define RUN_SETUP (1<<0)
22
24
#define RUN_SETUP_GENTLY (1<<1)
@@ -437,6 +439,67 @@ static int handle_alias(struct strvec *args)
437
439
return ret ;
438
440
}
439
441
442
+ /* Runs pre/post-command hook */
443
+ static struct strvec sargv = STRVEC_INIT ;
444
+ static int run_post_hook = 0 ;
445
+ static int exit_code = -1 ;
446
+
447
+ static int run_pre_command_hook (struct repository * r , const char * * argv )
448
+ {
449
+ char * lock ;
450
+ int ret = 0 ;
451
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT ;
452
+
453
+ /*
454
+ * Ensure the global pre/post command hook is only called for
455
+ * the outer command and not when git is called recursively
456
+ * or spawns multiple commands (like with the alias command)
457
+ */
458
+ lock = getenv ("COMMAND_HOOK_LOCK" );
459
+ if (lock && !strcmp (lock , "true" ))
460
+ return 0 ;
461
+ setenv ("COMMAND_HOOK_LOCK" , "true" , 1 );
462
+
463
+ /* call the hook proc */
464
+ strvec_pushv (& sargv , argv );
465
+ strvec_pushv (& opt .args , sargv .v );
466
+ ret = run_hooks_opt (r , "pre-command" , & opt );
467
+
468
+ if (!ret )
469
+ run_post_hook = 1 ;
470
+ return ret ;
471
+ }
472
+
473
+ static int run_post_command_hook (struct repository * r )
474
+ {
475
+ char * lock ;
476
+ int ret = 0 ;
477
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT ;
478
+
479
+ /*
480
+ * Only run post_command if pre_command succeeded in this process
481
+ */
482
+ if (!run_post_hook )
483
+ return 0 ;
484
+ lock = getenv ("COMMAND_HOOK_LOCK" );
485
+ if (!lock || strcmp (lock , "true" ))
486
+ return 0 ;
487
+
488
+ strvec_pushv (& opt .args , sargv .v );
489
+ strvec_pushf (& opt .args , "--exit_code=%u" , exit_code );
490
+ ret = run_hooks_opt (r , "post-command" , & opt );
491
+
492
+ run_post_hook = 0 ;
493
+ strvec_clear (& sargv );
494
+ setenv ("COMMAND_HOOK_LOCK" , "false" , 1 );
495
+ return ret ;
496
+ }
497
+
498
+ static void post_command_hook_atexit (void )
499
+ {
500
+ run_post_command_hook (the_repository );
501
+ }
502
+
440
503
static int run_builtin (struct cmd_struct * p , int argc , const char * * argv , struct repository * repo )
441
504
{
442
505
int status , help ;
@@ -473,16 +536,21 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv, struct
473
536
if (!help && p -> option & NEED_WORK_TREE )
474
537
setup_work_tree ();
475
538
539
+ if (run_pre_command_hook (the_repository , argv ))
540
+ die ("pre-command hook aborted command" );
541
+
476
542
trace_argv_printf (argv , "trace: built-in: git" );
477
543
trace2_cmd_name (p -> cmd );
478
544
479
545
validate_cache_entries (repo -> index );
480
- status = p -> fn (argc , argv , prefix , no_repo ? NULL : repo );
546
+ exit_code = status = p -> fn (argc , argv , prefix , no_repo ? NULL : repo );
481
547
validate_cache_entries (repo -> index );
482
548
483
549
if (status )
484
550
return status ;
485
551
552
+ run_post_command_hook (the_repository );
553
+
486
554
/* Somebody closed stdout? */
487
555
if (fstat (fileno (stdout ), & st ))
488
556
return 0 ;
@@ -775,13 +843,16 @@ static void execv_dashed_external(const char **argv)
775
843
*/
776
844
trace_argv_printf (cmd .args .v , "trace: exec:" );
777
845
846
+ if (run_pre_command_hook (the_repository , cmd .args .v ))
847
+ die ("pre-command hook aborted command" );
848
+
778
849
/*
779
850
* If we fail because the command is not found, it is
780
851
* OK to return. Otherwise, we just pass along the status code,
781
852
* or our usual generic code if we were not even able to exec
782
853
* the program.
783
854
*/
784
- status = run_command (& cmd );
855
+ exit_code = status = run_command (& cmd );
785
856
786
857
/*
787
858
* If the child process ran and we are now going to exit, emit a
@@ -792,6 +863,8 @@ static void execv_dashed_external(const char **argv)
792
863
exit (status );
793
864
else if (errno != ENOENT )
794
865
exit (128 );
866
+
867
+ run_post_command_hook (the_repository );
795
868
}
796
869
797
870
static int run_argv (struct strvec * args )
@@ -899,6 +972,7 @@ int cmd_main(int argc, const char **argv)
899
972
}
900
973
901
974
trace_command_performance (argv );
975
+ atexit (post_command_hook_atexit );
902
976
903
977
/*
904
978
* "git-xxxx" is the same as "git xxxx", but we obviously:
@@ -926,10 +1000,14 @@ int cmd_main(int argc, const char **argv)
926
1000
if (!argc ) {
927
1001
/* The user didn't specify a command; give them help */
928
1002
commit_pager_choice ();
1003
+ if (run_pre_command_hook (the_repository , argv ))
1004
+ die ("pre-command hook aborted command" );
929
1005
printf (_ ("usage: %s\n\n" ), git_usage_string );
930
1006
list_common_cmds_help ();
931
1007
printf ("\n%s\n" , _ (git_more_info_string ));
932
- exit (1 );
1008
+ exit_code = 1 ;
1009
+ run_post_command_hook (the_repository );
1010
+ exit (exit_code );
933
1011
}
934
1012
935
1013
if (!strcmp ("--version" , argv [0 ]) || !strcmp ("-v" , argv [0 ]))
0 commit comments