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  }