diff options
Diffstat (limited to 'pluginhook.go')
-rw-r--r-- | pluginhook.go | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/pluginhook.go b/pluginhook.go new file mode 100644 index 000000000000..5ee57a0b44f8 --- /dev/null +++ b/pluginhook.go @@ -0,0 +1,93 @@ +package main + +import ( + "os" + "fmt" + "os/exec" + "syscall" + "path/filepath" + "log" + "flag" + "bytes" + "strings" + "golang.org/x/crypto/ssh/terminal" +) + +func main() { + var parallel = flag.Bool("p", false, "Run hooks in parallel") + var trace = flag.Bool("x", false, "Trace mode") + flag.Parse() + + if len(os.Getenv("PLUGINHOOK_TRACE")) > 0 { + *trace = true + } + + pluginPath := os.Getenv("PLUGIN_PATH") + if pluginPath == "" { + log.Fatal("[ERROR] Unable to locate plugins: set $PLUGIN_PATH\n") + os.Exit(1) + } + if flag.NArg() < 1 { + log.Fatal("[ERROR] Hook name argument is required\n") + os.Exit(1) + } + cmds := make([]exec.Cmd, 0) + var matches, _ = filepath.Glob(fmt.Sprintf("%s/*/%s", pluginPath, flag.Arg(0))) + for _, hook := range matches { + cmd := exec.Command(hook, flag.Args()[1:]...) + cmds = append(cmds, *cmd) + } + for i := len(cmds)-1; i >= 0; i-- { + cmds[i].Stderr = os.Stderr + + if i == len(cmds)-1 { + cmds[i].Stdout = os.Stdout + } + if i > 0 { + if *parallel { + stdout, err := cmds[i-1].StdoutPipe() + if err != nil { + log.Fatal(err) + } + cmds[i].Stdin = stdout + } else { + var buf bytes.Buffer + cmds[i-1].Stdout = &buf + cmds[i].Stdin = &buf + } + } + if i == 0 && !terminal.IsTerminal(syscall.Stdin) { + cmds[i].Stdin = os.Stdin + } + } + + if *parallel { + done := make(chan bool, len(cmds)) + + for i := 0; i < len(cmds); i++ { + go func(cmd exec.Cmd, i int) { + if *trace { + fmt.Fprintln(os.Stderr, "+", strings.Join(cmds[i].Args, " ")) + } + err := cmd.Run() + if msg, ok := err.(*exec.ExitError); ok { // there is error code + os.Exit(msg.Sys().(syscall.WaitStatus).ExitStatus()) + } + done <- true + }(cmds[i], i) + } + for i := 0; i < len(cmds); i++ { + <-done + } + } else { + for i := 0; i < len(cmds); i++ { + if *trace { + fmt.Fprintln(os.Stderr, "+", strings.Join(cmds[i].Args, " ")) + } + err := cmds[i].Run() + if msg, ok := err.(*exec.ExitError); ok { // there is error code + os.Exit(msg.Sys().(syscall.WaitStatus).ExitStatus()) + } + } + } +} |