Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,12 @@ func (c *Cmd) Clone() *Cmd {
// Exactly one Status is sent on the channel when the command ends. The channel
// is not closed. Any Go error is set to Status.Error. Start is idempotent; it
// always returns the same channel.

func (c *Cmd) Start() <-chan Status {
return c.StartWithStdin(nil)
}

func (c *Cmd) StartWithStdin(in io.Reader) <-chan Status {
c.Lock()
defer c.Unlock()

Expand All @@ -204,7 +209,7 @@ func (c *Cmd) Start() <-chan Status {
}

c.statusChan = make(chan Status, 1)
go c.run()
go c.run(in)
return c.statusChan
}

Expand Down Expand Up @@ -290,7 +295,7 @@ func (c *Cmd) Done() <-chan struct{} {

// --------------------------------------------------------------------------

func (c *Cmd) run() {
func (c *Cmd) run(in io.Reader) {
defer func() {
c.statusChan <- c.Status() // unblocks Start if caller is waiting
close(c.doneChan)
Expand All @@ -300,6 +305,9 @@ func (c *Cmd) run() {
// Setup command
// //////////////////////////////////////////////////////////////////////
cmd := exec.Command(c.Name, c.Args...)
if in != nil {
cmd.Stdin = in
}

// Platform-specific SysProcAttr management
setProcessGroupID(cmd)
Expand Down
50 changes: 50 additions & 0 deletions cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package cmd_test

import (
"bytes"
"errors"
"io/ioutil"
"os"
Expand Down Expand Up @@ -1028,3 +1029,52 @@ func TestCmdNoOutput(t *testing.T) {
t.Errorf("got stderr, expected no output: %v", s.Stderr)
}
}

func TestStdinOk(t *testing.T) {

tests := []struct {
in []byte
}{
{
in: []byte("1"),
},
{
in: []byte("hello"),
},
{
in: []byte{65, 66, 67, 226, 130, 172}, // ABC€
},
}
for _, tt := range tests {
now := time.Now().Unix()
p := cmd.NewCmd("test/stdin")
gotStatus := <-p.StartWithStdin(bytes.NewReader(tt.in))
expectStatus := cmd.Status{
Cmd: "test/stdin",
PID: gotStatus.PID, // nondeterministic
Complete: true,
Exit: 0,
Error: nil,
Runtime: gotStatus.Runtime, // nondeterministic
Stdout: []string{"stdin: " + string(tt.in)},
Stderr: []string{},
}
if gotStatus.StartTs < now {
t.Error("StartTs < now")
}
if gotStatus.StopTs < gotStatus.StartTs {
t.Error("StopTs < StartTs")
}
gotStatus.StartTs = 0
gotStatus.StopTs = 0
if diffs := deep.Equal(gotStatus, expectStatus); diffs != nil {
t.Error(diffs)
}
if gotStatus.PID < 0 {
t.Errorf("got PID %d, expected non-zero", gotStatus.PID)
}
if gotStatus.Runtime < 0 {
t.Errorf("got runtime %f, expected non-zero", gotStatus.Runtime)
}
}
}
5 changes: 5 additions & 0 deletions test/stdin
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash

IN=$(< /dev/stdin)

echo "stdin: $IN"