blob: 6e8562b4c5fb8945548470962ea8d637ff160a6b [file] [log] [blame]
// 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)
}
}