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 "io/ioutil"
13 "os"
14 "os/exec"
15 "path/filepath"
16 "sort"
17 "strconv"
18 "strings"
19 "sync"
20 "time"
21 )
22
23
24
25 func pathf(format string, args ...interface{}) string {
26 return filepath.Clean(fmt.Sprintf(format, args...))
27 }
28
29
30 func filter(list []string, f func(string) bool) []string {
31 var out []string
32 for _, x := range list {
33 if f(x) {
34 out = append(out, x)
35 }
36 }
37 return out
38 }
39
40
41 func uniq(list []string) []string {
42 out := make([]string, len(list))
43 copy(out, list)
44 sort.Strings(out)
45 keep := out[:0]
46 for _, x := range out {
47 if len(keep) == 0 || keep[len(keep)-1] != x {
48 keep = append(keep, x)
49 }
50 }
51 return keep
52 }
53
54 const (
55 CheckExit = 1 << iota
56 ShowOutput
57 Background
58 )
59
60 var outputLock sync.Mutex
61
62
63
64
65
66
67
68
69 func run(dir string, mode int, cmd ...string) string {
70 if vflag > 1 {
71 errprintf("run: %s\n", strings.Join(cmd, " "))
72 }
73
74 xcmd := exec.Command(cmd[0], cmd[1:]...)
75 setDir(xcmd, dir)
76 var data []byte
77 var err error
78
79
80
81
82
83
84
85
86 if mode&(Background|ShowOutput) == ShowOutput {
87 xcmd.Stdout = os.Stdout
88 xcmd.Stderr = os.Stderr
89 err = xcmd.Run()
90 } else {
91 data, err = xcmd.CombinedOutput()
92 }
93 if err != nil && mode&CheckExit != 0 {
94 outputLock.Lock()
95 if len(data) > 0 {
96 xprintf("%s\n", data)
97 }
98 outputLock.Unlock()
99 if mode&Background != 0 {
100
101
102 bghelpers.Done()
103 }
104 fatalf("FAILED: %v: %v", strings.Join(cmd, " "), err)
105 }
106 if mode&ShowOutput != 0 {
107 outputLock.Lock()
108 os.Stdout.Write(data)
109 outputLock.Unlock()
110 }
111 if vflag > 2 {
112 errprintf("run: %s DONE\n", strings.Join(cmd, " "))
113 }
114 return string(data)
115 }
116
117 var maxbg = 4
118
119 var (
120 bgwork = make(chan func(), 1e5)
121
122 bghelpers sync.WaitGroup
123
124 dieOnce sync.Once
125 dying = make(chan struct{})
126 )
127
128 func bginit() {
129 bghelpers.Add(maxbg)
130 for i := 0; i < maxbg; i++ {
131 go bghelper()
132 }
133 }
134
135 func bghelper() {
136 defer bghelpers.Done()
137 for {
138 select {
139 case <-dying:
140 return
141 case w := <-bgwork:
142
143 select {
144 case <-dying:
145 return
146 default:
147 w()
148 }
149 }
150 }
151 }
152
153
154
155
156 func bgrun(wg *sync.WaitGroup, dir string, cmd ...string) {
157 wg.Add(1)
158 bgwork <- func() {
159 defer wg.Done()
160 run(dir, CheckExit|ShowOutput|Background, cmd...)
161 }
162 }
163
164
165
166 func bgwait(wg *sync.WaitGroup) {
167 done := make(chan struct{})
168 go func() {
169 wg.Wait()
170 close(done)
171 }()
172 select {
173 case <-done:
174 case <-dying:
175
176
177 select {}
178 }
179 }
180
181
182 func xgetwd() string {
183 wd, err := os.Getwd()
184 if err != nil {
185 fatalf("%s", err)
186 }
187 return wd
188 }
189
190
191
192 func xrealwd(path string) string {
193 old := xgetwd()
194 if err := os.Chdir(path); err != nil {
195 fatalf("chdir %s: %v", path, err)
196 }
197 real := xgetwd()
198 if err := os.Chdir(old); err != nil {
199 fatalf("chdir %s: %v", old, err)
200 }
201 return real
202 }
203
204
205 func isdir(p string) bool {
206 fi, err := os.Stat(p)
207 return err == nil && fi.IsDir()
208 }
209
210
211 func isfile(p string) bool {
212 fi, err := os.Stat(p)
213 return err == nil && fi.Mode().IsRegular()
214 }
215
216
217 func mtime(p string) time.Time {
218 fi, err := os.Stat(p)
219 if err != nil {
220 return time.Time{}
221 }
222 return fi.ModTime()
223 }
224
225
226 func readfile(file string) string {
227 data, err := ioutil.ReadFile(file)
228 if err != nil {
229 fatalf("%v", err)
230 }
231 return string(data)
232 }
233
234 const (
235 writeExec = 1 << iota
236 writeSkipSame
237 )
238
239
240
241
242
243 func writefile(text, file string, flag int) {
244 new := []byte(text)
245 if flag&writeSkipSame != 0 {
246 old, err := ioutil.ReadFile(file)
247 if err == nil && bytes.Equal(old, new) {
248 return
249 }
250 }
251 mode := os.FileMode(0666)
252 if flag&writeExec != 0 {
253 mode = 0777
254 }
255 xremove(file)
256 err := ioutil.WriteFile(file, new, mode)
257 if err != nil {
258 fatalf("%v", err)
259 }
260 }
261
262
263 func xmkdir(p string) {
264 err := os.Mkdir(p, 0777)
265 if err != nil {
266 fatalf("%v", err)
267 }
268 }
269
270
271 func xmkdirall(p string) {
272 err := os.MkdirAll(p, 0777)
273 if err != nil {
274 fatalf("%v", err)
275 }
276 }
277
278
279 func xremove(p string) {
280 if vflag > 2 {
281 errprintf("rm %s\n", p)
282 }
283 os.Remove(p)
284 }
285
286
287 func xremoveall(p string) {
288 if vflag > 2 {
289 errprintf("rm -r %s\n", p)
290 }
291 os.RemoveAll(p)
292 }
293
294
295
296 func xreaddir(dir string) []string {
297 f, err := os.Open(dir)
298 if err != nil {
299 fatalf("%v", err)
300 }
301 defer f.Close()
302 names, err := f.Readdirnames(-1)
303 if err != nil {
304 fatalf("reading %s: %v", dir, err)
305 }
306 return names
307 }
308
309
310
311 func xreaddirfiles(dir string) []string {
312 f, err := os.Open(dir)
313 if err != nil {
314 fatalf("%v", err)
315 }
316 defer f.Close()
317 infos, err := f.Readdir(-1)
318 if err != nil {
319 fatalf("reading %s: %v", dir, err)
320 }
321 var names []string
322 for _, fi := range infos {
323 if !fi.IsDir() {
324 names = append(names, fi.Name())
325 }
326 }
327 return names
328 }
329
330
331
332 func xworkdir() string {
333 name, err := ioutil.TempDir(os.Getenv("GOTMPDIR"), "go-tool-dist-")
334 if err != nil {
335 fatalf("%v", err)
336 }
337 return name
338 }
339
340
341 func fatalf(format string, args ...interface{}) {
342 fmt.Fprintf(os.Stderr, "go tool dist: %s\n", fmt.Sprintf(format, args...))
343
344 dieOnce.Do(func() { close(dying) })
345
346
347
348
349 bghelpers.Wait()
350
351 xexit(2)
352 }
353
354 var atexits []func()
355
356
357 func xexit(n int) {
358 for i := len(atexits) - 1; i >= 0; i-- {
359 atexits[i]()
360 }
361 os.Exit(n)
362 }
363
364
365 func xatexit(f func()) {
366 atexits = append(atexits, f)
367 }
368
369
370 func xprintf(format string, args ...interface{}) {
371 fmt.Printf(format, args...)
372 }
373
374
375 func errprintf(format string, args ...interface{}) {
376 fmt.Fprintf(os.Stderr, format, args...)
377 }
378
379
380 func xsamefile(f1, f2 string) bool {
381 fi1, err1 := os.Stat(f1)
382 fi2, err2 := os.Stat(f2)
383 if err1 != nil || err2 != nil {
384 return f1 == f2
385 }
386 return os.SameFile(fi1, fi2)
387 }
388
389 func xgetgoarm() string {
390 if goos == "android" {
391
392
393
394 return "7"
395 }
396 if goos == "windows" {
397
398 return "7"
399 }
400 if gohostarch != "arm" || goos != gohostos {
401
402 return "5"
403 }
404
405
406
407
408 out := run("", 0, os.Args[0], "-check-goarm")
409 v1ok := strings.Contains(out, "VFPv1 OK.")
410 v3ok := strings.Contains(out, "VFPv3 OK.")
411
412 if v1ok && v3ok {
413 return "7"
414 }
415 if v1ok {
416 return "6"
417 }
418 return "5"
419 }
420
421 func min(a, b int) int {
422 if a < b {
423 return a
424 }
425 return b
426 }
427
428
429 func elfIsLittleEndian(fn string) bool {
430
431
432 file, err := os.Open(fn)
433 if err != nil {
434 fatalf("failed to open file to determine endianness: %v", err)
435 }
436 defer file.Close()
437 var hdr [16]byte
438 if _, err := io.ReadFull(file, hdr[:]); err != nil {
439 fatalf("failed to read ELF header to determine endianness: %v", err)
440 }
441
442 switch hdr[5] {
443 default:
444 fatalf("unknown ELF endianness of %s: EI_DATA = %d", fn, hdr[5])
445 case 1:
446 return true
447 case 2:
448 return false
449 }
450 panic("unreachable")
451 }
452
453
454
455
456 type count int
457
458 func (c *count) String() string {
459 return fmt.Sprint(int(*c))
460 }
461
462 func (c *count) Set(s string) error {
463 switch s {
464 case "true":
465 *c++
466 case "false":
467 *c = 0
468 default:
469 n, err := strconv.Atoi(s)
470 if err != nil {
471 return fmt.Errorf("invalid count %q", s)
472 }
473 *c = count(n)
474 }
475 return nil
476 }
477
478 func (c *count) IsBoolFlag() bool {
479 return true
480 }
481
482 func xflagparse(maxargs int) {
483 flag.Var((*count)(&vflag), "v", "verbosity")
484 flag.Parse()
485 if maxargs >= 0 && flag.NArg() > maxargs {
486 flag.Usage()
487 }
488 }
489
View as plain text