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 xcmd.Dir = 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
178
179 func xgetwd() string {
180 wd, err := os.Getwd()
181 if err != nil {
182 fatalf("%s", err)
183 }
184 return wd
185 }
186
187
188
189 func xrealwd(path string) string {
190 old := xgetwd()
191 if err := os.Chdir(path); err != nil {
192 fatalf("chdir %s: %v", path, err)
193 }
194 real := xgetwd()
195 if err := os.Chdir(old); err != nil {
196 fatalf("chdir %s: %v", old, err)
197 }
198 return real
199 }
200
201
202 func isdir(p string) bool {
203 fi, err := os.Stat(p)
204 return err == nil && fi.IsDir()
205 }
206
207
208 func isfile(p string) bool {
209 fi, err := os.Stat(p)
210 return err == nil && fi.Mode().IsRegular()
211 }
212
213
214 func mtime(p string) time.Time {
215 fi, err := os.Stat(p)
216 if err != nil {
217 return time.Time{}
218 }
219 return fi.ModTime()
220 }
221
222
223 func readfile(file string) string {
224 data, err := ioutil.ReadFile(file)
225 if err != nil {
226 fatalf("%v", err)
227 }
228 return string(data)
229 }
230
231 const (
232 writeExec = 1 << iota
233 writeSkipSame
234 )
235
236
237
238
239
240 func writefile(text, file string, flag int) {
241 new := []byte(text)
242 if flag&writeSkipSame != 0 {
243 old, err := ioutil.ReadFile(file)
244 if err == nil && bytes.Equal(old, new) {
245 return
246 }
247 }
248 mode := os.FileMode(0666)
249 if flag&writeExec != 0 {
250 mode = 0777
251 }
252 err := ioutil.WriteFile(file, new, mode)
253 if err != nil {
254 fatalf("%v", err)
255 }
256 }
257
258
259 func xmkdir(p string) {
260 err := os.Mkdir(p, 0777)
261 if err != nil {
262 fatalf("%v", err)
263 }
264 }
265
266
267 func xmkdirall(p string) {
268 err := os.MkdirAll(p, 0777)
269 if err != nil {
270 fatalf("%v", err)
271 }
272 }
273
274
275 func xremove(p string) {
276 if vflag > 2 {
277 errprintf("rm %s\n", p)
278 }
279 os.Remove(p)
280 }
281
282
283 func xremoveall(p string) {
284 if vflag > 2 {
285 errprintf("rm -r %s\n", p)
286 }
287 os.RemoveAll(p)
288 }
289
290
291
292 func xreaddir(dir string) []string {
293 f, err := os.Open(dir)
294 if err != nil {
295 fatalf("%v", err)
296 }
297 defer f.Close()
298 names, err := f.Readdirnames(-1)
299 if err != nil {
300 fatalf("reading %s: %v", dir, err)
301 }
302 return names
303 }
304
305
306
307 func xreaddirfiles(dir string) []string {
308 f, err := os.Open(dir)
309 if err != nil {
310 fatalf("%v", err)
311 }
312 defer f.Close()
313 infos, err := f.Readdir(-1)
314 if err != nil {
315 fatalf("reading %s: %v", dir, err)
316 }
317 var names []string
318 for _, fi := range infos {
319 if !fi.IsDir() {
320 names = append(names, fi.Name())
321 }
322 }
323 return names
324 }
325
326
327
328 func xworkdir() string {
329 name, err := ioutil.TempDir(os.Getenv("GOTMPDIR"), "go-tool-dist-")
330 if err != nil {
331 fatalf("%v", err)
332 }
333 return name
334 }
335
336
337 func fatalf(format string, args ...interface{}) {
338 fmt.Fprintf(os.Stderr, "go tool dist: %s\n", fmt.Sprintf(format, args...))
339
340 dieOnce.Do(func() { close(dying) })
341
342
343
344
345 bghelpers.Wait()
346
347 xexit(2)
348 }
349
350 var atexits []func()
351
352
353 func xexit(n int) {
354 for i := len(atexits) - 1; i >= 0; i-- {
355 atexits[i]()
356 }
357 os.Exit(n)
358 }
359
360
361 func xatexit(f func()) {
362 atexits = append(atexits, f)
363 }
364
365
366 func xprintf(format string, args ...interface{}) {
367 fmt.Printf(format, args...)
368 }
369
370
371 func errprintf(format string, args ...interface{}) {
372 fmt.Fprintf(os.Stderr, format, args...)
373 }
374
375
376 func xsamefile(f1, f2 string) bool {
377 fi1, err1 := os.Stat(f1)
378 fi2, err2 := os.Stat(f2)
379 if err1 != nil || err2 != nil {
380 return f1 == f2
381 }
382 return os.SameFile(fi1, fi2)
383 }
384
385 func xgetgoarm() string {
386 if goos == "nacl" {
387
388 return "7"
389 }
390 if goos == "darwin" || goos == "android" {
391
392
393
394 return "7"
395 }
396 if gohostarch != "arm" || goos != gohostos {
397
398 return "5"
399 }
400
401
402
403
404 out := run("", 0, os.Args[0], "-check-goarm")
405 v1ok := strings.Contains(out, "VFPv1 OK.")
406 v3ok := strings.Contains(out, "VFPv3 OK.")
407
408 if v1ok && v3ok {
409 return "7"
410 }
411 if v1ok {
412 return "6"
413 }
414 return "5"
415 }
416
417 func min(a, b int) int {
418 if a < b {
419 return a
420 }
421 return b
422 }
423
424
425 func elfIsLittleEndian(fn string) bool {
426
427
428 file, err := os.Open(fn)
429 if err != nil {
430 fatalf("failed to open file to determine endianness: %v", err)
431 }
432 defer file.Close()
433 var hdr [16]byte
434 if _, err := io.ReadFull(file, hdr[:]); err != nil {
435 fatalf("failed to read ELF header to determine endianness: %v", err)
436 }
437
438 switch hdr[5] {
439 default:
440 fatalf("unknown ELF endianness of %s: EI_DATA = %d", fn, hdr[5])
441 case 1:
442 return true
443 case 2:
444 return false
445 }
446 panic("unreachable")
447 }
448
449
450
451
452 type count int
453
454 func (c *count) String() string {
455 return fmt.Sprint(int(*c))
456 }
457
458 func (c *count) Set(s string) error {
459 switch s {
460 case "true":
461 *c++
462 case "false":
463 *c = 0
464 default:
465 n, err := strconv.Atoi(s)
466 if err != nil {
467 return fmt.Errorf("invalid count %q", s)
468 }
469 *c = count(n)
470 }
471 return nil
472 }
473
474 func (c *count) IsBoolFlag() bool {
475 return true
476 }
477
478 func xflagparse(maxargs int) {
479 flag.Var((*count)(&vflag), "v", "verbosity")
480 flag.Parse()
481 if maxargs >= 0 && flag.NArg() > maxargs {
482 flag.Usage()
483 }
484 }
485
View as plain text