diff --git a/builder.go b/builder.go index 6686e02..70a5b1a 100644 --- a/builder.go +++ b/builder.go @@ -41,7 +41,7 @@ func main() { os.Exit(status) }`)) -// Build creates a test package like go test command. +// Build creates a test package like go test command at given target path. // If there are no go files in tested directory, then // it simply builds a godog executable to scan features. // @@ -53,16 +53,10 @@ func main() { // of tested package. // // Returns the path to generated executable -func Build() (string, error) { +func Build(bin string) error { abs, err := filepath.Abs(".") if err != nil { - return "", err - } - - bin := filepath.Join(abs, "godog.test") - // suffix with .exe for windows - if goos == "windows" { - bin += ".exe" + return err } // we allow package to be nil, if godog is run only when @@ -70,7 +64,7 @@ func Build() (string, error) { pkg := importPackage(abs) src, anyContexts, err := buildTestMain(pkg) if err != nil { - return bin, err + return err } workdir := fmt.Sprintf(filepath.Join("%s", "godog-%d"), os.TempDir(), time.Now().UnixNano()) @@ -84,7 +78,7 @@ func Build() (string, error) { // go does it better out, err := exec.Command("go", "test", "-i").CombinedOutput() if err != nil { - return bin, fmt.Errorf("failed to compile package %s:\n%s", pkg.Name, string(out)) + return fmt.Errorf("failed to compile package %s:\n%s", pkg.Name, string(out)) } // let go do the dirty work and compile test @@ -101,21 +95,21 @@ func Build() (string, error) { // go has built. We will reuse it for our suite workdir. out, err = exec.Command("go", "test", "-c", "-work", "-o", temp).CombinedOutput() if err != nil { - return bin, fmt.Errorf("failed to compile tested package %s:\n%s", pkg.Name, string(out)) + return fmt.Errorf("failed to compile tested package %s:\n%s", pkg.Name, string(out)) } defer os.Remove(temp) // extract go-build temporary directory as our workdir workdir = strings.TrimSpace(string(out)) if !strings.HasPrefix(workdir, "WORK=") { - return bin, fmt.Errorf("expected WORK dir path, but got: %s", workdir) + return fmt.Errorf("expected WORK dir path, but got: %s", workdir) } workdir = strings.Replace(workdir, "WORK=", "", 1) testdir = filepath.Join(workdir, pkg.ImportPath, "_test") } else { // still need to create temporary workdir if err = os.MkdirAll(testdir, 0755); err != nil { - return bin, err + return err } } defer os.RemoveAll(workdir) @@ -124,7 +118,7 @@ func Build() (string, error) { testmain := filepath.Join(testdir, "_testmain.go") err = ioutil.WriteFile(testmain, src, 0644) if err != nil { - return bin, err + return err } // godog library may not be imported in tested package @@ -137,7 +131,7 @@ func Build() (string, error) { } godogPkg, err := locatePackage(try) if err != nil { - return bin, err + return err } // make sure godog package archive is installed, gherkin @@ -146,7 +140,7 @@ func Build() (string, error) { cmd.Env = os.Environ() out, err := cmd.CombinedOutput() if err != nil { - return bin, fmt.Errorf("failed to install godog package:\n%s", string(out)) + return fmt.Errorf("failed to install godog package:\n%s", string(out)) } // collect all possible package dirs, will be @@ -179,7 +173,7 @@ func Build() (string, error) { cmd.Env = os.Environ() out, err = cmd.CombinedOutput() if err != nil { - return bin, fmt.Errorf("failed to compile testmain package:\n%s", string(out)) + return fmt.Errorf("failed to compile testmain package:\n%s", string(out)) } // link test suite executable @@ -199,10 +193,10 @@ func Build() (string, error) { msg := `failed to link test executable: reason: %s command: %s` - return bin, fmt.Errorf(msg, string(out), linker+" '"+strings.Join(args, "' '")+"'") + return fmt.Errorf(msg, string(out), linker+" '"+strings.Join(args, "' '")+"'") } - return bin, nil + return nil } func locatePackage(try []string) (*build.Package, error) { diff --git a/cmd/godog/main.go b/cmd/godog/main.go index ebf2d6a..1dab0b2 100644 --- a/cmd/godog/main.go +++ b/cmd/godog/main.go @@ -2,9 +2,11 @@ package main import ( "fmt" + "go/build" "io" "os" "os/exec" + "path/filepath" "regexp" "strconv" "syscall" @@ -18,23 +20,20 @@ var parsedStatus int var stdout = io.Writer(os.Stdout) var stderr = statusOutputFilter(os.Stderr) -func buildAndRun(output string) (int, error) { +func buildAndRun() (int, error) { var status int - bin, err := godog.Build() + bin, err := filepath.Abs("godog.test") if err != nil { return 1, err } + if build.Default.GOOS == "windows" { + bin += ".exe" + } + if err = godog.Build(bin); err != nil { + return 1, err + } defer os.Remove(bin) - //output the generated binary file and exit if the output option was provided - if output != ""{ - err = Copy(output,bin) - status := 0 - if err != nil { - status = 1 - } - return status, err - } cmd := exec.Command(bin, os.Args[1:]...) cmd.Stdout = stdout @@ -78,6 +77,19 @@ func main() { os.Exit(1) } + if len(output) > 0 { + bin, err := filepath.Abs(output) + if err != nil { + fmt.Fprintln(stderr, "could not locate absolute path for:", output, err) + os.Exit(1) + } + if err = godog.Build(bin); err != nil { + fmt.Fprintln(stderr, "could not build binary at:", output, err) + os.Exit(1) + } + os.Exit(0) + } + if noclr { stdout = noColorsWriter(stdout) stderr = noColorsWriter(stderr) @@ -91,7 +103,7 @@ func main() { os.Exit(0) // should it be 0? } - status, err := buildAndRun(output) + status, err := buildAndRun() if err != nil { fmt.Fprintln(stderr, err) os.Exit(1) @@ -120,16 +132,3 @@ type writerFunc func([]byte) (int, error) func (w writerFunc) Write(b []byte) (int, error) { return w(b) } - -func Copy(dst, src string) error { - in, err := os.Open(src) - if err != nil { return err } - defer in.Close() - out, err := os.Create(dst) - if err != nil { return err } - defer out.Close() - _, err = io.Copy(out, in) - cerr := out.Close() - if err != nil { return err } - return cerr -} diff --git a/flags.go b/flags.go index 20b0280..bdcad34 100644 --- a/flags.go +++ b/flags.go @@ -24,7 +24,7 @@ var descTagsOption = "Filter scenarios by tags. Expression can be:\n" + s(4) + "- " + cl(`"@wip,@undone"`, yellow) + ": run wip or undone scenarios" var descOutputOption = "Output the temporary test runner executable:\n" + - s(4) + "- supply the name to give the executable " + cl("test_features.exe", yellow) + "\n" + s(4) + "- supply the name to give the executable " + cl("test_features.exe", yellow) + "\n" // FlagSet allows to manage flags by external suite runner func FlagSet(format, tags *string, defs, sof, noclr *bool, cr *int, output *string) *flag.FlagSet { @@ -45,8 +45,8 @@ func FlagSet(format, tags *string, defs, sof, noclr *bool, cr *int, output *stri set.BoolVar(defs, "d", false, "Print all available step definitions.") set.BoolVar(sof, "stop-on-failure", false, "Stop processing on first failed scenario.") set.BoolVar(noclr, "no-colors", false, "Disable ansi colors.") - set.StringVar(output, "output", "", descOutputOption) - set.StringVar(output, "o", "", descOutputOption) + set.StringVar(output, "output", "", descOutputOption) + set.StringVar(output, "o", "", descOutputOption) set.Usage = usage(set) return set }