14
14
#include "shallow.h"
15
15
#include "trace.h"
16
16
#include "trace2.h"
17
+ #include "dir.h"
18
+ #include "hook.h"
17
19
18
20
#define RUN_SETUP (1<<0)
19
21
#define RUN_SETUP_GENTLY (1<<1)
@@ -425,6 +427,67 @@ static int handle_alias(int *argcp, const char ***argv)
425
427
return ret ;
426
428
}
427
429
430
+ /* Runs pre/post-command hook */
431
+ static struct strvec sargv = STRVEC_INIT ;
432
+ static int run_post_hook = 0 ;
433
+ static int exit_code = -1 ;
434
+
435
+ static int run_pre_command_hook (const char * * argv )
436
+ {
437
+ char * lock ;
438
+ int ret = 0 ;
439
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT ;
440
+
441
+ /*
442
+ * Ensure the global pre/post command hook is only called for
443
+ * the outer command and not when git is called recursively
444
+ * or spawns multiple commands (like with the alias command)
445
+ */
446
+ lock = getenv ("COMMAND_HOOK_LOCK" );
447
+ if (lock && !strcmp (lock , "true" ))
448
+ return 0 ;
449
+ setenv ("COMMAND_HOOK_LOCK" , "true" , 1 );
450
+
451
+ /* call the hook proc */
452
+ strvec_pushv (& sargv , argv );
453
+ strvec_pushv (& opt .args , sargv .v );
454
+ ret = run_hooks_opt ("pre-command" , & opt );
455
+
456
+ if (!ret )
457
+ run_post_hook = 1 ;
458
+ return ret ;
459
+ }
460
+
461
+ static int run_post_command_hook (void )
462
+ {
463
+ char * lock ;
464
+ int ret = 0 ;
465
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT ;
466
+
467
+ /*
468
+ * Only run post_command if pre_command succeeded in this process
469
+ */
470
+ if (!run_post_hook )
471
+ return 0 ;
472
+ lock = getenv ("COMMAND_HOOK_LOCK" );
473
+ if (!lock || strcmp (lock , "true" ))
474
+ return 0 ;
475
+
476
+ strvec_pushv (& opt .args , sargv .v );
477
+ strvec_pushf (& opt .args , "--exit_code=%u" , exit_code );
478
+ ret = run_hooks_opt ("post-command" , & opt );
479
+
480
+ run_post_hook = 0 ;
481
+ strvec_clear (& sargv );
482
+ setenv ("COMMAND_HOOK_LOCK" , "false" , 1 );
483
+ return ret ;
484
+ }
485
+
486
+ static void post_command_hook_atexit (void )
487
+ {
488
+ run_post_command_hook ();
489
+ }
490
+
428
491
static int run_builtin (struct cmd_struct * p , int argc , const char * * argv )
429
492
{
430
493
int status , help ;
@@ -460,18 +523,23 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
460
523
if (!help && p -> option & NEED_WORK_TREE )
461
524
setup_work_tree ();
462
525
526
+ if (run_pre_command_hook (argv ))
527
+ die ("pre-command hook aborted command" );
528
+
463
529
trace_argv_printf (argv , "trace: built-in: git" );
464
530
trace2_cmd_name (p -> cmd );
465
531
trace2_cmd_list_config ();
466
532
trace2_cmd_list_env_vars ();
467
533
468
534
validate_cache_entries (the_repository -> index );
469
- status = p -> fn (argc , argv , prefix );
535
+ exit_code = status = p -> fn (argc , argv , prefix );
470
536
validate_cache_entries (the_repository -> index );
471
537
472
538
if (status )
473
539
return status ;
474
540
541
+ run_post_command_hook ();
542
+
475
543
/* Somebody closed stdout? */
476
544
if (fstat (fileno (stdout ), & st ))
477
545
return 0 ;
@@ -748,13 +816,16 @@ static void execv_dashed_external(const char **argv)
748
816
*/
749
817
trace_argv_printf (cmd .args .v , "trace: exec:" );
750
818
819
+ if (run_pre_command_hook (cmd .args .v ))
820
+ die ("pre-command hook aborted command" );
821
+
751
822
/*
752
823
* If we fail because the command is not found, it is
753
824
* OK to return. Otherwise, we just pass along the status code,
754
825
* or our usual generic code if we were not even able to exec
755
826
* the program.
756
827
*/
757
- status = run_command (& cmd );
828
+ exit_code = status = run_command (& cmd );
758
829
759
830
/*
760
831
* If the child process ran and we are now going to exit, emit a
@@ -765,6 +836,8 @@ static void execv_dashed_external(const char **argv)
765
836
exit (status );
766
837
else if (errno != ENOENT )
767
838
exit (128 );
839
+
840
+ run_post_command_hook ();
768
841
}
769
842
770
843
static int run_argv (int * argcp , const char * * * argv )
@@ -872,6 +945,7 @@ int cmd_main(int argc, const char **argv)
872
945
}
873
946
874
947
trace_command_performance (argv );
948
+ atexit (post_command_hook_atexit );
875
949
876
950
/*
877
951
* "git-xxxx" is the same as "git xxxx", but we obviously:
@@ -897,10 +971,14 @@ int cmd_main(int argc, const char **argv)
897
971
if (!argc ) {
898
972
/* The user didn't specify a command; give them help */
899
973
commit_pager_choice ();
974
+ if (run_pre_command_hook (argv ))
975
+ die ("pre-command hook aborted command" );
900
976
printf (_ ("usage: %s\n\n" ), git_usage_string );
901
977
list_common_cmds_help ();
902
978
printf ("\n%s\n" , _ (git_more_info_string ));
903
- exit (1 );
979
+ exit_code = 1 ;
980
+ run_post_command_hook ();
981
+ exit (exit_code );
904
982
}
905
983
906
984
if (!strcmp ("--version" , argv [0 ]) || !strcmp ("-v" , argv [0 ]))
0 commit comments