diff --git a/pkg/commands/exec_live_default.go b/pkg/commands/exec_live_default.go index 27363c3b9..e717d972d 100644 --- a/pkg/commands/exec_live_default.go +++ b/pkg/commands/exec_live_default.go @@ -9,6 +9,7 @@ import ( "regexp" "strings" "sync" + "unicode/utf8" "github.com/kr/pty" ) @@ -33,6 +34,7 @@ func RunCommandWithOutputLiveWrapper(c *OSCommand, command string, output func(s return errorMessage, err } + // canAsk makes sure there are no data races in go var canAskLock sync.Mutex canAskValue := true canAsk := func() bool { @@ -59,7 +61,7 @@ func RunCommandWithOutputLiveWrapper(c *OSCommand, command string, output func(s re := regexp.MustCompile(`(^\s*)|(\s*$)`) scanner := bufio.NewScanner(tty) - scanner.Split(bufio.ScanWords) + scanner.Split(scanWordsWithNewLines) for scanner.Scan() { // canAsk prefrents calls to output when the program is already closed if canAsk() { @@ -74,7 +76,7 @@ func RunCommandWithOutputLiveWrapper(c *OSCommand, command string, output func(s waitForBufio.Done() }() - if err := cmd.Wait(); err != nil { + if err = cmd.Wait(); err != nil { stopCanAsk() waitForBufio.Wait() return strings.Join(cmdOutput, " "), err @@ -82,3 +84,49 @@ func RunCommandWithOutputLiveWrapper(c *OSCommand, command string, output func(s return errorMessage, nil } + +// scanWordsWithNewLines is a copy of bufio.ScanWords but this also captures new lines +func scanWordsWithNewLines(data []byte, atEOF bool) (advance int, token []byte, err error) { + start := 0 + for width := 0; start < len(data); start += width { + var r rune + r, width = utf8.DecodeRune(data[start:]) + if !isSpace(r) { + break + } + } + for width, i := 0, start; i < len(data); i += width { + var r rune + r, width = utf8.DecodeRune(data[i:]) + if isSpace(r) { + return i + width, data[start:i], nil + } + } + if atEOF && len(data) > start { + return len(data), data[start:], nil + } + return start, nil, nil +} + +// isSpace is also copied form bufio.ScanWords and has been modiefied to also captures new lines +func isSpace(r rune) bool { + if r <= '\u00FF' { + // Obvious ASCII ones: \t through \r plus space. Plus two Latin-1 oddballs. + switch r { + case ' ', '\t', '\v', '\f': + return true + case '\u0085', '\u00A0': + return true + } + return false + } + // High-valued ones. + if '\u2000' <= r && r <= '\u200a' { + return true + } + switch r { + case '\u1680', '\u2028', '\u2029', '\u202f', '\u205f', '\u3000': + return true + } + return false +} diff --git a/pkg/commands/os.go b/pkg/commands/os.go index 8a36d9851..ab545a00b 100644 --- a/pkg/commands/os.go +++ b/pkg/commands/os.go @@ -87,8 +87,9 @@ func (c *OSCommand) DetectUnamePass(command string, ask func(string) string) err return "" }) if err != nil { - if errorCode := err.Error(); strings.Contains("exit status 128", errorCode) { - errMessage = "exit status 128" + if strings.Contains("exit status 128", err.Error()) { + // errMessage = "exit status 128" + errMessage = errMessage } return errors.New(errMessage) }