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  }