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