package openwrt import ( "bytes" "fmt" "log" "os/exec" "syscall" ) // Executor interface to describe command runners signature type Executor interface { Run(command string, params ...string) *CommandResult } // CommandResult contain all information about a command execution, stdout, stderr type CommandResult struct { Stdout string Stderr string ReturnCode int } type localExecutor struct{} func (e *localExecutor) Run(command string, params ...string) *CommandResult { var out bytes.Buffer var stderr bytes.Buffer var exitCode int defaultFailedCode := 255 exe := exec.Command(command, params...) exe.Stdout = &out exe.Stderr = &stderr err := exe.Run() if err != nil { if exitError, ok := err.(*exec.ExitError); ok { ws := exitError.Sys().(syscall.WaitStatus) exitCode = ws.ExitStatus() } else { // This will happen (in OSX) if `name` is not available in $PATH, // in this situation, exit code could not be get, and stderr will be // empty string very likely, so we use the default fail code, and format err // to string and set to stderr log.Printf("Could not get exit code for failed program: %v, %v", command, params) exitCode = defaultFailedCode } fmt.Println(fmt.Sprint(err) + ": " + stderr.String()) log.Fatal(err) } if err != nil { // try to get the exit code } else { // success, exitCode should be 0 if go is ok ws := exe.ProcessState.Sys().(syscall.WaitStatus) exitCode = ws.ExitStatus() } return &CommandResult{ Stdout: out.String(), Stderr: stderr.String(), ReturnCode: exitCode, } }