aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/go/internal/modcmd/vendor.go
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2018-07-11 23:55:39 -0400
committerRuss Cox <rsc@golang.org>2018-07-12 20:46:50 +0000
commitf7248f05946c1804b5519d0b3eb0db054dc9c5d6 (patch)
tree73a9d64a6af33d4feefa5f3acf6eb7f7206a8a95 /src/cmd/go/internal/modcmd/vendor.go
parentf22dd66b23ec1a703a3984cad1840bc8692cf1d0 (diff)
downloadgo-f7248f05946c1804b5519d0b3eb0db054dc9c5d6.tar.gz
go-f7248f05946c1804b5519d0b3eb0db054dc9c5d6.zip
cmd/go: merge module support from x/vgo repo
This CL corresponds to CL 123361, the final manual CL in that repo, making this the final manual sync. All future commits will happen in this repo (the main Go repo), and we'll update x/vgo automatically with a fixed patch+script. Change-Id: I572243309c1809727604fd704705a23c30e85d1a Reviewed-on: https://go-review.googlesource.com/123576 Run-TryBot: Russ Cox <rsc@golang.org> Reviewed-by: Bryan C. Mills <bcmills@google.com>
Diffstat (limited to 'src/cmd/go/internal/modcmd/vendor.go')
-rw-r--r--src/cmd/go/internal/modcmd/vendor.go178
1 files changed, 178 insertions, 0 deletions
diff --git a/src/cmd/go/internal/modcmd/vendor.go b/src/cmd/go/internal/modcmd/vendor.go
new file mode 100644
index 0000000000..078c44fd2c
--- /dev/null
+++ b/src/cmd/go/internal/modcmd/vendor.go
@@ -0,0 +1,178 @@
+// Copyright 2018 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.
+
+package modcmd
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "cmd/go/internal/base"
+ "cmd/go/internal/modload"
+ "cmd/go/internal/module"
+)
+
+func runVendor() {
+ pkgs := modload.LoadVendor()
+
+ vdir := filepath.Join(modload.ModRoot, "vendor")
+ if err := os.RemoveAll(vdir); err != nil {
+ base.Fatalf("go vendor: %v", err)
+ }
+
+ modpkgs := make(map[module.Version][]string)
+ for _, pkg := range pkgs {
+ m := modload.PackageModule(pkg)
+ if m == modload.Target {
+ continue
+ }
+ modpkgs[m] = append(modpkgs[m], pkg)
+ }
+
+ var buf bytes.Buffer
+ for _, m := range modload.BuildList()[1:] {
+ if pkgs := modpkgs[m]; len(pkgs) > 0 {
+ repl := ""
+ if r := modload.Replacement(m); r.Path != "" {
+ repl = " => " + r.Path
+ if r.Version != "" {
+ repl += " " + r.Version
+ }
+ }
+ fmt.Fprintf(&buf, "# %s %s%s\n", m.Path, m.Version, repl)
+ if *modV {
+ fmt.Fprintf(os.Stderr, "# %s %s%s\n", m.Path, m.Version, repl)
+ }
+ for _, pkg := range pkgs {
+ fmt.Fprintf(&buf, "%s\n", pkg)
+ if *modV {
+ fmt.Fprintf(os.Stderr, "%s\n", pkg)
+ }
+ vendorPkg(vdir, pkg)
+ }
+ }
+ }
+ if buf.Len() == 0 {
+ fmt.Fprintf(os.Stderr, "go: no dependencies to vendor\n")
+ return
+ }
+ if err := ioutil.WriteFile(filepath.Join(vdir, "modules.txt"), buf.Bytes(), 0666); err != nil {
+ base.Fatalf("go vendor: %v", err)
+ }
+}
+
+func vendorPkg(vdir, pkg string) {
+ realPath := modload.ImportMap(pkg)
+ if realPath != pkg && modload.ImportMap(realPath) != "" {
+ fmt.Fprintf(os.Stderr, "warning: %s imported as both %s and %s; making two copies.\n", realPath, realPath, pkg)
+ }
+
+ dst := filepath.Join(vdir, pkg)
+ src := modload.PackageDir(realPath)
+ if src == "" {
+ fmt.Fprintf(os.Stderr, "internal error: no pkg for %s -> %s\n", pkg, realPath)
+ }
+ copyDir(dst, src, matchNonTest)
+ if m := modload.PackageModule(realPath); m.Path != "" {
+ copyMetadata(m.Path, realPath, dst, src)
+ }
+}
+
+type metakey struct {
+ modPath string
+ dst string
+}
+
+var copiedMetadata = make(map[metakey]bool)
+
+// copyMetadata copies metadata files from parents of src to parents of dst,
+// stopping after processing the src parent for modPath.
+func copyMetadata(modPath, pkg, dst, src string) {
+ for parent := 0; ; parent++ {
+ if copiedMetadata[metakey{modPath, dst}] {
+ break
+ }
+ copiedMetadata[metakey{modPath, dst}] = true
+ if parent > 0 {
+ copyDir(dst, src, matchMetadata)
+ }
+ if modPath == pkg {
+ break
+ }
+ pkg = filepath.Dir(pkg)
+ dst = filepath.Dir(dst)
+ src = filepath.Dir(src)
+ }
+}
+
+// metaPrefixes is the list of metadata file prefixes.
+// Vendoring copies metadata files from parents of copied directories.
+// Note that this list could be arbitrarily extended, and it is longer
+// in other tools (such as godep or dep). By using this limited set of
+// prefixes and also insisting on capitalized file names, we are trying
+// to nudge people toward more agreement on the naming
+// and also trying to avoid false positives.
+var metaPrefixes = []string{
+ "AUTHORS",
+ "CONTRIBUTORS",
+ "COPYLEFT",
+ "COPYING",
+ "COPYRIGHT",
+ "LEGAL",
+ "LICENSE",
+ "NOTICE",
+ "PATENTS",
+}
+
+// matchMetadata reports whether info is a metadata file.
+func matchMetadata(info os.FileInfo) bool {
+ name := info.Name()
+ for _, p := range metaPrefixes {
+ if strings.HasPrefix(name, p) {
+ return true
+ }
+ }
+ return false
+}
+
+// matchNonTest reports whether info is any non-test file (including non-Go files).
+func matchNonTest(info os.FileInfo) bool {
+ return !strings.HasSuffix(info.Name(), "_test.go")
+}
+
+// copyDir copies all regular files satisfying match(info) from src to dst.
+func copyDir(dst, src string, match func(os.FileInfo) bool) {
+ files, err := ioutil.ReadDir(src)
+ if err != nil {
+ base.Fatalf("go vendor: %v", err)
+ }
+ if err := os.MkdirAll(dst, 0777); err != nil {
+ base.Fatalf("go vendor: %v", err)
+ }
+ for _, file := range files {
+ if file.IsDir() || !file.Mode().IsRegular() || !match(file) {
+ continue
+ }
+ r, err := os.Open(filepath.Join(src, file.Name()))
+ if err != nil {
+ base.Fatalf("go vendor: %v", err)
+ }
+ w, err := os.Create(filepath.Join(dst, file.Name()))
+ if err != nil {
+ base.Fatalf("go vendor: %v", err)
+ }
+ if _, err := io.Copy(w, r); err != nil {
+ base.Fatalf("go vendor: %v", err)
+ }
+ r.Close()
+ if err := w.Close(); err != nil {
+ base.Fatalf("go vendor: %v", err)
+ }
+ }
+}