| // Copyright 2016 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| /* |
| The genbootstrap command prepares GOROOT_BOOTSTRAP tarballs suitable for |
| use on builders. It's a wrapper around bootstrap.bash. After |
| bootstrap.bash produces the full output, genbootstrap trims it up, |
| removing unnecessary and unwanted files. |
| |
| Usage: genbootstrap GOOS/GOARCH |
| */ |
| package main |
| |
| import ( |
| "flag" |
| "fmt" |
| "log" |
| "os" |
| "os/exec" |
| "path/filepath" |
| "strings" |
| |
| "golang.org/x/build/internal/envutil" |
| ) |
| |
| var skipBuild = flag.Bool("skip_build", false, "skip bootstrap.bash step; useful during development of cleaning code") |
| |
| func usage() { |
| fmt.Fprintln(os.Stderr, "Usage: genbootstrap GOOS/GOARCH") |
| flag.PrintDefaults() |
| } |
| |
| func main() { |
| flag.Usage = usage |
| flag.Parse() |
| if flag.NArg() != 1 { |
| flag.Usage() |
| os.Exit(2) |
| } |
| f := strings.Split(flag.Arg(0), "/") |
| if len(f) != 2 { |
| flag.Usage() |
| os.Exit(2) |
| } |
| goos, goarch := f[0], f[1] |
| if os.Getenv("GOROOT") == "" { |
| log.Fatalf("GOROOT not set in environment") |
| } |
| |
| tgz := filepath.Join(os.Getenv("GOROOT"), "src", "..", "..", "gobootstrap-"+goos+"-"+goarch+".tar.gz") |
| os.Remove(tgz) |
| outDir := filepath.Join(os.Getenv("GOROOT"), "src", "..", "..", "go-"+goos+"-"+goarch+"-bootstrap") |
| if !*skipBuild { |
| os.RemoveAll(outDir) |
| cmd := exec.Command(filepath.Join(os.Getenv("GOROOT"), "src", "bootstrap.bash")) |
| envutil.SetDir(cmd, filepath.Join(os.Getenv("GOROOT"), "src")) |
| envutil.SetEnv(cmd, "GOOS="+goos, "GOARCH="+goarch) |
| cmd.Stdout = os.Stdout |
| cmd.Stderr = os.Stderr |
| if err := cmd.Run(); err != nil { |
| log.Fatal(err) |
| } |
| |
| // bootstrap.bash makes a bzipped tar file too, but it's fat and full of stuff we |
| // dont need it. delete it. |
| os.Remove(outDir + ".tbz") |
| } |
| |
| if err := filepath.Walk(outDir, func(path string, fi os.FileInfo, err error) error { |
| if err != nil { |
| return err |
| } |
| rel := strings.TrimPrefix(strings.TrimPrefix(path, outDir), "/") |
| base := filepath.Base(path) |
| var pkgrel string // relative to pkg/<goos>_<goarch>/, or empty |
| if strings.HasPrefix(rel, "pkg/") && strings.Count(rel, "/") >= 2 { |
| pkgrel = strings.TrimPrefix(rel, "pkg/") |
| pkgrel = pkgrel[strings.Index(pkgrel, "/")+1:] |
| log.Printf("rel %q => %q", rel, pkgrel) |
| } |
| remove := func() error { |
| if err := os.RemoveAll(path); err != nil { |
| return err |
| } |
| if fi.IsDir() { |
| return filepath.SkipDir |
| } |
| return nil |
| } |
| switch pkgrel { |
| case "cmd": |
| return remove() |
| } |
| switch rel { |
| case "api", |
| "bin/gofmt", |
| "doc", |
| "misc/android", |
| "misc/cgo", |
| "misc/chrome", |
| "misc/swig", |
| "test": |
| return remove() |
| } |
| if base == "testdata" { |
| return remove() |
| } |
| if strings.HasPrefix(rel, "pkg/tool/") { |
| switch base { |
| case "addr2line", "api", "cgo", "cover", |
| "dist", "doc", "fix", "nm", |
| "objdump", "pack", "pprof", |
| "trace", "vet", "yacc": |
| return remove() |
| } |
| } |
| if fi.IsDir() { |
| return nil |
| } |
| if isEditorJunkFile(path) { |
| return remove() |
| } |
| if !fi.Mode().IsRegular() { |
| return remove() |
| } |
| if strings.HasSuffix(path, "_test.go") { |
| return remove() |
| } |
| log.Printf("keeping: %s\n", rel) |
| return nil |
| }); err != nil { |
| log.Fatal(err) |
| } |
| |
| log.Printf("Running: tar zcf %s .", tgz) |
| cmd := exec.Command("tar", "zcf", tgz, ".") |
| envutil.SetDir(cmd, outDir) |
| if err := cmd.Run(); err != nil { |
| log.Fatalf("tar zf failed: %v", err) |
| } |
| log.Printf("Done. Output is %s", tgz) |
| } |
| |
| func isEditorJunkFile(path string) bool { |
| path = filepath.Base(path) |
| if strings.HasPrefix(path, "#") && strings.HasSuffix(path, "#") { |
| return true |
| } |
| if strings.HasSuffix(path, "~") { |
| return true |
| } |
| return false |
| } |