1 package rpctest
2 3 import (
4 "fmt"
5 "go/build"
6 "os/exec"
7 "path/filepath"
8 "runtime"
9 "sync"
10 11 "github.com/p9c/p9/pkg/util/gobin"
12 )
13 14 var (
15 // compileMtx guards access to the executable path so that the project is only compiled once.
16 compileMtx sync.Mutex
17 // executablePath is the path to the compiled executable. This is the empty string until pod is compiled. This
18 // should not be accessed directly; instead use the function podExecutablePath().
19 executablePath string
20 )
21 22 // podExecutablePath returns a path to the pod executable to be used by rpctests. To ensure the code tests against the
23 // most up-to-date version of pod, this method compiles pod the first time it is called. After that, the generated
24 // binary is used for subsequent test harnesses. The executable file is not cleaned up, but since it lives at a static
25 // path in a temp directory, it is not a big deal.
26 func podExecutablePath() (string, error) {
27 compileMtx.Lock()
28 defer compileMtx.Unlock()
29 // If pod has already been compiled, just use that.
30 if len(executablePath) != 0 {
31 return executablePath, nil
32 }
33 testDir, e := baseDir()
34 if e != nil {
35 return "", e
36 }
37 // Determine import path of this package. Not necessarily pod if this is a forked repo.
38 _, rpctestDir, _, ok := runtime.Caller(1)
39 if !ok {
40 return "", fmt.Errorf("cannot get path to pod source code")
41 }
42 podPkgPath := filepath.Join(rpctestDir, "..", "..", "..")
43 podPkg, e := build.ImportDir(podPkgPath, build.FindOnly)
44 if e != nil {
45 return "", fmt.Errorf("failed to podbuild pod: %v", e)
46 }
47 // Build pod and output an executable in a static temp path.
48 outputPath := filepath.Join(testDir, "pod")
49 if runtime.GOOS == "windows" {
50 outputPath += ".exe"
51 }
52 var gb string
53 if gb, e = gobin.Get(); E.Chk(e) {
54 return "", e
55 }
56 cmd := exec.Command(gb, "podbuild", "-o", outputPath, podPkg.ImportPath)
57 e = cmd.Run()
58 if e != nil {
59 return "", fmt.Errorf("failed to podbuild pod: %v", e)
60 }
61 // Save executable path so future calls do not recompile.
62 executablePath = outputPath
63 return executablePath, nil
64 }
65