blob: f7000b259ac8fc7b593d96a2460814da2ee63f29 [file] [log] [blame]
// 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 vgo
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"cmd/go/internal/base"
"cmd/go/internal/module"
)
var CmdVendor = &base.Command{
UsageLine: "vendor [-v]",
Short: "vendor dependencies of current module",
Long: `
Vendor resets the module's vendor directory to include all
packages needed to build and test all packages in the module
and their dependencies.
The -v flag causes vendor to print to standard error the
module paths of the modules processed and the import paths
of the packages copied.
`,
}
var vendorV = CmdVendor.Flag.Bool("v", false, "")
func init() {
CmdVendor.Run = runVendor // break init cycle
}
func runVendor(cmd *base.Command, args []string) {
if Init(); !Enabled() {
base.Fatalf("vgo vendor: cannot use -m outside module")
}
if len(args) != 0 {
base.Fatalf("vgo vendor: vendor takes no arguments")
}
InitMod()
pkgs := ImportPaths([]string{"ALL"})
vdir := filepath.Join(ModRoot, "vendor")
if err := os.RemoveAll(vdir); err != nil {
base.Fatalf("vgo vendor: %v", err)
}
modpkgs := make(map[module.Version][]string)
for _, pkg := range pkgs {
m := pkgmod[pkg]
if m == Target {
continue
}
modpkgs[m] = append(modpkgs[m], pkg)
}
var buf bytes.Buffer
for _, m := range buildList[1:] {
if pkgs := modpkgs[m]; len(pkgs) > 0 {
repl := ""
if r := replaced(m); r != nil {
repl = " => " + r.New.Path
if r.New.Version != "" {
repl += " " + r.New.Version
}
}
fmt.Fprintf(&buf, "# %s %s%s\n", m.Path, m.Version, repl)
if *vendorV {
fmt.Fprintf(os.Stderr, "# %s %s%s\n", m.Path, m.Version, repl)
}
for _, pkg := range pkgs {
fmt.Fprintf(&buf, "%s\n", pkg)
if *vendorV {
fmt.Fprintf(os.Stderr, "%s\n", pkg)
}
vendorPkg(vdir, pkg)
}
}
}
if buf.Len() == 0 {
fmt.Fprintf(os.Stderr, "vgo: no dependencies to vendor\n")
return
}
if err := ioutil.WriteFile(filepath.Join(vdir, "vgo.list"), buf.Bytes(), 0666); err != nil {
base.Fatalf("vgo vendor: %v", err)
}
}
func vendorPkg(vdir, pkg string) {
realPath := importmap[pkg]
if realPath != pkg && 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 := pkgdir[realPath]
if src == "" {
fmt.Fprintf(os.Stderr, "internal error: no pkg for %s -> %s\n", pkg, realPath)
}
copyDir(dst, src, false)
}
func copyDir(dst, src string, recursive bool) {
files, err := ioutil.ReadDir(src)
if err != nil {
base.Fatalf("vgo vendor: %v", err)
}
if err := os.MkdirAll(dst, 0777); err != nil {
base.Fatalf("vgo vendor: %v", err)
}
for _, file := range files {
if file.IsDir() {
if recursive || file.Name() == "testdata" {
copyDir(filepath.Join(dst, file.Name()), filepath.Join(src, file.Name()), true)
}
continue
}
if !file.Mode().IsRegular() {
continue
}
r, err := os.Open(filepath.Join(src, file.Name()))
if err != nil {
base.Fatalf("vgo vendor: %v", err)
}
w, err := os.Create(filepath.Join(dst, file.Name()))
if err != nil {
base.Fatalf("vgo vendor: %v", err)
}
if _, err := io.Copy(w, r); err != nil {
base.Fatalf("vgo vendor: %v", err)
}
r.Close()
if err := w.Close(); err != nil {
base.Fatalf("vgo vendor: %v", err)
}
}
}
// hasPathPrefix reports whether the path s begins with the
// elements in prefix.
func hasPathPrefix(s, prefix string) bool {
switch {
default:
return false
case len(s) == len(prefix):
return s == prefix
case len(s) > len(prefix):
if prefix != "" && prefix[len(prefix)-1] == '/' {
return strings.HasPrefix(s, prefix)
}
return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
}
}