github.com/sirkon/goproxy@v1.4.8/internal/modcmd/vendor.go (about) 1 // Copyright 2018 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package modcmd 6 7 import ( 8 "bytes" 9 "fmt" 10 "io" 11 "io/ioutil" 12 "os" 13 "path/filepath" 14 "strings" 15 16 "github.com/sirkon/goproxy/internal/base" 17 "github.com/sirkon/goproxy/internal/cfg" 18 "github.com/sirkon/goproxy/internal/modload" 19 "github.com/sirkon/goproxy/internal/module" 20 ) 21 22 var cmdVendor = &base.Command{ 23 UsageLine: "go mod vendor [-v]", 24 Short: "make vendored copy of dependencies", 25 Long: ` 26 Vendor resets the main module's vendor directory to include all packages 27 needed to build and test all the main module's packages. 28 It does not include test code for vendored packages. 29 30 The -v flag causes vendor to print the names of vendored 31 modules and packages to standard error. 32 `, 33 Run: runVendor, 34 } 35 36 func init() { 37 cmdVendor.Flag.BoolVar(&cfg.BuildV, "v", false, "") 38 } 39 40 func runVendor(cmd *base.Command, args []string) { 41 if len(args) != 0 { 42 base.Fatalf("go mod vendor: vendor takes no arguments") 43 } 44 pkgs := modload.LoadVendor() 45 46 vdir := filepath.Join(modload.ModRoot, "vendor") 47 if err := os.RemoveAll(vdir); err != nil { 48 base.Fatalf("go vendor: %v", err) 49 } 50 51 modpkgs := make(map[module.Version][]string) 52 for _, pkg := range pkgs { 53 m := modload.PackageModule(pkg) 54 if m == modload.Target { 55 continue 56 } 57 modpkgs[m] = append(modpkgs[m], pkg) 58 } 59 60 var buf bytes.Buffer 61 for _, m := range modload.BuildList()[1:] { 62 if pkgs := modpkgs[m]; len(pkgs) > 0 { 63 repl := "" 64 if r := modload.Replacement(m); r.Path != "" { 65 repl = " => " + r.Path 66 if r.Version != "" { 67 repl += " " + r.Version 68 } 69 } 70 fmt.Fprintf(&buf, "# %s %s%s\n", m.Path, m.Version, repl) 71 if cfg.BuildV { 72 fmt.Fprintf(os.Stderr, "# %s %s%s\n", m.Path, m.Version, repl) 73 } 74 for _, pkg := range pkgs { 75 fmt.Fprintf(&buf, "%s\n", pkg) 76 if cfg.BuildV { 77 fmt.Fprintf(os.Stderr, "%s\n", pkg) 78 } 79 vendorPkg(vdir, pkg) 80 } 81 } 82 } 83 if buf.Len() == 0 { 84 fmt.Fprintf(os.Stderr, "go: no dependencies to vendor\n") 85 return 86 } 87 if err := ioutil.WriteFile(filepath.Join(vdir, "modules.txt"), buf.Bytes(), 0666); err != nil { 88 base.Fatalf("go vendor: %v", err) 89 } 90 } 91 92 func vendorPkg(vdir, pkg string) { 93 realPath := modload.ImportMap(pkg) 94 if realPath != pkg && modload.ImportMap(realPath) != "" { 95 fmt.Fprintf(os.Stderr, "warning: %s imported as both %s and %s; making two copies.\n", realPath, realPath, pkg) 96 } 97 98 dst := filepath.Join(vdir, pkg) 99 src := modload.PackageDir(realPath) 100 if src == "" { 101 fmt.Fprintf(os.Stderr, "internal error: no pkg for %s -> %s\n", pkg, realPath) 102 } 103 copyDir(dst, src, matchNonTest) 104 if m := modload.PackageModule(realPath); m.Path != "" { 105 copyMetadata(m.Path, realPath, dst, src) 106 } 107 } 108 109 type metakey struct { 110 modPath string 111 dst string 112 } 113 114 var copiedMetadata = make(map[metakey]bool) 115 116 // copyMetadata copies metadata files from parents of src to parents of dst, 117 // stopping after processing the src parent for modPath. 118 func copyMetadata(modPath, pkg, dst, src string) { 119 for parent := 0; ; parent++ { 120 if copiedMetadata[metakey{modPath, dst}] { 121 break 122 } 123 copiedMetadata[metakey{modPath, dst}] = true 124 if parent > 0 { 125 copyDir(dst, src, matchMetadata) 126 } 127 if modPath == pkg { 128 break 129 } 130 pkg = filepath.Dir(pkg) 131 dst = filepath.Dir(dst) 132 src = filepath.Dir(src) 133 } 134 } 135 136 // metaPrefixes is the list of metadata file prefixes. 137 // Vendoring copies metadata files from parents of copied directories. 138 // Note that this list could be arbitrarily extended, and it is longer 139 // in other tools (such as godep or dep). By using this limited set of 140 // prefixes and also insisting on capitalized file names, we are trying 141 // to nudge people toward more agreement on the naming 142 // and also trying to avoid false positives. 143 var metaPrefixes = []string{ 144 "AUTHORS", 145 "CONTRIBUTORS", 146 "COPYLEFT", 147 "COPYING", 148 "COPYRIGHT", 149 "LEGAL", 150 "LICENSE", 151 "NOTICE", 152 "PATENTS", 153 } 154 155 // matchMetadata reports whether info is a metadata file. 156 func matchMetadata(info os.FileInfo) bool { 157 name := info.Name() 158 for _, p := range metaPrefixes { 159 if strings.HasPrefix(name, p) { 160 return true 161 } 162 } 163 return false 164 } 165 166 // matchNonTest reports whether info is any non-test file (including non-Go files). 167 func matchNonTest(info os.FileInfo) bool { 168 return !strings.HasSuffix(info.Name(), "_test.go") 169 } 170 171 // copyDir copies all regular files satisfying match(info) from src to dst. 172 func copyDir(dst, src string, match func(os.FileInfo) bool) { 173 files, err := ioutil.ReadDir(src) 174 if err != nil { 175 base.Fatalf("go vendor: %v", err) 176 } 177 if err := os.MkdirAll(dst, 0777); err != nil { 178 base.Fatalf("go vendor: %v", err) 179 } 180 for _, file := range files { 181 if file.IsDir() || !file.Mode().IsRegular() || !match(file) { 182 continue 183 } 184 r, err := os.Open(filepath.Join(src, file.Name())) 185 if err != nil { 186 base.Fatalf("go vendor: %v", err) 187 } 188 w, err := os.Create(filepath.Join(dst, file.Name())) 189 if err != nil { 190 base.Fatalf("go vendor: %v", err) 191 } 192 if _, err := io.Copy(w, r); err != nil { 193 base.Fatalf("go vendor: %v", err) 194 } 195 r.Close() 196 if err := w.Close(); err != nil { 197 base.Fatalf("go vendor: %v", err) 198 } 199 } 200 }