github.com/kcmerrill/alfred@v0.0.0-20180727171036-06445dcb5e3d/pkg/alfred/command.go (about) 1 package alfred 2 3 import ( 4 "bufio" 5 "bytes" 6 "os" 7 "os/exec" 8 "sync" 9 ) 10 11 // the task component 12 func commandC(task Task, context *Context, tasks map[string]Task) { 13 command(task.Command, task, context, tasks) 14 } 15 16 func commandInteractive(commandStr string, task Task, context *Context, tasks map[string]Task) { 17 if commandStr == "" { 18 return 19 } 20 21 for retry := 0; retry <= task.Retry; retry++ { 22 cmd := exec.Command("bash", "-c", translate(commandStr, context)) 23 cmd.Stdin = os.Stdin 24 cmd.Stdout = os.Stdout 25 cmd.Stderr = os.Stderr 26 cmd.Run() 27 } 28 } 29 30 // within the context of a task, run a command with proper output 31 // looking for eval, or simple execs? If so, see utils.go 32 // this one will hook into the GUI where appropriate 33 func command(commandStr string, task Task, context *Context, tasks map[string]Task) { 34 if commandStr == "" { 35 return 36 } 37 38 translatedCMD := translate(commandStr, context) 39 40 if context.Debug { 41 cmdOK(translatedCMD, context) 42 return 43 } 44 45 // skip the beautification 46 if context.Interactive { 47 commandInteractive(commandStr, task, context, tasks) 48 return 49 } 50 51 for retry := 0; retry <= task.Retry; retry++ { 52 cmd := exec.Command("bash", "-c", translatedCMD) 53 if context.Stdin != "" { 54 cmd.Stdin = bytes.NewBufferString(context.Stdin) 55 } 56 57 // set the directory where to run 58 cmd.Dir, _ = task.dir(context) 59 60 // wait for output to be completed before moving on 61 var wg sync.WaitGroup 62 cmdReaderStdOut, _ := cmd.StdoutPipe() 63 scannerStdOut := bufio.NewScanner(cmdReaderStdOut) 64 scannerStdOut.Split(bufio.ScanLines) 65 go func() { 66 wg.Add(1) 67 defer wg.Done() 68 for scannerStdOut.Scan() { 69 cmdOK(scannerStdOut.Text(), context) 70 } 71 }() 72 73 cmdReaderStdErr, _ := cmd.StderrPipe() 74 scannerStdErr := bufio.NewScanner(cmdReaderStdErr) 75 scannerStdErr.Split(bufio.ScanLines) 76 go func() { 77 wg.Add(1) 78 defer wg.Done() 79 for scannerStdErr.Scan() { 80 cmdFail(scannerStdErr.Text(), context) 81 } 82 }() 83 84 err := cmd.Start() 85 if err != nil { 86 cmdFail(scannerStdErr.Text(), context) 87 } 88 wg.Wait() 89 statusCode := cmd.Wait() 90 91 if statusCode != nil { 92 task.Exit(context, tasks) 93 } else { 94 return 95 } 96 } 97 // was the last thing we saw a not failure? 98 outFail("command failed", "", context) 99 }