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 xremove(file)
253 err := ioutil.WriteFile(file, new, mode)
254 if err != nil {
255 fatalf("%v", err)
256 }
257 }
258
259
260 func xmkdir(p string) {
261 err := os.Mkdir(p, 0777)
262 if err != nil {
263 fatalf("%v", err)
264 }
265 }
266
267
268 func xmkdirall(p string) {
269 err := os.MkdirAll(p, 0777)
270 if err != nil {
271 fatalf("%v", err)
272 }
273 }
274
275
276 func xremove(p string) {
277 if vflag > 2 {
278 errprintf("rm %s\n", p)
279 }
280 os.Remove(p)
281 }
282
283
284 func xremoveall(p string) {
285 if vflag > 2 {
286 errprintf("rm -r %s\n", p)
287 }
288 os.RemoveAll(p)
289 }
290
291
292
293 func xreaddir(dir string) []string {
294 f, err := os.Open(dir)
295 if err != nil {
296 fatalf("%v", err)
297 }
298 defer f.Close()
299 names, err := f.Readdirnames(-1)
300 if err != nil {
301 fatalf("reading %s: %v", dir, err)
302 }
303 return names
304 }
305
306
307
308 func xreaddirfiles(dir string) []string {
309 f, err := os.Open(dir)
310 if err != nil {
311 fatalf("%v", err)
312 }
313 defer f.Close()
314 infos, err := f.Readdir(-1)
315 if err != nil {
316 fatalf("reading %s: %v", dir, err)
317 }
318 var names []string
319 for _, fi := range infos {
320 if !fi.IsDir() {
321 names = append(names, fi.Name())
322 }
323 }
324 return names
325 }
326
327
328
329 func xworkdir() string {
330 name, err := ioutil.TempDir(os.Getenv("GOTMPDIR"), "go-tool-dist-")
331 if err != nil {
332 fatalf("%v", err)
333 }
334 return name
335 }
336
337
338 func fatalf(format string, args ...interface{}) {
339 fmt.Fprintf(os.Stderr, "go tool dist: %s\n", fmt.Sprintf(format, args...))
340
341 dieOnce.Do(func() { close(dying) })
342
343
344
345
346 bghelpers.Wait()
347
348 xexit(2)
349 }
350
351 var atexits []func()
352
353
354 func xexit(n int) {
355 for i := len(atexits) - 1; i >= 0; i-- {
356 atexits[i]()
357 }
358 os.Exit(n)
359 }
360
361
362 func xatexit(f func()) {
363 atexits = append(atexits, f)
364 }
365
366
367 func xprintf(format string, args ...interface{}) {
368 fmt.Printf(format, args...)
369 }
370
371
372 func errprintf(format string, args ...interface{}) {
373 fmt.Fprintf(os.Stderr, format, args...)
374 }
375
376
377 func xsamefile(f1, f2 string) bool {
378 fi1, err1 := os.Stat(f1)
379 fi2, err2 := os.Stat(f2)
380 if err1 != nil || err2 != nil {
381 return f1 == f2
382 }
383 return os.SameFile(fi1, fi2)
384 }
385
386 func xgetgoarm() string {
387 if goos == "android" {
388
389
390
391 return "7"
392 }
393 if goos == "windows" {
394
395 return "7"
396 }
397 if gohostarch != "arm" || goos != gohostos {
398
399 return "5"
400 }
401
402
403
404
405 out := run("", 0, os.Args[0], "-check-goarm")
406 v1ok := strings.Contains(out, "VFPv1 OK.")
407 v3ok := strings.Contains(out, "VFPv3 OK.")
408
409 if v1ok && v3ok {
410 return "7"
411 }
412 if v1ok {
413 return "6"
414 }
415 return "5"
416 }
417
418 func min(a, b int) int {
419 if a < b {
420 return a
421 }
422 return b
423 }
424
425
426 func elfIsLittleEndian(fn string) bool {
427
428
429 file, err := os.Open(fn)
430 if err != nil {
431 fatalf("failed to open file to determine endianness: %v", err)
432 }
433 defer file.Close()
434 var hdr [16]byte
435 if _, err := io.ReadFull(file, hdr[:]); err != nil {
436 fatalf("failed to read ELF header to determine endianness: %v", err)
437 }
438
439 switch hdr[5] {
440 default:
441 fatalf("unknown ELF endianness of %s: EI_DATA = %d", fn, hdr[5])
442 case 1:
443 return true
444 case 2:
445 return false
446 }
447 panic("unreachable")
448 }
449
450
451
452
453 type count int
454
455 func (c *count) String() string {
456 return fmt.Sprint(int(*c))
457 }
458
459 func (c *count) Set(s string) error {
460 switch s {
461 case "true":
462 *c++
463 case "false":
464 *c = 0
465 default:
466 n, err := strconv.Atoi(s)
467 if err != nil {
468 return fmt.Errorf("invalid count %q", s)
469 }
470 *c = count(n)
471 }
472 return nil
473 }
474
475 func (c *count) IsBoolFlag() bool {
476 return true
477 }
478
479 func xflagparse(maxargs int) {
480 flag.Var((*count)(&vflag), "v", "verbosity")
481 flag.Parse()
482 if maxargs >= 0 && flag.NArg() > maxargs {
483 flag.Usage()
484 }
485 }
486
View as plain text