fix: `exec` template func should not throw away stdout when stdin is non empty (#1151)

Fixes #1149
This commit is contained in:
KUOKA Yusuke 2020-03-20 12:23:34 +09:00 committed by GitHub
parent 499f6ec6e3
commit 994e4b66fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 26 additions and 30 deletions

1
go.mod
View File

@ -35,6 +35,7 @@ require (
go.uber.org/zap v1.9.1 go.uber.org/zap v1.9.1
golang.org/x/crypto v0.0.0-20191029031824-8986dd9e96cf // indirect golang.org/x/crypto v0.0.0-20191029031824-8986dd9e96cf // indirect
golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271 // indirect golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271 // indirect
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
golang.org/x/sys v0.0.0-20191029155521-f43be2a4598c // indirect golang.org/x/sys v0.0.0-20191029155521-f43be2a4598c // indirect
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
google.golang.org/api v0.13.0 // indirect google.golang.org/api v0.13.0 // indirect

View File

@ -2,6 +2,7 @@ package tmpl
import ( import (
"fmt" "fmt"
"golang.org/x/sync/errgroup"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
"io" "io"
"os" "os"
@ -58,60 +59,54 @@ func (c *Context) Exec(command string, args []interface{}, inputs ...string) (st
cmd := exec.Command(command, strArgs...) cmd := exec.Command(command, strArgs...)
cmd.Dir = c.basePath cmd.Dir = c.basePath
writeErrs := make(chan error) g := errgroup.Group{}
cmdErrs := make(chan error)
cmdOuts := make(chan []byte)
if len(input) > 0 { if len(input) > 0 {
stdin, err := cmd.StdinPipe() stdin, err := cmd.StdinPipe()
if err != nil { if err != nil {
return "", err return "", err
} }
go func(input string, stdin io.WriteCloser) {
g.Go(func() error {
defer stdin.Close() defer stdin.Close()
defer close(writeErrs)
size := len(input) size := len(input)
var n int
var err error
i := 0 i := 0
for { for {
n, err = io.WriteString(stdin, input[i:]) n, err := io.WriteString(stdin, input[i:])
if err != nil { if err != nil {
writeErrs <- fmt.Errorf("failed while writing %d bytes to stdin of \"%s\": %v", len(input), command, err) return fmt.Errorf("failed while writing %d bytes to stdin of \"%s\": %v", len(input), command, err)
break
} }
i += n i += n
if n == size {
break if i == size {
return nil
} }
} }
}(input, stdin) })
} }
go func() { var bytes []byte
defer close(cmdOuts)
defer close(cmdErrs)
bytes, err := cmd.Output() g.Go(func() error {
bs, err := cmd.Output()
if err != nil { if err != nil {
cmdErrs <- fmt.Errorf("exec cmd=%s args=[%s] failed: %v", command, strings.Join(strArgs, ", "), err) return fmt.Errorf("exec cmd=%s args=[%s] failed: %v", command, strings.Join(strArgs, ", "), err)
} else {
cmdOuts <- bytes
} }
}()
for { bytes = bs
select {
case bytes := <-cmdOuts: return nil
return string(bytes), nil })
case err := <-cmdErrs:
return "", err if err := g.Wait(); err != nil {
case err := <-writeErrs: return "", err
return "", err
}
} }
return string(bytes), nil
} }
func (c *Context) ReadFile(filename string) (string, error) { func (c *Context) ReadFile(filename string) (string, error) {