Source file
src/cmd/go/scriptconds_test.go
1
2
3
4
5 package main_test
6
7 import (
8 "cmd/go/internal/cfg"
9 "cmd/internal/script"
10 "cmd/internal/script/scripttest"
11 "errors"
12 "fmt"
13 "internal/buildcfg"
14 "internal/testenv"
15 "os"
16 "os/exec"
17 "path/filepath"
18 "regexp"
19 "runtime"
20 "runtime/debug"
21 "sync"
22 "testing"
23
24 "golang.org/x/mod/semver"
25 )
26
27 func scriptConditions(t *testing.T) map[string]script.Cond {
28 conds := scripttest.DefaultConds()
29
30 scripttest.AddToolChainScriptConditions(t, conds, goHostOS, goHostArch)
31
32 add := func(name string, cond script.Cond) {
33 if _, ok := conds[name]; ok {
34 panic(fmt.Sprintf("condition %q is already registered", name))
35 }
36 conds[name] = cond
37 }
38
39 lazyBool := func(summary string, f func() bool) script.Cond {
40 return script.OnceCondition(summary, func() (bool, error) { return f(), nil })
41 }
42
43 add("abscc", script.Condition("default $CC path is absolute and exists", defaultCCIsAbsolute))
44 add("bzr", lazyBool("the 'bzr' executable exists and provides the standard CLI", hasWorkingBzr))
45 add("case-sensitive", script.OnceCondition("$WORK filesystem is case-sensitive", isCaseSensitive))
46 add("cc", script.PrefixCondition("go env CC = <suffix> (ignoring the go/env file)", ccIs))
47 add("git", lazyBool("the 'git' executable exists and provides the standard CLI", hasWorkingGit))
48 add("git-sha256", script.OnceCondition("the local 'git' version is recent enough to support sha256 object/commit hashes", gitSupportsSHA256))
49 add("net", script.PrefixCondition("can connect to external network host <suffix>", hasNet))
50 add("trimpath", script.OnceCondition("test binary was built with -trimpath", isTrimpath))
51 add("default-cgo", lazyBool("when CGO_ENABLED=1|0 was set in make.bash", defaultCgo))
52
53 return conds
54 }
55
56 func defaultCCIsAbsolute(s *script.State) (bool, error) {
57 GOOS, _ := s.LookupEnv("GOOS")
58 GOARCH, _ := s.LookupEnv("GOARCH")
59 defaultCC := cfg.DefaultCC(GOOS, GOARCH)
60 if filepath.IsAbs(defaultCC) {
61 if _, err := exec.LookPath(defaultCC); err == nil {
62 return true, nil
63 }
64 }
65 return false, nil
66 }
67
68 func ccIs(s *script.State, want string) (bool, error) {
69 CC, _ := s.LookupEnv("CC")
70 if CC != "" {
71 return CC == want, nil
72 }
73 GOOS, _ := s.LookupEnv("GOOS")
74 GOARCH, _ := s.LookupEnv("GOARCH")
75 return cfg.DefaultCC(GOOS, GOARCH) == want, nil
76 }
77
78 var scriptNetEnabled sync.Map
79
80 func hasNet(s *script.State, host string) (bool, error) {
81 if !testenv.HasExternalNetwork() {
82 return false, nil
83 }
84
85
86
87
88 t, ok := tbFromContext(s.Context())
89 if !ok {
90 return false, errors.New("script Context unexpectedly missing testing.TB key")
91 }
92
93 if netTestSem != nil {
94
95
96
97 _, dup := scriptNetEnabled.LoadOrStore(t, true)
98 if !dup {
99
100 netTestSem <- struct{}{}
101 t.Cleanup(func() {
102 <-netTestSem
103 scriptNetEnabled.Delete(t)
104 })
105 }
106 }
107
108
109
110 s.Setenv("TESTGONETWORK", "")
111 return true, nil
112 }
113
114 func isCaseSensitive() (bool, error) {
115 tmpdir, err := os.MkdirTemp(testTmpDir, "case-sensitive")
116 if err != nil {
117 return false, fmt.Errorf("failed to create directory to determine case-sensitivity: %w", err)
118 }
119 defer os.RemoveAll(tmpdir)
120
121 fcap := filepath.Join(tmpdir, "FILE")
122 if err := os.WriteFile(fcap, []byte{}, 0644); err != nil {
123 return false, fmt.Errorf("error writing file to determine case-sensitivity: %w", err)
124 }
125
126 flow := filepath.Join(tmpdir, "file")
127 _, err = os.ReadFile(flow)
128 switch {
129 case err == nil:
130 return false, nil
131 case os.IsNotExist(err):
132 return true, nil
133 default:
134 return false, fmt.Errorf("unexpected error reading file when determining case-sensitivity: %w", err)
135 }
136 }
137
138 func isTrimpath() (bool, error) {
139 info, _ := debug.ReadBuildInfo()
140 if info == nil {
141 return false, errors.New("missing build info")
142 }
143
144 for _, s := range info.Settings {
145 if s.Key == "-trimpath" && s.Value == "true" {
146 return true, nil
147 }
148 }
149 return false, nil
150 }
151
152 func hasWorkingGit() bool {
153 if runtime.GOOS == "plan9" {
154
155
156 return false
157 }
158 _, err := exec.LookPath("git")
159 return err == nil
160 }
161
162
163 var gitVersLineExtract = regexp.MustCompile(`git version\s+(\d+\.\d+(?:\.\d+)?)`)
164
165 func gitVersion() (string, error) {
166 gitOut, runErr := exec.Command("git", "version").CombinedOutput()
167 if runErr != nil {
168 return "v0", fmt.Errorf("failed to execute git version: %w", runErr)
169 }
170 matches := gitVersLineExtract.FindSubmatch(gitOut)
171 if len(matches) < 2 {
172 return "v0", fmt.Errorf("git version extraction regexp did not match version line: %q", gitOut)
173 }
174 return "v" + string(matches[1]), nil
175 }
176
177 func hasAtLeastGitVersion(minVers string) (bool, error) {
178 gitVers, gitVersErr := gitVersion()
179 if gitVersErr != nil {
180 return false, gitVersErr
181 }
182 return semver.Compare(minVers, gitVers) <= 0, nil
183 }
184
185 func gitSupportsSHA256() (bool, error) {
186 return hasAtLeastGitVersion("v2.29")
187 }
188
189 func hasWorkingBzr() bool {
190 bzr, err := exec.LookPath("bzr")
191 if err != nil {
192 return false
193 }
194
195
196 err = exec.Command(bzr, "help").Run()
197 return err == nil
198 }
199
200 func defaultCgo() bool {
201 return buildcfg.DefaultCGO_ENABLED == "1" || buildcfg.DefaultCGO_ENABLED == "0"
202 }
203
View as plain text