Skip to content

Commit

Permalink
Merge pull request #4 from placer14/master
Browse files Browse the repository at this point in the history
Fix improper use of os.Stat
  • Loading branch information
progrium authored Oct 23, 2018
2 parents d521067 + 7757ae6 commit 104b119
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 3 deletions.
50 changes: 48 additions & 2 deletions shell.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,13 +145,23 @@ func (c *Command) shellCmd(quote bool) string {
}

func (c *Command) Run() *Process {
cmd := exec.Command(Shell[0], append(Shell[1:], c.shellCmd(false))...)
return c.execute(cmd, cmd.Run)
}

func (c *Command) Start() *Process {
cmd := exec.Command(Shell[0], append(Shell[1:], c.shellCmd(false))...)
return c.execute(cmd, cmd.Start)
}

func (c *Command) execute(cmd *exec.Cmd, call func() error) *Process {
if Trace {
fmt.Fprintln(os.Stderr, TracePrefix, c.shellCmd(false))
}
cmd := exec.Command(Shell[0], append(Shell[1:], c.shellCmd(false))...)
cmd.Dir = c.wd
log.Println(cmd.Args)
p := new(Process)
p.cmd = cmd
if c.in != nil {
cmd.Stdin = c.in.Run()
} else {
Expand All @@ -173,7 +183,7 @@ func (c *Command) Run() *Process {
cmd.Stderr = &stderr
}
p.Stderr = &stderr
err := cmd.Run()
err := call()
if err != nil {
if exiterr, ok := err.(*exec.ExitError); ok {
if stat, ok := exiterr.Sys().(syscall.WaitStatus); ok {
Expand All @@ -196,12 +206,44 @@ func Cmd(cmd ...interface{}) *Command {
}

type Process struct {
cmd *exec.Cmd
killed bool

Stdout *bytes.Buffer
Stderr *bytes.Buffer
Stdin io.WriteCloser
ExitStatus int
}

func (p *Process) Wait() error {
err := p.cmd.Wait()
if err != nil {
if exiterr, ok := err.(*exec.ExitError); ok {
if stat, ok := exiterr.Sys().(syscall.WaitStatus); ok {
p.ExitStatus = int(stat.ExitStatus())
if Panic && !p.killed {
panic(p)
}
}
}
}
return err
}

func (p *Process) Kill() error {
p.killed = true
err := p.cmd.Process.Kill()
if err != nil {
return fmt.Errorf("killed error: %s", err)
}
if err := p.Wait(); err == nil {
if !strings.Contains(err.Error(), "signal: killed") {
return err
}
}
return nil
}

func (p *Process) String() string {
return strings.Trim(p.Stdout.String(), "\n")
}
Expand Down Expand Up @@ -232,3 +274,7 @@ func (p *Process) Write(b []byte) (int, error) {
func Run(cmd ...interface{}) *Process {
return Cmd(cmd...).Run()
}

func Start(cmd ...interface{}) *Process {
return Cmd(cmd...).Start()
}
38 changes: 37 additions & 1 deletion shell_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"os"
"strings"
"testing"
"time"
)

func TestCmdRun(t *testing.T) {
Expand All @@ -22,6 +23,41 @@ func TestRun(t *testing.T) {
}
}

func TestStartWait(t *testing.T) {
p := Start("echo", "foobar")
err := p.Wait()
if err != nil {
t.Fatal("error not expected:", err)
}
output := p.String()
if output != "foobar" {
t.Fatal("output not expected:", output)
}
}

func TestStartKillWait(t *testing.T) {
p := Start("cat")
err := p.Kill()
if err != nil {
t.Fatal("error not expected:", err)
}

var (
done = make(chan interface{}, 0)
timer = time.NewTimer(2 * time.Second)
)
go func() {
p.Wait()
done <- struct{}{}
}()
select {
case <-timer.C:
t.Fatal("kill timeout reached")
case <-done:
break
}
}

func TestPanic(t *testing.T) {
defer func() {
p := recover().(*Process).ExitStatus
Expand Down Expand Up @@ -141,7 +177,7 @@ func TestSetWorkDir(t *testing.T) {
t.Fatal("unexpected error:", p.Error())
}

_, err := os.Stat(testPath, "testfile")
_, err := os.Stat(Path(testPath, "testfile"))
if err != nil {
t.Errorf("expected touched file to be present in correct working dir but was not")
}
Expand Down

0 comments on commit 104b119

Please sign in to comment.