Этот коммит содержится в:
gedi 2016-05-13 08:32:15 +03:00
родитель a7c71e3171
коммит 60f8b3340e

Просмотреть файл

@ -1,44 +1,44 @@
package main package main
import ( import (
"bytes"
"fmt" "fmt"
"io" "io"
"os" "os"
"os/exec" "os/exec"
"regexp" "regexp"
"strconv" "strconv"
"strings" "syscall"
"time" "time"
"github.com/DATA-DOG/godog" "github.com/DATA-DOG/godog"
"github.com/shiena/ansicolor" "github.com/shiena/ansicolor"
) )
var statusMatch = regexp.MustCompile("^exit status (\\d+)$") var statusMatch = regexp.MustCompile("^exit status (\\d+)")
var parsedStatus int
func buildAndRun() (status int, err error) { func buildAndRun() (int, error) {
var status int
// will support Ansi colors for windows // will support Ansi colors for windows
stdout := ansicolor.NewAnsiColorWriter(os.Stdout) stdout := ansicolor.NewAnsiColorWriter(os.Stdout)
buffer := bytes.NewBuffer([]byte("")) stderr := ansicolor.NewAnsiColorWriter(statusOutputFilter(os.Stderr))
stderr := ansicolor.NewAnsiColorWriter(buffer)
builtFile := fmt.Sprintf("%s/%dgodog.go", os.TempDir(), time.Now().UnixNano()) builtFile := fmt.Sprintf("%s/%dgodog.go", os.TempDir(), time.Now().UnixNano())
buf, err := godog.Build() buf, err := godog.Build()
if err != nil { if err != nil {
return return status, err
} }
w, err := os.Create(builtFile) w, err := os.Create(builtFile)
if err != nil { if err != nil {
return return status, err
} }
defer os.Remove(builtFile) defer os.Remove(builtFile)
if _, err = w.Write(buf); err != nil { if _, err = w.Write(buf); err != nil {
w.Close() w.Close()
return return status, err
} }
w.Close() w.Close()
@ -46,27 +46,55 @@ func buildAndRun() (status int, err error) {
cmd.Stdout = stdout cmd.Stdout = stdout
cmd.Stderr = stderr cmd.Stderr = stderr
defer func() { if err = cmd.Start(); err != nil {
s := strings.TrimSpace(buffer.String()) return status, err
if s == "" {
status = 0
} else if m := statusMatch.FindStringSubmatch(s); len(m) > 1 {
status, _ = strconv.Atoi(m[1])
} else {
io.Copy(stdout, buffer)
} }
}()
return status, cmd.Run() if err = cmd.Wait(); err != nil {
if exiterr, ok := err.(*exec.ExitError); ok {
// The program has exited with an exit code != 0
status = 1
// This works on both Unix and Windows. Although package
// syscall is generally platform dependent, WaitStatus is
// defined for both Unix and Windows and in both cases has
// an ExitStatus() method with the same signature.
if st, ok := exiterr.Sys().(syscall.WaitStatus); ok {
status = st.ExitStatus()
}
return status, nil
}
return status, err
}
return status, nil
} }
func main() { func main() {
status, err := buildAndRun() status, err := buildAndRun()
switch e := err.(type) { if err != nil {
case nil: panic(err)
case *exec.ExitError:
os.Exit(status)
default:
panic(e)
} }
// it might be a case, that status might not be resolved
// in some OSes. this is attempt to parse it from stderr
if parsedStatus > status {
status = parsedStatus
}
os.Exit(status)
}
func statusOutputFilter(w io.Writer) io.Writer {
return writerFunc(func(b []byte) (int, error) {
if m := statusMatch.FindStringSubmatch(string(b)); len(m) > 1 {
parsedStatus, _ = strconv.Atoi(m[1])
// skip status stderr output
return len(b), nil
}
return w.Write(b)
})
}
type writerFunc func([]byte) (int, error)
func (w writerFunc) Write(b []byte) (int, error) {
return w(b)
} }