diff --git a/.travis.yml b/.travis.yml index be20a8f2..c6d43f1b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,17 +1,17 @@ -sudo: required -services: -- docker -install: -- set -e +language: go +go: 1.12.x + +env: + global: + - GO111MODULE=on + jobs: include: - - stage: unit test - language: go - go: - - 1.11.x - env: - - GO111MODULE=on - go_import_path: github.com/buildpack/lifecycle - script: | - test -z "$(bin/format | tee >(cat >&2))" - go test -v -parallel=1 -p=1 -count=1 ./... \ No newline at end of file + - os: linux + script: + - docker info + - make + +branches: + only: + - master \ No newline at end of file diff --git a/Makefile b/Makefile index 9d31a5e0..6ca40546 100644 --- a/Makefile +++ b/Makefile @@ -1,18 +1,23 @@ # Go parameters GOCMD?=go GOTEST=$(GOCMD) test -mod=vendor +PACKAGE_BASE=github.com/buildpack/imgutil +PACKAGES:=$(shell $(GOCMD) list -mod=vendor ./... | grep -v /testdata/) +SRC:=$(shell find . -type f -name '*.go' -not -path "*/vendor/*") all: test -imports: - $(GOCMD) install -mod=vendor golang.org/x/tools/cmd/goimports - test -z $$(goimports -l -w -local github.com/buildpack/imgutil $$(find . -type f -name '*.go' -not -path "./vendor/*")) +install-goimports: + @echo "> Installing goimports..." + cd tools; $(GOCMD) install -mod=vendor golang.org/x/tools/cmd/goimports -format: - test -z $$($(GOCMD) fmt ./...) +format: install-goimports + @echo "> Formating code..." + @goimports -l -w -local ${PACKAGE_BASE} ${SRC} vet: - $(GOCMD) vet $$($(GOCMD) list ./... | grep -v /testdata/) + @echo "> Vetting code..." + @$(GOCMD) vet -mod=vendor ${PACKAGES} -test: format imports vet +test: format vet $(GOTEST) -parallel=1 -count=1 -v ./... diff --git a/README.md b/README.md index bd34cc8b..2caa4b9d 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Helpful utilities for working with images To format: ```bash -$ make format imports +$ make format ``` To run tests: diff --git a/go.mod b/go.mod index 889927f9..ba397ca7 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,6 @@ require ( golang.org/x/sync v0.0.0-20190423024810-112230192c58 golang.org/x/sys v0.0.0-20190416152802-12500544f89f // indirect golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect - golang.org/x/tools v0.0.0-20190624190245-7f2218787638 google.golang.org/grpc v1.20.0 // indirect gotest.tools v2.2.0+incompatible // indirect ) diff --git a/go.sum b/go.sum index e8e62a5b..ba332132 100644 --- a/go.sum +++ b/go.sum @@ -79,8 +79,6 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZe golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190624190245-7f2218787638 h1:uIfBkD8gLczr4XDgYpt/qJYds2YJwZRNw4zs7wSnNhk= -golang.org/x/tools v0.0.0-20190624190245-7f2218787638/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= diff --git a/tools/go.mod b/tools/go.mod new file mode 100644 index 00000000..2fc21778 --- /dev/null +++ b/tools/go.mod @@ -0,0 +1,5 @@ +module github.com/buildpack/pack/tools + +go 1.13 + +require golang.org/x/tools v0.0.0-20190929041059-e7abfedfabcf diff --git a/tools/go.sum b/tools/go.sum new file mode 100644 index 00000000..a1059c7c --- /dev/null +++ b/tools/go.sum @@ -0,0 +1,8 @@ +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190929041059-e7abfedfabcf h1:NvypsVlesF+lEDKVK5RNkww4fzArJXChZxNin79j05M= +golang.org/x/tools v0.0.0-20190929041059-e7abfedfabcf/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/vendor/golang.org/x/tools/AUTHORS b/tools/vendor/golang.org/x/tools/AUTHORS similarity index 100% rename from vendor/golang.org/x/tools/AUTHORS rename to tools/vendor/golang.org/x/tools/AUTHORS diff --git a/vendor/golang.org/x/tools/CONTRIBUTORS b/tools/vendor/golang.org/x/tools/CONTRIBUTORS similarity index 100% rename from vendor/golang.org/x/tools/CONTRIBUTORS rename to tools/vendor/golang.org/x/tools/CONTRIBUTORS diff --git a/vendor/golang.org/x/tools/LICENSE b/tools/vendor/golang.org/x/tools/LICENSE similarity index 100% rename from vendor/golang.org/x/tools/LICENSE rename to tools/vendor/golang.org/x/tools/LICENSE diff --git a/vendor/golang.org/x/tools/PATENTS b/tools/vendor/golang.org/x/tools/PATENTS similarity index 100% rename from vendor/golang.org/x/tools/PATENTS rename to tools/vendor/golang.org/x/tools/PATENTS diff --git a/vendor/golang.org/x/tools/cmd/goimports/doc.go b/tools/vendor/golang.org/x/tools/cmd/goimports/doc.go similarity index 100% rename from vendor/golang.org/x/tools/cmd/goimports/doc.go rename to tools/vendor/golang.org/x/tools/cmd/goimports/doc.go diff --git a/vendor/golang.org/x/tools/cmd/goimports/goimports.go b/tools/vendor/golang.org/x/tools/cmd/goimports/goimports.go similarity index 100% rename from vendor/golang.org/x/tools/cmd/goimports/goimports.go rename to tools/vendor/golang.org/x/tools/cmd/goimports/goimports.go diff --git a/vendor/golang.org/x/tools/cmd/goimports/goimports_gc.go b/tools/vendor/golang.org/x/tools/cmd/goimports/goimports_gc.go similarity index 100% rename from vendor/golang.org/x/tools/cmd/goimports/goimports_gc.go rename to tools/vendor/golang.org/x/tools/cmd/goimports/goimports_gc.go diff --git a/vendor/golang.org/x/tools/cmd/goimports/goimports_not_gc.go b/tools/vendor/golang.org/x/tools/cmd/goimports/goimports_not_gc.go similarity index 100% rename from vendor/golang.org/x/tools/cmd/goimports/goimports_not_gc.go rename to tools/vendor/golang.org/x/tools/cmd/goimports/goimports_not_gc.go diff --git a/vendor/golang.org/x/tools/go/ast/astutil/enclosing.go b/tools/vendor/golang.org/x/tools/go/ast/astutil/enclosing.go similarity index 100% rename from vendor/golang.org/x/tools/go/ast/astutil/enclosing.go rename to tools/vendor/golang.org/x/tools/go/ast/astutil/enclosing.go diff --git a/vendor/golang.org/x/tools/go/ast/astutil/imports.go b/tools/vendor/golang.org/x/tools/go/ast/astutil/imports.go similarity index 100% rename from vendor/golang.org/x/tools/go/ast/astutil/imports.go rename to tools/vendor/golang.org/x/tools/go/ast/astutil/imports.go diff --git a/vendor/golang.org/x/tools/go/ast/astutil/rewrite.go b/tools/vendor/golang.org/x/tools/go/ast/astutil/rewrite.go similarity index 100% rename from vendor/golang.org/x/tools/go/ast/astutil/rewrite.go rename to tools/vendor/golang.org/x/tools/go/ast/astutil/rewrite.go diff --git a/vendor/golang.org/x/tools/go/ast/astutil/util.go b/tools/vendor/golang.org/x/tools/go/ast/astutil/util.go similarity index 100% rename from vendor/golang.org/x/tools/go/ast/astutil/util.go rename to tools/vendor/golang.org/x/tools/go/ast/astutil/util.go diff --git a/vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go b/tools/vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go similarity index 100% rename from vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go rename to tools/vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go diff --git a/vendor/golang.org/x/tools/go/gcexportdata/importer.go b/tools/vendor/golang.org/x/tools/go/gcexportdata/importer.go similarity index 100% rename from vendor/golang.org/x/tools/go/gcexportdata/importer.go rename to tools/vendor/golang.org/x/tools/go/gcexportdata/importer.go diff --git a/vendor/golang.org/x/tools/go/gcexportdata/main.go b/tools/vendor/golang.org/x/tools/go/gcexportdata/main.go similarity index 100% rename from vendor/golang.org/x/tools/go/gcexportdata/main.go rename to tools/vendor/golang.org/x/tools/go/gcexportdata/main.go diff --git a/vendor/golang.org/x/tools/go/internal/gcimporter/bexport.go b/tools/vendor/golang.org/x/tools/go/internal/gcimporter/bexport.go similarity index 100% rename from vendor/golang.org/x/tools/go/internal/gcimporter/bexport.go rename to tools/vendor/golang.org/x/tools/go/internal/gcimporter/bexport.go diff --git a/vendor/golang.org/x/tools/go/internal/gcimporter/bimport.go b/tools/vendor/golang.org/x/tools/go/internal/gcimporter/bimport.go similarity index 99% rename from vendor/golang.org/x/tools/go/internal/gcimporter/bimport.go rename to tools/vendor/golang.org/x/tools/go/internal/gcimporter/bimport.go index e3c31078..e9f73d14 100644 --- a/vendor/golang.org/x/tools/go/internal/gcimporter/bimport.go +++ b/tools/vendor/golang.org/x/tools/go/internal/gcimporter/bimport.go @@ -332,7 +332,7 @@ func (p *importer) pos() token.Pos { p.prevFile = file p.prevLine = line - return p.fake.pos(file, line) + return p.fake.pos(file, line, 0) } // Synthesize a token.Pos @@ -341,7 +341,9 @@ type fakeFileSet struct { files map[string]*token.File } -func (s *fakeFileSet) pos(file string, line int) token.Pos { +func (s *fakeFileSet) pos(file string, line, column int) token.Pos { + // TODO(mdempsky): Make use of column. + // Since we don't know the set of needed file positions, we // reserve maxlines positions per file. const maxlines = 64 * 1024 @@ -976,10 +978,11 @@ const ( aliasTag ) +var predeclOnce sync.Once var predecl []types.Type // initialized lazily func predeclared() []types.Type { - if predecl == nil { + predeclOnce.Do(func() { // initialize lazily to be sure that all // elements have been initialized before predecl = []types.Type{ // basic types @@ -1026,7 +1029,7 @@ func predeclared() []types.Type { // used internally by gc; never used by this package or in .a files anyType{}, } - } + }) return predecl } diff --git a/vendor/golang.org/x/tools/go/internal/gcimporter/exportdata.go b/tools/vendor/golang.org/x/tools/go/internal/gcimporter/exportdata.go similarity index 100% rename from vendor/golang.org/x/tools/go/internal/gcimporter/exportdata.go rename to tools/vendor/golang.org/x/tools/go/internal/gcimporter/exportdata.go diff --git a/vendor/golang.org/x/tools/go/internal/gcimporter/gcimporter.go b/tools/vendor/golang.org/x/tools/go/internal/gcimporter/gcimporter.go similarity index 100% rename from vendor/golang.org/x/tools/go/internal/gcimporter/gcimporter.go rename to tools/vendor/golang.org/x/tools/go/internal/gcimporter/gcimporter.go diff --git a/vendor/golang.org/x/tools/go/internal/gcimporter/iexport.go b/tools/vendor/golang.org/x/tools/go/internal/gcimporter/iexport.go similarity index 100% rename from vendor/golang.org/x/tools/go/internal/gcimporter/iexport.go rename to tools/vendor/golang.org/x/tools/go/internal/gcimporter/iexport.go diff --git a/vendor/golang.org/x/tools/go/internal/gcimporter/iimport.go b/tools/vendor/golang.org/x/tools/go/internal/gcimporter/iimport.go similarity index 95% rename from vendor/golang.org/x/tools/go/internal/gcimporter/iimport.go rename to tools/vendor/golang.org/x/tools/go/internal/gcimporter/iimport.go index 3cb7ae5b..a9c5733e 100644 --- a/vendor/golang.org/x/tools/go/internal/gcimporter/iimport.go +++ b/tools/vendor/golang.org/x/tools/go/internal/gcimporter/iimport.go @@ -63,8 +63,8 @@ const ( // If the export data version is not recognized or the format is otherwise // compromised, an error is returned. func IImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) { - const currentVersion = 0 - version := -1 + const currentVersion = 1 + version := int64(-1) defer func() { if e := recover(); e != nil { if version > currentVersion { @@ -77,9 +77,9 @@ func IImportData(fset *token.FileSet, imports map[string]*types.Package, data [] r := &intReader{bytes.NewReader(data), path} - version = int(r.uint64()) + version = int64(r.uint64()) switch version { - case currentVersion: + case currentVersion, 0: default: errorf("unknown iexport format version %d", version) } @@ -93,7 +93,8 @@ func IImportData(fset *token.FileSet, imports map[string]*types.Package, data [] r.Seek(sLen+dLen, io.SeekCurrent) p := iimporter{ - ipath: path, + ipath: path, + version: int(version), stringData: stringData, stringCache: make(map[uint64]string), @@ -175,7 +176,8 @@ func IImportData(fset *token.FileSet, imports map[string]*types.Package, data [] } type iimporter struct { - ipath string + ipath string + version int stringData []byte stringCache map[uint64]string @@ -255,6 +257,7 @@ type importReader struct { currPkg *types.Package prevFile string prevLine int64 + prevColumn int64 } func (r *importReader) obj(name string) { @@ -448,6 +451,19 @@ func (r *importReader) qualifiedIdent() (*types.Package, string) { } func (r *importReader) pos() token.Pos { + if r.p.version >= 1 { + r.posv1() + } else { + r.posv0() + } + + if r.prevFile == "" && r.prevLine == 0 && r.prevColumn == 0 { + return token.NoPos + } + return r.p.fake.pos(r.prevFile, int(r.prevLine), int(r.prevColumn)) +} + +func (r *importReader) posv0() { delta := r.int64() if delta != deltaNewFile { r.prevLine += delta @@ -457,12 +473,18 @@ func (r *importReader) pos() token.Pos { r.prevFile = r.string() r.prevLine = l } +} - if r.prevFile == "" && r.prevLine == 0 { - return token.NoPos +func (r *importReader) posv1() { + delta := r.int64() + r.prevColumn += delta >> 1 + if delta&1 != 0 { + delta = r.int64() + r.prevLine += delta >> 1 + if delta&1 != 0 { + r.prevFile = r.string() + } } - - return r.p.fake.pos(r.prevFile, int(r.prevLine)) } func (r *importReader) typ() types.Type { diff --git a/vendor/golang.org/x/tools/go/internal/gcimporter/newInterface10.go b/tools/vendor/golang.org/x/tools/go/internal/gcimporter/newInterface10.go similarity index 100% rename from vendor/golang.org/x/tools/go/internal/gcimporter/newInterface10.go rename to tools/vendor/golang.org/x/tools/go/internal/gcimporter/newInterface10.go diff --git a/vendor/golang.org/x/tools/go/internal/gcimporter/newInterface11.go b/tools/vendor/golang.org/x/tools/go/internal/gcimporter/newInterface11.go similarity index 100% rename from vendor/golang.org/x/tools/go/internal/gcimporter/newInterface11.go rename to tools/vendor/golang.org/x/tools/go/internal/gcimporter/newInterface11.go diff --git a/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go b/tools/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go similarity index 87% rename from vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go rename to tools/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go index fdc7da05..ea15d57b 100644 --- a/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go +++ b/tools/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go @@ -82,15 +82,28 @@ func GetSizesGolist(ctx context.Context, buildFlags, env []string, dir string, u args = append(args, buildFlags...) args = append(args, "--", "unsafe") stdout, err := InvokeGo(ctx, env, dir, usesExportData, args...) + var goarch, compiler string if err != nil { - return nil, err - } - fields := strings.Fields(stdout.String()) - if len(fields) < 2 { - return nil, fmt.Errorf("could not determine GOARCH and Go compiler") + if strings.Contains(err.Error(), "cannot find main module") { + // User's running outside of a module. All bets are off. Get GOARCH and guess compiler is gc. + // TODO(matloob): Is this a problem in practice? + envout, enverr := InvokeGo(ctx, env, dir, usesExportData, "env", "GOARCH") + if enverr != nil { + return nil, err + } + goarch = strings.TrimSpace(envout.String()) + compiler = "gc" + } else { + return nil, err + } + } else { + fields := strings.Fields(stdout.String()) + if len(fields) < 2 { + return nil, fmt.Errorf("could not determine GOARCH and Go compiler") + } + goarch = fields[0] + compiler = fields[1] } - goarch := fields[0] - compiler := fields[1] return types.SizesFor(compiler, goarch), nil } diff --git a/vendor/golang.org/x/tools/go/packages/doc.go b/tools/vendor/golang.org/x/tools/go/packages/doc.go similarity index 100% rename from vendor/golang.org/x/tools/go/packages/doc.go rename to tools/vendor/golang.org/x/tools/go/packages/doc.go diff --git a/vendor/golang.org/x/tools/go/packages/external.go b/tools/vendor/golang.org/x/tools/go/packages/external.go similarity index 58% rename from vendor/golang.org/x/tools/go/packages/external.go rename to tools/vendor/golang.org/x/tools/go/packages/external.go index 22ff769e..b696b687 100644 --- a/vendor/golang.org/x/tools/go/packages/external.go +++ b/tools/vendor/golang.org/x/tools/go/packages/external.go @@ -16,14 +16,29 @@ import ( "strings" ) -// Driver +// The Driver Protocol +// +// The driver, given the inputs to a call to Load, returns metadata about the packages specified. +// This allows for different build systems to support go/packages by telling go/packages how the +// packages' source is organized. +// The driver is a binary, either specified by the GOPACKAGESDRIVER environment variable or in +// the path as gopackagesdriver. It's given the inputs to load in its argv. See the package +// documentation in doc.go for the full description of the patterns that need to be supported. +// A driver receives as a JSON-serialized driverRequest struct in standard input and will +// produce a JSON-serialized driverResponse (see definition in packages.go) in its standard output. + +// driverRequest is used to provide the portion of Load's Config that is needed by a driver. type driverRequest struct { - Command string `json:"command"` - Mode LoadMode `json:"mode"` - Env []string `json:"env"` - BuildFlags []string `json:"build_flags"` - Tests bool `json:"tests"` - Overlay map[string][]byte `json:"overlay"` + Mode LoadMode `json:"mode"` + // Env specifies the environment the underlying build system should be run in. + Env []string `json:"env"` + // BuildFlags are flags that should be passed to the underlying build system. + BuildFlags []string `json:"build_flags"` + // Tests specifies whether the patterns should also return test packages. + Tests bool `json:"tests"` + // Overlay maps file paths (relative to the driver's working directory) to the byte contents + // of overlay files. + Overlay map[string][]byte `json:"overlay"` } // findExternalDriver returns the file path of a tool that supplies diff --git a/vendor/golang.org/x/tools/go/packages/golist.go b/tools/vendor/golang.org/x/tools/go/packages/golist.go similarity index 77% rename from vendor/golang.org/x/tools/go/packages/golist.go rename to tools/vendor/golang.org/x/tools/go/packages/golist.go index 04c6396d..6b341b7e 100644 --- a/vendor/golang.org/x/tools/go/packages/golist.go +++ b/tools/vendor/golang.org/x/tools/go/packages/golist.go @@ -13,6 +13,7 @@ import ( "log" "os" "os/exec" + "path" "path/filepath" "reflect" "regexp" @@ -20,6 +21,7 @@ import ( "strings" "sync" "time" + "unicode" "golang.org/x/tools/go/internal/packagesdriver" "golang.org/x/tools/internal/gopathwalk" @@ -71,6 +73,28 @@ func (r *responseDeduper) addRoot(id string) { r.dr.Roots = append(r.dr.Roots, id) } +// goInfo contains global information from the go tool. +type goInfo struct { + rootDirs map[string]string + env goEnv +} + +type goEnv struct { + modulesOn bool +} + +func determineEnv(cfg *Config) goEnv { + buf, err := invokeGo(cfg, "env", "GOMOD") + if err != nil { + return goEnv{} + } + gomod := bytes.TrimSpace(buf.Bytes()) + + env := goEnv{} + env.modulesOn = len(gomod) > 0 + return env +} + // goListDriver uses the go list command to interpret the patterns and produce // the build system package structure. // See driver for more details. @@ -86,6 +110,28 @@ func goListDriver(cfg *Config, patterns ...string) (*driverResponse, error) { }() } + // start fetching rootDirs + var info goInfo + var rootDirsReady, envReady = make(chan struct{}), make(chan struct{}) + go func() { + info.rootDirs = determineRootDirs(cfg) + close(rootDirsReady) + }() + go func() { + info.env = determineEnv(cfg) + close(envReady) + }() + getGoInfo := func() *goInfo { + <-rootDirsReady + <-envReady + return &info + } + + // always pass getGoInfo to golistDriver + golistDriver := func(cfg *Config, patterns ...string) (*driverResponse, error) { + return golistDriver(cfg, getGoInfo, patterns...) + } + // Determine files requested in contains patterns var containFiles []string var packagesNamed []string @@ -147,7 +193,7 @@ extractQueries: var containsCandidates []string if len(containFiles) != 0 { - if err := runContainsQueries(cfg, golistDriver, response, containFiles); err != nil { + if err := runContainsQueries(cfg, golistDriver, response, containFiles, getGoInfo); err != nil { return nil, err } } @@ -158,7 +204,7 @@ extractQueries: } } - modifiedPkgs, needPkgs, err := processGolistOverlay(cfg, response) + modifiedPkgs, needPkgs, err := processGolistOverlay(cfg, response, getGoInfo) if err != nil { return nil, err } @@ -166,7 +212,7 @@ extractQueries: containsCandidates = append(containsCandidates, modifiedPkgs...) containsCandidates = append(containsCandidates, needPkgs...) } - if err := addNeededOverlayPackages(cfg, golistDriver, response, needPkgs); err != nil { + if err := addNeededOverlayPackages(cfg, golistDriver, response, needPkgs, getGoInfo); err != nil { return nil, err } // Check candidate packages for containFiles. @@ -198,26 +244,33 @@ extractQueries: return response.dr, nil } -func addNeededOverlayPackages(cfg *Config, driver driver, response *responseDeduper, pkgs []string) error { +func addNeededOverlayPackages(cfg *Config, driver driver, response *responseDeduper, pkgs []string, getGoInfo func() *goInfo) error { if len(pkgs) == 0 { return nil } - dr, err := driver(cfg, pkgs...) + drivercfg := *cfg + if getGoInfo().env.modulesOn { + drivercfg.BuildFlags = append(drivercfg.BuildFlags, "-mod=readonly") + } + dr, err := driver(&drivercfg, pkgs...) + if err != nil { return err } for _, pkg := range dr.Packages { response.addPackage(pkg) } - _, needPkgs, err := processGolistOverlay(cfg, response) + _, needPkgs, err := processGolistOverlay(cfg, response, getGoInfo) if err != nil { return err } - addNeededOverlayPackages(cfg, driver, response, needPkgs) + if err := addNeededOverlayPackages(cfg, driver, response, needPkgs, getGoInfo); err != nil { + return err + } return nil } -func runContainsQueries(cfg *Config, driver driver, response *responseDeduper, queries []string) error { +func runContainsQueries(cfg *Config, driver driver, response *responseDeduper, queries []string, goInfo func() *goInfo) error { for _, query := range queries { // TODO(matloob): Do only one query per directory. fdir := filepath.Dir(query) @@ -228,14 +281,31 @@ func runContainsQueries(cfg *Config, driver driver, response *responseDeduper, q return fmt.Errorf("could not determine absolute path of file= query path %q: %v", query, err) } dirResponse, err := driver(cfg, pattern) - if err != nil { - // Couldn't find a package for the directory. Try to load the file as an ad-hoc package. + if err != nil || (len(dirResponse.Packages) == 1 && len(dirResponse.Packages[0].Errors) == 1) { + // There was an error loading the package. Try to load the file as an ad-hoc package. + // Usually the error will appear in a returned package, but may not if we're in modules mode + // and the ad-hoc is located outside a module. var queryErr error dirResponse, queryErr = driver(cfg, query) if queryErr != nil { // Return the original error if the attempt to fall back failed. return err } + // Special case to handle issue #33482: + // If this is a file= query for ad-hoc packages where the file only exists on an overlay, + // and exists outside of a module, add the file in for the package. + if len(dirResponse.Packages) == 1 && len(dirResponse.Packages) == 1 && + dirResponse.Packages[0].ID == "command-line-arguments" && len(dirResponse.Packages[0].GoFiles) == 0 { + filename := filepath.Join(pattern, filepath.Base(query)) // avoid recomputing abspath + // TODO(matloob): check if the file is outside of a root dir? + for path := range cfg.Overlay { + if path == filename { + dirResponse.Packages[0].Errors = nil + dirResponse.Packages[0].GoFiles = []string{path} + dirResponse.Packages[0].CompiledGoFiles = []string{path} + } + } + } } isRoot := make(map[string]bool, len(dirResponse.Roots)) for _, root := range dirResponse.Roots { @@ -312,9 +382,7 @@ func runNamedQueries(cfg *Config, driver driver, response *responseDeduper, quer startWalk := time.Now() gopathwalk.Walk(roots, add, gopathwalk.Options{ModulesEnabled: modRoot != "", Debug: debug}) - if debug { - log.Printf("%v for walk", time.Since(startWalk)) - } + cfg.Logf("%v for walk", time.Since(startWalk)) // Weird special case: the top-level package in a module will be in // whatever directory the user checked the repository out into. It's @@ -565,7 +633,7 @@ func otherFiles(p *jsonPackage) [][]string { // golistDriver uses the "go list" command to expand the pattern // words and return metadata for the specified packages. dir may be // "" and env may be nil, as per os/exec.Command. -func golistDriver(cfg *Config, words ...string) (*driverResponse, error) { +func golistDriver(cfg *Config, rootsDirs func() *goInfo, words ...string) (*driverResponse, error) { // go list uses the following identifiers in ImportPath and Imports: // // "p" -- importable package or main (command) @@ -606,6 +674,20 @@ func golistDriver(cfg *Config, words ...string) (*driverResponse, error) { return nil, fmt.Errorf("package missing import path: %+v", p) } + // Work around https://golang.org/issue/33157: + // go list -e, when given an absolute path, will find the package contained at + // that directory. But when no package exists there, it will return a fake package + // with an error and the ImportPath set to the absolute path provided to go list. + // Try to convert that absolute path to what its package path would be if it's + // contained in a known module or GOPATH entry. This will allow the package to be + // properly "reclaimed" when overlays are processed. + if filepath.IsAbs(p.ImportPath) && p.Error != nil { + pkgPath, ok := getPkgPath(p.ImportPath, rootsDirs) + if ok { + p.ImportPath = pkgPath + } + } + if old, found := seen[p.ImportPath]; found { if !reflect.DeepEqual(p, old) { return nil, fmt.Errorf("internal error: go list gives conflicting information for package %v", p.ImportPath) @@ -709,6 +791,27 @@ func golistDriver(cfg *Config, words ...string) (*driverResponse, error) { return &response, nil } +// getPkgPath finds the package path of a directory if it's relative to a root directory. +func getPkgPath(dir string, goInfo func() *goInfo) (string, bool) { + for rdir, rpath := range goInfo().rootDirs { + // TODO(matloob): This doesn't properly handle symlinks. + r, err := filepath.Rel(rdir, dir) + if err != nil { + continue + } + if rpath != "" { + // We choose only ore root even though the directory even it can belong in multiple modules + // or GOPATH entries. This is okay because we only need to work with absolute dirs when a + // file is missing from disk, for instance when gopls calls go/packages in an overlay. + // Once the file is saved, gopls, or the next invocation of the tool will get the correct + // result straight from golist. + // TODO(matloob): Implement module tiebreaking? + return path.Join(rpath, filepath.ToSlash(r)), true + } + } + return "", false +} + // absJoin absolutizes and flattens the lists of files. func absJoin(dir string, fileses ...[]string) (res []string) { for _, files := range fileses { @@ -729,7 +832,7 @@ func golistargs(cfg *Config, words []string) []string { fmt.Sprintf("-compiled=%t", cfg.Mode&(NeedCompiledGoFiles|NeedSyntax|NeedTypesInfo|NeedTypesSizes) != 0), fmt.Sprintf("-test=%t", cfg.Tests), fmt.Sprintf("-export=%t", usesExportData(cfg)), - fmt.Sprintf("-deps=%t", cfg.Mode&NeedDeps != 0), + fmt.Sprintf("-deps=%t", cfg.Mode&NeedImports != 0), // go list doesn't let you pass -test and -find together, // probably because you'd just get the TestMain. fmt.Sprintf("-find=%t", !cfg.Tests && cfg.Mode&findFlags == 0), @@ -755,11 +858,9 @@ func invokeGo(cfg *Config, args ...string) (*bytes.Buffer, error) { cmd.Dir = cfg.Dir cmd.Stdout = stdout cmd.Stderr = stderr - if debug { - defer func(start time.Time) { - log.Printf("%s for %v, stderr: <<%s>>\n", time.Since(start), cmdDebugStr(cmd, args...), stderr) - }(time.Now()) - } + defer func(start time.Time) { + cfg.Logf("%s for %v, stderr: <<%s>>\n", time.Since(start), cmdDebugStr(cmd, args...), stderr) + }(time.Now()) if err := cmd.Run(); err != nil { // Check for 'go' executable not being found. @@ -779,6 +880,30 @@ func invokeGo(cfg *Config, args ...string) (*bytes.Buffer, error) { return nil, goTooOldError{fmt.Errorf("unsupported version of go: %s: %s", exitErr, stderr)} } + // Related to #24854 + if len(stderr.String()) > 0 && strings.Contains(stderr.String(), "unexpected directory layout") { + return nil, fmt.Errorf("%s", stderr.String()) + } + + // Is there an error running the C compiler in cgo? This will be reported in the "Error" field + // and should be suppressed by go list -e. + // + // This condition is not perfect yet because the error message can include other error messages than runtime/cgo. + isPkgPathRune := func(r rune) bool { + // From https://golang.org/ref/spec#Import_declarations: + // Implementation restriction: A compiler may restrict ImportPaths to non-empty strings + // using only characters belonging to Unicode's L, M, N, P, and S general categories + // (the Graphic characters without spaces) and may also exclude the + // characters !"#$%&'()*,:;<=>?[\]^`{|} and the Unicode replacement character U+FFFD. + return unicode.IsOneOf([]*unicode.RangeTable{unicode.L, unicode.M, unicode.N, unicode.P, unicode.S}, r) && + strings.IndexRune("!\"#$%&'()*,:;<=>?[\\]^`{|}\uFFFD", r) == -1 + } + if len(stderr.String()) > 0 && strings.HasPrefix(stderr.String(), "# ") { + if strings.HasPrefix(strings.TrimLeftFunc(stderr.String()[len("# "):], isPkgPathRune), "\n") { + return stdout, nil + } + } + // This error only appears in stderr. See golang.org/cl/166398 for a fix in go list to show // the error in the Err section of stdout in case -e option is provided. // This fix is provided for backwards compatibility. @@ -788,13 +913,43 @@ func invokeGo(cfg *Config, args ...string) (*bytes.Buffer, error) { return bytes.NewBufferString(output), nil } + // Similar to the previous error, but currently lacks a fix in Go. + if len(stderr.String()) > 0 && strings.Contains(stderr.String(), "named files must all be in one directory") { + output := fmt.Sprintf(`{"ImportPath": "command-line-arguments","Incomplete": true,"Error": {"Pos": "","Err": %q}}`, + strings.Trim(stderr.String(), "\n")) + return bytes.NewBufferString(output), nil + } + + // Backwards compatibility for Go 1.11 because 1.12 and 1.13 put the directory in the ImportPath. + // If the package doesn't exist, put the absolute path of the directory into the error message, + // as Go 1.13 list does. + const noSuchDirectory = "no such directory" + if len(stderr.String()) > 0 && strings.Contains(stderr.String(), noSuchDirectory) { + errstr := stderr.String() + abspath := strings.TrimSpace(errstr[strings.Index(errstr, noSuchDirectory)+len(noSuchDirectory):]) + output := fmt.Sprintf(`{"ImportPath": %q,"Incomplete": true,"Error": {"Pos": "","Err": %q}}`, + abspath, strings.Trim(stderr.String(), "\n")) + return bytes.NewBufferString(output), nil + } + // Workaround for #29280: go list -e has incorrect behavior when an ad-hoc package doesn't exist. + // Note that the error message we look for in this case is different that the one looked for above. if len(stderr.String()) > 0 && strings.Contains(stderr.String(), "no such file or directory") { output := fmt.Sprintf(`{"ImportPath": "command-line-arguments","Incomplete": true,"Error": {"Pos": "","Err": %q}}`, strings.Trim(stderr.String(), "\n")) return bytes.NewBufferString(output), nil } + // Workaround for #34273. go list -e with GO111MODULE=on has incorrect behavior when listing a + // directory outside any module. + if len(stderr.String()) > 0 && strings.Contains(stderr.String(), "outside available modules") { + output := fmt.Sprintf(`{"ImportPath": %q,"Incomplete": true,"Error": {"Pos": "","Err": %q}}`, + // TODO(matloob): command-line-arguments isn't correct here. + "command-line-arguments", strings.Trim(stderr.String(), "\n")) + return bytes.NewBufferString(output), nil + + } + // Workaround for an instance of golang.org/issue/26755: go list -e will return a non-zero exit // status if there's a dependency on a package that doesn't exist. But it should return // a zero exit status and set an error on that package. diff --git a/vendor/golang.org/x/tools/go/packages/golist_overlay.go b/tools/vendor/golang.org/x/tools/go/packages/golist_overlay.go similarity index 82% rename from vendor/golang.org/x/tools/go/packages/golist_overlay.go rename to tools/vendor/golang.org/x/tools/go/packages/golist_overlay.go index b35399ef..308e79c5 100644 --- a/vendor/golang.org/x/tools/go/packages/golist_overlay.go +++ b/tools/vendor/golang.org/x/tools/go/packages/golist_overlay.go @@ -10,7 +10,6 @@ import ( "path/filepath" "strconv" "strings" - "sync" ) // processGolistOverlay provides rudimentary support for adding @@ -18,7 +17,7 @@ import ( // sometimes incorrect. // TODO(matloob): Handle unsupported cases, including the following: // - determining the correct package to add given a new import path -func processGolistOverlay(cfg *Config, response *responseDeduper) (modifiedPkgs, needPkgs []string, err error) { +func processGolistOverlay(cfg *Config, response *responseDeduper, rootDirs func() *goInfo) (modifiedPkgs, needPkgs []string, err error) { havePkgs := make(map[string]string) // importPath -> non-test package ID needPkgsSet := make(map[string]bool) modifiedPkgsSet := make(map[string]bool) @@ -29,16 +28,20 @@ func processGolistOverlay(cfg *Config, response *responseDeduper) (modifiedPkgs, havePkgs[pkg.PkgPath] = pkg.ID } - var rootDirs map[string]string - var onceGetRootDirs sync.Once + // If no new imports are added, it is safe to avoid loading any needPkgs. + // Otherwise, it's hard to tell which package is actually being loaded + // (due to vendoring) and whether any modified package will show up + // in the transitive set of dependencies (because new imports are added, + // potentially modifying the transitive set of dependencies). + var overlayAddsImports bool for opath, contents := range cfg.Overlay { base := filepath.Base(opath) dir := filepath.Dir(opath) - var pkg *Package + var pkg *Package // if opath belongs to both a package and its test variant, this will be the test variant var testVariantOf *Package // if opath is a test file, this is the package it is testing var fileExists bool - isTest := strings.HasSuffix(opath, "_test.go") + isTestFile := strings.HasSuffix(opath, "_test.go") pkgName, ok := extractPackageName(opath, contents) if !ok { // Don't bother adding a file that doesn't even have a parsable package statement @@ -47,20 +50,33 @@ func processGolistOverlay(cfg *Config, response *responseDeduper) (modifiedPkgs, } nextPackage: for _, p := range response.dr.Packages { - if pkgName != p.Name { + if pkgName != p.Name && p.ID != "command-line-arguments" { continue } for _, f := range p.GoFiles { if !sameFile(filepath.Dir(f), dir) { continue } - if isTest && !hasTestFiles(p) { + // Make sure to capture information on the package's test variant, if needed. + if isTestFile && !hasTestFiles(p) { // TODO(matloob): Are there packages other than the 'production' variant // of a package that this can match? This shouldn't match the test main package // because the file is generated in another directory. testVariantOf = p continue nextPackage } + if pkg != nil && p != pkg && pkg.PkgPath == p.PkgPath { + // If we've already seen the test variant, + // make sure to label which package it is a test variant of. + if hasTestFiles(pkg) { + testVariantOf = p + continue nextPackage + } + // If we have already seen the package of which this is a test variant. + if hasTestFiles(p) { + testVariantOf = pkg + } + } pkg = p if filepath.Base(f) == base { fileExists = true @@ -69,13 +85,10 @@ func processGolistOverlay(cfg *Config, response *responseDeduper) (modifiedPkgs, } // The overlay could have included an entirely new package. if pkg == nil { - onceGetRootDirs.Do(func() { - rootDirs = determineRootDirs(cfg) - }) // Try to find the module or gopath dir the file is contained in. // Then for modules, add the module opath to the beginning. var pkgPath string - for rdir, rpath := range rootDirs { + for rdir, rpath := range rootDirs().rootDirs { // TODO(matloob): This doesn't properly handle symlinks. r, err := filepath.Rel(rdir, dir) if err != nil { @@ -99,7 +112,7 @@ func processGolistOverlay(cfg *Config, response *responseDeduper) (modifiedPkgs, pkgPath += "_test" } id := pkgPath - if isTest && !isXTest { + if isTestFile && !isXTest { id = fmt.Sprintf("%s [%s.test]", pkgPath, pkgPath) } // Try to reclaim a package with the same id if it exists in the response. @@ -115,7 +128,7 @@ func processGolistOverlay(cfg *Config, response *responseDeduper) (modifiedPkgs, response.addPackage(pkg) havePkgs[pkg.PkgPath] = id // Add the production package's sources for a test variant. - if isTest && !isXTest && testVariantOf != nil { + if isTestFile && !isXTest && testVariantOf != nil { pkg.GoFiles = append(pkg.GoFiles, testVariantOf.GoFiles...) pkg.CompiledGoFiles = append(pkg.CompiledGoFiles, testVariantOf.CompiledGoFiles...) } @@ -136,13 +149,18 @@ func processGolistOverlay(cfg *Config, response *responseDeduper) (modifiedPkgs, for _, imp := range imports { _, found := pkg.Imports[imp] if !found { + overlayAddsImports = true // TODO(matloob): Handle cases when the following block isn't correct. - // These include imports of test variants, imports of vendored packages, etc. + // These include imports of vendored packages, etc. id, ok := havePkgs[imp] if !ok { id = imp } pkg.Imports[imp] = &Package{ID: id} + // Add dependencies to the non-test variant version of this package as wel. + if testVariantOf != nil { + testVariantOf.Imports[imp] = &Package{ID: id} + } } } continue @@ -171,9 +189,11 @@ func processGolistOverlay(cfg *Config, response *responseDeduper) (modifiedPkgs, } } - needPkgs = make([]string, 0, len(needPkgsSet)) - for pkg := range needPkgsSet { - needPkgs = append(needPkgs, pkg) + if overlayAddsImports { + needPkgs = make([]string, 0, len(needPkgsSet)) + for pkg := range needPkgsSet { + needPkgs = append(needPkgs, pkg) + } } modifiedPkgs = make([]string, 0, len(modifiedPkgsSet)) for pkg := range modifiedPkgsSet { diff --git a/vendor/golang.org/x/tools/go/packages/packages.go b/tools/vendor/golang.org/x/tools/go/packages/packages.go similarity index 88% rename from vendor/golang.org/x/tools/go/packages/packages.go rename to tools/vendor/golang.org/x/tools/go/packages/packages.go index cd151469..b29c9136 100644 --- a/vendor/golang.org/x/tools/go/packages/packages.go +++ b/tools/vendor/golang.org/x/tools/go/packages/packages.go @@ -48,8 +48,7 @@ const ( // "placeholder" Packages with only the ID set. NeedImports - // NeedDeps adds the fields requested by the LoadMode in the packages in Imports. If NeedImports - // is not set NeedDeps has no effect. + // NeedDeps adds the fields requested by the LoadMode in the packages in Imports. NeedDeps // NeedExportsFile adds ExportsFile. @@ -75,7 +74,7 @@ const ( // Deprecated: LoadImports exists for historical compatibility // and should not be used. Please directly specify the needed fields using the Need values. - LoadImports = LoadFiles | NeedImports | NeedDeps + LoadImports = LoadFiles | NeedImports // Deprecated: LoadTypes exists for historical compatibility // and should not be used. Please directly specify the needed fields using the Need values. @@ -87,7 +86,7 @@ const ( // Deprecated: LoadAllSyntax exists for historical compatibility // and should not be used. Please directly specify the needed fields using the Need values. - LoadAllSyntax = LoadSyntax + LoadAllSyntax = LoadSyntax | NeedDeps ) // A Config specifies details about how packages should be loaded. @@ -103,6 +102,12 @@ type Config struct { // If Context is nil, the load cannot be cancelled. Context context.Context + // Logf is the logger for the config. + // If the user provides a logger, debug logging is enabled. + // If the GOPACKAGESDEBUG environment variable is set to true, + // but the logger is nil, default to log.Printf. + Logf func(format string, args ...interface{}) + // Dir is the directory in which to run the build system's query tool // that provides information about the packages. // If Dir is empty, the tool is run in the current directory. @@ -410,11 +415,13 @@ type loader struct { parseCacheMu sync.Mutex exportMu sync.Mutex // enforces mutual exclusion of exportdata operations - // TODO(matloob): Add an implied mode here and use that instead of mode. - // Implied mode would contain all the fields we need the data for so we can - // get the actually requested fields. We'll zero them out before returning - // packages to the user. This will make it easier for us to get the conditions - // where we need certain modes right. + // Config.Mode contains the implied mode (see impliedLoadMode). + // Implied mode contains all the fields we need the data for. + // In requestedMode there are the actually requested fields. + // We'll zero them out before returning packages to the user. + // This makes it easier for us to get the conditions where + // we need certain modes right. + requestedMode LoadMode } type parseValue struct { @@ -429,6 +436,17 @@ func newLoader(cfg *Config) *loader { } if cfg != nil { ld.Config = *cfg + // If the user has provided a logger, use it. + ld.Config.Logf = cfg.Logf + } + if ld.Config.Logf == nil { + // If the GOPACKAGESDEBUG environment variable is set to true, + // but the user has not provided a logger, default to log.Printf. + if debug { + ld.Config.Logf = log.Printf + } else { + ld.Config.Logf = func(format string, args ...interface{}) {} + } } if ld.Config.Mode == 0 { ld.Config.Mode = NeedName | NeedFiles | NeedCompiledGoFiles // Preserve zero behavior of Mode for backwards compatibility. @@ -445,6 +463,10 @@ func newLoader(cfg *Config) *loader { } } + // Save the actually requested fields. We'll zero them out before returning packages to the user. + ld.requestedMode = ld.Mode + ld.Mode = impliedLoadMode(ld.Mode) + if ld.Mode&NeedTypes != 0 { if ld.Fset == nil { ld.Fset = token.NewFileSet() @@ -459,6 +481,7 @@ func newLoader(cfg *Config) *loader { } } } + return ld } @@ -479,8 +502,8 @@ func (ld *loader) refine(roots []string, list ...*Package) ([]*Package, error) { } lpkg := &loaderPackage{ Package: pkg, - needtypes: (ld.Mode&(NeedTypes|NeedTypesInfo) != 0 && rootIndex < 0) || rootIndex >= 0, - needsrc: (ld.Mode&(NeedSyntax|NeedTypesInfo) != 0 && rootIndex < 0) || rootIndex >= 0 || + needtypes: (ld.Mode&(NeedTypes|NeedTypesInfo) != 0 && ld.Mode&NeedDeps != 0 && rootIndex < 0) || rootIndex >= 0, + needsrc: (ld.Mode&(NeedSyntax|NeedTypesInfo) != 0 && ld.Mode&NeedDeps != 0 && rootIndex < 0) || rootIndex >= 0 || len(ld.Overlay) > 0 || // Overlays can invalidate export data. TODO(matloob): make this check fine-grained based on dependencies on overlaid files pkg.ExportFile == "" && pkg.PkgPath != "unsafe", } @@ -527,28 +550,31 @@ func (ld *loader) refine(roots []string, list ...*Package) ([]*Package, error) { lpkg.color = grey stack = append(stack, lpkg) // push stubs := lpkg.Imports // the structure form has only stubs with the ID in the Imports - lpkg.Imports = make(map[string]*Package, len(stubs)) - for importPath, ipkg := range stubs { - var importErr error - imp := ld.pkgs[ipkg.ID] - if imp == nil { - // (includes package "C" when DisableCgo) - importErr = fmt.Errorf("missing package: %q", ipkg.ID) - } else if imp.color == grey { - importErr = fmt.Errorf("import cycle: %s", stack) - } - if importErr != nil { - if lpkg.importErrors == nil { - lpkg.importErrors = make(map[string]error) + // If NeedImports isn't set, the imports fields will all be zeroed out. + if ld.Mode&NeedImports != 0 { + lpkg.Imports = make(map[string]*Package, len(stubs)) + for importPath, ipkg := range stubs { + var importErr error + imp := ld.pkgs[ipkg.ID] + if imp == nil { + // (includes package "C" when DisableCgo) + importErr = fmt.Errorf("missing package: %q", ipkg.ID) + } else if imp.color == grey { + importErr = fmt.Errorf("import cycle: %s", stack) + } + if importErr != nil { + if lpkg.importErrors == nil { + lpkg.importErrors = make(map[string]error) + } + lpkg.importErrors[importPath] = importErr + continue } - lpkg.importErrors[importPath] = importErr - continue - } - if visit(imp) { - lpkg.needsrc = true + if visit(imp) { + lpkg.needsrc = true + } + lpkg.Imports[importPath] = imp.Package } - lpkg.Imports[importPath] = imp.Package } if lpkg.needsrc { srcPkgs = append(srcPkgs, lpkg) @@ -562,7 +588,7 @@ func (ld *loader) refine(roots []string, list ...*Package) ([]*Package, error) { return lpkg.needsrc } - if ld.Mode&(NeedImports|NeedDeps) == 0 { + if ld.Mode&NeedImports == 0 { // We do this to drop the stub import packages that we are not even going to try to resolve. for _, lpkg := range initial { lpkg.Imports = nil @@ -573,7 +599,7 @@ func (ld *loader) refine(roots []string, list ...*Package) ([]*Package, error) { visit(lpkg) } } - if ld.Mode&NeedDeps != 0 { // TODO(matloob): This is only the case if NeedTypes is also set, right? + if ld.Mode&NeedImports != 0 && ld.Mode&NeedTypes != 0 { for _, lpkg := range srcPkgs { // Complete type information is required for the // immediate dependencies of each source package. @@ -598,54 +624,44 @@ func (ld *loader) refine(roots []string, list ...*Package) ([]*Package, error) { } result := make([]*Package, len(initial)) - importPlaceholders := make(map[string]*Package) for i, lpkg := range initial { result[i] = lpkg.Package } for i := range ld.pkgs { // Clear all unrequested fields, for extra de-Hyrum-ization. - if ld.Mode&NeedName == 0 { + if ld.requestedMode&NeedName == 0 { ld.pkgs[i].Name = "" ld.pkgs[i].PkgPath = "" } - if ld.Mode&NeedFiles == 0 { + if ld.requestedMode&NeedFiles == 0 { ld.pkgs[i].GoFiles = nil ld.pkgs[i].OtherFiles = nil } - if ld.Mode&NeedCompiledGoFiles == 0 { + if ld.requestedMode&NeedCompiledGoFiles == 0 { ld.pkgs[i].CompiledGoFiles = nil } - if ld.Mode&NeedImports == 0 { + if ld.requestedMode&NeedImports == 0 { ld.pkgs[i].Imports = nil } - if ld.Mode&NeedExportsFile == 0 { + if ld.requestedMode&NeedExportsFile == 0 { ld.pkgs[i].ExportFile = "" } - if ld.Mode&NeedTypes == 0 { + if ld.requestedMode&NeedTypes == 0 { ld.pkgs[i].Types = nil ld.pkgs[i].Fset = nil ld.pkgs[i].IllTyped = false } - if ld.Mode&NeedSyntax == 0 { + if ld.requestedMode&NeedSyntax == 0 { ld.pkgs[i].Syntax = nil } - if ld.Mode&NeedTypesInfo == 0 { + if ld.requestedMode&NeedTypesInfo == 0 { ld.pkgs[i].TypesInfo = nil } - if ld.Mode&NeedTypesSizes == 0 { + if ld.requestedMode&NeedTypesSizes == 0 { ld.pkgs[i].TypesSizes = nil } - if ld.Mode&NeedDeps == 0 { - for j, pkg := range ld.pkgs[i].Imports { - ph, ok := importPlaceholders[pkg.ID] - if !ok { - ph = &Package{ID: pkg.ID} - importPlaceholders[pkg.ID] = ph - } - ld.pkgs[i].Imports[j] = ph - } - } } + return result, nil } @@ -666,7 +682,6 @@ func (ld *loader) loadRecursive(lpkg *loaderPackage) { }(imp) } wg.Wait() - ld.loadPackage(lpkg) }) } @@ -755,6 +770,14 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) { lpkg.Errors = append(lpkg.Errors, errs...) } + if len(lpkg.CompiledGoFiles) == 0 && lpkg.ExportFile != "" { + // The config requested loading sources and types, but sources are missing. + // Add an error to the package and fall back to loading from export data. + appendError(Error{"-", fmt.Sprintf("sources missing for package %s", lpkg.ID), ParseError}) + ld.loadFromExportData(lpkg) + return // can't get syntax trees for this package + } + files, errs := ld.parseFiles(lpkg.CompiledGoFiles) for _, err := range errs { appendError(err) @@ -793,7 +816,7 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) { if ipkg.Types != nil && ipkg.Types.Complete() { return ipkg.Types, nil } - log.Fatalf("internal error: nil Pkg importing %q from %q", path, lpkg) + log.Fatalf("internal error: package %q without types was imported from %q", path, lpkg) panic("unreachable") }) @@ -804,7 +827,7 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) { // Type-check bodies of functions only in non-initial packages. // Example: for import graph A->B->C and initial packages {A,C}, // we can ignore function bodies in B. - IgnoreFuncBodies: (ld.Mode&(NeedDeps|NeedTypesInfo) == 0) && !lpkg.initial, + IgnoreFuncBodies: ld.Mode&NeedDeps == 0 && !lpkg.initial, Error: appendError, Sizes: ld.sizes, @@ -1066,6 +1089,25 @@ func (ld *loader) loadFromExportData(lpkg *loaderPackage) (*types.Package, error return tpkg, nil } +// impliedLoadMode returns loadMode with its dependencies. +func impliedLoadMode(loadMode LoadMode) LoadMode { + if loadMode&NeedTypesInfo != 0 && loadMode&NeedImports == 0 { + // If NeedTypesInfo, go/packages needs to do typechecking itself so it can + // associate type info with the AST. To do so, we need the export data + // for dependencies, which means we need to ask for the direct dependencies. + // NeedImports is used to ask for the direct dependencies. + loadMode |= NeedImports + } + + if loadMode&NeedDeps != 0 && loadMode&NeedImports == 0 { + // With NeedDeps we need to load at least direct dependencies. + // NeedImports is used to ask for the direct dependencies. + loadMode |= NeedImports + } + + return loadMode +} + func usesExportData(cfg *Config) bool { - return cfg.Mode&NeedExportsFile != 0 || cfg.Mode&NeedTypes != 0 && cfg.Mode&NeedTypesInfo == 0 + return cfg.Mode&NeedExportsFile != 0 || cfg.Mode&NeedTypes != 0 && cfg.Mode&NeedDeps == 0 } diff --git a/vendor/golang.org/x/tools/go/packages/visit.go b/tools/vendor/golang.org/x/tools/go/packages/visit.go similarity index 100% rename from vendor/golang.org/x/tools/go/packages/visit.go rename to tools/vendor/golang.org/x/tools/go/packages/visit.go diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go b/tools/vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go similarity index 100% rename from vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go rename to tools/vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_fileno.go b/tools/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_fileno.go similarity index 100% rename from vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_fileno.go rename to tools/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_fileno.go diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_ino.go b/tools/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_ino.go similarity index 100% rename from vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_ino.go rename to tools/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_ino.go diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_bsd.go b/tools/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_bsd.go similarity index 100% rename from vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_bsd.go rename to tools/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_bsd.go diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_linux.go b/tools/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_linux.go similarity index 100% rename from vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_linux.go rename to tools/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_linux.go diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_portable.go b/tools/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_portable.go similarity index 100% rename from vendor/golang.org/x/tools/internal/fastwalk/fastwalk_portable.go rename to tools/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_portable.go diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_unix.go b/tools/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_unix.go similarity index 100% rename from vendor/golang.org/x/tools/internal/fastwalk/fastwalk_unix.go rename to tools/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_unix.go diff --git a/vendor/golang.org/x/tools/internal/gopathwalk/walk.go b/tools/vendor/golang.org/x/tools/internal/gopathwalk/walk.go similarity index 79% rename from vendor/golang.org/x/tools/internal/gopathwalk/walk.go rename to tools/vendor/golang.org/x/tools/internal/gopathwalk/walk.go index 04bb96a3..60eb67b6 100644 --- a/vendor/golang.org/x/tools/internal/gopathwalk/walk.go +++ b/tools/vendor/golang.org/x/tools/internal/gopathwalk/walk.go @@ -59,15 +59,27 @@ func SrcDirsRoots(ctx *build.Context) []Root { // paths of the containing source directory and the package directory. // add will be called concurrently. func Walk(roots []Root, add func(root Root, dir string), opts Options) { + WalkSkip(roots, add, func(Root, string) bool { return false }, opts) +} + +// WalkSkip walks Go source directories ($GOROOT, $GOPATH, etc) to find packages. +// For each package found, add will be called (concurrently) with the absolute +// paths of the containing source directory and the package directory. +// For each directory that will be scanned, skip will be called (concurrently) +// with the absolute paths of the containing source directory and the directory. +// If skip returns false on a directory it will be processed. +// add will be called concurrently. +// skip will be called concurrently. +func WalkSkip(roots []Root, add func(root Root, dir string), skip func(root Root, dir string) bool, opts Options) { for _, root := range roots { - walkDir(root, add, opts) + walkDir(root, add, skip, opts) } } -func walkDir(root Root, add func(Root, string), opts Options) { +func walkDir(root Root, add func(Root, string), skip func(root Root, dir string) bool, opts Options) { if _, err := os.Stat(root.Path); os.IsNotExist(err) { if opts.Debug { - log.Printf("skipping nonexistant directory: %v", root.Path) + log.Printf("skipping nonexistent directory: %v", root.Path) } return } @@ -77,6 +89,7 @@ func walkDir(root Root, add func(Root, string), opts Options) { w := &walker{ root: root, add: add, + skip: skip, opts: opts, } w.init() @@ -91,9 +104,10 @@ func walkDir(root Root, add func(Root, string), opts Options) { // walker is the callback for fastwalk.Walk. type walker struct { - root Root // The source directory to scan. - add func(Root, string) // The callback that will be invoked for every possible Go package dir. - opts Options // Options passed to Walk by the user. + root Root // The source directory to scan. + add func(Root, string) // The callback that will be invoked for every possible Go package dir. + skip func(Root, string) bool // The callback that will be invoked for every dir. dir is skipped if it returns true. + opts Options // Options passed to Walk by the user. ignoredDirs []os.FileInfo // The ignored directories, loaded from .goimportsignore files. } @@ -151,12 +165,16 @@ func (w *walker) getIgnoredDirs(path string) []string { return ignoredDirs } -func (w *walker) shouldSkipDir(fi os.FileInfo) bool { +func (w *walker) shouldSkipDir(fi os.FileInfo, dir string) bool { for _, ignoredDir := range w.ignoredDirs { if os.SameFile(fi, ignoredDir) { return true } } + if w.skip != nil { + // Check with the user specified callback. + return w.skip(w.root, dir) + } return false } @@ -184,7 +202,7 @@ func (w *walker) walk(path string, typ os.FileMode) error { return filepath.SkipDir } fi, err := os.Lstat(path) - if err == nil && w.shouldSkipDir(fi) { + if err == nil && w.shouldSkipDir(fi, path) { return filepath.SkipDir } return nil @@ -224,7 +242,7 @@ func (w *walker) shouldTraverse(dir string, fi os.FileInfo) bool { if !ts.IsDir() { return false } - if w.shouldSkipDir(ts) { + if w.shouldSkipDir(ts, dir) { return false } // Check for symlink loops by statting each directory component diff --git a/vendor/golang.org/x/tools/internal/imports/fix.go b/tools/vendor/golang.org/x/tools/internal/imports/fix.go similarity index 77% rename from vendor/golang.org/x/tools/internal/imports/fix.go rename to tools/vendor/golang.org/x/tools/internal/imports/fix.go index d9ba3b78..bcfbb07e 100644 --- a/vendor/golang.org/x/tools/internal/imports/fix.go +++ b/tools/vendor/golang.org/x/tools/internal/imports/fix.go @@ -13,7 +13,6 @@ import ( "go/parser" "go/token" "io/ioutil" - "log" "os" "os/exec" "path" @@ -68,10 +67,27 @@ func importGroup(env *ProcessEnv, importPath string) int { return 0 } -// An importInfo represents a single import statement. -type importInfo struct { - importPath string // import path, e.g. "crypto/rand". - name string // import name, e.g. "crand", or "" if none. +type ImportFixType int + +const ( + AddImport ImportFixType = iota + DeleteImport + SetImportName +) + +type ImportFix struct { + // StmtInfo represents the import statement this fix will add, remove, or change. + StmtInfo ImportInfo + // IdentName is the identifier that this fix will add or remove. + IdentName string + // FixType is the type of fix this is (AddImport, DeleteImport, SetImportName). + FixType ImportFixType +} + +// An ImportInfo represents a single import statement. +type ImportInfo struct { + ImportPath string // import path, e.g. "crypto/rand". + Name string // import name, e.g. "crand", or "" if none. } // A packageInfo represents what's known about a package. @@ -169,10 +185,10 @@ func collectReferences(f *ast.File) references { return refs } -// collectImports returns all the imports in f, keyed by their package name as -// determined by pathToName. Unnamed imports (., _) and "C" are ignored. -func collectImports(f *ast.File) []*importInfo { - var imports []*importInfo +// collectImports returns all the imports in f. +// Unnamed imports (., _) and "C" are ignored. +func collectImports(f *ast.File) []*ImportInfo { + var imports []*ImportInfo for _, imp := range f.Imports { var name string if imp.Name != nil { @@ -182,9 +198,9 @@ func collectImports(f *ast.File) []*importInfo { continue } path := strings.Trim(imp.Path.Value, `"`) - imports = append(imports, &importInfo{ - name: name, - importPath: path, + imports = append(imports, &ImportInfo{ + Name: name, + ImportPath: path, }) } return imports @@ -192,9 +208,9 @@ func collectImports(f *ast.File) []*importInfo { // findMissingImport searches pass's candidates for an import that provides // pkg, containing all of syms. -func (p *pass) findMissingImport(pkg string, syms map[string]bool) *importInfo { +func (p *pass) findMissingImport(pkg string, syms map[string]bool) *ImportInfo { for _, candidate := range p.candidates { - pkgInfo, ok := p.knownPackages[candidate.importPath] + pkgInfo, ok := p.knownPackages[candidate.ImportPath] if !ok { continue } @@ -234,27 +250,33 @@ type pass struct { otherFiles []*ast.File // sibling files. // Intermediate state, generated by load. - existingImports map[string]*importInfo + existingImports map[string]*ImportInfo allRefs references missingRefs references // Inputs to fix. These can be augmented between successive fix calls. lastTry bool // indicates that this is the last call and fix should clean up as best it can. - candidates []*importInfo // candidate imports in priority order. + candidates []*ImportInfo // candidate imports in priority order. knownPackages map[string]*packageInfo // information about all known packages. } // loadPackageNames saves the package names for everything referenced by imports. -func (p *pass) loadPackageNames(imports []*importInfo) error { +func (p *pass) loadPackageNames(imports []*ImportInfo) error { + if p.env.Debug { + p.env.Logf("loading package names for %v packages", len(imports)) + defer func() { + p.env.Logf("done loading package names for %v packages", len(imports)) + }() + } var unknown []string for _, imp := range imports { - if _, ok := p.knownPackages[imp.importPath]; ok { + if _, ok := p.knownPackages[imp.ImportPath]; ok { continue } - unknown = append(unknown, imp.importPath) + unknown = append(unknown, imp.ImportPath) } - names, err := p.env.getResolver().loadPackageNames(unknown, p.srcDir) + names, err := p.env.GetResolver().loadPackageNames(unknown, p.srcDir) if err != nil { return err } @@ -271,24 +293,24 @@ func (p *pass) loadPackageNames(imports []*importInfo) error { // importIdentifier returns the identifier that imp will introduce. It will // guess if the package name has not been loaded, e.g. because the source // is not available. -func (p *pass) importIdentifier(imp *importInfo) string { - if imp.name != "" { - return imp.name +func (p *pass) importIdentifier(imp *ImportInfo) string { + if imp.Name != "" { + return imp.Name } - known := p.knownPackages[imp.importPath] + known := p.knownPackages[imp.ImportPath] if known != nil && known.name != "" { return known.name } - return importPathToAssumedName(imp.importPath) + return importPathToAssumedName(imp.ImportPath) } // load reads in everything necessary to run a pass, and reports whether the // file already has all the imports it needs. It fills in p.missingRefs with the // file's missing symbols, if any, or removes unused imports if not. -func (p *pass) load() bool { +func (p *pass) load() ([]*ImportFix, bool) { p.knownPackages = map[string]*packageInfo{} p.missingRefs = references{} - p.existingImports = map[string]*importInfo{} + p.existingImports = map[string]*ImportInfo{} // Load basic information about the file in question. p.allRefs = collectReferences(p.f) @@ -313,9 +335,9 @@ func (p *pass) load() bool { err := p.loadPackageNames(append(imports, p.candidates...)) if err != nil { if p.env.Debug { - log.Printf("loading package names: %v", err) + p.env.Logf("loading package names: %v", err) } - return false + return nil, false } } for _, imp := range imports { @@ -334,18 +356,18 @@ func (p *pass) load() bool { } } if len(p.missingRefs) != 0 { - return false + return nil, false } return p.fix() } // fix attempts to satisfy missing imports using p.candidates. If it finds -// everything, or if p.lastTry is true, it adds the imports it found, -// removes anything unused, and returns true. -func (p *pass) fix() bool { +// everything, or if p.lastTry is true, it updates fixes to add the imports it found, +// delete anything unused, and update import names, and returns true. +func (p *pass) fix() ([]*ImportFix, bool) { // Find missing imports. - var selected []*importInfo + var selected []*ImportInfo for left, rights := range p.missingRefs { if imp := p.findMissingImport(left, rights); imp != nil { selected = append(selected, imp) @@ -353,10 +375,11 @@ func (p *pass) fix() bool { } if !p.lastTry && len(selected) != len(p.missingRefs) { - return false + return nil, false } // Found everything, or giving up. Add the new imports and remove any unused. + var fixes []*ImportFix for _, imp := range p.existingImports { // We deliberately ignore globals here, because we can't be sure // they're in the same package. People do things like put multiple @@ -364,28 +387,80 @@ func (p *pass) fix() bool { // remove imports if they happen to have the same name as a var in // a different package. if _, ok := p.allRefs[p.importIdentifier(imp)]; !ok { - astutil.DeleteNamedImport(p.fset, p.f, imp.name, imp.importPath) + fixes = append(fixes, &ImportFix{ + StmtInfo: *imp, + IdentName: p.importIdentifier(imp), + FixType: DeleteImport, + }) + continue + } + + // An existing import may need to update its import name to be correct. + if name := p.importSpecName(imp); name != imp.Name { + fixes = append(fixes, &ImportFix{ + StmtInfo: ImportInfo{ + Name: name, + ImportPath: imp.ImportPath, + }, + IdentName: p.importIdentifier(imp), + FixType: SetImportName, + }) } } for _, imp := range selected { - astutil.AddNamedImport(p.fset, p.f, imp.name, imp.importPath) + fixes = append(fixes, &ImportFix{ + StmtInfo: ImportInfo{ + Name: p.importSpecName(imp), + ImportPath: imp.ImportPath, + }, + IdentName: p.importIdentifier(imp), + FixType: AddImport, + }) } - if p.loadRealPackageNames { - for _, imp := range p.f.Imports { - if imp.Name != nil { - continue - } - path := strings.Trim(imp.Path.Value, `""`) - ident := p.importIdentifier(&importInfo{importPath: path}) - if ident != importPathToAssumedName(path) { - imp.Name = &ast.Ident{Name: ident, NamePos: imp.Pos()} + return fixes, true +} + +// importSpecName gets the import name of imp in the import spec. +// +// When the import identifier matches the assumed import name, the import name does +// not appear in the import spec. +func (p *pass) importSpecName(imp *ImportInfo) string { + // If we did not load the real package names, or the name is already set, + // we just return the existing name. + if !p.loadRealPackageNames || imp.Name != "" { + return imp.Name + } + + ident := p.importIdentifier(imp) + if ident == importPathToAssumedName(imp.ImportPath) { + return "" // ident not needed since the assumed and real names are the same. + } + return ident +} + +// apply will perform the fixes on f in order. +func apply(fset *token.FileSet, f *ast.File, fixes []*ImportFix) { + for _, fix := range fixes { + switch fix.FixType { + case DeleteImport: + astutil.DeleteNamedImport(fset, f, fix.StmtInfo.Name, fix.StmtInfo.ImportPath) + case AddImport: + astutil.AddNamedImport(fset, f, fix.StmtInfo.Name, fix.StmtInfo.ImportPath) + case SetImportName: + // Find the matching import path and change the name. + for _, spec := range f.Imports { + path := strings.Trim(spec.Path.Value, `"`) + if path == fix.StmtInfo.ImportPath { + spec.Name = &ast.Ident{ + Name: fix.StmtInfo.Name, + NamePos: spec.Pos(), + } + } } } } - - return true } // assumeSiblingImportsValid assumes that siblings' use of packages is valid, @@ -394,15 +469,15 @@ func (p *pass) assumeSiblingImportsValid() { for _, f := range p.otherFiles { refs := collectReferences(f) imports := collectImports(f) - importsByName := map[string]*importInfo{} + importsByName := map[string]*ImportInfo{} for _, imp := range imports { importsByName[p.importIdentifier(imp)] = imp } for left, rights := range refs { if imp, ok := importsByName[left]; ok { - if _, ok := stdlib[imp.importPath]; ok { + if _, ok := stdlib[imp.ImportPath]; ok { // We have the stdlib in memory; no need to guess. - rights = stdlib[imp.importPath] + rights = stdlib[imp.ImportPath] } p.addCandidate(imp, &packageInfo{ // no name; we already know it. @@ -415,9 +490,9 @@ func (p *pass) assumeSiblingImportsValid() { // addCandidate adds a candidate import to p, and merges in the information // in pkg. -func (p *pass) addCandidate(imp *importInfo, pkg *packageInfo) { +func (p *pass) addCandidate(imp *ImportInfo, pkg *packageInfo) { p.candidates = append(p.candidates, imp) - if existing, ok := p.knownPackages[imp.importPath]; ok { + if existing, ok := p.knownPackages[imp.ImportPath]; ok { if existing.name == "" { existing.name = pkg.name } @@ -425,7 +500,7 @@ func (p *pass) addCandidate(imp *importInfo, pkg *packageInfo) { existing.exports[export] = true } } else { - p.knownPackages[imp.importPath] = pkg + p.knownPackages[imp.ImportPath] = pkg } } @@ -437,13 +512,24 @@ func (p *pass) addCandidate(imp *importInfo, pkg *packageInfo) { var fixImports = fixImportsDefault func fixImportsDefault(fset *token.FileSet, f *ast.File, filename string, env *ProcessEnv) error { - abs, err := filepath.Abs(filename) + fixes, err := getFixes(fset, f, filename, env) if err != nil { return err } + apply(fset, f, fixes) + return err +} + +// getFixes gets the import fixes that need to be made to f in order to fix the imports. +// It does not modify the ast. +func getFixes(fset *token.FileSet, f *ast.File, filename string, env *ProcessEnv) ([]*ImportFix, error) { + abs, err := filepath.Abs(filename) + if err != nil { + return nil, err + } srcDir := filepath.Dir(abs) if env.Debug { - log.Printf("fixImports(filename=%q), abs=%q, srcDir=%q ...", filename, abs, srcDir) + env.Logf("fixImports(filename=%q), abs=%q, srcDir=%q ...", filename, abs, srcDir) } // First pass: looking only at f, and using the naive algorithm to @@ -451,8 +537,8 @@ func fixImportsDefault(fset *token.FileSet, f *ast.File, filename string, env *P // complete. We can't add any imports yet, because we don't know // if missing references are actually package vars. p := &pass{fset: fset, f: f, srcDir: srcDir} - if p.load() { - return nil + if fixes, done := p.load(); done { + return fixes, nil } otherFiles := parseOtherFiles(fset, srcDir, filename) @@ -460,15 +546,15 @@ func fixImportsDefault(fset *token.FileSet, f *ast.File, filename string, env *P // Second pass: add information from other files in the same package, // like their package vars and imports. p.otherFiles = otherFiles - if p.load() { - return nil + if fixes, done := p.load(); done { + return fixes, nil } // Now we can try adding imports from the stdlib. p.assumeSiblingImportsValid() addStdlibCandidates(p, p.missingRefs) - if p.fix() { - return nil + if fixes, done := p.fix(); done { + return fixes, nil } // Third pass: get real package names where we had previously used @@ -477,25 +563,50 @@ func fixImportsDefault(fset *token.FileSet, f *ast.File, filename string, env *P p = &pass{fset: fset, f: f, srcDir: srcDir, env: env} p.loadRealPackageNames = true p.otherFiles = otherFiles - if p.load() { - return nil + if fixes, done := p.load(); done { + return fixes, nil } addStdlibCandidates(p, p.missingRefs) p.assumeSiblingImportsValid() - if p.fix() { - return nil + if fixes, done := p.fix(); done { + return fixes, nil } // Go look for candidates in $GOPATH, etc. We don't necessarily load // the real exports of sibling imports, so keep assuming their contents. if err := addExternalCandidates(p, p.missingRefs, filename); err != nil { - return err + return nil, err } p.lastTry = true - p.fix() - return nil + fixes, _ := p.fix() + return fixes, nil +} + +// getAllCandidates gets all of the candidates to be imported, regardless of if they are needed. +func getAllCandidates(filename string, env *ProcessEnv) ([]ImportFix, error) { + // TODO(suzmue): scan for additional candidates and filter out + // current package. + + // Get the stdlib candidates and sort by import path. + var paths []string + for importPath := range stdlib { + paths = append(paths, importPath) + } + sort.Strings(paths) + + var imports []ImportFix + for _, importPath := range paths { + imports = append(imports, ImportFix{ + StmtInfo: ImportInfo{ + ImportPath: importPath, + }, + IdentName: path.Base(importPath), + FixType: AddImport, + }) + } + return imports, nil } // ProcessEnv contains environment variables and settings that affect the use of @@ -512,7 +623,10 @@ type ProcessEnv struct { // If true, use go/packages regardless of the environment. ForceGoPackages bool - resolver resolver + // Logf is the default logger for the ProcessEnv. + Logf func(format string, args ...interface{}) + + resolver Resolver } func (e *ProcessEnv) env() []string { @@ -534,7 +648,7 @@ func (e *ProcessEnv) env() []string { return env } -func (e *ProcessEnv) getResolver() resolver { +func (e *ProcessEnv) GetResolver() Resolver { if e.resolver != nil { return e.resolver } @@ -548,7 +662,7 @@ func (e *ProcessEnv) getResolver() resolver { e.resolver = &gopathResolver{env: e} return e.resolver } - e.resolver = &moduleResolver{env: e} + e.resolver = &ModuleResolver{env: e} return e.resolver } @@ -577,7 +691,7 @@ func (e *ProcessEnv) invokeGo(args ...string) (*bytes.Buffer, error) { cmd.Dir = e.WorkingDir if e.Debug { - defer func(start time.Time) { log.Printf("%s for %v", time.Since(start), cmdDebugStr(cmd)) }(time.Now()) + defer func(start time.Time) { e.Logf("%s for %v", time.Since(start), cmdDebugStr(cmd)) }(time.Now()) } if err := cmd.Run(); err != nil { return nil, fmt.Errorf("running go: %v (stderr:\n%s)", err, stderr) @@ -599,7 +713,7 @@ func cmdDebugStr(cmd *exec.Cmd) string { func addStdlibCandidates(pass *pass, refs references) { add := func(pkg string) { pass.addCandidate( - &importInfo{importPath: pkg}, + &ImportInfo{ImportPath: pkg}, &packageInfo{name: path.Base(pkg), exports: stdlib[pkg]}) } for left := range refs { @@ -617,20 +731,27 @@ func addStdlibCandidates(pass *pass, refs references) { } } -// A resolver does the build-system-specific parts of goimports. -type resolver interface { +// A Resolver does the build-system-specific parts of goimports. +type Resolver interface { // loadPackageNames loads the package names in importPaths. loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) // scan finds (at least) the packages satisfying refs. The returned slice is unordered. scan(refs references) ([]*pkg, error) + // loadExports returns the set of exported symbols in the package at dir. + // It returns an error if the package name in dir does not match expectPackage. + // loadExports may be called concurrently. + loadExports(ctx context.Context, expectPackage string, pkg *pkg) (map[string]bool, error) } -// gopathResolver implements resolver for GOPATH and module workspaces using go/packages. +// gopackagesResolver implements resolver for GOPATH and module workspaces using go/packages. type goPackagesResolver struct { env *ProcessEnv } func (r *goPackagesResolver) loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) { + if len(importPaths) == 0 { + return nil, nil + } cfg := r.env.newPackagesConfig(packages.LoadFiles) pkgs, err := packages.Load(cfg, importPaths...) if err != nil { @@ -674,15 +795,35 @@ func (r *goPackagesResolver) scan(refs references) ([]*pkg, error) { return scan, nil } +func (r *goPackagesResolver) loadExports(ctx context.Context, expectPackage string, pkg *pkg) (map[string]bool, error) { + if pkg.goPackage == nil { + return nil, fmt.Errorf("goPackage not set") + } + exports := map[string]bool{} + fset := token.NewFileSet() + for _, fname := range pkg.goPackage.CompiledGoFiles { + f, err := parser.ParseFile(fset, fname, nil, 0) + if err != nil { + return nil, fmt.Errorf("parsing %s: %v", fname, err) + } + for name := range f.Scope.Objects { + if ast.IsExported(name) { + exports[name] = true + } + } + } + return exports, nil +} + func addExternalCandidates(pass *pass, refs references, filename string) error { - dirScan, err := pass.env.getResolver().scan(refs) + dirScan, err := pass.env.GetResolver().scan(refs) if err != nil { return err } // Search for imports matching potential package references. type result struct { - imp *importInfo + imp *ImportInfo pkg *packageInfo } results := make(chan result, len(refs)) @@ -716,8 +857,8 @@ func addExternalCandidates(pass *pass, refs references, filename string) error { return // No matching package. } - imp := &importInfo{ - importPath: found.importPathShort, + imp := &ImportInfo{ + ImportPath: found.importPathShort, } pkg := &packageInfo{ @@ -784,7 +925,7 @@ func (r *gopathResolver) loadPackageNames(importPaths []string, srcDir string) ( return names, nil } -// importPathToNameGoPath finds out the actual package name, as declared in its .go files. +// importPathToName finds out the actual package name, as declared in its .go files. // If there's a problem, it returns "". func importPathToName(env *ProcessEnv, importPath, srcDir string) (packageName string) { // Fast path for standard library without going to disk. @@ -804,8 +945,8 @@ func importPathToName(env *ProcessEnv, importPath, srcDir string) (packageName s } // packageDirToName is a faster version of build.Import if -// the only thing desired is the package name. It uses build.FindOnly -// to find the directory and then only parses one file in the package, +// the only thing desired is the package name. Given a directory, +// packageDirToName then only parses one file in the package, // trusting that the files in the directory are consistent. func packageDirToName(dir string) (packageName string, err error) { d, err := os.Open(dir) @@ -926,6 +1067,10 @@ func (r *gopathResolver) scan(_ references) ([]*pkg, error) { return result, nil } +func (r *gopathResolver) loadExports(ctx context.Context, expectPackage string, pkg *pkg) (map[string]bool, error) { + return loadExportsFromFiles(ctx, r.env, expectPackage, pkg.dir) +} + // VendorlessPath returns the devendorized version of the import path ipath. // For example, VendorlessPath("foo/bar/vendor/a/b") returns "a/b". func VendorlessPath(ipath string) string { @@ -939,33 +1084,11 @@ func VendorlessPath(ipath string) string { return ipath } -// loadExports returns the set of exported symbols in the package at dir. -// It returns nil on error or if the package name in dir does not match expectPackage. -func loadExports(ctx context.Context, env *ProcessEnv, expectPackage string, pkg *pkg) (map[string]bool, error) { - if env.Debug { - log.Printf("loading exports in dir %s (seeking package %s)", pkg.dir, expectPackage) - } - if pkg.goPackage != nil { - exports := map[string]bool{} - fset := token.NewFileSet() - for _, fname := range pkg.goPackage.CompiledGoFiles { - f, err := parser.ParseFile(fset, fname, nil, 0) - if err != nil { - return nil, fmt.Errorf("parsing %s: %v", fname, err) - } - for name := range f.Scope.Objects { - if ast.IsExported(name) { - exports[name] = true - } - } - } - return exports, nil - } - +func loadExportsFromFiles(ctx context.Context, env *ProcessEnv, expectPackage string, dir string) (map[string]bool, error) { exports := make(map[string]bool) // Look for non-test, buildable .go files which could provide exports. - all, err := ioutil.ReadDir(pkg.dir) + all, err := ioutil.ReadDir(dir) if err != nil { return nil, err } @@ -975,7 +1098,7 @@ func loadExports(ctx context.Context, env *ProcessEnv, expectPackage string, pkg if !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") { continue } - match, err := env.buildContext().MatchFile(pkg.dir, fi.Name()) + match, err := env.buildContext().MatchFile(dir, fi.Name()) if err != nil || !match { continue } @@ -983,7 +1106,7 @@ func loadExports(ctx context.Context, env *ProcessEnv, expectPackage string, pkg } if len(files) == 0 { - return nil, fmt.Errorf("dir %v contains no buildable, non-test .go files", pkg.dir) + return nil, fmt.Errorf("dir %v contains no buildable, non-test .go files", dir) } fset := token.NewFileSet() @@ -994,7 +1117,7 @@ func loadExports(ctx context.Context, env *ProcessEnv, expectPackage string, pkg default: } - fullFile := filepath.Join(pkg.dir, fi.Name()) + fullFile := filepath.Join(dir, fi.Name()) f, err := parser.ParseFile(fset, fullFile, nil, 0) if err != nil { return nil, fmt.Errorf("parsing %s: %v", fullFile, err) @@ -1006,7 +1129,7 @@ func loadExports(ctx context.Context, env *ProcessEnv, expectPackage string, pkg continue } if pkgName != expectPackage { - return nil, fmt.Errorf("scan of dir %v is not expected package %v (actually %v)", pkg.dir, expectPackage, pkgName) + return nil, fmt.Errorf("scan of dir %v is not expected package %v (actually %v)", dir, expectPackage, pkgName) } for name := range f.Scope.Objects { if ast.IsExported(name) { @@ -1021,7 +1144,7 @@ func loadExports(ctx context.Context, env *ProcessEnv, expectPackage string, pkg exportList = append(exportList, k) } sort.Strings(exportList) - log.Printf("loaded exports in dir %v (package %v): %v", pkg.dir, expectPackage, strings.Join(exportList, ", ")) + env.Logf("loaded exports in dir %v (package %v): %v", dir, expectPackage, strings.Join(exportList, ", ")) } return exports, nil } @@ -1058,7 +1181,7 @@ func findImport(ctx context.Context, pass *pass, dirScan []*pkg, pkgName string, sort.Sort(byDistanceOrImportPathShortLength(candidates)) if pass.env.Debug { for i, c := range candidates { - log.Printf("%s candidate %d/%d: %v in %v", pkgName, i+1, len(candidates), c.pkg.importPathShort, c.pkg.dir) + pass.env.Logf("%s candidate %d/%d: %v in %v", pkgName, i+1, len(candidates), c.pkg.importPathShort, c.pkg.dir) } } @@ -1095,10 +1218,13 @@ func findImport(ctx context.Context, pass *pass, dirScan []*pkg, pkgName string, wg.Done() }() - exports, err := loadExports(ctx, pass.env, pkgName, c.pkg) + if pass.env.Debug { + pass.env.Logf("loading exports in dir %s (seeking package %s)", c.pkg.dir, pkgName) + } + exports, err := pass.env.GetResolver().loadExports(ctx, pkgName, c.pkg) if err != nil { if pass.env.Debug { - log.Printf("loading exports in dir %s (seeking package %s): %v", c.pkg.dir, pkgName, err) + pass.env.Logf("loading exports in dir %s (seeking package %s): %v", c.pkg.dir, pkgName, err) } resc <- nil return diff --git a/vendor/golang.org/x/tools/internal/imports/imports.go b/tools/vendor/golang.org/x/tools/internal/imports/imports.go similarity index 75% rename from vendor/golang.org/x/tools/internal/imports/imports.go rename to tools/vendor/golang.org/x/tools/internal/imports/imports.go index 62533376..2c074cb2 100644 --- a/vendor/golang.org/x/tools/internal/imports/imports.go +++ b/tools/vendor/golang.org/x/tools/internal/imports/imports.go @@ -13,12 +13,14 @@ import ( "bytes" "fmt" "go/ast" + "go/build" "go/format" "go/parser" "go/printer" "go/token" "io" "io/ioutil" + "log" "regexp" "strconv" "strings" @@ -41,13 +43,10 @@ type Options struct { } // Process implements golang.org/x/tools/imports.Process with explicit context in env. -func Process(filename string, src []byte, opt *Options) ([]byte, error) { - if src == nil { - b, err := ioutil.ReadFile(filename) - if err != nil { - return nil, err - } - src = b +func Process(filename string, src []byte, opt *Options) (formatted []byte, err error) { + src, opt, err = initialize(filename, src, opt) + if err != nil { + return nil, err } fileSet := token.NewFileSet() @@ -61,7 +60,93 @@ func Process(filename string, src []byte, opt *Options) ([]byte, error) { return nil, err } } + return formatFile(fileSet, file, src, adjust, opt) +} + +// FixImports returns a list of fixes to the imports that, when applied, +// will leave the imports in the same state as Process. +// +// Note that filename's directory influences which imports can be chosen, +// so it is important that filename be accurate. +func FixImports(filename string, src []byte, opt *Options) (fixes []*ImportFix, err error) { + src, opt, err = initialize(filename, src, opt) + if err != nil { + return nil, err + } + + fileSet := token.NewFileSet() + file, _, err := parse(fileSet, filename, src, opt) + if err != nil { + return nil, err + } + + return getFixes(fileSet, file, filename, opt.Env) +} + +// ApplyFix will apply all of the fixes to the file and format it. +func ApplyFixes(fixes []*ImportFix, filename string, src []byte, opt *Options) (formatted []byte, err error) { + src, opt, err = initialize(filename, src, opt) + if err != nil { + return nil, err + } + + fileSet := token.NewFileSet() + file, adjust, err := parse(fileSet, filename, src, opt) + if err != nil { + return nil, err + } + + // Apply the fixes to the file. + apply(fileSet, file, fixes) + + return formatFile(fileSet, file, src, adjust, opt) +} + +// GetAllCandidates gets all of the standard library candidate packages to import in +// sorted order on import path. +func GetAllCandidates(filename string, opt *Options) (pkgs []ImportFix, err error) { + _, opt, err = initialize(filename, []byte{}, opt) + if err != nil { + return nil, err + } + return getAllCandidates(filename, opt.Env) +} + +// initialize sets the values for opt and src. +// If they are provided, they are not changed. Otherwise opt is set to the +// default values and src is read from the file system. +func initialize(filename string, src []byte, opt *Options) ([]byte, *Options, error) { + // Use defaults if opt is nil. + if opt == nil { + opt = &Options{Comments: true, TabIndent: true, TabWidth: 8} + } + + // Set the env if the user has not provided it. + if opt.Env == nil { + opt.Env = &ProcessEnv{ + GOPATH: build.Default.GOPATH, + GOROOT: build.Default.GOROOT, + } + } + + // Set the logger if the user has not provided it. + if opt.Env.Logf == nil { + opt.Env.Logf = log.Printf + } + + if src == nil { + b, err := ioutil.ReadFile(filename) + if err != nil { + return nil, nil, err + } + src = b + } + + return src, opt, nil +} +func formatFile(fileSet *token.FileSet, file *ast.File, src []byte, adjust func(orig []byte, src []byte) []byte, opt *Options) ([]byte, error) { + mergeImports(opt.Env, fileSet, file) sortImports(opt.Env, fileSet, file) imps := astutil.Imports(fileSet, file) var spacesBefore []string // import paths we need spaces before @@ -89,7 +174,7 @@ func Process(filename string, src []byte, opt *Options) ([]byte, error) { printConfig := &printer.Config{Mode: printerMode, Tabwidth: opt.TabWidth} var buf bytes.Buffer - err = printConfig.Fprint(&buf, fileSet, file) + err := printConfig.Fprint(&buf, fileSet, file) if err != nil { return nil, err } diff --git a/vendor/golang.org/x/tools/internal/imports/mkindex.go b/tools/vendor/golang.org/x/tools/internal/imports/mkindex.go similarity index 100% rename from vendor/golang.org/x/tools/internal/imports/mkindex.go rename to tools/vendor/golang.org/x/tools/internal/imports/mkindex.go diff --git a/vendor/golang.org/x/tools/internal/imports/mkstdlib.go b/tools/vendor/golang.org/x/tools/internal/imports/mkstdlib.go similarity index 94% rename from vendor/golang.org/x/tools/internal/imports/mkstdlib.go rename to tools/vendor/golang.org/x/tools/internal/imports/mkstdlib.go index f67b5c1e..fa69eebb 100644 --- a/vendor/golang.org/x/tools/internal/imports/mkstdlib.go +++ b/tools/vendor/golang.org/x/tools/internal/imports/mkstdlib.go @@ -3,7 +3,7 @@ // mkstdlib generates the zstdlib.go file, containing the Go standard // library API symbols. It's baked into the binary to avoid scanning // GOPATH in the common case. -package imports +package main import ( "bufio" @@ -19,7 +19,6 @@ import ( "regexp" "runtime" "sort" - "strings" ) func mustOpen(name string) io.Reader { @@ -60,6 +59,7 @@ func main() { mustOpen(api("go1.10.txt")), mustOpen(api("go1.11.txt")), mustOpen(api("go1.12.txt")), + mustOpen(api("go1.13.txt")), // The API of the syscall/js package needs to be computed explicitly, // because it's not included in the GOROOT/api/go1.*.txt files at this time. @@ -74,10 +74,6 @@ func main() { for sc.Scan() { l := sc.Text() - has := func(v string) bool { return strings.Contains(l, v) } - if has("struct, ") || has("interface, ") || has(", method (") { - continue - } if m := sym.FindStringSubmatch(l); m != nil { path, sym := m[1], m[2] diff --git a/tools/vendor/golang.org/x/tools/internal/imports/mod.go b/tools/vendor/golang.org/x/tools/internal/imports/mod.go new file mode 100644 index 00000000..387799bd --- /dev/null +++ b/tools/vendor/golang.org/x/tools/internal/imports/mod.go @@ -0,0 +1,500 @@ +package imports + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path" + "path/filepath" + "regexp" + "sort" + "strconv" + "strings" + "sync" + "time" + + "golang.org/x/tools/internal/gopathwalk" + "golang.org/x/tools/internal/module" +) + +// ModuleResolver implements resolver for modules using the go command as little +// as feasible. +type ModuleResolver struct { + env *ProcessEnv + moduleCacheDir string + + Initialized bool + Main *ModuleJSON + ModsByModPath []*ModuleJSON // All modules, ordered by # of path components in module Path... + ModsByDir []*ModuleJSON // ...or Dir. + + // moduleCacheInfo stores information about the module cache. + moduleCacheInfo *moduleCacheInfo +} + +type ModuleJSON struct { + Path string // module path + Version string // module version + Versions []string // available module versions (with -versions) + Replace *ModuleJSON // replaced by this module + Time *time.Time // time version was created + Update *ModuleJSON // available update, if any (with -u) + Main bool // is this the main module? + Indirect bool // is this module only an indirect dependency of main module? + Dir string // directory holding files for this module, if any + GoMod string // path to go.mod file for this module, if any + Error *ModuleErrorJSON // error loading module +} + +type ModuleErrorJSON struct { + Err string // the error itself +} + +func (r *ModuleResolver) init() error { + if r.Initialized { + return nil + } + stdout, err := r.env.invokeGo("list", "-m", "-json", "...") + if err != nil { + return err + } + for dec := json.NewDecoder(stdout); dec.More(); { + mod := &ModuleJSON{} + if err := dec.Decode(mod); err != nil { + return err + } + if mod.Dir == "" { + if r.env.Debug { + r.env.Logf("module %v has not been downloaded and will be ignored", mod.Path) + } + // Can't do anything with a module that's not downloaded. + continue + } + r.ModsByModPath = append(r.ModsByModPath, mod) + r.ModsByDir = append(r.ModsByDir, mod) + if mod.Main { + r.Main = mod + } + } + + sort.Slice(r.ModsByModPath, func(i, j int) bool { + count := func(x int) int { + return strings.Count(r.ModsByModPath[x].Path, "/") + } + return count(j) < count(i) // descending order + }) + sort.Slice(r.ModsByDir, func(i, j int) bool { + count := func(x int) int { + return strings.Count(r.ModsByDir[x].Dir, "/") + } + return count(j) < count(i) // descending order + }) + + if r.moduleCacheInfo == nil { + r.moduleCacheInfo = &moduleCacheInfo{ + modCacheDirInfo: make(map[string]*directoryPackageInfo), + } + } + + r.Initialized = true + return nil +} + +// findPackage returns the module and directory that contains the package at +// the given import path, or returns nil, "" if no module is in scope. +func (r *ModuleResolver) findPackage(importPath string) (*ModuleJSON, string) { + // This can't find packages in the stdlib, but that's harmless for all + // the existing code paths. + for _, m := range r.ModsByModPath { + if !strings.HasPrefix(importPath, m.Path) { + continue + } + pathInModule := importPath[len(m.Path):] + pkgDir := filepath.Join(m.Dir, pathInModule) + if r.dirIsNestedModule(pkgDir, m) { + continue + } + + if info, ok := r.moduleCacheInfo.Load(pkgDir); ok { + if packageScanned, err := info.reachedStatus(directoryScanned); packageScanned { + if err != nil { + // There was some error with scanning this directory. + // It does not contain a valid package. + continue + } + return m, pkgDir + } + } + + pkgFiles, err := ioutil.ReadDir(pkgDir) + if err != nil { + continue + } + + // A module only contains a package if it has buildable go + // files in that directory. If not, it could be provided by an + // outer module. See #29736. + for _, fi := range pkgFiles { + if ok, _ := r.env.buildContext().MatchFile(pkgDir, fi.Name()); ok { + return m, pkgDir + } + } + } + return nil, "" +} + +// findModuleByDir returns the module that contains dir, or nil if no such +// module is in scope. +func (r *ModuleResolver) findModuleByDir(dir string) *ModuleJSON { + // This is quite tricky and may not be correct. dir could be: + // - a package in the main module. + // - a replace target underneath the main module's directory. + // - a nested module in the above. + // - a replace target somewhere totally random. + // - a nested module in the above. + // - in the mod cache. + // - in /vendor/ in -mod=vendor mode. + // - nested module? Dunno. + // Rumor has it that replace targets cannot contain other replace targets. + for _, m := range r.ModsByDir { + if !strings.HasPrefix(dir, m.Dir) { + continue + } + + if r.dirIsNestedModule(dir, m) { + continue + } + + return m + } + return nil +} + +// dirIsNestedModule reports if dir is contained in a nested module underneath +// mod, not actually in mod. +func (r *ModuleResolver) dirIsNestedModule(dir string, mod *ModuleJSON) bool { + if !strings.HasPrefix(dir, mod.Dir) { + return false + } + if r.dirInModuleCache(dir) { + // Nested modules in the module cache are pruned, + // so it cannot be a nested module. + return false + } + mf := r.findModFile(dir) + if mf == "" { + return false + } + return filepath.Dir(mf) != mod.Dir +} + +func (r *ModuleResolver) findModFile(dir string) string { + if r.dirInModuleCache(dir) { + matches := modCacheRegexp.FindStringSubmatch(dir) + index := strings.Index(dir, matches[1]+"@"+matches[2]) + return filepath.Join(dir[:index], matches[1]+"@"+matches[2], "go.mod") + } + for { + f := filepath.Join(dir, "go.mod") + info, err := os.Stat(f) + if err == nil && !info.IsDir() { + return f + } + d := filepath.Dir(dir) + if len(d) >= len(dir) { + return "" // reached top of file system, no go.mod + } + dir = d + } +} + +func (r *ModuleResolver) dirInModuleCache(dir string) bool { + if r.moduleCacheDir == "" { + return false + } + return strings.HasPrefix(dir, r.moduleCacheDir) +} + +func (r *ModuleResolver) loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) { + if err := r.init(); err != nil { + return nil, err + } + names := map[string]string{} + for _, path := range importPaths { + _, packageDir := r.findPackage(path) + if packageDir == "" { + continue + } + name, err := packageDirToName(packageDir) + if err != nil { + continue + } + names[path] = name + } + return names, nil +} + +func (r *ModuleResolver) scan(_ references) ([]*pkg, error) { + if err := r.init(); err != nil { + return nil, err + } + + // Walk GOROOT, GOPATH/pkg/mod, and the main module. + roots := []gopathwalk.Root{ + {filepath.Join(r.env.GOROOT, "/src"), gopathwalk.RootGOROOT}, + } + if r.Main != nil { + roots = append(roots, gopathwalk.Root{r.Main.Dir, gopathwalk.RootCurrentModule}) + } + if r.moduleCacheDir == "" { + r.moduleCacheDir = filepath.Join(filepath.SplitList(r.env.GOPATH)[0], "/pkg/mod") + } + roots = append(roots, gopathwalk.Root{r.moduleCacheDir, gopathwalk.RootModuleCache}) + + // Walk replace targets, just in case they're not in any of the above. + for _, mod := range r.ModsByModPath { + if mod.Replace != nil { + roots = append(roots, gopathwalk.Root{mod.Dir, gopathwalk.RootOther}) + } + } + + var result []*pkg + dupCheck := make(map[string]bool) + var mu sync.Mutex + + // Packages in the module cache are immutable. If we have + // already seen this package on a previous scan of the module + // cache, return that result. + skip := func(root gopathwalk.Root, dir string) bool { + mu.Lock() + defer mu.Unlock() + // If we have already processed this directory on this walk, skip it. + if _, dup := dupCheck[dir]; dup { + return true + } + + // If we have saved this directory information, skip it. + info, ok := r.moduleCacheInfo.Load(dir) + if !ok { + return false + } + // This directory can be skipped as long as we have already scanned it. + // Packages with errors will continue to have errors, so there is no need + // to rescan them. + packageScanned, _ := info.reachedStatus(directoryScanned) + return packageScanned + } + + add := func(root gopathwalk.Root, dir string) { + mu.Lock() + defer mu.Unlock() + if _, dup := dupCheck[dir]; dup { + return + } + + info, err := r.scanDirForPackage(root, dir) + if err != nil { + return + } + if root.Type == gopathwalk.RootModuleCache { + // Save this package information in the cache and return. + // Packages from the module cache are added after Walk. + r.moduleCacheInfo.Store(dir, info) + return + } + + // Skip this package if there was an error loading package info. + if info.err != nil { + return + } + + // The rest of this function canonicalizes the packages using the results + // of initializing the resolver from 'go list -m'. + res, err := r.canonicalize(root.Type, info.nonCanonicalImportPath, info.dir, info.needsReplace) + if err != nil { + return + } + + result = append(result, res) + } + + gopathwalk.WalkSkip(roots, add, skip, gopathwalk.Options{Debug: r.env.Debug, ModulesEnabled: true}) + + // Add the packages from the modules in the mod cache that were skipped. + for _, dir := range r.moduleCacheInfo.Keys() { + info, ok := r.moduleCacheInfo.Load(dir) + if !ok { + continue + } + + // Skip this directory if we were not able to get the package information successfully. + if scanned, err := info.reachedStatus(directoryScanned); !scanned || err != nil { + continue + } + + res, err := r.canonicalize(gopathwalk.RootModuleCache, info.nonCanonicalImportPath, info.dir, info.needsReplace) + if err != nil { + continue + } + result = append(result, res) + } + + return result, nil +} + +// canonicalize gets the result of canonicalizing the packages using the results +// of initializing the resolver from 'go list -m'. +func (r *ModuleResolver) canonicalize(rootType gopathwalk.RootType, importPath, dir string, needsReplace bool) (res *pkg, err error) { + // Packages in GOROOT are already canonical, regardless of the std/cmd modules. + if rootType == gopathwalk.RootGOROOT { + return &pkg{ + importPathShort: importPath, + dir: dir, + }, nil + } + + // Check if the directory is underneath a module that's in scope. + if mod := r.findModuleByDir(dir); mod != nil { + // It is. If dir is the target of a replace directive, + // our guessed import path is wrong. Use the real one. + if mod.Dir == dir { + importPath = mod.Path + } else { + dirInMod := dir[len(mod.Dir)+len("/"):] + importPath = path.Join(mod.Path, filepath.ToSlash(dirInMod)) + } + } else if needsReplace { + return nil, fmt.Errorf("needed this package to be in scope: %s", dir) + } + + // We may have discovered a package that has a different version + // in scope already. Canonicalize to that one if possible. + if _, canonicalDir := r.findPackage(importPath); canonicalDir != "" { + dir = canonicalDir + } + return &pkg{ + importPathShort: VendorlessPath(importPath), + dir: dir, + }, nil +} + +func (r *ModuleResolver) loadExports(ctx context.Context, expectPackage string, pkg *pkg) (map[string]bool, error) { + if err := r.init(); err != nil { + return nil, err + } + return loadExportsFromFiles(ctx, r.env, expectPackage, pkg.dir) +} + +func (r *ModuleResolver) scanDirForPackage(root gopathwalk.Root, dir string) (directoryPackageInfo, error) { + subdir := "" + if dir != root.Path { + subdir = dir[len(root.Path)+len("/"):] + } + importPath := filepath.ToSlash(subdir) + if strings.HasPrefix(importPath, "vendor/") { + // Ignore vendor dirs. If -mod=vendor is on, then things + // should mostly just work, but when it's not vendor/ + // is a mess. There's no easy way to tell if it's on. + // We can still find things in the mod cache and + // map them into /vendor when -mod=vendor is on. + return directoryPackageInfo{}, fmt.Errorf("vendor directory") + } + switch root.Type { + case gopathwalk.RootCurrentModule: + importPath = path.Join(r.Main.Path, filepath.ToSlash(subdir)) + case gopathwalk.RootModuleCache: + matches := modCacheRegexp.FindStringSubmatch(subdir) + if len(matches) == 0 { + return directoryPackageInfo{ + status: directoryScanned, + err: fmt.Errorf("invalid module cache path: %v", subdir), + }, nil + } + modPath, err := module.DecodePath(filepath.ToSlash(matches[1])) + if err != nil { + if r.env.Debug { + r.env.Logf("decoding module cache path %q: %v", subdir, err) + } + return directoryPackageInfo{ + status: directoryScanned, + err: fmt.Errorf("decoding module cache path %q: %v", subdir, err), + }, nil + } + importPath = path.Join(modPath, filepath.ToSlash(matches[3])) + case gopathwalk.RootGOROOT: + importPath = subdir + } + + result := directoryPackageInfo{ + status: directoryScanned, + dir: dir, + nonCanonicalImportPath: importPath, + needsReplace: false, + } + if root.Type == gopathwalk.RootGOROOT { + // stdlib packages are always in scope, despite the confusing go.mod + return result, nil + } + // Check that this package is not obviously impossible to import. + modFile := r.findModFile(dir) + + modBytes, err := ioutil.ReadFile(modFile) + if err == nil && !strings.HasPrefix(importPath, modulePath(modBytes)) { + // The module's declared path does not match + // its expected path. It probably needs a + // replace directive we don't have. + result.needsReplace = true + } + + return result, nil +} + +// modCacheRegexp splits a path in a module cache into module, module version, and package. +var modCacheRegexp = regexp.MustCompile(`(.*)@([^/\\]*)(.*)`) + +var ( + slashSlash = []byte("//") + moduleStr = []byte("module") +) + +// modulePath returns the module path from the gomod file text. +// If it cannot find a module path, it returns an empty string. +// It is tolerant of unrelated problems in the go.mod file. +// +// Copied from cmd/go/internal/modfile. +func modulePath(mod []byte) string { + for len(mod) > 0 { + line := mod + mod = nil + if i := bytes.IndexByte(line, '\n'); i >= 0 { + line, mod = line[:i], line[i+1:] + } + if i := bytes.Index(line, slashSlash); i >= 0 { + line = line[:i] + } + line = bytes.TrimSpace(line) + if !bytes.HasPrefix(line, moduleStr) { + continue + } + line = line[len(moduleStr):] + n := len(line) + line = bytes.TrimSpace(line) + if len(line) == n || len(line) == 0 { + continue + } + + if line[0] == '"' || line[0] == '`' { + p, err := strconv.Unquote(string(line)) + if err != nil { + return "" // malformed quoted string or multiline module path + } + return p + } + + return string(line) + } + return "" // missing module path +} diff --git a/tools/vendor/golang.org/x/tools/internal/imports/mod_cache.go b/tools/vendor/golang.org/x/tools/internal/imports/mod_cache.go new file mode 100644 index 00000000..f96b92d0 --- /dev/null +++ b/tools/vendor/golang.org/x/tools/internal/imports/mod_cache.go @@ -0,0 +1,121 @@ +package imports + +import ( + "sync" +) + +// ModuleResolver implements Resolver for modules using the go command as little +// as feasible. +// +// To find packages to import, the resolver needs to know about all of the +// the packages that could be imported. This includes packages that are +// already in modules that are in (1) the current module, (2) replace targets, +// and (3) packages in the module cache. Packages in (1) and (2) may change over +// time, as the client may edit the current module and locally replaced modules. +// The module cache (which includes all of the packages in (3)) can only +// ever be added to. +// +// The resolver can thus save state about packages in the module cache +// and guarantee that this will not change over time. To obtain information +// about new modules added to the module cache, the module cache should be +// rescanned. +// +// It is OK to serve information about modules that have been deleted, +// as they do still exist. +// TODO(suzmue): can we share information with the caller about +// what module needs to be downloaded to import this package? + +type directoryPackageStatus int + +const ( + _ directoryPackageStatus = iota + directoryScanned +) + +type directoryPackageInfo struct { + // status indicates the extent to which this struct has been filled in. + status directoryPackageStatus + // err is non-nil when there was an error trying to reach status. + err error + + // Set when status > directoryScanned. + + // dir is the absolute directory of this package. + dir string + // nonCanonicalImportPath is the expected import path for this package. + // This may not be an import path that can be used to import this package. + nonCanonicalImportPath string + // needsReplace is true if the nonCanonicalImportPath does not match the + // the modules declared path, making it impossible to import without a + // replace directive. + needsReplace bool +} + +// reachedStatus returns true when info has a status at least target and any error associated with +// an attempt to reach target. +func (info *directoryPackageInfo) reachedStatus(target directoryPackageStatus) (bool, error) { + if info.err == nil { + return info.status >= target, nil + } + if info.status == target { + return true, info.err + } + return true, nil +} + +// moduleCacheInfo is a concurrency safe map for storing information about +// the directories in the module cache. +// +// The information in this cache is built incrementally. Entries are initialized in scan. +// No new keys should be added in any other functions, as all directories containing +// packages are identified in scan. +// +// Other functions, including loadExports and findPackage, may update entries in this cache +// as they discover new things about the directory. +// +// We do not need to protect the data in the cache for multiple writes, because it only stores +// module cache directories, which do not change. If two competing stores take place, there will be +// one store that wins. Although this could result in a loss of information it will not be incorrect +// and may just result in recomputing the same result later. +// +// TODO(suzmue): consider other concurrency strategies and data structures (RWLocks, sync.Map, etc) +type moduleCacheInfo struct { + mu sync.Mutex + // modCacheDirInfo stores information about packages in + // module cache directories. Keyed by absolute directory. + modCacheDirInfo map[string]*directoryPackageInfo +} + +// Store stores the package info for dir. +func (d *moduleCacheInfo) Store(dir string, info directoryPackageInfo) { + d.mu.Lock() + defer d.mu.Unlock() + d.modCacheDirInfo[dir] = &directoryPackageInfo{ + status: info.status, + err: info.err, + dir: info.dir, + nonCanonicalImportPath: info.nonCanonicalImportPath, + needsReplace: info.needsReplace, + } +} + +// Load returns a copy of the directoryPackageInfo for absolute directory dir. +func (d *moduleCacheInfo) Load(dir string) (directoryPackageInfo, bool) { + d.mu.Lock() + defer d.mu.Unlock() + info, ok := d.modCacheDirInfo[dir] + if !ok { + return directoryPackageInfo{}, false + } + return *info, true +} + +// Keys returns the keys currently present in d. +func (d *moduleCacheInfo) Keys() (keys []string) { + d.mu.Lock() + defer d.mu.Unlock() + for key := range d.modCacheDirInfo { + keys = append(keys, key) + } + return keys +} diff --git a/vendor/golang.org/x/tools/internal/imports/sortimports.go b/tools/vendor/golang.org/x/tools/internal/imports/sortimports.go similarity index 81% rename from vendor/golang.org/x/tools/internal/imports/sortimports.go rename to tools/vendor/golang.org/x/tools/internal/imports/sortimports.go index 0a156fe2..22627947 100644 --- a/vendor/golang.org/x/tools/internal/imports/sortimports.go +++ b/tools/vendor/golang.org/x/tools/internal/imports/sortimports.go @@ -58,6 +58,53 @@ func sortImports(env *ProcessEnv, fset *token.FileSet, f *ast.File) { } } +// mergeImports merges all the import declarations into the first one. +// Taken from golang.org/x/tools/ast/astutil. +func mergeImports(env *ProcessEnv, fset *token.FileSet, f *ast.File) { + if len(f.Decls) <= 1 { + return + } + + // Merge all the import declarations into the first one. + var first *ast.GenDecl + for i := 0; i < len(f.Decls); i++ { + decl := f.Decls[i] + gen, ok := decl.(*ast.GenDecl) + if !ok || gen.Tok != token.IMPORT || declImports(gen, "C") { + continue + } + if first == nil { + first = gen + continue // Don't touch the first one. + } + // We now know there is more than one package in this import + // declaration. Ensure that it ends up parenthesized. + first.Lparen = first.Pos() + // Move the imports of the other import declaration to the first one. + for _, spec := range gen.Specs { + spec.(*ast.ImportSpec).Path.ValuePos = first.Pos() + first.Specs = append(first.Specs, spec) + } + f.Decls = append(f.Decls[:i], f.Decls[i+1:]...) + i-- + } +} + +// declImports reports whether gen contains an import of path. +// Taken from golang.org/x/tools/ast/astutil. +func declImports(gen *ast.GenDecl, path string) bool { + if gen.Tok != token.IMPORT { + return false + } + for _, spec := range gen.Specs { + impspec := spec.(*ast.ImportSpec) + if importPath(impspec) == path { + return true + } + } + return false +} + func importPath(s ast.Spec) string { t, err := strconv.Unquote(s.(*ast.ImportSpec).Path.Value) if err == nil { diff --git a/vendor/golang.org/x/tools/internal/imports/zstdlib.go b/tools/vendor/golang.org/x/tools/internal/imports/zstdlib.go similarity index 99% rename from vendor/golang.org/x/tools/internal/imports/zstdlib.go rename to tools/vendor/golang.org/x/tools/internal/imports/zstdlib.go index d81b8c53..544339e5 100644 --- a/vendor/golang.org/x/tools/internal/imports/zstdlib.go +++ b/tools/vendor/golang.org/x/tools/internal/imports/zstdlib.go @@ -125,6 +125,7 @@ var stdlib = map[string]map[string]bool{ "ToTitleSpecial": true, "ToUpper": true, "ToUpperSpecial": true, + "ToValidUTF8": true, "Trim": true, "TrimFunc": true, "TrimLeft": true, @@ -304,6 +305,18 @@ var stdlib = map[string]map[string]bool{ "Sign": true, "Verify": true, }, + "crypto/ed25519": map[string]bool{ + "GenerateKey": true, + "NewKeyFromSeed": true, + "PrivateKey": true, + "PrivateKeySize": true, + "PublicKey": true, + "PublicKeySize": true, + "SeedSize": true, + "Sign": true, + "SignatureSize": true, + "Verify": true, + }, "crypto/elliptic": map[string]bool{ "Curve": true, "CurveParams": true, @@ -420,6 +433,7 @@ var stdlib = map[string]map[string]bool{ "ECDSAWithP384AndSHA384": true, "ECDSAWithP521AndSHA512": true, "ECDSAWithSHA1": true, + "Ed25519": true, "Listen": true, "LoadX509KeyPair": true, "NewLRUClientSessionCache": true, @@ -478,35 +492,36 @@ var stdlib = map[string]map[string]bool{ "X509KeyPair": true, }, "crypto/x509": map[string]bool{ - "CANotAuthorizedForExtKeyUsage": true, - "CANotAuthorizedForThisName": true, - "CertPool": true, - "Certificate": true, - "CertificateInvalidError": true, - "CertificateRequest": true, - "ConstraintViolationError": true, - "CreateCertificate": true, - "CreateCertificateRequest": true, - "DSA": true, - "DSAWithSHA1": true, - "DSAWithSHA256": true, - "DecryptPEMBlock": true, - "ECDSA": true, - "ECDSAWithSHA1": true, - "ECDSAWithSHA256": true, - "ECDSAWithSHA384": true, - "ECDSAWithSHA512": true, - "EncryptPEMBlock": true, - "ErrUnsupportedAlgorithm": true, - "Expired": true, - "ExtKeyUsage": true, - "ExtKeyUsageAny": true, - "ExtKeyUsageClientAuth": true, - "ExtKeyUsageCodeSigning": true, - "ExtKeyUsageEmailProtection": true, - "ExtKeyUsageIPSECEndSystem": true, - "ExtKeyUsageIPSECTunnel": true, - "ExtKeyUsageIPSECUser": true, + "CANotAuthorizedForExtKeyUsage": true, + "CANotAuthorizedForThisName": true, + "CertPool": true, + "Certificate": true, + "CertificateInvalidError": true, + "CertificateRequest": true, + "ConstraintViolationError": true, + "CreateCertificate": true, + "CreateCertificateRequest": true, + "DSA": true, + "DSAWithSHA1": true, + "DSAWithSHA256": true, + "DecryptPEMBlock": true, + "ECDSA": true, + "ECDSAWithSHA1": true, + "ECDSAWithSHA256": true, + "ECDSAWithSHA384": true, + "ECDSAWithSHA512": true, + "Ed25519": true, + "EncryptPEMBlock": true, + "ErrUnsupportedAlgorithm": true, + "Expired": true, + "ExtKeyUsage": true, + "ExtKeyUsageAny": true, + "ExtKeyUsageClientAuth": true, + "ExtKeyUsageCodeSigning": true, + "ExtKeyUsageEmailProtection": true, + "ExtKeyUsageIPSECEndSystem": true, + "ExtKeyUsageIPSECTunnel": true, + "ExtKeyUsageIPSECUser": true, "ExtKeyUsageMicrosoftCommercialCodeSigning": true, "ExtKeyUsageMicrosoftKernelCodeSigning": true, "ExtKeyUsageMicrosoftServerGatedCrypto": true, @@ -558,6 +573,7 @@ var stdlib = map[string]map[string]bool{ "ParsePKCS8PrivateKey": true, "ParsePKIXPublicKey": true, "PublicKeyAlgorithm": true, + "PureEd25519": true, "RSA": true, "SHA1WithRSA": true, "SHA256WithRSA": true, @@ -612,8 +628,10 @@ var stdlib = map[string]map[string]bool{ "NamedArg": true, "NullBool": true, "NullFloat64": true, + "NullInt32": true, "NullInt64": true, "NullString": true, + "NullTime": true, "Open": true, "OpenDB": true, "Out": true, @@ -860,6 +878,7 @@ var stdlib = map[string]map[string]bool{ "UcharType": true, "UintType": true, "UnspecifiedType": true, + "UnsupportedType": true, "VoidType": true, }, "debug/elf": map[string]bool{ @@ -2505,7 +2524,10 @@ var stdlib = map[string]map[string]bool{ "UnsupportedTypeError": true, }, "errors": map[string]bool{ - "New": true, + "As": true, + "Is": true, + "New": true, + "Unwrap": true, }, "expvar": map[string]bool{ "Do": true, @@ -2615,10 +2637,12 @@ var stdlib = map[string]map[string]bool{ "CommentMap": true, "CompositeLit": true, "Con": true, + "Decl": true, "DeclStmt": true, "DeferStmt": true, "Ellipsis": true, "EmptyStmt": true, + "Expr": true, "ExprStmt": true, "Field": true, "FieldFilter": true, @@ -2679,7 +2703,9 @@ var stdlib = map[string]map[string]bool{ "SendStmt": true, "SliceExpr": true, "SortImports": true, + "Spec": true, "StarExpr": true, + "Stmt": true, "StructType": true, "SwitchStmt": true, "Typ": true, @@ -2725,6 +2751,7 @@ var stdlib = map[string]map[string]bool{ "Int": true, "Int64Val": true, "Kind": true, + "Make": true, "MakeBool": true, "MakeFloat64": true, "MakeFromBytes": true, @@ -2746,6 +2773,8 @@ var stdlib = map[string]map[string]bool{ "Uint64Val": true, "UnaryOp": true, "Unknown": true, + "Val": true, + "Value": true, }, "go/doc": map[string]bool{ "AllDecls": true, @@ -2855,6 +2884,9 @@ var stdlib = map[string]map[string]bool{ "INC": true, "INT": true, "INTERFACE": true, + "IsExported": true, + "IsIdentifier": true, + "IsKeyword": true, "LAND": true, "LBRACE": true, "LBRACK": true, @@ -2916,6 +2948,7 @@ var stdlib = map[string]map[string]bool{ "Byte": true, "Chan": true, "ChanDir": true, + "CheckExpr": true, "Checker": true, "Comparable": true, "Complex128": true, @@ -2991,6 +3024,7 @@ var stdlib = map[string]map[string]bool{ "NewTypeName": true, "NewVar": true, "Nil": true, + "Object": true, "ObjectString": true, "Package": true, "PkgName": true, @@ -3349,6 +3383,7 @@ var stdlib = map[string]map[string]bool{ "SetFlags": true, "SetOutput": true, "SetPrefix": true, + "Writer": true, }, "log/syslog": map[string]bool{ "Dial": true, @@ -3801,6 +3836,7 @@ var stdlib = map[string]map[string]bool{ "MethodTrace": true, "NewFileTransport": true, "NewRequest": true, + "NewRequestWithContext": true, "NewServeMux": true, "NoBody": true, "NotFound": true, @@ -3825,6 +3861,7 @@ var stdlib = map[string]map[string]bool{ "SameSite": true, "SameSiteDefaultMode": true, "SameSiteLaxMode": true, + "SameSiteNoneMode": true, "SameSiteStrictMode": true, "Serve": true, "ServeContent": true, @@ -3846,6 +3883,7 @@ var stdlib = map[string]map[string]bool{ "StatusConflict": true, "StatusContinue": true, "StatusCreated": true, + "StatusEarlyHints": true, "StatusExpectationFailed": true, "StatusFailedDependency": true, "StatusForbidden": true, @@ -4163,6 +4201,7 @@ var stdlib = map[string]map[string]bool{ "Truncate": true, "Unsetenv": true, "UserCacheDir": true, + "UserConfigDir": true, "UserHomeDir": true, }, "os/exec": map[string]bool{ @@ -4293,6 +4332,7 @@ var stdlib = map[string]map[string]bool{ "StructOf": true, "StructTag": true, "Swapper": true, + "Type": true, "TypeOf": true, "Uint": true, "Uint16": true, @@ -4588,6 +4628,7 @@ var stdlib = map[string]map[string]bool{ "ToTitleSpecial": true, "ToUpper": true, "ToUpperSpecial": true, + "ToValidUTF8": true, "Trim": true, "TrimFunc": true, "TrimLeft": true, @@ -7989,6 +8030,7 @@ var stdlib = map[string]map[string]bool{ "Rmdir": true, "RouteMessage": true, "RouteRIB": true, + "RoutingMessage": true, "RtAttr": true, "RtGenmsg": true, "RtMetrics": true, @@ -9357,6 +9399,7 @@ var stdlib = map[string]map[string]bool{ "SlicePtrFromStrings": true, "SockFilter": true, "SockFprog": true, + "Sockaddr": true, "SockaddrDatalink": true, "SockaddrGen": true, "SockaddrInet4": true, @@ -9784,6 +9827,8 @@ var stdlib = map[string]map[string]bool{ "XP1_UNI_SEND": true, }, "syscall/js": map[string]bool{ + "CopyBytesToGo": true, + "CopyBytesToJS": true, "Error": true, "Func": true, "FuncOf": true, @@ -9798,8 +9843,6 @@ var stdlib = map[string]map[string]bool{ "TypeString": true, "TypeSymbol": true, "TypeUndefined": true, - "TypedArray": true, - "TypedArrayOf": true, "Undefined": true, "Value": true, "ValueError": true, @@ -9815,6 +9858,7 @@ var stdlib = map[string]map[string]bool{ "CoverBlock": true, "CoverMode": true, "Coverage": true, + "Init": true, "InternalBenchmark": true, "InternalExample": true, "InternalTest": true, @@ -9828,6 +9872,7 @@ var stdlib = map[string]map[string]bool{ "RunTests": true, "Short": true, "T": true, + "TB": true, "Verbose": true, }, "testing/iotest": map[string]bool{ @@ -10063,6 +10108,7 @@ var stdlib = map[string]map[string]bool{ "Devanagari": true, "Diacritic": true, "Digit": true, + "Dogra": true, "Duployan": true, "Egyptian_Hieroglyphs": true, "Elbasan": true, @@ -10077,9 +10123,11 @@ var stdlib = map[string]map[string]bool{ "GraphicRanges": true, "Greek": true, "Gujarati": true, + "Gunjala_Gondi": true, "Gurmukhi": true, "Han": true, "Hangul": true, + "Hanifi_Rohingya": true, "Hanunoo": true, "Hatran": true, "Hebrew": true, @@ -10140,6 +10188,7 @@ var stdlib = map[string]map[string]bool{ "Lydian": true, "M": true, "Mahajani": true, + "Makasar": true, "Malayalam": true, "Mandaic": true, "Manichaean": true, @@ -10152,6 +10201,7 @@ var stdlib = map[string]map[string]bool{ "MaxRune": true, "Mc": true, "Me": true, + "Medefaidrin": true, "Meetei_Mayek": true, "Mende_Kikakui": true, "Meroitic_Cursive": true, @@ -10181,6 +10231,7 @@ var stdlib = map[string]map[string]bool{ "Old_North_Arabian": true, "Old_Permic": true, "Old_Persian": true, + "Old_Sogdian": true, "Old_South_Arabian": true, "Old_Turkic": true, "Oriya": true, @@ -10241,6 +10292,7 @@ var stdlib = map[string]map[string]bool{ "Sm": true, "So": true, "Soft_Dotted": true, + "Sogdian": true, "Sora_Sompeng": true, "Soyombo": true, "Space": true, diff --git a/vendor/golang.org/x/tools/internal/module/module.go b/tools/vendor/golang.org/x/tools/internal/module/module.go similarity index 100% rename from vendor/golang.org/x/tools/internal/module/module.go rename to tools/vendor/golang.org/x/tools/internal/module/module.go diff --git a/vendor/golang.org/x/tools/internal/semver/semver.go b/tools/vendor/golang.org/x/tools/internal/semver/semver.go similarity index 100% rename from vendor/golang.org/x/tools/internal/semver/semver.go rename to tools/vendor/golang.org/x/tools/internal/semver/semver.go diff --git a/tools/vendor/modules.txt b/tools/vendor/modules.txt new file mode 100644 index 00000000..1d279128 --- /dev/null +++ b/tools/vendor/modules.txt @@ -0,0 +1,12 @@ +# golang.org/x/tools v0.0.0-20190929041059-e7abfedfabcf +golang.org/x/tools/cmd/goimports +golang.org/x/tools/internal/imports +golang.org/x/tools/go/ast/astutil +golang.org/x/tools/go/packages +golang.org/x/tools/internal/gopathwalk +golang.org/x/tools/internal/module +golang.org/x/tools/go/gcexportdata +golang.org/x/tools/go/internal/packagesdriver +golang.org/x/tools/internal/semver +golang.org/x/tools/internal/fastwalk +golang.org/x/tools/go/internal/gcimporter diff --git a/vendor/golang.org/x/tools/internal/imports/mod.go b/vendor/golang.org/x/tools/internal/imports/mod.go deleted file mode 100644 index a072214e..00000000 --- a/vendor/golang.org/x/tools/internal/imports/mod.go +++ /dev/null @@ -1,355 +0,0 @@ -package imports - -import ( - "bytes" - "encoding/json" - "io/ioutil" - "log" - "os" - "path" - "path/filepath" - "regexp" - "sort" - "strconv" - "strings" - "sync" - "time" - - "golang.org/x/tools/internal/gopathwalk" - "golang.org/x/tools/internal/module" -) - -// moduleResolver implements resolver for modules using the go command as little -// as feasible. -type moduleResolver struct { - env *ProcessEnv - - initialized bool - main *moduleJSON - modsByModPath []*moduleJSON // All modules, ordered by # of path components in module Path... - modsByDir []*moduleJSON // ...or Dir. -} - -type moduleJSON struct { - Path string // module path - Version string // module version - Versions []string // available module versions (with -versions) - Replace *moduleJSON // replaced by this module - Time *time.Time // time version was created - Update *moduleJSON // available update, if any (with -u) - Main bool // is this the main module? - Indirect bool // is this module only an indirect dependency of main module? - Dir string // directory holding files for this module, if any - GoMod string // path to go.mod file for this module, if any - Error *moduleErrorJSON // error loading module -} - -type moduleErrorJSON struct { - Err string // the error itself -} - -func (r *moduleResolver) init() error { - if r.initialized { - return nil - } - stdout, err := r.env.invokeGo("list", "-m", "-json", "...") - if err != nil { - return err - } - for dec := json.NewDecoder(stdout); dec.More(); { - mod := &moduleJSON{} - if err := dec.Decode(mod); err != nil { - return err - } - if mod.Dir == "" { - if r.env.Debug { - log.Printf("module %v has not been downloaded and will be ignored", mod.Path) - } - // Can't do anything with a module that's not downloaded. - continue - } - r.modsByModPath = append(r.modsByModPath, mod) - r.modsByDir = append(r.modsByDir, mod) - if mod.Main { - r.main = mod - } - } - - sort.Slice(r.modsByModPath, func(i, j int) bool { - count := func(x int) int { - return strings.Count(r.modsByModPath[x].Path, "/") - } - return count(j) < count(i) // descending order - }) - sort.Slice(r.modsByDir, func(i, j int) bool { - count := func(x int) int { - return strings.Count(r.modsByDir[x].Dir, "/") - } - return count(j) < count(i) // descending order - }) - - r.initialized = true - return nil -} - -// findPackage returns the module and directory that contains the package at -// the given import path, or returns nil, "" if no module is in scope. -func (r *moduleResolver) findPackage(importPath string) (*moduleJSON, string) { - for _, m := range r.modsByModPath { - if !strings.HasPrefix(importPath, m.Path) { - continue - } - pathInModule := importPath[len(m.Path):] - pkgDir := filepath.Join(m.Dir, pathInModule) - if dirIsNestedModule(pkgDir, m) { - continue - } - - pkgFiles, err := ioutil.ReadDir(pkgDir) - if err != nil { - continue - } - - // A module only contains a package if it has buildable go - // files in that directory. If not, it could be provided by an - // outer module. See #29736. - for _, fi := range pkgFiles { - if ok, _ := r.env.buildContext().MatchFile(pkgDir, fi.Name()); ok { - return m, pkgDir - } - } - } - return nil, "" -} - -// findModuleByDir returns the module that contains dir, or nil if no such -// module is in scope. -func (r *moduleResolver) findModuleByDir(dir string) *moduleJSON { - // This is quite tricky and may not be correct. dir could be: - // - a package in the main module. - // - a replace target underneath the main module's directory. - // - a nested module in the above. - // - a replace target somewhere totally random. - // - a nested module in the above. - // - in the mod cache. - // - in /vendor/ in -mod=vendor mode. - // - nested module? Dunno. - // Rumor has it that replace targets cannot contain other replace targets. - for _, m := range r.modsByDir { - if !strings.HasPrefix(dir, m.Dir) { - continue - } - - if dirIsNestedModule(dir, m) { - continue - } - - return m - } - return nil -} - -// dirIsNestedModule reports if dir is contained in a nested module underneath -// mod, not actually in mod. -func dirIsNestedModule(dir string, mod *moduleJSON) bool { - if !strings.HasPrefix(dir, mod.Dir) { - return false - } - mf := findModFile(dir) - if mf == "" { - return false - } - return filepath.Dir(mf) != mod.Dir -} - -func findModFile(dir string) string { - for { - f := filepath.Join(dir, "go.mod") - info, err := os.Stat(f) - if err == nil && !info.IsDir() { - return f - } - d := filepath.Dir(dir) - if len(d) >= len(dir) { - return "" // reached top of file system, no go.mod - } - dir = d - } -} - -func (r *moduleResolver) loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) { - if err := r.init(); err != nil { - return nil, err - } - names := map[string]string{} - for _, path := range importPaths { - _, packageDir := r.findPackage(path) - if packageDir == "" { - continue - } - name, err := packageDirToName(packageDir) - if err != nil { - continue - } - names[path] = name - } - return names, nil -} - -func (r *moduleResolver) scan(_ references) ([]*pkg, error) { - if err := r.init(); err != nil { - return nil, err - } - - // Walk GOROOT, GOPATH/pkg/mod, and the main module. - roots := []gopathwalk.Root{ - {filepath.Join(r.env.GOROOT, "/src"), gopathwalk.RootGOROOT}, - } - if r.main != nil { - roots = append(roots, gopathwalk.Root{r.main.Dir, gopathwalk.RootCurrentModule}) - } - for _, p := range filepath.SplitList(r.env.GOPATH) { - roots = append(roots, gopathwalk.Root{filepath.Join(p, "/pkg/mod"), gopathwalk.RootModuleCache}) - } - - // Walk replace targets, just in case they're not in any of the above. - for _, mod := range r.modsByModPath { - if mod.Replace != nil { - roots = append(roots, gopathwalk.Root{mod.Dir, gopathwalk.RootOther}) - } - } - - var result []*pkg - dupCheck := make(map[string]bool) - var mu sync.Mutex - - gopathwalk.Walk(roots, func(root gopathwalk.Root, dir string) { - mu.Lock() - defer mu.Unlock() - - if _, dup := dupCheck[dir]; dup { - return - } - - dupCheck[dir] = true - - subdir := "" - if dir != root.Path { - subdir = dir[len(root.Path)+len("/"):] - } - importPath := filepath.ToSlash(subdir) - if strings.HasPrefix(importPath, "vendor/") { - // Ignore vendor dirs. If -mod=vendor is on, then things - // should mostly just work, but when it's not vendor/ - // is a mess. There's no easy way to tell if it's on. - // We can still find things in the mod cache and - // map them into /vendor when -mod=vendor is on. - return - } - switch root.Type { - case gopathwalk.RootCurrentModule: - importPath = path.Join(r.main.Path, filepath.ToSlash(subdir)) - case gopathwalk.RootModuleCache: - matches := modCacheRegexp.FindStringSubmatch(subdir) - modPath, err := module.DecodePath(filepath.ToSlash(matches[1])) - if err != nil { - if r.env.Debug { - log.Printf("decoding module cache path %q: %v", subdir, err) - } - return - } - importPath = path.Join(modPath, filepath.ToSlash(matches[3])) - case gopathwalk.RootGOROOT: - importPath = subdir - } - - // Check if the directory is underneath a module that's in scope. - if mod := r.findModuleByDir(dir); mod != nil { - // It is. If dir is the target of a replace directive, - // our guessed import path is wrong. Use the real one. - if mod.Dir == dir { - importPath = mod.Path - } else { - dirInMod := dir[len(mod.Dir)+len("/"):] - importPath = path.Join(mod.Path, filepath.ToSlash(dirInMod)) - } - } else { - // The package is in an unknown module. Check that it's - // not obviously impossible to import. - var modFile string - switch root.Type { - case gopathwalk.RootModuleCache: - matches := modCacheRegexp.FindStringSubmatch(subdir) - modFile = filepath.Join(matches[1], "@", matches[2], "go.mod") - default: - modFile = findModFile(dir) - } - - modBytes, err := ioutil.ReadFile(modFile) - if err == nil && !strings.HasPrefix(importPath, modulePath(modBytes)) { - // The module's declared path does not match - // its expected path. It probably needs a - // replace directive we don't have. - return - } - } - // We may have discovered a package that has a different version - // in scope already. Canonicalize to that one if possible. - if _, canonicalDir := r.findPackage(importPath); canonicalDir != "" { - dir = canonicalDir - } - - result = append(result, &pkg{ - importPathShort: VendorlessPath(importPath), - dir: dir, - }) - }, gopathwalk.Options{Debug: r.env.Debug, ModulesEnabled: true}) - return result, nil -} - -// modCacheRegexp splits a path in a module cache into module, module version, and package. -var modCacheRegexp = regexp.MustCompile(`(.*)@([^/\\]*)(.*)`) - -var ( - slashSlash = []byte("//") - moduleStr = []byte("module") -) - -// modulePath returns the module path from the gomod file text. -// If it cannot find a module path, it returns an empty string. -// It is tolerant of unrelated problems in the go.mod file. -// -// Copied from cmd/go/internal/modfile. -func modulePath(mod []byte) string { - for len(mod) > 0 { - line := mod - mod = nil - if i := bytes.IndexByte(line, '\n'); i >= 0 { - line, mod = line[:i], line[i+1:] - } - if i := bytes.Index(line, slashSlash); i >= 0 { - line = line[:i] - } - line = bytes.TrimSpace(line) - if !bytes.HasPrefix(line, moduleStr) { - continue - } - line = line[len(moduleStr):] - n := len(line) - line = bytes.TrimSpace(line) - if len(line) == n || len(line) == 0 { - continue - } - - if line[0] == '"' || line[0] == '`' { - p, err := strconv.Unquote(string(line)) - if err != nil { - return "" // malformed quoted string or multiline module path - } - return p - } - - return string(line) - } - return "" // missing module path -} diff --git a/vendor/modules.txt b/vendor/modules.txt index e3871d97..71295891 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -67,15 +67,3 @@ golang.org/x/sync/singleflight golang.org/x/sync/errgroup # golang.org/x/sys v0.0.0-20190416152802-12500544f89f golang.org/x/sys/windows -# golang.org/x/tools v0.0.0-20190624190245-7f2218787638 -golang.org/x/tools/cmd/goimports -golang.org/x/tools/internal/imports -golang.org/x/tools/go/ast/astutil -golang.org/x/tools/go/packages -golang.org/x/tools/internal/gopathwalk -golang.org/x/tools/internal/module -golang.org/x/tools/go/gcexportdata -golang.org/x/tools/go/internal/packagesdriver -golang.org/x/tools/internal/semver -golang.org/x/tools/internal/fastwalk -golang.org/x/tools/go/internal/gcimporter