Source file
src/cmd/dist/util.go
1
2
3
4
5 package main
6
7 import (
8 "bytes"
9 "flag"
10 "fmt"
11 "io"
12 "os"
13 "os/exec"
14 "path/filepath"
15 "strconv"
16 "strings"
17 "sync"
18 )
19
20
21
22 func pathf(format string, args ...any) string {
23 return filepath.Clean(fmt.Sprintf(format, args...))
24 }
25
26 const (
27 CheckExit = 1 << iota
28 ShowOutput
29 )
30
31 var outputLock sync.Mutex
32
33
34 func run(dir string, mode int, cmd ...string) string {
35 return runEnv(dir, mode, nil, cmd...)
36 }
37
38
39
40
41
42 func runEnv(dir string, mode int, env []string, cmd ...string) string {
43 if vflag > 1 {
44 errprintf("run: %s\n", strings.Join(cmd, " "))
45 }
46
47 xcmd := exec.Command(cmd[0], cmd[1:]...)
48 if env != nil {
49 xcmd.Env = append(os.Environ(), env...)
50 }
51 setDir(xcmd, dir)
52 var data []byte
53 var err error
54
55
56
57
58
59
60
61
62 if mode&ShowOutput != 0 {
63 xcmd.Stdout = os.Stdout
64 xcmd.Stderr = os.Stderr
65 err = xcmd.Run()
66 } else {
67 data, err = xcmd.CombinedOutput()
68 }
69 if err != nil && mode&CheckExit != 0 {
70 outputLock.Lock()
71 if len(data) > 0 {
72 xprintf("%s\n", data)
73 }
74 outputLock.Unlock()
75 fatalf("FAILED: %v: %v", strings.Join(cmd, " "), err)
76 }
77 if mode&ShowOutput != 0 {
78 outputLock.Lock()
79 os.Stdout.Write(data)
80 outputLock.Unlock()
81 }
82 if vflag > 2 {
83 errprintf("run: %s DONE\n", strings.Join(cmd, " "))
84 }
85 return string(data)
86 }
87
88 var maxbg = 4
89
90
91 func isdir(p string) bool {
92 fi, err := os.Stat(p)
93 return err == nil && fi.IsDir()
94 }
95
96
97 func isfile(p string) bool {
98 fi, err := os.Stat(p)
99 return err == nil && fi.Mode().IsRegular()
100 }
101
102
103 func readfile(file string) string {
104 data, err := os.ReadFile(file)
105 if err != nil {
106 fatalf("%v", err)
107 }
108 return string(data)
109 }
110
111 const (
112 writeExec = 1 << iota
113 writeSkipSame
114 )
115
116
117
118
119
120 func writefile(text, file string, flag int) {
121 new := []byte(text)
122 if flag&writeSkipSame != 0 {
123 old, err := os.ReadFile(file)
124 if err == nil && bytes.Equal(old, new) {
125 return
126 }
127 }
128 mode := os.FileMode(0666)
129 if flag&writeExec != 0 {
130 mode = 0777
131 }
132 xremove(file)
133 err := os.WriteFile(file, new, mode)
134 if err != nil {
135 fatalf("%v", err)
136 }
137 }
138
139
140 func xmkdir(p string) {
141 err := os.Mkdir(p, 0777)
142 if err != nil {
143 fatalf("%v", err)
144 }
145 }
146
147
148 func xmkdirall(p string) {
149 err := os.MkdirAll(p, 0777)
150 if err != nil {
151 fatalf("%v", err)
152 }
153 }
154
155
156 func xremove(p string) {
157 if vflag > 2 {
158 errprintf("rm %s\n", p)
159 }
160 os.Remove(p)
161 }
162
163
164 func xremoveall(p string) {
165 if vflag > 2 {
166 errprintf("rm -r %s\n", p)
167 }
168 os.RemoveAll(p)
169 }
170
171
172
173 func xreaddir(dir string) []string {
174 f, err := os.Open(dir)
175 if err != nil {
176 fatalf("%v", err)
177 }
178 defer f.Close()
179 names, err := f.Readdirnames(-1)
180 if err != nil {
181 fatalf("reading %s: %v", dir, err)
182 }
183 return names
184 }
185
186
187
188 func xworkdir() string {
189 name, err := os.MkdirTemp(os.Getenv("GOTMPDIR"), "go-tool-dist-")
190 if err != nil {
191 fatalf("%v", err)
192 }
193 return name
194 }
195
196
197 func fatalf(format string, args ...any) {
198 fmt.Fprintf(os.Stderr, "go tool dist: %s\n", fmt.Sprintf(format, args...))
199 xexit(2)
200 }
201
202 var atexits []func()
203
204
205 func xexit(n int) {
206 for i := len(atexits) - 1; i >= 0; i-- {
207 atexits[i]()
208 }
209 os.Exit(n)
210 }
211
212
213 func xatexit(f func()) {
214 atexits = append(atexits, f)
215 }
216
217
218 func xprintf(format string, args ...any) {
219 fmt.Printf(format, args...)
220 }
221
222
223 func errprintf(format string, args ...any) {
224 fmt.Fprintf(os.Stderr, format, args...)
225 }
226
227 func xgetgoarm() string {
228
229
230
231
232 if gohostarch == "arm" && goarch == "arm" && goos == gohostos && goos != "android" {
233
234
235
236 out := run("", 0, os.Args[0], "-check-goarm")
237 v1ok := strings.Contains(out, "VFPv1 OK.")
238 v3ok := strings.Contains(out, "VFPv3 OK.")
239 if v1ok && v3ok {
240 return "7"
241 }
242 if v1ok {
243 return "6"
244 }
245 return "5"
246 }
247
248
249
250
251
252
253
254
255
256 return "7"
257 }
258
259
260 func elfIsLittleEndian(fn string) bool {
261
262
263 file, err := os.Open(fn)
264 if err != nil {
265 fatalf("failed to open file to determine endianness: %v", err)
266 }
267 defer file.Close()
268 var hdr [16]byte
269 if _, err := io.ReadFull(file, hdr[:]); err != nil {
270 fatalf("failed to read ELF header to determine endianness: %v", err)
271 }
272
273 switch hdr[5] {
274 default:
275 fatalf("unknown ELF endianness of %s: EI_DATA = %d", fn, hdr[5])
276 case 1:
277 return true
278 case 2:
279 return false
280 }
281 panic("unreachable")
282 }
283
284
285
286
287 type count int
288
289 func (c *count) String() string {
290 return fmt.Sprint(int(*c))
291 }
292
293 func (c *count) Set(s string) error {
294 switch s {
295 case "true":
296 *c++
297 case "false":
298 *c = 0
299 default:
300 n, err := strconv.Atoi(s)
301 if err != nil {
302 return fmt.Errorf("invalid count %q", s)
303 }
304 *c = count(n)
305 }
306 return nil
307 }
308
309 func (c *count) IsBoolFlag() bool {
310 return true
311 }
312
313 func xflagparse(maxargs int) {
314 flag.Var((*count)(&vflag), "v", "verbosity")
315 flag.Parse()
316 if maxargs >= 0 && flag.NArg() > maxargs {
317 flag.Usage()
318 }
319 }
320
View as plain text