Skip to content

Commit

Permalink
Merge pull request #1 from asymmetric-research/ignore-incomplete-lines
Browse files Browse the repository at this point in the history
added IgnoreIncompleteLines option
  • Loading branch information
johnstonematt committed Aug 26, 2024
2 parents 7e4872c + 3903712 commit 3c4438a
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 23 deletions.
32 changes: 22 additions & 10 deletions cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@ type Options struct {
// value DEFAULT_LINE_BUFFER_SIZE is usually sufficient, but if
// ErrLineBufferOverflow errors occur, try increasing the size with this field.
LineBufferSize uint

// IgnoreIncompleteLines configures the 'ignoreIncompleteLines' option of the command's
// OutputStream's. If set to true, lines that do not end in '\n' are ignored.
IgnoreIncompleteLines bool
}

// NewCmdOptions creates a new Cmd with options. The command is not started
Expand Down Expand Up @@ -214,11 +218,11 @@ func NewCmdOptions(options Options, name string, args ...string) *Cmd {

if options.Streaming {
c.Stdout = make(chan string, DEFAULT_STREAM_CHAN_SIZE)
c.stdoutStream = NewOutputStream(c.Stdout)
c.stdoutStream = NewOutputStream(c.Stdout, options.IgnoreIncompleteLines)
c.stdoutStream.SetLineBufferSize(int(options.LineBufferSize))

c.Stderr = make(chan string, DEFAULT_STREAM_CHAN_SIZE)
c.stderrStream = NewOutputStream(c.Stderr)
c.stderrStream = NewOutputStream(c.Stderr, options.IgnoreIncompleteLines)
c.stderrStream.SetLineBufferSize(int(options.LineBufferSize))
}

Expand Down Expand Up @@ -682,22 +686,24 @@ func (e ErrLineBufferOverflow) Error() string {
// While runnableCmd is running, lines are sent to the channel as soon as they
// are written and newline-terminated by the command.
type OutputStream struct {
streamChan chan string
bufSize int
buf []byte
lastChar int
streamChan chan string
bufSize int
buf []byte
lastChar int
ignoreIncompleteLines bool
}

// NewOutputStream creates a new streaming output on the given channel. The
// caller must begin receiving on the channel before the command is started.
// The OutputStream never closes the channel.
func NewOutputStream(streamChan chan string) *OutputStream {
func NewOutputStream(streamChan chan string, ignoreIncompleteLines bool) *OutputStream {
out := &OutputStream{
streamChan: streamChan,
// --
bufSize: DEFAULT_LINE_BUFFER_SIZE,
buf: make([]byte, DEFAULT_LINE_BUFFER_SIZE),
lastChar: 0,
bufSize: DEFAULT_LINE_BUFFER_SIZE,
buf: make([]byte, DEFAULT_LINE_BUFFER_SIZE),
lastChar: 0,
ignoreIncompleteLines: ignoreIncompleteLines,
}
return out
}
Expand Down Expand Up @@ -738,7 +744,13 @@ func (rw *OutputStream) Write(p []byte) (n int, err error) {
firstChar += newlineOffset + 1
}

// if the stream (p) does not end in a '\n', then we will have firstChar < n
if firstChar < n {
// if we are ignoring incomplete lines, then we can just exit here
if rw.ignoreIncompleteLines {
return // implicit
}

remain := len(p[firstChar:])
bufFree := len(rw.buf[rw.lastChar:])
if remain > bufFree {
Expand Down
18 changes: 9 additions & 9 deletions cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"testing"
"time"

"github.com/go-cmd/cmd"
"github.com/asymmetric-research/cmd"
"github.com/go-test/deep"
)

Expand Down Expand Up @@ -752,7 +752,7 @@ func TestCmdOnlyStreamingOutput(t *testing.T) {

func TestStreamingMultipleLines(t *testing.T) {
lines := make(chan string, 5)
out := cmd.NewOutputStream(lines)
out := cmd.NewOutputStream(lines, false)

// Quick side test: Lines() chan string should be the same chan string
// we created the object with
Expand Down Expand Up @@ -799,7 +799,7 @@ func TestStreamingMultipleLinesLastNotTerminated(t *testing.T) {
// If last line isn't \n terminated, go-cmd should flush it anyway
// https://github.com/go-cmd/cmd/pull/48
lines := make(chan string, 5)
out := cmd.NewOutputStream(lines)
out := cmd.NewOutputStream(lines, false)

// Quick side test: Lines() chan string should be the same chan string
// we created the object with
Expand Down Expand Up @@ -846,7 +846,7 @@ func TestStreamingMultipleLinesLastNotTerminated(t *testing.T) {

func TestStreamingBlankLines(t *testing.T) {
lines := make(chan string, 5)
out := cmd.NewOutputStream(lines)
out := cmd.NewOutputStream(lines, false)

// Blank line in the middle
input := "foo\n\nbar\n"
Expand Down Expand Up @@ -924,7 +924,7 @@ LINES3:
func TestStreamingCarriageReturn(t *testing.T) {
// Carriage return should be stripped
lines := make(chan string, 5)
out := cmd.NewOutputStream(lines)
out := cmd.NewOutputStream(lines, false)

input := "foo\r\nbar\r\n"
expectLines := []string{"foo", "bar"}
Expand Down Expand Up @@ -955,7 +955,7 @@ func TestStreamingLineBuffering(t *testing.T) {
// write. When line is later terminated with newline, we prepend the buffered
// line and send the complete line.
lines := make(chan string, 1)
out := cmd.NewOutputStream(lines)
out := cmd.NewOutputStream(lines, false)

// Write 3 unterminated lines. Without a newline, they'll be buffered until...
for i := 0; i < 3; i++ {
Expand Down Expand Up @@ -1018,7 +1018,7 @@ func TestStreamingErrLineBufferOverflow1(t *testing.T) {
longLine[cmd.DEFAULT_LINE_BUFFER_SIZE+1] = 'z'

lines := make(chan string, 5)
out := cmd.NewOutputStream(lines)
out := cmd.NewOutputStream(lines, false)

// Write the long line, it should only write (n) 3 bytes for "bc\n"
n, err := out.Write(longLine)
Expand Down Expand Up @@ -1079,7 +1079,7 @@ func TestStreamingErrLineBufferOverflow2(t *testing.T) {
// Overflow line buffer on 2nd write. So first write puts something in the
// buffer, and then 2nd overflows it instead of completing the line.
lines := make(chan string, 1)
out := cmd.NewOutputStream(lines)
out := cmd.NewOutputStream(lines, false)

// Get "bar" into the buffer by omitting its newline
input := "foo\nbar"
Expand Down Expand Up @@ -1143,7 +1143,7 @@ func TestStreamingSetLineBufferSize(t *testing.T) {
longLine[cmd.DEFAULT_LINE_BUFFER_SIZE+1] = '\n'

lines := make(chan string, 5)
out := cmd.NewOutputStream(lines)
out := cmd.NewOutputStream(lines, false)
out.SetLineBufferSize(cmd.DEFAULT_LINE_BUFFER_SIZE * 2)

n, err := out.Write(longLine)
Expand Down
2 changes: 1 addition & 1 deletion cmd_windows_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"testing"
"time"

"github.com/go-cmd/cmd"
"github.com/asymmetric-research/cmd"
"github.com/go-test/deep"
)

Expand Down
2 changes: 1 addition & 1 deletion examples/blocking-buffered/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package main
import (
"fmt"

"github.com/go-cmd/cmd"
"github.com/asymmetric-research/cmd"
)

func main() {
Expand Down
2 changes: 1 addition & 1 deletion examples/blocking-streaming/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"fmt"
"os"

"github.com/go-cmd/cmd"
"github.com/asymmetric-research/cmd"
)

func main() {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module github.com/go-cmd/cmd
module github.com/asymmetric-research/cmd

go 1.20

Expand Down

0 comments on commit 3c4438a

Please sign in to comment.