| // Copyright 2018 The Fuchsia 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 makeroot.go script copies a GOROOT. It is a precursor to makefuchsia.go, |
| // used to stage a clean GOROOT into the build directory. |
| // Note: this script exists because the `go` tool globs for inputs, as such, a |
| // copy tool is required that will actively remove files that are not found in |
| // the source. |
| |
| package main |
| |
| import ( |
| "bytes" |
| "flag" |
| "fmt" |
| "io" |
| "io/ioutil" |
| "log" |
| "os" |
| "path/filepath" |
| "strings" |
| "time" |
| ) |
| |
| var ( |
| sourceGoroot = flag.String("source-goroot", "", "GOROOT to copy from") |
| targetGoroot = flag.String("target-goroot", "", "GOROOT to copy into") |
| depfilePath = flag.String("depfile", "", "depfile to write into") |
| depfileRoot = flag.String("depfile-root", "", "Path from which dependency paths should be rooted") |
| stampPath = flag.String("stamp-file", "", "Path of a file to create upon completion") |
| ) |
| |
| func mkdir(path ...string) { |
| if err := os.MkdirAll(join(path...), 0755); err != nil { |
| log.Fatal(err) |
| } |
| } |
| |
| func join(path ...string) string { return filepath.Join(path...) } |
| |
| func copyfile(src, dst string) { |
| srcfile, err := os.Open(src) |
| if err != nil { |
| log.Fatal(err) |
| } |
| defer srcfile.Close() |
| |
| fi, err := srcfile.Stat() |
| if err != nil { |
| log.Fatal(err) |
| } |
| |
| mkdir(filepath.Dir(dst)) |
| f, err := os.OpenFile(dst, os.O_CREATE|os.O_RDWR|os.O_TRUNC, fi.Mode()) |
| if err != nil { |
| log.Fatal(err) |
| } |
| if _, err := io.Copy(f, srcfile); err != nil { |
| log.Fatalf("cp %s %s: %v", src, dst, err) |
| } |
| if err := f.Close(); err != nil { |
| log.Fatalf("cp %s %s: close: %v", src, dst, err) |
| } |
| } |
| |
| // allFilesIn recursively walks a set of files, returning the entire tree in |
| // paths relative to the given root. A map is returned for convenience. If |
| // prefix is given, only files that match the prefix are considered. |
| func allFilesIn(root string, paths map[string]struct{}, prefix ...string) error { |
| return filepath.Walk(root, func(path string, info os.FileInfo, err error) error { |
| if err != nil || info.IsDir() { |
| return err |
| } |
| for _, pfx := range prefix { |
| if strings.HasPrefix(path, join(root, pfx)) { |
| relPath := strings.TrimPrefix(path, root)[1:] |
| paths[relPath] = struct{}{} |
| return err |
| } |
| } |
| return err |
| }) |
| } |
| |
| func main() { |
| log.SetFlags(0) |
| log.SetPrefix("makeroot.go: ") |
| flag.Parse() |
| |
| srcFiles := map[string]struct{}{} |
| |
| // The list of files included below should include everything that Go itself |
| // cares about. It used to avoid containing some of the "extraneous" files such |
| // as doc/ and test/, however, eliding those files results in `go doc -http` |
| // not presenting well for the user, so it's simply better to include |
| // everything. |
| err := allFilesIn(join(*sourceGoroot), srcFiles, |
| "AUTHORS", |
| "CONTRIBUTING.md", |
| "CONTRIBUTORS", |
| "LICENSE", |
| "PATENTS", |
| "README.md", |
| "VERSION", |
| "makefuchsia.go", |
| "api/", |
| "doc/", |
| "favicon.ico", |
| "lib/", |
| "misc/", |
| "robots.txt", |
| "src/", |
| "test/", |
| ) |
| if err != nil { |
| log.Fatal(err) |
| } |
| |
| dstFiles := map[string]struct{}{} |
| if _, err := os.Stat(join(*targetGoroot)); err == nil { |
| if err := allFilesIn(join(*targetGoroot), dstFiles, ""); err != nil { |
| log.Fatal(err) |
| } |
| } |
| |
| for f := range dstFiles { |
| if _, ok := srcFiles[f]; !ok { |
| // try to preserve the bin/ and pkg/ trees, as they can be used to do faster |
| // rebuilds of the toolchain. |
| if strings.HasPrefix(f, "src/") || strings.HasPrefix(f, "misc/fuchsia/") { |
| os.Remove(filepath.Join(*targetGoroot, f)) |
| } |
| } |
| } |
| |
| buf := bytes.NewBuffer(nil) |
| fmt.Fprintf(buf, "%s:", *stampPath) |
| for f := range srcFiles { |
| src, dst := join(*sourceGoroot, f), join(*targetGoroot, f) |
| copyfile(src, dst) |
| fmt.Fprintf(buf, " %s", src) |
| } |
| fmt.Fprintf(buf, "\n") |
| |
| if err := ioutil.WriteFile(*depfilePath, buf.Bytes(), os.ModePerm); err != nil { |
| log.Fatal(err) |
| } |
| |
| if err := ioutil.WriteFile(*stampPath, []byte(fmt.Sprintf("%s", time.Now())), os.ModePerm); err != nil { |
| log.Fatal(err) |
| } |
| } |