@@ -8,9 +8,11 @@ import (
88 "os"
99 "os/exec"
1010 "regexp"
11+ "sync"
1112 "time"
1213
1314 "github.com/go-tstr/tstr/strerr"
15+ "golang.org/x/sync/errgroup"
1416)
1517
1618const (
@@ -225,16 +227,20 @@ func WithPreCmd(cmd *exec.Cmd) Opt {
225227}
226228
227229// WithGoCode builds the given Go projects and sets the main package as the command.
228- // By default the command is set to collect coverage data.
230+ // By default the the output binary is instrumented to collect coverage data
229231// Working directory for build command is set to modulePath which means that the mainPkg should be relative to it.
232+ // Building the binary is done in a separate goroutine and the command is started only after the build is finished.
233+ // Also building is done only once which allows to reuse the reusing the the same Cmd instance without rebuilding the binary.
230234func WithGoCode (modulePath , mainPkg string ) Opt {
231- return func (c * Cmd ) error {
235+ var target string
236+ eg := & errgroup.Group {}
237+ eg .Go (sync .OnceValue (func () error {
232238 dir , err := os .MkdirTemp ("" , "go-tstr" )
233239 if err != nil {
234240 return fmt .Errorf ("failed to create tmp dir for go binary: %w" , err )
235241 }
236242
237- target : = dir + "/" + "go-app"
243+ target = dir + "/" + "go-app"
238244 buildCmd := exec .Command ("go" , "build" , "-race" , "-cover" , "-covermode" , "atomic" , "-o" , target , mainPkg )
239245 buildCmd .Env = append (os .Environ (), "CGO_ENABLED=1" ) // Required for -race flag
240246 buildCmd .Stdout = os .Stdout
@@ -244,6 +250,13 @@ func WithGoCode(modulePath, mainPkg string) Opt {
244250 if err != nil {
245251 return fmt .Errorf ("%w: %w" , ErrBuildFailed , err )
246252 }
253+ return nil
254+ }))
255+
256+ return func (c * Cmd ) error {
257+ if err := eg .Wait (); err != nil {
258+ return err
259+ }
247260
248261 c .cmd = exec .Command (target )
249262 c .cmd .Stdout = os .Stdout
0 commit comments