Bumping k8s dependencies to 1.13
This commit is contained in:
210
vendor/golang.org/x/tools/go/packages/doc.go
generated
vendored
210
vendor/golang.org/x/tools/go/packages/doc.go
generated
vendored
@@ -3,112 +3,81 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
Package packages loads Go packages for inspection and analysis.
|
||||
|
||||
Package packages provides information about Go packages,
|
||||
such as their path, source files, and imports.
|
||||
It can optionally load, parse, and type-check the source files of a
|
||||
package, and obtain type information for their dependencies either by
|
||||
loading export data files produced by the Go compiler or by
|
||||
recursively loading dependencies from source code.
|
||||
Note: Though this package is ready for widespread use, we may make minor
|
||||
breaking changes if absolutely necessary. Any such change will be
|
||||
announced on golang-tools@ at least one week before it is committed. No
|
||||
more breaking changes will be made after December 1, 2018.
|
||||
|
||||
THIS INTERFACE IS EXPERIMENTAL AND IS LIKELY TO CHANGE.
|
||||
The Load function takes as input a list of patterns and return a list of Package
|
||||
structs describing individual packages matched by those patterns.
|
||||
The LoadMode controls the amount of detail in the loaded packages.
|
||||
|
||||
This package is intended to replace golang.org/x/tools/go/loader.
|
||||
It provides a simpler interface to the same functionality and serves
|
||||
as a foundation for analysis tools that work with 'go build',
|
||||
including its support for versioned packages,
|
||||
and also with alternative build systems such as Bazel and Blaze.
|
||||
Load passes most patterns directly to the underlying build tool,
|
||||
but all patterns with the prefix "query=", where query is a
|
||||
non-empty string of letters from [a-z], are reserved and may be
|
||||
interpreted as query operators.
|
||||
|
||||
Its primary operation is to load packages through
|
||||
the Metadata, TypeCheck, and WholeProgram functions,
|
||||
which accept a list of string arguments that denote
|
||||
one or more packages according to the conventions
|
||||
of the underlying build system.
|
||||
Only two query operators are currently supported, "file" and "pattern".
|
||||
|
||||
For example, in a 'go build' workspace,
|
||||
they may be a list of package names,
|
||||
or relative directory names,
|
||||
or even an ad-hoc list of source files:
|
||||
The query "file=path/to/file.go" matches the package or packages enclosing
|
||||
the Go source file path/to/file.go. For example "file=~/go/src/fmt/print.go"
|
||||
might returns the packages "fmt" and "fmt [fmt.test]".
|
||||
|
||||
fmt
|
||||
encoding/json
|
||||
./json
|
||||
a.go b.go
|
||||
The query "pattern=string" causes "string" to be passed directly to
|
||||
the underlying build tool. In most cases this is unnecessary,
|
||||
but an application can use Load("pattern=" + x) as an escaping mechanism
|
||||
to ensure that x is not interpreted as a query operator if it contains '='.
|
||||
|
||||
For a Bazel project, the arguments use Bazel's package notation:
|
||||
A third query "name=identifier" will be added soon.
|
||||
It will match packages whose package declaration contains the specified identifier.
|
||||
For example, "name=rand" would match the packages "math/rand" and "crypto/rand",
|
||||
and "name=main" would match all executables.
|
||||
|
||||
@repo//project:target
|
||||
//project:target
|
||||
:target
|
||||
target
|
||||
All other query operators are reserved for future use and currently
|
||||
cause Load to report an error.
|
||||
|
||||
An application that loads packages can thus pass its command-line
|
||||
arguments directly to the loading functions and it will integrate with the
|
||||
usual conventions for that project.
|
||||
The Package struct provides basic information about the package, including
|
||||
|
||||
The result of a call to a loading function is a set of Package
|
||||
objects describing the packages denoted by the arguments.
|
||||
These "initial" packages are in fact the roots of a graph of Packages,
|
||||
the import graph, that includes complete transitive dependencies.
|
||||
Clients may traverse the import graph by following the edges in the
|
||||
Package.Imports map, which relates the import paths that appear in the
|
||||
package's source files to the packages they import.
|
||||
- ID, a unique identifier for the package in the returned set;
|
||||
- GoFiles, the names of the package's Go source files;
|
||||
- Imports, a map from source import strings to the Packages they name;
|
||||
- Types, the type information for the package's exported symbols;
|
||||
- Syntax, the parsed syntax trees for the package's source code; and
|
||||
- TypeInfo, the result of a complete type-check of the package syntax trees.
|
||||
|
||||
Each package has three kinds of name: ID, PkgPath, and Name.
|
||||
A package's ID is an unspecified identifier that uniquely
|
||||
identifies it throughout the workspace, and thus may be used as a key in
|
||||
a map of packages. Clients should not interpret this string, no matter
|
||||
how intelligible it looks, as its structure varies across build systems.
|
||||
A package's PkgPath is the name by which the package is known to the
|
||||
compiler, linker, and runtime: it is the string returned by
|
||||
reflect.Type.PkgPath or fmt.Sprintf("%T", x). The PkgPath is not
|
||||
necessarily unique throughout the workspace; for example, an in-package
|
||||
test has the same PkgPath as the package under test.
|
||||
A package's Name is the identifier that appears in the "package"
|
||||
declaration at the start of each of its source files,
|
||||
and is the name declared when importing it into another file.
|
||||
A package whose Name is "main" is linked as an executable.
|
||||
(See the documentation for type Package for the complete list of fields
|
||||
and more detailed descriptions.)
|
||||
|
||||
The loader's three entry points, Metadata, TypeCheck, and
|
||||
WholeProgram, provide increasing levels of detail.
|
||||
For example,
|
||||
|
||||
Metadata returns only a description of each package,
|
||||
its source files and imports.
|
||||
Some build systems permit build steps to generate
|
||||
Go source files that are then compiled.
|
||||
The Packages describing such a program report
|
||||
the locations of the generated files.
|
||||
The process of loading packages invokes the
|
||||
underlying build system to ensure that these
|
||||
files are present and up-to-date.
|
||||
Load(nil, "bytes", "unicode...")
|
||||
|
||||
Although 'go build' does not in general allow code generation,
|
||||
it does in a limited form in its support for cgo.
|
||||
For a package whose source files import "C", subjecting them to cgo
|
||||
preprocessing, the loader reports the location of the pure-Go source
|
||||
files generated by cgo. This too may entail a partial build.
|
||||
Cgo processing is disabled for Metadata queries,
|
||||
or when the DisableCgo option is set.
|
||||
returns four Package structs describing the standard library packages
|
||||
bytes, unicode, unicode/utf16, and unicode/utf8. Note that one pattern
|
||||
can match multiple packages and that a package might be matched by
|
||||
multiple patterns: in general it is not possible to determine which
|
||||
packages correspond to which patterns.
|
||||
|
||||
TypeCheck additionally loads, parses, and type-checks
|
||||
the source files of the initial packages,
|
||||
and exposes their syntax trees and type information.
|
||||
Type information for dependencies of the initial
|
||||
packages is obtained not from Go source code but from
|
||||
compiler-generated export data files.
|
||||
Again, loading invokes the underlying build system to
|
||||
ensure that these files are present and up-to-date.
|
||||
Note that the list returned by Load contains only the packages matched
|
||||
by the patterns. Their dependencies can be found by walking the import
|
||||
graph using the Imports fields.
|
||||
|
||||
WholeProgram loads complete type information about
|
||||
the initial packages and all of their transitive dependencies.
|
||||
The Load function can be configured by passing a pointer to a Config as
|
||||
the first argument. A nil Config is equivalent to the zero Config, which
|
||||
causes Load to run in LoadFiles mode, collecting minimal information.
|
||||
See the documentation for type Config for details.
|
||||
|
||||
Example:
|
||||
As noted earlier, the Config.Mode controls the amount of detail
|
||||
reported about the loaded packages, with each mode returning all the data of the
|
||||
previous mode with some extra added. See the documentation for type LoadMode
|
||||
for details.
|
||||
|
||||
pkgs, err := packages.TypeCheck(nil, flag.Args()...)
|
||||
if err != nil { ... }
|
||||
for _, pkg := range pkgs {
|
||||
...
|
||||
}
|
||||
Most tools should pass their command-line arguments (after any flags)
|
||||
uninterpreted to the loader, so that the loader can interpret them
|
||||
according to the conventions of the underlying build system.
|
||||
See the Example function for typical usage.
|
||||
|
||||
*/
|
||||
package packages // import "golang.org/x/tools/go/packages"
|
||||
@@ -143,12 +112,6 @@ about one package without visiting all its dependencies too, so there is
|
||||
no additional asymptotic cost to providing transitive information.
|
||||
(This property might not be true of a hypothetical 5th build system.)
|
||||
|
||||
This package provides no parse-but-don't-typecheck operation because most tools
|
||||
that need only untyped syntax (such as gofmt, goimports, and golint)
|
||||
seem not to care about any files other than the ones they are directly
|
||||
instructed to look at. Also, it is trivial for a client to supplement
|
||||
this functionality on top of a Metadata query.
|
||||
|
||||
In calls to TypeCheck, all initial packages, and any package that
|
||||
transitively depends on one of them, must be loaded from source.
|
||||
Consider A->B->C->D->E: if A,C are initial, A,B,C must be loaded from
|
||||
@@ -169,12 +132,9 @@ files were nearly always missing or stale. Now that 'go build' supports
|
||||
caching, all the underlying build systems can guarantee to produce
|
||||
export data in a reasonable (amortized) time.
|
||||
|
||||
Packages that are part of a test are marked IsTest=true.
|
||||
Such packages include in-package tests, external tests,
|
||||
and the test "main" packages synthesized by the build system.
|
||||
The latter packages are reported as first-class packages,
|
||||
avoiding the need for clients (such as go/ssa) to reinvent this
|
||||
generation logic.
|
||||
Test "main" packages synthesized by the build system are now reported as
|
||||
first-class packages, avoiding the need for clients (such as go/ssa) to
|
||||
reinvent this generation logic.
|
||||
|
||||
One way in which go/packages is simpler than the old loader is in its
|
||||
treatment of in-package tests. In-package tests are packages that
|
||||
@@ -201,15 +161,13 @@ type-check again. This two-phase approach had four major problems:
|
||||
in several times in sequence as is now possible in WholeProgram mode.
|
||||
(TypeCheck mode has a similar one-shot restriction for a different reason.)
|
||||
|
||||
Early drafts of this package supported "multi-shot" operation
|
||||
in the Metadata and WholeProgram modes, although this feature is not exposed
|
||||
through the API and will likely be removed.
|
||||
Early drafts of this package supported "multi-shot" operation.
|
||||
Although it allowed clients to make a sequence of calls (or concurrent
|
||||
calls) to Load, building up the graph of Packages incrementally,
|
||||
it was of marginal value: it complicated the API
|
||||
(since it allowed some options to vary across calls but not others),
|
||||
it complicated the implementation,
|
||||
it cannot be made to work in TypeCheck mode, as explained above,
|
||||
it cannot be made to work in Types mode, as explained above,
|
||||
and it was less efficient than making one combined call (when this is possible).
|
||||
Among the clients we have inspected, none made multiple calls to load
|
||||
but could not be easily and satisfactorily modified to make only a single call.
|
||||
@@ -241,42 +199,25 @@ application, but not by the metadata query, so, for example:
|
||||
|
||||
Questions & Tasks
|
||||
|
||||
- Add pass-through options for the underlying query tool:
|
||||
Dir string
|
||||
Environ []string
|
||||
Flags []string
|
||||
Do away with GOROOT and don't add GOARCH/GOOS:
|
||||
they are not portable concepts.
|
||||
The goal is to allow users to express themselves using the conventions
|
||||
- Add GOARCH/GOOS?
|
||||
They are not portable concepts, but could be made portable.
|
||||
Our goal has been to allow users to express themselves using the conventions
|
||||
of the underlying build system: if the build system honors GOARCH
|
||||
during a build and during a metadata query, then so should
|
||||
applications built atop that query mechanism.
|
||||
Conversely, if the target architecture of the build is determined by
|
||||
command-line flags, the application must pass the relevant
|
||||
command-line flags, the application can pass the relevant
|
||||
flags through to the build system using a command such as:
|
||||
myapp -query_flag="--cpu=amd64" -query_flag="--os=darwin"
|
||||
|
||||
- Build tags: where do they fit in? How does Bazel/Blaze handle them?
|
||||
|
||||
- Add an 'IncludeTests bool' option to include tests among the results.
|
||||
This flag is needed to avoid unnecessary dependencies (and, for vgo, downloads).
|
||||
Should it include/skip implied tests? (all tests are implied in go build)
|
||||
Or include/skip all tests?
|
||||
However, this approach is low-level, unwieldy, and non-portable.
|
||||
GOOS and GOARCH seem important enough to warrant a dedicated option.
|
||||
|
||||
- How should we handle partial failures such as a mixture of good and
|
||||
malformed patterns, existing and non-existent packages, succesful and
|
||||
malformed patterns, existing and non-existent packages, successful and
|
||||
failed builds, import failures, import cycles, and so on, in a call to
|
||||
Load?
|
||||
|
||||
- Do we need a GeneratedBy map that maps the name of each generated Go
|
||||
source file in Srcs to that of the original file, if known, or "" otherwise?
|
||||
Or are //line directives and "Generated" comments in those files enough?
|
||||
|
||||
- Support bazel/blaze, not just "go list".
|
||||
|
||||
- Support a "contains" query: a boolean option would cause the the
|
||||
pattern words to be interpreted as filenames, and the query would
|
||||
return the package(s) to which the file(s) belong.
|
||||
- Support bazel, blaze, and go1.10 list, not just go1.11 list.
|
||||
|
||||
- Handle (and test) various partial success cases, e.g.
|
||||
a mixture of good packages and:
|
||||
@@ -297,15 +238,4 @@ Questions & Tasks
|
||||
order. I suspect this is due to the breadth-first resolution now used
|
||||
by go/types. Is that a bug? Discuss with gri.
|
||||
|
||||
- https://github.com/golang/go/issues/25980 causes these commands to crash:
|
||||
$ GOPATH=/none ./gopackages -all all
|
||||
due to:
|
||||
$ GOPATH=/none go list -e -test -json all
|
||||
and:
|
||||
$ go list -e -test ./relative/path
|
||||
|
||||
- Modify stringer to use go/packages, perhaps initially under flag control.
|
||||
|
||||
- Bug: "gopackages fmt a.go" doesn't produce an error.
|
||||
|
||||
*/
|
||||
|
34
vendor/golang.org/x/tools/go/packages/example_test.go
generated
vendored
Normal file
34
vendor/golang.org/x/tools/go/packages/example_test.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
package packages_test
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"golang.org/x/tools/go/packages"
|
||||
)
|
||||
|
||||
// Example demonstrates how to load the packages specified on the
|
||||
// command line from source syntax.
|
||||
func Example() {
|
||||
flag.Parse()
|
||||
|
||||
// Many tools pass their command-line arguments (after any flags)
|
||||
// uninterpreted to packages.Load so that it can interpret them
|
||||
// according to the conventions of the underlying build system.
|
||||
cfg := &packages.Config{Mode: packages.LoadSyntax}
|
||||
pkgs, err := packages.Load(cfg, flag.Args()...)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "load: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if packages.PrintErrors(pkgs) > 0 {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Print the names of the source files
|
||||
// for each package listed on the command line.
|
||||
for _, pkg := range pkgs {
|
||||
fmt.Println(pkg.ID, pkg.GoFiles)
|
||||
}
|
||||
}
|
68
vendor/golang.org/x/tools/go/packages/external.go
generated
vendored
Normal file
68
vendor/golang.org/x/tools/go/packages/external.go
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file enables an external tool to intercept package requests.
|
||||
// If the tool is present then its results are used in preference to
|
||||
// the go list command.
|
||||
|
||||
package packages
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// findExternalTool returns the file path of a tool that supplies
|
||||
// the build system package structure, or "" if not found."
|
||||
// If GOPACKAGESDRIVER is set in the environment findExternalTool returns its
|
||||
// value, otherwise it searches for a binary named gopackagesdriver on the PATH.
|
||||
func findExternalDriver(cfg *Config) driver {
|
||||
const toolPrefix = "GOPACKAGESDRIVER="
|
||||
tool := ""
|
||||
for _, env := range cfg.Env {
|
||||
if val := strings.TrimPrefix(env, toolPrefix); val != env {
|
||||
tool = val
|
||||
}
|
||||
}
|
||||
if tool != "" && tool == "off" {
|
||||
return nil
|
||||
}
|
||||
if tool == "" {
|
||||
var err error
|
||||
tool, err = exec.LookPath("gopackagesdriver")
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return func(cfg *Config, words ...string) (*driverResponse, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
fullargs := []string{
|
||||
"list",
|
||||
fmt.Sprintf("-test=%t", cfg.Tests),
|
||||
fmt.Sprintf("-export=%t", usesExportData(cfg)),
|
||||
fmt.Sprintf("-deps=%t", cfg.Mode >= LoadImports),
|
||||
}
|
||||
for _, f := range cfg.BuildFlags {
|
||||
fullargs = append(fullargs, fmt.Sprintf("-buildflag=%v", f))
|
||||
}
|
||||
fullargs = append(fullargs, "--")
|
||||
fullargs = append(fullargs, words...)
|
||||
cmd := exec.CommandContext(cfg.Context, tool, fullargs...)
|
||||
cmd.Env = cfg.Env
|
||||
cmd.Dir = cfg.Dir
|
||||
cmd.Stdout = buf
|
||||
cmd.Stderr = new(bytes.Buffer)
|
||||
if err := cmd.Run(); err != nil {
|
||||
return nil, fmt.Errorf("%v: %v: %s", tool, err, cmd.Stderr)
|
||||
}
|
||||
var response driverResponse
|
||||
if err := json.Unmarshal(buf.Bytes(), &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &response, nil
|
||||
}
|
||||
}
|
736
vendor/golang.org/x/tools/go/packages/golist.go
generated
vendored
736
vendor/golang.org/x/tools/go/packages/golist.go
generated
vendored
@@ -1,43 +1,496 @@
|
||||
package packages
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file defines the "go list" implementation of the Packages metadata query.
|
||||
package packages
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"go/types"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/tools/internal/gopathwalk"
|
||||
"golang.org/x/tools/internal/semver"
|
||||
)
|
||||
|
||||
// golistPackages uses the "go list" command to expand the
|
||||
// pattern words and return metadata for the specified packages.
|
||||
func golistPackages(ctx context.Context, gopath string, cgo, export bool, words []string) ([]*Package, error) {
|
||||
// Fields must match go list;
|
||||
// see $GOROOT/src/cmd/go/internal/load/pkg.go.
|
||||
type jsonPackage struct {
|
||||
ImportPath string
|
||||
Dir string
|
||||
Name string
|
||||
Export string
|
||||
GoFiles []string
|
||||
CFiles []string
|
||||
CgoFiles []string
|
||||
SFiles []string
|
||||
Imports []string
|
||||
ImportMap map[string]string
|
||||
Deps []string
|
||||
TestGoFiles []string
|
||||
TestImports []string
|
||||
XTestGoFiles []string
|
||||
XTestImports []string
|
||||
ForTest string // q in a "p [q.test]" package, else ""
|
||||
DepOnly bool
|
||||
// debug controls verbose logging.
|
||||
const debug = false
|
||||
|
||||
// A goTooOldError reports that the go command
|
||||
// found by exec.LookPath is too old to use the new go list behavior.
|
||||
type goTooOldError struct {
|
||||
error
|
||||
}
|
||||
|
||||
// goListDriver uses the go list command to interpret the patterns and produce
|
||||
// the build system package structure.
|
||||
// See driver for more details.
|
||||
func goListDriver(cfg *Config, patterns ...string) (*driverResponse, error) {
|
||||
var sizes types.Sizes
|
||||
var sizeserr error
|
||||
var sizeswg sync.WaitGroup
|
||||
if cfg.Mode >= LoadTypes {
|
||||
sizeswg.Add(1)
|
||||
go func() {
|
||||
sizes, sizeserr = getSizes(cfg)
|
||||
sizeswg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
// Determine files requested in contains patterns
|
||||
var containFiles []string
|
||||
var packagesNamed []string
|
||||
restPatterns := make([]string, 0, len(patterns))
|
||||
// Extract file= and other [querytype]= patterns. Report an error if querytype
|
||||
// doesn't exist.
|
||||
extractQueries:
|
||||
for _, pattern := range patterns {
|
||||
eqidx := strings.Index(pattern, "=")
|
||||
if eqidx < 0 {
|
||||
restPatterns = append(restPatterns, pattern)
|
||||
} else {
|
||||
query, value := pattern[:eqidx], pattern[eqidx+len("="):]
|
||||
switch query {
|
||||
case "file":
|
||||
containFiles = append(containFiles, value)
|
||||
case "pattern":
|
||||
restPatterns = append(restPatterns, value)
|
||||
case "name":
|
||||
packagesNamed = append(packagesNamed, value)
|
||||
case "": // not a reserved query
|
||||
restPatterns = append(restPatterns, pattern)
|
||||
default:
|
||||
for _, rune := range query {
|
||||
if rune < 'a' || rune > 'z' { // not a reserved query
|
||||
restPatterns = append(restPatterns, pattern)
|
||||
continue extractQueries
|
||||
}
|
||||
}
|
||||
// Reject all other patterns containing "="
|
||||
return nil, fmt.Errorf("invalid query type %q in query pattern %q", query, pattern)
|
||||
}
|
||||
}
|
||||
}
|
||||
patterns = restPatterns
|
||||
|
||||
// TODO(matloob): Remove the definition of listfunc and just use golistPackages once go1.12 is released.
|
||||
var listfunc driver
|
||||
listfunc = func(cfg *Config, words ...string) (*driverResponse, error) {
|
||||
response, err := golistDriverCurrent(cfg, words...)
|
||||
if _, ok := err.(goTooOldError); ok {
|
||||
listfunc = golistDriverFallback
|
||||
return listfunc(cfg, words...)
|
||||
}
|
||||
listfunc = golistDriverCurrent
|
||||
return response, err
|
||||
}
|
||||
|
||||
var response *driverResponse
|
||||
var err error
|
||||
|
||||
// see if we have any patterns to pass through to go list.
|
||||
if len(restPatterns) > 0 {
|
||||
response, err = listfunc(cfg, restPatterns...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
response = &driverResponse{}
|
||||
}
|
||||
|
||||
sizeswg.Wait()
|
||||
if sizeserr != nil {
|
||||
return nil, sizeserr
|
||||
}
|
||||
// types.SizesFor always returns nil or a *types.StdSizes
|
||||
response.Sizes, _ = sizes.(*types.StdSizes)
|
||||
|
||||
if len(containFiles) == 0 && len(packagesNamed) == 0 {
|
||||
return response, nil
|
||||
}
|
||||
|
||||
seenPkgs := make(map[string]*Package) // for deduplication. different containing queries could produce same packages
|
||||
for _, pkg := range response.Packages {
|
||||
seenPkgs[pkg.ID] = pkg
|
||||
}
|
||||
addPkg := func(p *Package) {
|
||||
if _, ok := seenPkgs[p.ID]; ok {
|
||||
return
|
||||
}
|
||||
seenPkgs[p.ID] = p
|
||||
response.Packages = append(response.Packages, p)
|
||||
}
|
||||
|
||||
containsResults, err := runContainsQueries(cfg, listfunc, addPkg, containFiles)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response.Roots = append(response.Roots, containsResults...)
|
||||
|
||||
namedResults, err := runNamedQueries(cfg, listfunc, addPkg, packagesNamed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response.Roots = append(response.Roots, namedResults...)
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func runContainsQueries(cfg *Config, driver driver, addPkg func(*Package), queries []string) ([]string, error) {
|
||||
var results []string
|
||||
for _, query := range queries {
|
||||
// TODO(matloob): Do only one query per directory.
|
||||
fdir := filepath.Dir(query)
|
||||
cfg.Dir = fdir
|
||||
dirResponse, err := driver(cfg, ".")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
isRoot := make(map[string]bool, len(dirResponse.Roots))
|
||||
for _, root := range dirResponse.Roots {
|
||||
isRoot[root] = true
|
||||
}
|
||||
for _, pkg := range dirResponse.Packages {
|
||||
// Add any new packages to the main set
|
||||
// We don't bother to filter packages that will be dropped by the changes of roots,
|
||||
// that will happen anyway during graph construction outside this function.
|
||||
// Over-reporting packages is not a problem.
|
||||
addPkg(pkg)
|
||||
// if the package was not a root one, it cannot have the file
|
||||
if !isRoot[pkg.ID] {
|
||||
continue
|
||||
}
|
||||
for _, pkgFile := range pkg.GoFiles {
|
||||
if filepath.Base(query) == filepath.Base(pkgFile) {
|
||||
results = append(results, pkg.ID)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// modCacheRegexp splits a path in a module cache into module, module version, and package.
|
||||
var modCacheRegexp = regexp.MustCompile(`(.*)@([^/\\]*)(.*)`)
|
||||
|
||||
func runNamedQueries(cfg *Config, driver driver, addPkg func(*Package), queries []string) ([]string, error) {
|
||||
// calling `go env` isn't free; bail out if there's nothing to do.
|
||||
if len(queries) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
// Determine which directories are relevant to scan.
|
||||
roots, modRoot, err := roots(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Scan the selected directories. Simple matches, from GOPATH/GOROOT
|
||||
// or the local module, can simply be "go list"ed. Matches from the
|
||||
// module cache need special treatment.
|
||||
var matchesMu sync.Mutex
|
||||
var simpleMatches, modCacheMatches []string
|
||||
add := func(root gopathwalk.Root, dir string) {
|
||||
// Walk calls this concurrently; protect the result slices.
|
||||
matchesMu.Lock()
|
||||
defer matchesMu.Unlock()
|
||||
|
||||
path := dir[len(root.Path)+1:]
|
||||
if pathMatchesQueries(path, queries) {
|
||||
switch root.Type {
|
||||
case gopathwalk.RootModuleCache:
|
||||
modCacheMatches = append(modCacheMatches, path)
|
||||
case gopathwalk.RootCurrentModule:
|
||||
// We'd need to read go.mod to find the full
|
||||
// import path. Relative's easier.
|
||||
rel, err := filepath.Rel(cfg.Dir, dir)
|
||||
if err != nil {
|
||||
// This ought to be impossible, since
|
||||
// we found dir in the current module.
|
||||
panic(err)
|
||||
}
|
||||
simpleMatches = append(simpleMatches, "./"+rel)
|
||||
case gopathwalk.RootGOPATH, gopathwalk.RootGOROOT:
|
||||
simpleMatches = append(simpleMatches, path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
startWalk := time.Now()
|
||||
gopathwalk.Walk(roots, add, gopathwalk.Options{ModulesEnabled: modRoot != "", Debug: debug})
|
||||
if debug {
|
||||
log.Printf("%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
|
||||
// more reasonable for that to not match the package name. So, if there
|
||||
// are any Go files in the mod root, query it just to be safe.
|
||||
if modRoot != "" {
|
||||
rel, err := filepath.Rel(cfg.Dir, modRoot)
|
||||
if err != nil {
|
||||
panic(err) // See above.
|
||||
}
|
||||
|
||||
files, err := ioutil.ReadDir(modRoot)
|
||||
for _, f := range files {
|
||||
if strings.HasSuffix(f.Name(), ".go") {
|
||||
simpleMatches = append(simpleMatches, rel)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var results []string
|
||||
addResponse := func(r *driverResponse) {
|
||||
for _, pkg := range r.Packages {
|
||||
addPkg(pkg)
|
||||
for _, name := range queries {
|
||||
if pkg.Name == name {
|
||||
results = append(results, pkg.ID)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(simpleMatches) != 0 {
|
||||
resp, err := driver(cfg, simpleMatches...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addResponse(resp)
|
||||
}
|
||||
|
||||
// Module cache matches are tricky. We want to avoid downloading new
|
||||
// versions of things, so we need to use the ones present in the cache.
|
||||
// go list doesn't accept version specifiers, so we have to write out a
|
||||
// temporary module, and do the list in that module.
|
||||
if len(modCacheMatches) != 0 {
|
||||
// Collect all the matches, deduplicating by major version
|
||||
// and preferring the newest.
|
||||
type modInfo struct {
|
||||
mod string
|
||||
major string
|
||||
}
|
||||
mods := make(map[modInfo]string)
|
||||
var imports []string
|
||||
for _, modPath := range modCacheMatches {
|
||||
matches := modCacheRegexp.FindStringSubmatch(modPath)
|
||||
mod, ver := filepath.ToSlash(matches[1]), matches[2]
|
||||
importPath := filepath.ToSlash(filepath.Join(matches[1], matches[3]))
|
||||
|
||||
major := semver.Major(ver)
|
||||
if prevVer, ok := mods[modInfo{mod, major}]; !ok || semver.Compare(ver, prevVer) > 0 {
|
||||
mods[modInfo{mod, major}] = ver
|
||||
}
|
||||
|
||||
imports = append(imports, importPath)
|
||||
}
|
||||
|
||||
// Build the temporary module.
|
||||
var gomod bytes.Buffer
|
||||
gomod.WriteString("module modquery\nrequire (\n")
|
||||
for mod, version := range mods {
|
||||
gomod.WriteString("\t" + mod.mod + " " + version + "\n")
|
||||
}
|
||||
gomod.WriteString(")\n")
|
||||
|
||||
tmpCfg := *cfg
|
||||
|
||||
// We're only trying to look at stuff in the module cache, so
|
||||
// disable the network. This should speed things up, and has
|
||||
// prevented errors in at least one case, #28518.
|
||||
tmpCfg.Env = append(append([]string{"GOPROXY=off"}, cfg.Env...))
|
||||
|
||||
var err error
|
||||
tmpCfg.Dir, err = ioutil.TempDir("", "gopackages-modquery")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer os.RemoveAll(tmpCfg.Dir)
|
||||
|
||||
if err := ioutil.WriteFile(filepath.Join(tmpCfg.Dir, "go.mod"), gomod.Bytes(), 0777); err != nil {
|
||||
return nil, fmt.Errorf("writing go.mod for module cache query: %v", err)
|
||||
}
|
||||
|
||||
// Run the query, using the import paths calculated from the matches above.
|
||||
resp, err := driver(&tmpCfg, imports...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("querying module cache matches: %v", err)
|
||||
}
|
||||
addResponse(resp)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func getSizes(cfg *Config) (types.Sizes, error) {
|
||||
stdout, err := invokeGo(cfg, "env", "GOARCH")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
goarch := strings.TrimSpace(stdout.String())
|
||||
// Assume "gc" because SizesFor doesn't respond to other compilers.
|
||||
// TODO(matloob): add support for gccgo as needed.
|
||||
return types.SizesFor("gc", goarch), nil
|
||||
}
|
||||
|
||||
// roots selects the appropriate paths to walk based on the passed-in configuration,
|
||||
// particularly the environment and the presence of a go.mod in cfg.Dir's parents.
|
||||
func roots(cfg *Config) ([]gopathwalk.Root, string, error) {
|
||||
stdout, err := invokeGo(cfg, "env", "GOROOT", "GOPATH", "GOMOD")
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
fields := strings.Split(stdout.String(), "\n")
|
||||
if len(fields) != 4 || len(fields[3]) != 0 {
|
||||
return nil, "", fmt.Errorf("go env returned unexpected output: %q", stdout.String())
|
||||
}
|
||||
goroot, gopath, gomod := fields[0], filepath.SplitList(fields[1]), fields[2]
|
||||
var modDir string
|
||||
if gomod != "" {
|
||||
modDir = filepath.Dir(gomod)
|
||||
}
|
||||
|
||||
var roots []gopathwalk.Root
|
||||
// Always add GOROOT.
|
||||
roots = append(roots, gopathwalk.Root{filepath.Join(goroot, "/src"), gopathwalk.RootGOROOT})
|
||||
// If modules are enabled, scan the module dir.
|
||||
if modDir != "" {
|
||||
roots = append(roots, gopathwalk.Root{modDir, gopathwalk.RootCurrentModule})
|
||||
}
|
||||
// Add either GOPATH/src or GOPATH/pkg/mod, depending on module mode.
|
||||
for _, p := range gopath {
|
||||
if modDir != "" {
|
||||
roots = append(roots, gopathwalk.Root{filepath.Join(p, "/pkg/mod"), gopathwalk.RootModuleCache})
|
||||
} else {
|
||||
roots = append(roots, gopathwalk.Root{filepath.Join(p, "/src"), gopathwalk.RootGOPATH})
|
||||
}
|
||||
}
|
||||
|
||||
return roots, modDir, nil
|
||||
}
|
||||
|
||||
// These functions were copied from goimports. See further documentation there.
|
||||
|
||||
// pathMatchesQueries is adapted from pkgIsCandidate.
|
||||
// TODO: is it reasonable to do Contains here, rather than an exact match on a path component?
|
||||
func pathMatchesQueries(path string, queries []string) bool {
|
||||
lastTwo := lastTwoComponents(path)
|
||||
for _, query := range queries {
|
||||
if strings.Contains(lastTwo, query) {
|
||||
return true
|
||||
}
|
||||
if hasHyphenOrUpperASCII(lastTwo) && !hasHyphenOrUpperASCII(query) {
|
||||
lastTwo = lowerASCIIAndRemoveHyphen(lastTwo)
|
||||
if strings.Contains(lastTwo, query) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// lastTwoComponents returns at most the last two path components
|
||||
// of v, using either / or \ as the path separator.
|
||||
func lastTwoComponents(v string) string {
|
||||
nslash := 0
|
||||
for i := len(v) - 1; i >= 0; i-- {
|
||||
if v[i] == '/' || v[i] == '\\' {
|
||||
nslash++
|
||||
if nslash == 2 {
|
||||
return v[i:]
|
||||
}
|
||||
}
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func hasHyphenOrUpperASCII(s string) bool {
|
||||
for i := 0; i < len(s); i++ {
|
||||
b := s[i]
|
||||
if b == '-' || ('A' <= b && b <= 'Z') {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func lowerASCIIAndRemoveHyphen(s string) (ret string) {
|
||||
buf := make([]byte, 0, len(s))
|
||||
for i := 0; i < len(s); i++ {
|
||||
b := s[i]
|
||||
switch {
|
||||
case b == '-':
|
||||
continue
|
||||
case 'A' <= b && b <= 'Z':
|
||||
buf = append(buf, b+('a'-'A'))
|
||||
default:
|
||||
buf = append(buf, b)
|
||||
}
|
||||
}
|
||||
return string(buf)
|
||||
}
|
||||
|
||||
// Fields must match go list;
|
||||
// see $GOROOT/src/cmd/go/internal/load/pkg.go.
|
||||
type jsonPackage struct {
|
||||
ImportPath string
|
||||
Dir string
|
||||
Name string
|
||||
Export string
|
||||
GoFiles []string
|
||||
CompiledGoFiles []string
|
||||
CFiles []string
|
||||
CgoFiles []string
|
||||
CXXFiles []string
|
||||
MFiles []string
|
||||
HFiles []string
|
||||
FFiles []string
|
||||
SFiles []string
|
||||
SwigFiles []string
|
||||
SwigCXXFiles []string
|
||||
SysoFiles []string
|
||||
Imports []string
|
||||
ImportMap map[string]string
|
||||
Deps []string
|
||||
TestGoFiles []string
|
||||
TestImports []string
|
||||
XTestGoFiles []string
|
||||
XTestImports []string
|
||||
ForTest string // q in a "p [q.test]" package, else ""
|
||||
DepOnly bool
|
||||
|
||||
Error *jsonPackageError
|
||||
}
|
||||
|
||||
type jsonPackageError struct {
|
||||
ImportStack []string
|
||||
Pos string
|
||||
Err string
|
||||
}
|
||||
|
||||
func otherFiles(p *jsonPackage) [][]string {
|
||||
return [][]string{p.CFiles, p.CXXFiles, p.MFiles, p.HFiles, p.FFiles, p.SFiles, p.SwigFiles, p.SwigCXXFiles, p.SysoFiles}
|
||||
}
|
||||
|
||||
// golistDriverCurrent 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 golistDriverCurrent(cfg *Config, words ...string) (*driverResponse, error) {
|
||||
// go list uses the following identifiers in ImportPath and Imports:
|
||||
//
|
||||
// "p" -- importable package or main (command)
|
||||
@@ -51,61 +504,81 @@ func golistPackages(ctx context.Context, gopath string, cgo, export bool, words
|
||||
|
||||
// Run "go list" for complete
|
||||
// information on the specified packages.
|
||||
|
||||
buf, err := golist(ctx, gopath, cgo, export, words)
|
||||
buf, err := invokeGo(cfg, golistargs(cfg, words)...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
seen := make(map[string]*jsonPackage)
|
||||
// Decode the JSON and convert it to Package form.
|
||||
var result []*Package
|
||||
var response driverResponse
|
||||
for dec := json.NewDecoder(buf); dec.More(); {
|
||||
p := new(jsonPackage)
|
||||
if err := dec.Decode(p); err != nil {
|
||||
return nil, fmt.Errorf("JSON decoding failed: %v", err)
|
||||
}
|
||||
|
||||
// Bad package?
|
||||
if p.Name == "" {
|
||||
// This could be due to:
|
||||
// - no such package
|
||||
// - package directory contains no Go source files
|
||||
// - all package declarations are mangled
|
||||
// - and possibly other things.
|
||||
//
|
||||
// For now, we throw it away and let later
|
||||
// stages rediscover the problem, but this
|
||||
// discards the error message computed by go list
|
||||
// and computes a new one---by different logic:
|
||||
// if only one of the package declarations is
|
||||
// bad, for example, should we report an error
|
||||
// in Metadata mode?
|
||||
// Unless we parse and typecheck, we might not
|
||||
// notice there's a problem.
|
||||
//
|
||||
// Perhaps we should save a map of PackageID to
|
||||
// errors for such cases.
|
||||
if p.ImportPath == "" {
|
||||
// The documentation for go list says that “[e]rroneous packages will have
|
||||
// a non-empty ImportPath”. If for some reason it comes back empty, we
|
||||
// prefer to error out rather than silently discarding data or handing
|
||||
// back a package without any way to refer to it.
|
||||
if p.Error != nil {
|
||||
return nil, Error{
|
||||
Pos: p.Error.Pos,
|
||||
Msg: p.Error.Err,
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("package missing import path: %+v", p)
|
||||
}
|
||||
|
||||
if old, found := seen[p.ImportPath]; found {
|
||||
if !reflect.DeepEqual(p, old) {
|
||||
return nil, fmt.Errorf("go list repeated package %v with different values", p.ImportPath)
|
||||
}
|
||||
// skip the duplicate
|
||||
continue
|
||||
}
|
||||
seen[p.ImportPath] = p
|
||||
|
||||
id := p.ImportPath
|
||||
pkg := &Package{
|
||||
Name: p.Name,
|
||||
ID: p.ImportPath,
|
||||
GoFiles: absJoin(p.Dir, p.GoFiles, p.CgoFiles),
|
||||
CompiledGoFiles: absJoin(p.Dir, p.CompiledGoFiles),
|
||||
OtherFiles: absJoin(p.Dir, otherFiles(p)...),
|
||||
}
|
||||
|
||||
// Workaround for github.com/golang/go/issues/28749.
|
||||
// TODO(adonovan): delete before go1.12 release.
|
||||
out := pkg.CompiledGoFiles[:0]
|
||||
for _, f := range pkg.CompiledGoFiles {
|
||||
if strings.HasSuffix(f, ".s") {
|
||||
continue
|
||||
}
|
||||
out = append(out, f)
|
||||
}
|
||||
pkg.CompiledGoFiles = out
|
||||
|
||||
// Extract the PkgPath from the package's ID.
|
||||
pkgpath := id
|
||||
if i := strings.IndexByte(id, ' '); i >= 0 {
|
||||
pkgpath = id[:i]
|
||||
if i := strings.IndexByte(pkg.ID, ' '); i >= 0 {
|
||||
pkg.PkgPath = pkg.ID[:i]
|
||||
} else {
|
||||
pkg.PkgPath = pkg.ID
|
||||
}
|
||||
|
||||
// Is this a test?
|
||||
// ("foo [foo.test]" package or "foo.test" command)
|
||||
isTest := p.ForTest != "" || strings.HasSuffix(pkgpath, ".test")
|
||||
|
||||
if pkgpath == "unsafe" {
|
||||
p.GoFiles = nil // ignore fake unsafe.go file
|
||||
if pkg.PkgPath == "unsafe" {
|
||||
pkg.GoFiles = nil // ignore fake unsafe.go file
|
||||
}
|
||||
|
||||
export := p.Export
|
||||
if export != "" && !filepath.IsAbs(export) {
|
||||
export = filepath.Join(p.Dir, export)
|
||||
// Assume go list emits only absolute paths for Dir.
|
||||
if p.Dir != "" && !filepath.IsAbs(p.Dir) {
|
||||
log.Fatalf("internal error: go list returned non-absolute Package.Dir: %s", p.Dir)
|
||||
}
|
||||
|
||||
if p.Export != "" && !filepath.IsAbs(p.Export) {
|
||||
pkg.ExportFile = filepath.Join(p.Dir, p.Export)
|
||||
} else {
|
||||
pkg.ExportFile = p.Export
|
||||
}
|
||||
|
||||
// imports
|
||||
@@ -116,40 +589,40 @@ func golistPackages(ctx context.Context, gopath string, cgo, export bool, words
|
||||
for _, id := range p.Imports {
|
||||
ids[id] = true
|
||||
}
|
||||
imports := make(map[string]string)
|
||||
pkg.Imports = make(map[string]*Package)
|
||||
for path, id := range p.ImportMap {
|
||||
imports[path] = id // non-identity import
|
||||
pkg.Imports[path] = &Package{ID: id} // non-identity import
|
||||
delete(ids, id)
|
||||
}
|
||||
for id := range ids {
|
||||
// Go issue 26136: go list omits imports in cgo-generated files.
|
||||
if id == "C" && cgo {
|
||||
imports["unsafe"] = "unsafe"
|
||||
imports["syscall"] = "syscall"
|
||||
if pkgpath != "runtime/cgo" {
|
||||
imports["runtime/cgo"] = "runtime/cgo"
|
||||
}
|
||||
if id == "C" {
|
||||
continue
|
||||
}
|
||||
|
||||
imports[id] = id // identity import
|
||||
pkg.Imports[id] = &Package{ID: id} // identity import
|
||||
}
|
||||
if !p.DepOnly {
|
||||
response.Roots = append(response.Roots, pkg.ID)
|
||||
}
|
||||
|
||||
pkg := &Package{
|
||||
ID: id,
|
||||
Name: p.Name,
|
||||
PkgPath: pkgpath,
|
||||
IsTest: isTest,
|
||||
Srcs: absJoin(p.Dir, p.GoFiles, p.CgoFiles),
|
||||
OtherSrcs: absJoin(p.Dir, p.SFiles, p.CFiles),
|
||||
imports: imports,
|
||||
export: export,
|
||||
indirect: p.DepOnly,
|
||||
// Work around for pre-go.1.11 versions of go list.
|
||||
// TODO(matloob): they should be handled by the fallback.
|
||||
// Can we delete this?
|
||||
if len(pkg.CompiledGoFiles) == 0 {
|
||||
pkg.CompiledGoFiles = pkg.GoFiles
|
||||
}
|
||||
result = append(result, pkg)
|
||||
|
||||
if p.Error != nil {
|
||||
pkg.Errors = append(pkg.Errors, Error{
|
||||
Pos: p.Error.Pos,
|
||||
Msg: p.Error.Err,
|
||||
})
|
||||
}
|
||||
|
||||
response.Packages = append(response.Packages, pkg)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
// absJoin absolutizes and flattens the lists of files.
|
||||
@@ -165,70 +638,85 @@ func absJoin(dir string, fileses ...[]string) (res []string) {
|
||||
return res
|
||||
}
|
||||
|
||||
// golist returns the JSON-encoded result of a "go list args..." query.
|
||||
func golist(ctx context.Context, gopath string, cgo, export bool, args []string) (*bytes.Buffer, error) {
|
||||
out := new(bytes.Buffer)
|
||||
if len(args) == 0 {
|
||||
return out, nil
|
||||
func golistargs(cfg *Config, words []string) []string {
|
||||
fullargs := []string{
|
||||
"list", "-e", "-json", "-compiled",
|
||||
fmt.Sprintf("-test=%t", cfg.Tests),
|
||||
fmt.Sprintf("-export=%t", usesExportData(cfg)),
|
||||
fmt.Sprintf("-deps=%t", cfg.Mode >= LoadImports),
|
||||
}
|
||||
fullargs = append(fullargs, cfg.BuildFlags...)
|
||||
fullargs = append(fullargs, "--")
|
||||
fullargs = append(fullargs, words...)
|
||||
return fullargs
|
||||
}
|
||||
|
||||
const test = true // TODO(adonovan): expose a flag for this.
|
||||
|
||||
cmd := exec.CommandContext(ctx, "go", append([]string{
|
||||
"list",
|
||||
"-e",
|
||||
fmt.Sprintf("-cgo=%t", cgo),
|
||||
fmt.Sprintf("-test=%t", test),
|
||||
fmt.Sprintf("-export=%t", export),
|
||||
"-deps",
|
||||
"-json",
|
||||
"--",
|
||||
}, args...)...)
|
||||
cmd.Env = append(append([]string(nil), os.Environ()...), "GOPATH="+gopath)
|
||||
if !cgo {
|
||||
cmd.Env = append(cmd.Env, "CGO_ENABLED=0")
|
||||
// invokeGo returns the stdout of a go command invocation.
|
||||
func invokeGo(cfg *Config, args ...string) (*bytes.Buffer, error) {
|
||||
if debug {
|
||||
defer func(start time.Time) { log.Printf("%s for %v", time.Since(start), cmdDebugStr(cfg, args...)) }(time.Now())
|
||||
}
|
||||
cmd.Stdout = out
|
||||
cmd.Stderr = new(bytes.Buffer)
|
||||
stdout := new(bytes.Buffer)
|
||||
stderr := new(bytes.Buffer)
|
||||
cmd := exec.CommandContext(cfg.Context, "go", args...)
|
||||
// On darwin the cwd gets resolved to the real path, which breaks anything that
|
||||
// expects the working directory to keep the original path, including the
|
||||
// go command when dealing with modules.
|
||||
// The Go stdlib has a special feature where if the cwd and the PWD are the
|
||||
// same node then it trusts the PWD, so by setting it in the env for the child
|
||||
// process we fix up all the paths returned by the go command.
|
||||
cmd.Env = append(append([]string{}, cfg.Env...), "PWD="+cfg.Dir)
|
||||
cmd.Dir = cfg.Dir
|
||||
cmd.Stdout = stdout
|
||||
cmd.Stderr = stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
exitErr, ok := err.(*exec.ExitError)
|
||||
if !ok {
|
||||
// Catastrophic error:
|
||||
// - executable not found
|
||||
// - context cancellation
|
||||
return nil, fmt.Errorf("couldn't exec 'go list': %s %T", err, err)
|
||||
return nil, fmt.Errorf("couldn't exec 'go %v': %s %T", args, err, err)
|
||||
}
|
||||
|
||||
// Old go list?
|
||||
if strings.Contains(fmt.Sprint(cmd.Stderr), "flag provided but not defined") {
|
||||
return nil, fmt.Errorf("unsupported version of go list: %s: %s", exitErr, cmd.Stderr)
|
||||
// Old go version?
|
||||
if strings.Contains(stderr.String(), "flag provided but not defined") {
|
||||
return nil, goTooOldError{fmt.Errorf("unsupported version of go: %s: %s", exitErr, stderr)}
|
||||
}
|
||||
|
||||
// Export mode entails a build.
|
||||
// If that build fails, errors appear on stderr
|
||||
// (despite the -e flag) and the Export field is blank.
|
||||
// Do not fail in that case.
|
||||
if !export {
|
||||
return nil, fmt.Errorf("go list: %s: %s", exitErr, cmd.Stderr)
|
||||
if !usesExportData(cfg) {
|
||||
return nil, fmt.Errorf("go %v: %s: %s", args, exitErr, stderr)
|
||||
}
|
||||
}
|
||||
|
||||
// Print standard error output from "go list".
|
||||
// Due to the -e flag, this should be empty.
|
||||
// However, in -export mode it contains build errors.
|
||||
// Should go list save build errors in the Package.Error JSON field?
|
||||
// See https://github.com/golang/go/issues/26319.
|
||||
// If so, then we should continue to print stderr as go list
|
||||
// will be silent unless something unexpected happened.
|
||||
// If not, perhaps we should suppress it to reduce noise.
|
||||
if stderr := fmt.Sprint(cmd.Stderr); stderr != "" {
|
||||
fmt.Fprintf(os.Stderr, "go list stderr <<%s>>\n", stderr)
|
||||
// As of writing, go list -export prints some non-fatal compilation
|
||||
// errors to stderr, even with -e set. We would prefer that it put
|
||||
// them in the Package.Error JSON (see http://golang.org/issue/26319).
|
||||
// In the meantime, there's nowhere good to put them, but they can
|
||||
// be useful for debugging. Print them if $GOPACKAGESPRINTGOLISTERRORS
|
||||
// is set.
|
||||
if len(stderr.Bytes()) != 0 && os.Getenv("GOPACKAGESPRINTGOLISTERRORS") != "" {
|
||||
fmt.Fprintf(os.Stderr, "%s stderr: <<%s>>\n", cmdDebugStr(cfg, args...), stderr)
|
||||
}
|
||||
|
||||
// debugging
|
||||
if false {
|
||||
fmt.Fprintln(os.Stderr, out)
|
||||
fmt.Fprintf(os.Stderr, "%s stdout: <<%s>>\n", cmdDebugStr(cfg, args...), stdout)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
return stdout, nil
|
||||
}
|
||||
|
||||
func cmdDebugStr(cfg *Config, args ...string) string {
|
||||
env := make(map[string]string)
|
||||
for _, kv := range cfg.Env {
|
||||
split := strings.Split(kv, "=")
|
||||
k, v := split[0], split[1]
|
||||
env[k] = v
|
||||
}
|
||||
|
||||
return fmt.Sprintf("GOROOT=%v GOPATH=%v GO111MODULE=%v PWD=%v go %v", env["GOROOT"], env["GOPATH"], env["GO111MODULE"], env["PWD"], args)
|
||||
}
|
||||
|
450
vendor/golang.org/x/tools/go/packages/golist_fallback.go
generated
vendored
Normal file
450
vendor/golang.org/x/tools/go/packages/golist_fallback.go
generated
vendored
Normal file
@@ -0,0 +1,450 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package packages
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/go/internal/cgo"
|
||||
)
|
||||
|
||||
// TODO(matloob): Delete this file once Go 1.12 is released.
|
||||
|
||||
// This file provides backwards compatibility support for
|
||||
// loading for versions of Go earlier than 1.10.4. This support is meant to
|
||||
// assist with migration to the Package API until there's
|
||||
// widespread adoption of these newer Go versions.
|
||||
// This support will be removed once Go 1.12 is released
|
||||
// in Q1 2019.
|
||||
|
||||
func golistDriverFallback(cfg *Config, words ...string) (*driverResponse, error) {
|
||||
// Turn absolute paths into GOROOT and GOPATH-relative paths to provide to go list.
|
||||
// This will have surprising behavior if GOROOT or GOPATH contain multiple packages with the same
|
||||
// path and a user provides an absolute path to a directory that's shadowed by an earlier
|
||||
// directory in GOROOT or GOPATH with the same package path.
|
||||
words = cleanAbsPaths(cfg, words)
|
||||
|
||||
original, deps, err := getDeps(cfg, words...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tmpdir string // used for generated cgo files
|
||||
var needsTestVariant []struct {
|
||||
pkg, xtestPkg *Package
|
||||
}
|
||||
|
||||
var response driverResponse
|
||||
allPkgs := make(map[string]bool)
|
||||
addPackage := func(p *jsonPackage, isRoot bool) {
|
||||
id := p.ImportPath
|
||||
|
||||
if allPkgs[id] {
|
||||
return
|
||||
}
|
||||
allPkgs[id] = true
|
||||
|
||||
pkgpath := id
|
||||
|
||||
if pkgpath == "unsafe" {
|
||||
p.GoFiles = nil // ignore fake unsafe.go file
|
||||
}
|
||||
|
||||
importMap := func(importlist []string) map[string]*Package {
|
||||
importMap := make(map[string]*Package)
|
||||
for _, id := range importlist {
|
||||
|
||||
if id == "C" {
|
||||
for _, path := range []string{"unsafe", "syscall", "runtime/cgo"} {
|
||||
if pkgpath != path && importMap[path] == nil {
|
||||
importMap[path] = &Package{ID: path}
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
importMap[vendorlessPath(id)] = &Package{ID: id}
|
||||
}
|
||||
return importMap
|
||||
}
|
||||
compiledGoFiles := absJoin(p.Dir, p.GoFiles)
|
||||
// Use a function to simplify control flow. It's just a bunch of gotos.
|
||||
var cgoErrors []error
|
||||
var outdir string
|
||||
getOutdir := func() (string, error) {
|
||||
if outdir != "" {
|
||||
return outdir, nil
|
||||
}
|
||||
if tmpdir == "" {
|
||||
if tmpdir, err = ioutil.TempDir("", "gopackages"); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
// Add a "go-build" component to the path to make the tests think the files are in the cache.
|
||||
// This allows the same test to test the pre- and post-Go 1.11 go list logic because the Go 1.11
|
||||
// go list generates test mains in the cache, and the test code knows not to rely on paths in the
|
||||
// cache to stay stable.
|
||||
outdir = filepath.Join(tmpdir, "go-build", strings.Replace(p.ImportPath, "/", "_", -1))
|
||||
if err := os.MkdirAll(outdir, 0755); err != nil {
|
||||
outdir = ""
|
||||
return "", err
|
||||
}
|
||||
return outdir, nil
|
||||
}
|
||||
processCgo := func() bool {
|
||||
// Suppress any cgo errors. Any relevant errors will show up in typechecking.
|
||||
// TODO(matloob): Skip running cgo if Mode < LoadTypes.
|
||||
outdir, err := getOutdir()
|
||||
if err != nil {
|
||||
cgoErrors = append(cgoErrors, err)
|
||||
return false
|
||||
}
|
||||
files, _, err := runCgo(p.Dir, outdir, cfg.Env)
|
||||
if err != nil {
|
||||
cgoErrors = append(cgoErrors, err)
|
||||
return false
|
||||
}
|
||||
compiledGoFiles = append(compiledGoFiles, files...)
|
||||
return true
|
||||
}
|
||||
if len(p.CgoFiles) == 0 || !processCgo() {
|
||||
compiledGoFiles = append(compiledGoFiles, absJoin(p.Dir, p.CgoFiles)...) // Punt to typechecker.
|
||||
}
|
||||
if isRoot {
|
||||
response.Roots = append(response.Roots, id)
|
||||
}
|
||||
pkg := &Package{
|
||||
ID: id,
|
||||
Name: p.Name,
|
||||
GoFiles: absJoin(p.Dir, p.GoFiles, p.CgoFiles),
|
||||
CompiledGoFiles: compiledGoFiles,
|
||||
OtherFiles: absJoin(p.Dir, otherFiles(p)...),
|
||||
PkgPath: pkgpath,
|
||||
Imports: importMap(p.Imports),
|
||||
// TODO(matloob): set errors on the Package to cgoErrors
|
||||
}
|
||||
if p.Error != nil {
|
||||
pkg.Errors = append(pkg.Errors, Error{
|
||||
Pos: p.Error.Pos,
|
||||
Msg: p.Error.Err,
|
||||
})
|
||||
}
|
||||
response.Packages = append(response.Packages, pkg)
|
||||
if cfg.Tests && isRoot {
|
||||
testID := fmt.Sprintf("%s [%s.test]", id, id)
|
||||
if len(p.TestGoFiles) > 0 || len(p.XTestGoFiles) > 0 {
|
||||
response.Roots = append(response.Roots, testID)
|
||||
testPkg := &Package{
|
||||
ID: testID,
|
||||
Name: p.Name,
|
||||
GoFiles: absJoin(p.Dir, p.GoFiles, p.CgoFiles, p.TestGoFiles),
|
||||
CompiledGoFiles: append(compiledGoFiles, absJoin(p.Dir, p.TestGoFiles)...),
|
||||
OtherFiles: absJoin(p.Dir, otherFiles(p)...),
|
||||
PkgPath: pkgpath,
|
||||
Imports: importMap(append(p.Imports, p.TestImports...)),
|
||||
// TODO(matloob): set errors on the Package to cgoErrors
|
||||
}
|
||||
response.Packages = append(response.Packages, testPkg)
|
||||
var xtestPkg *Package
|
||||
if len(p.XTestGoFiles) > 0 {
|
||||
xtestID := fmt.Sprintf("%s_test [%s.test]", id, id)
|
||||
response.Roots = append(response.Roots, xtestID)
|
||||
// Generate test variants for all packages q where a path exists
|
||||
// such that xtestPkg -> ... -> q -> ... -> p (where p is the package under test)
|
||||
// and rewrite all import map entries of p to point to testPkg (the test variant of
|
||||
// p), and of each q to point to the test variant of that q.
|
||||
xtestPkg = &Package{
|
||||
ID: xtestID,
|
||||
Name: p.Name + "_test",
|
||||
GoFiles: absJoin(p.Dir, p.XTestGoFiles),
|
||||
CompiledGoFiles: absJoin(p.Dir, p.XTestGoFiles),
|
||||
PkgPath: pkgpath + "_test",
|
||||
Imports: importMap(p.XTestImports),
|
||||
}
|
||||
// Add to list of packages we need to rewrite imports for to refer to test variants.
|
||||
// We may need to create a test variant of a package that hasn't been loaded yet, so
|
||||
// the test variants need to be created later.
|
||||
needsTestVariant = append(needsTestVariant, struct{ pkg, xtestPkg *Package }{pkg, xtestPkg})
|
||||
response.Packages = append(response.Packages, xtestPkg)
|
||||
}
|
||||
// testmain package
|
||||
testmainID := id + ".test"
|
||||
response.Roots = append(response.Roots, testmainID)
|
||||
imports := map[string]*Package{}
|
||||
imports[testPkg.PkgPath] = &Package{ID: testPkg.ID}
|
||||
if xtestPkg != nil {
|
||||
imports[xtestPkg.PkgPath] = &Package{ID: xtestPkg.ID}
|
||||
}
|
||||
testmainPkg := &Package{
|
||||
ID: testmainID,
|
||||
Name: "main",
|
||||
PkgPath: testmainID,
|
||||
Imports: imports,
|
||||
}
|
||||
response.Packages = append(response.Packages, testmainPkg)
|
||||
outdir, err := getOutdir()
|
||||
if err != nil {
|
||||
testmainPkg.Errors = append(testmainPkg.Errors, Error{
|
||||
Pos: "-",
|
||||
Msg: fmt.Sprintf("failed to generate testmain: %v", err),
|
||||
Kind: ListError,
|
||||
})
|
||||
return
|
||||
}
|
||||
testmain := filepath.Join(outdir, "testmain.go")
|
||||
extraimports, extradeps, err := generateTestmain(testmain, testPkg, xtestPkg)
|
||||
if err != nil {
|
||||
testmainPkg.Errors = append(testmainPkg.Errors, Error{
|
||||
Pos: "-",
|
||||
Msg: fmt.Sprintf("failed to generate testmain: %v", err),
|
||||
Kind: ListError,
|
||||
})
|
||||
}
|
||||
deps = append(deps, extradeps...)
|
||||
for _, imp := range extraimports { // testing, testing/internal/testdeps, and maybe os
|
||||
imports[imp] = &Package{ID: imp}
|
||||
}
|
||||
testmainPkg.GoFiles = []string{testmain}
|
||||
testmainPkg.CompiledGoFiles = []string{testmain}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, pkg := range original {
|
||||
addPackage(pkg, true)
|
||||
}
|
||||
if cfg.Mode < LoadImports || len(deps) == 0 {
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
buf, err := invokeGo(cfg, golistArgsFallback(cfg, deps)...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Decode the JSON and convert it to Package form.
|
||||
for dec := json.NewDecoder(buf); dec.More(); {
|
||||
p := new(jsonPackage)
|
||||
if err := dec.Decode(p); err != nil {
|
||||
return nil, fmt.Errorf("JSON decoding failed: %v", err)
|
||||
}
|
||||
|
||||
addPackage(p, false)
|
||||
}
|
||||
|
||||
for _, v := range needsTestVariant {
|
||||
createTestVariants(&response, v.pkg, v.xtestPkg)
|
||||
}
|
||||
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
func createTestVariants(response *driverResponse, pkgUnderTest, xtestPkg *Package) {
|
||||
allPkgs := make(map[string]*Package)
|
||||
for _, pkg := range response.Packages {
|
||||
allPkgs[pkg.ID] = pkg
|
||||
}
|
||||
needsTestVariant := make(map[string]bool)
|
||||
needsTestVariant[pkgUnderTest.ID] = true
|
||||
var needsVariantRec func(p *Package) bool
|
||||
needsVariantRec = func(p *Package) bool {
|
||||
if needsTestVariant[p.ID] {
|
||||
return true
|
||||
}
|
||||
for _, imp := range p.Imports {
|
||||
if needsVariantRec(allPkgs[imp.ID]) {
|
||||
// Don't break because we want to make sure all dependencies
|
||||
// have been processed, and all required test variants of our dependencies
|
||||
// exist.
|
||||
needsTestVariant[p.ID] = true
|
||||
}
|
||||
}
|
||||
if !needsTestVariant[p.ID] {
|
||||
return false
|
||||
}
|
||||
// Create a clone of the package. It will share the same strings and lists of source files,
|
||||
// but that's okay. It's only necessary for the Imports map to have a separate identity.
|
||||
testVariant := *p
|
||||
testVariant.ID = fmt.Sprintf("%s [%s.test]", p.ID, pkgUnderTest.ID)
|
||||
testVariant.Imports = make(map[string]*Package)
|
||||
for imp, pkg := range p.Imports {
|
||||
testVariant.Imports[imp] = pkg
|
||||
if needsTestVariant[pkg.ID] {
|
||||
testVariant.Imports[imp] = &Package{ID: fmt.Sprintf("%s [%s.test]", pkg.ID, pkgUnderTest.ID)}
|
||||
}
|
||||
}
|
||||
response.Packages = append(response.Packages, &testVariant)
|
||||
return needsTestVariant[p.ID]
|
||||
}
|
||||
// finally, update the xtest package's imports
|
||||
for imp, pkg := range xtestPkg.Imports {
|
||||
if allPkgs[pkg.ID] == nil {
|
||||
fmt.Printf("for %s: package %s doesn't exist\n", xtestPkg.ID, pkg.ID)
|
||||
}
|
||||
if needsVariantRec(allPkgs[pkg.ID]) {
|
||||
xtestPkg.Imports[imp] = &Package{ID: fmt.Sprintf("%s [%s.test]", pkg.ID, pkgUnderTest.ID)}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// cleanAbsPaths replaces all absolute paths with GOPATH- and GOROOT-relative
|
||||
// paths. If an absolute path is not GOPATH- or GOROOT- relative, it is left as an
|
||||
// absolute path so an error can be returned later.
|
||||
func cleanAbsPaths(cfg *Config, words []string) []string {
|
||||
var searchpaths []string
|
||||
var cleaned = make([]string, len(words))
|
||||
for i := range cleaned {
|
||||
cleaned[i] = words[i]
|
||||
// Ignore relative directory paths (they must already be goroot-relative) and Go source files
|
||||
// (absolute source files are already allowed for ad-hoc packages).
|
||||
// TODO(matloob): Can there be non-.go files in ad-hoc packages.
|
||||
if !filepath.IsAbs(cleaned[i]) || strings.HasSuffix(cleaned[i], ".go") {
|
||||
continue
|
||||
}
|
||||
// otherwise, it's an absolute path. Search GOPATH and GOROOT to find it.
|
||||
if searchpaths == nil {
|
||||
cmd := exec.Command("go", "env", "GOPATH", "GOROOT")
|
||||
cmd.Env = cfg.Env
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
searchpaths = []string{}
|
||||
continue // suppress the error, it will show up again when running go list
|
||||
}
|
||||
lines := strings.Split(string(out), "\n")
|
||||
if len(lines) != 3 || lines[0] == "" || lines[1] == "" || lines[2] != "" {
|
||||
continue // suppress error
|
||||
}
|
||||
// first line is GOPATH
|
||||
for _, path := range filepath.SplitList(lines[0]) {
|
||||
searchpaths = append(searchpaths, filepath.Join(path, "src"))
|
||||
}
|
||||
// second line is GOROOT
|
||||
searchpaths = append(searchpaths, filepath.Join(lines[1], "src"))
|
||||
}
|
||||
for _, sp := range searchpaths {
|
||||
if strings.HasPrefix(cleaned[i], sp) {
|
||||
cleaned[i] = strings.TrimPrefix(cleaned[i], sp)
|
||||
cleaned[i] = strings.TrimLeft(cleaned[i], string(filepath.Separator))
|
||||
}
|
||||
}
|
||||
}
|
||||
return cleaned
|
||||
}
|
||||
|
||||
// vendorlessPath returns the devendorized version of the import path ipath.
|
||||
// For example, VendorlessPath("foo/bar/vendor/a/b") returns "a/b".
|
||||
// Copied from golang.org/x/tools/imports/fix.go.
|
||||
func vendorlessPath(ipath string) string {
|
||||
// Devendorize for use in import statement.
|
||||
if i := strings.LastIndex(ipath, "/vendor/"); i >= 0 {
|
||||
return ipath[i+len("/vendor/"):]
|
||||
}
|
||||
if strings.HasPrefix(ipath, "vendor/") {
|
||||
return ipath[len("vendor/"):]
|
||||
}
|
||||
return ipath
|
||||
}
|
||||
|
||||
// getDeps runs an initial go list to determine all the dependency packages.
|
||||
func getDeps(cfg *Config, words ...string) (initial []*jsonPackage, deps []string, err error) {
|
||||
buf, err := invokeGo(cfg, golistArgsFallback(cfg, words)...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
depsSet := make(map[string]bool)
|
||||
var testImports []string
|
||||
|
||||
// Extract deps from the JSON.
|
||||
for dec := json.NewDecoder(buf); dec.More(); {
|
||||
p := new(jsonPackage)
|
||||
if err := dec.Decode(p); err != nil {
|
||||
return nil, nil, fmt.Errorf("JSON decoding failed: %v", err)
|
||||
}
|
||||
|
||||
initial = append(initial, p)
|
||||
for _, dep := range p.Deps {
|
||||
depsSet[dep] = true
|
||||
}
|
||||
if cfg.Tests {
|
||||
// collect the additional imports of the test packages.
|
||||
pkgTestImports := append(p.TestImports, p.XTestImports...)
|
||||
for _, imp := range pkgTestImports {
|
||||
if depsSet[imp] {
|
||||
continue
|
||||
}
|
||||
depsSet[imp] = true
|
||||
testImports = append(testImports, imp)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Get the deps of the packages imported by tests.
|
||||
if len(testImports) > 0 {
|
||||
buf, err = invokeGo(cfg, golistArgsFallback(cfg, testImports)...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// Extract deps from the JSON.
|
||||
for dec := json.NewDecoder(buf); dec.More(); {
|
||||
p := new(jsonPackage)
|
||||
if err := dec.Decode(p); err != nil {
|
||||
return nil, nil, fmt.Errorf("JSON decoding failed: %v", err)
|
||||
}
|
||||
for _, dep := range p.Deps {
|
||||
depsSet[dep] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, orig := range initial {
|
||||
delete(depsSet, orig.ImportPath)
|
||||
}
|
||||
|
||||
deps = make([]string, 0, len(depsSet))
|
||||
for dep := range depsSet {
|
||||
deps = append(deps, dep)
|
||||
}
|
||||
sort.Strings(deps) // ensure output is deterministic
|
||||
return initial, deps, nil
|
||||
}
|
||||
|
||||
func golistArgsFallback(cfg *Config, words []string) []string {
|
||||
fullargs := []string{"list", "-e", "-json"}
|
||||
fullargs = append(fullargs, cfg.BuildFlags...)
|
||||
fullargs = append(fullargs, "--")
|
||||
fullargs = append(fullargs, words...)
|
||||
return fullargs
|
||||
}
|
||||
|
||||
func runCgo(pkgdir, tmpdir string, env []string) (files, displayfiles []string, err error) {
|
||||
// Use go/build to open cgo files and determine the cgo flags, etc, from them.
|
||||
// This is tricky so it's best to avoid reimplementing as much as we can, and
|
||||
// we plan to delete this support once Go 1.12 is released anyways.
|
||||
// TODO(matloob): This isn't completely correct because we're using the Default
|
||||
// context. Perhaps we should more accurately fill in the context.
|
||||
bp, err := build.ImportDir(pkgdir, build.ImportMode(0))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
for _, ev := range env {
|
||||
if v := strings.TrimPrefix(ev, "CGO_CPPFLAGS"); v != ev {
|
||||
bp.CgoCPPFLAGS = append(bp.CgoCPPFLAGS, strings.Fields(v)...)
|
||||
} else if v := strings.TrimPrefix(ev, "CGO_CFLAGS"); v != ev {
|
||||
bp.CgoCFLAGS = append(bp.CgoCFLAGS, strings.Fields(v)...)
|
||||
} else if v := strings.TrimPrefix(ev, "CGO_CXXFLAGS"); v != ev {
|
||||
bp.CgoCXXFLAGS = append(bp.CgoCXXFLAGS, strings.Fields(v)...)
|
||||
} else if v := strings.TrimPrefix(ev, "CGO_LDFLAGS"); v != ev {
|
||||
bp.CgoLDFLAGS = append(bp.CgoLDFLAGS, strings.Fields(v)...)
|
||||
}
|
||||
}
|
||||
return cgo.Run(bp, pkgdir, tmpdir, true)
|
||||
}
|
318
vendor/golang.org/x/tools/go/packages/golist_fallback_testmain.go
generated
vendored
Normal file
318
vendor/golang.org/x/tools/go/packages/golist_fallback_testmain.go
generated
vendored
Normal file
@@ -0,0 +1,318 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file is largely based on the Go 1.10-era cmd/go/internal/test/test.go
|
||||
// testmain generation code.
|
||||
|
||||
package packages
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/doc"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/template"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// TODO(matloob): Delete this file once Go 1.12 is released.
|
||||
|
||||
// This file complements golist_fallback.go by providing
|
||||
// support for generating testmains.
|
||||
|
||||
func generateTestmain(out string, testPkg, xtestPkg *Package) (extraimports, extradeps []string, err error) {
|
||||
testFuncs, err := loadTestFuncs(testPkg, xtestPkg)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
extraimports = []string{"testing", "testing/internal/testdeps"}
|
||||
if testFuncs.TestMain == nil {
|
||||
extraimports = append(extraimports, "os")
|
||||
}
|
||||
// Transitive dependencies of ("testing", "testing/internal/testdeps").
|
||||
// os is part of the transitive closure so it and its transitive dependencies are
|
||||
// included regardless of whether it's imported in the template below.
|
||||
extradeps = []string{
|
||||
"errors",
|
||||
"internal/cpu",
|
||||
"unsafe",
|
||||
"internal/bytealg",
|
||||
"internal/race",
|
||||
"runtime/internal/atomic",
|
||||
"runtime/internal/sys",
|
||||
"runtime",
|
||||
"sync/atomic",
|
||||
"sync",
|
||||
"io",
|
||||
"unicode",
|
||||
"unicode/utf8",
|
||||
"bytes",
|
||||
"math",
|
||||
"syscall",
|
||||
"time",
|
||||
"internal/poll",
|
||||
"internal/syscall/unix",
|
||||
"internal/testlog",
|
||||
"os",
|
||||
"math/bits",
|
||||
"strconv",
|
||||
"reflect",
|
||||
"fmt",
|
||||
"sort",
|
||||
"strings",
|
||||
"flag",
|
||||
"runtime/debug",
|
||||
"context",
|
||||
"runtime/trace",
|
||||
"testing",
|
||||
"bufio",
|
||||
"regexp/syntax",
|
||||
"regexp",
|
||||
"compress/flate",
|
||||
"encoding/binary",
|
||||
"hash",
|
||||
"hash/crc32",
|
||||
"compress/gzip",
|
||||
"path/filepath",
|
||||
"io/ioutil",
|
||||
"text/tabwriter",
|
||||
"runtime/pprof",
|
||||
"testing/internal/testdeps",
|
||||
}
|
||||
return extraimports, extradeps, writeTestmain(out, testFuncs)
|
||||
}
|
||||
|
||||
// The following is adapted from the cmd/go testmain generation code.
|
||||
|
||||
// isTestFunc tells whether fn has the type of a testing function. arg
|
||||
// specifies the parameter type we look for: B, M or T.
|
||||
func isTestFunc(fn *ast.FuncDecl, arg string) bool {
|
||||
if fn.Type.Results != nil && len(fn.Type.Results.List) > 0 ||
|
||||
fn.Type.Params.List == nil ||
|
||||
len(fn.Type.Params.List) != 1 ||
|
||||
len(fn.Type.Params.List[0].Names) > 1 {
|
||||
return false
|
||||
}
|
||||
ptr, ok := fn.Type.Params.List[0].Type.(*ast.StarExpr)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
// We can't easily check that the type is *testing.M
|
||||
// because we don't know how testing has been imported,
|
||||
// but at least check that it's *M or *something.M.
|
||||
// Same applies for B and T.
|
||||
if name, ok := ptr.X.(*ast.Ident); ok && name.Name == arg {
|
||||
return true
|
||||
}
|
||||
if sel, ok := ptr.X.(*ast.SelectorExpr); ok && sel.Sel.Name == arg {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isTest tells whether name looks like a test (or benchmark, according to prefix).
|
||||
// It is a Test (say) if there is a character after Test that is not a lower-case letter.
|
||||
// We don't want TesticularCancer.
|
||||
func isTest(name, prefix string) bool {
|
||||
if !strings.HasPrefix(name, prefix) {
|
||||
return false
|
||||
}
|
||||
if len(name) == len(prefix) { // "Test" is ok
|
||||
return true
|
||||
}
|
||||
rune, _ := utf8.DecodeRuneInString(name[len(prefix):])
|
||||
return !unicode.IsLower(rune)
|
||||
}
|
||||
|
||||
// loadTestFuncs returns the testFuncs describing the tests that will be run.
|
||||
func loadTestFuncs(ptest, pxtest *Package) (*testFuncs, error) {
|
||||
t := &testFuncs{
|
||||
TestPackage: ptest,
|
||||
XTestPackage: pxtest,
|
||||
}
|
||||
for _, file := range ptest.GoFiles {
|
||||
if !strings.HasSuffix(file, "_test.go") {
|
||||
continue
|
||||
}
|
||||
if err := t.load(file, "_test", &t.ImportTest, &t.NeedTest); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if pxtest != nil {
|
||||
for _, file := range pxtest.GoFiles {
|
||||
if err := t.load(file, "_xtest", &t.ImportXtest, &t.NeedXtest); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// writeTestmain writes the _testmain.go file for t to the file named out.
|
||||
func writeTestmain(out string, t *testFuncs) error {
|
||||
f, err := os.Create(out)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
if err := testmainTmpl.Execute(f, t); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type testFuncs struct {
|
||||
Tests []testFunc
|
||||
Benchmarks []testFunc
|
||||
Examples []testFunc
|
||||
TestMain *testFunc
|
||||
TestPackage *Package
|
||||
XTestPackage *Package
|
||||
ImportTest bool
|
||||
NeedTest bool
|
||||
ImportXtest bool
|
||||
NeedXtest bool
|
||||
}
|
||||
|
||||
// Tested returns the name of the package being tested.
|
||||
func (t *testFuncs) Tested() string {
|
||||
return t.TestPackage.Name
|
||||
}
|
||||
|
||||
type testFunc struct {
|
||||
Package string // imported package name (_test or _xtest)
|
||||
Name string // function name
|
||||
Output string // output, for examples
|
||||
Unordered bool // output is allowed to be unordered.
|
||||
}
|
||||
|
||||
func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error {
|
||||
var fset = token.NewFileSet()
|
||||
|
||||
f, err := parser.ParseFile(fset, filename, nil, parser.ParseComments)
|
||||
if err != nil {
|
||||
return errors.New("failed to parse test file " + filename)
|
||||
}
|
||||
for _, d := range f.Decls {
|
||||
n, ok := d.(*ast.FuncDecl)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if n.Recv != nil {
|
||||
continue
|
||||
}
|
||||
name := n.Name.String()
|
||||
switch {
|
||||
case name == "TestMain":
|
||||
if isTestFunc(n, "T") {
|
||||
t.Tests = append(t.Tests, testFunc{pkg, name, "", false})
|
||||
*doImport, *seen = true, true
|
||||
continue
|
||||
}
|
||||
err := checkTestFunc(fset, n, "M")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if t.TestMain != nil {
|
||||
return errors.New("multiple definitions of TestMain")
|
||||
}
|
||||
t.TestMain = &testFunc{pkg, name, "", false}
|
||||
*doImport, *seen = true, true
|
||||
case isTest(name, "Test"):
|
||||
err := checkTestFunc(fset, n, "T")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.Tests = append(t.Tests, testFunc{pkg, name, "", false})
|
||||
*doImport, *seen = true, true
|
||||
case isTest(name, "Benchmark"):
|
||||
err := checkTestFunc(fset, n, "B")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, "", false})
|
||||
*doImport, *seen = true, true
|
||||
}
|
||||
}
|
||||
ex := doc.Examples(f)
|
||||
sort.Slice(ex, func(i, j int) bool { return ex[i].Order < ex[j].Order })
|
||||
for _, e := range ex {
|
||||
*doImport = true // import test file whether executed or not
|
||||
if e.Output == "" && !e.EmptyOutput {
|
||||
// Don't run examples with no output.
|
||||
continue
|
||||
}
|
||||
t.Examples = append(t.Examples, testFunc{pkg, "Example" + e.Name, e.Output, e.Unordered})
|
||||
*seen = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkTestFunc(fset *token.FileSet, fn *ast.FuncDecl, arg string) error {
|
||||
if !isTestFunc(fn, arg) {
|
||||
name := fn.Name.String()
|
||||
pos := fset.Position(fn.Pos())
|
||||
return fmt.Errorf("%s: wrong signature for %s, must be: func %s(%s *testing.%s)", pos, name, name, strings.ToLower(arg), arg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var testmainTmpl = template.Must(template.New("main").Parse(`
|
||||
package main
|
||||
|
||||
import (
|
||||
{{if not .TestMain}}
|
||||
"os"
|
||||
{{end}}
|
||||
"testing"
|
||||
"testing/internal/testdeps"
|
||||
|
||||
{{if .ImportTest}}
|
||||
{{if .NeedTest}}_test{{else}}_{{end}} {{.TestPackage.PkgPath | printf "%q"}}
|
||||
{{end}}
|
||||
{{if .ImportXtest}}
|
||||
{{if .NeedXtest}}_xtest{{else}}_{{end}} {{.XTestPackage.PkgPath | printf "%q"}}
|
||||
{{end}}
|
||||
)
|
||||
|
||||
var tests = []testing.InternalTest{
|
||||
{{range .Tests}}
|
||||
{"{{.Name}}", {{.Package}}.{{.Name}}},
|
||||
{{end}}
|
||||
}
|
||||
|
||||
var benchmarks = []testing.InternalBenchmark{
|
||||
{{range .Benchmarks}}
|
||||
{"{{.Name}}", {{.Package}}.{{.Name}}},
|
||||
{{end}}
|
||||
}
|
||||
|
||||
var examples = []testing.InternalExample{
|
||||
{{range .Examples}}
|
||||
{"{{.Name}}", {{.Package}}.{{.Name}}, {{.Output | printf "%q"}}, {{.Unordered}}},
|
||||
{{end}}
|
||||
}
|
||||
|
||||
func init() {
|
||||
testdeps.ImportPath = {{.TestPackage.PkgPath | printf "%q"}}
|
||||
}
|
||||
|
||||
func main() {
|
||||
m := testing.MainStart(testdeps.TestDeps{}, tests, benchmarks, examples)
|
||||
{{with .TestMain}}
|
||||
{{.Package}}.{{.Name}}(m)
|
||||
{{else}}
|
||||
os.Exit(m.Run())
|
||||
{{end}}
|
||||
}
|
||||
|
||||
`))
|
89
vendor/golang.org/x/tools/go/packages/gopackages/main.go
generated
vendored
89
vendor/golang.org/x/tools/go/packages/gopackages/main.go
generated
vendored
@@ -9,6 +9,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/types"
|
||||
@@ -26,16 +27,23 @@ import (
|
||||
|
||||
// flags
|
||||
var (
|
||||
depsFlag = flag.Bool("deps", false, "show dependencies too")
|
||||
cgoFlag = flag.Bool("cgo", true, "process cgo files")
|
||||
mode = flag.String("mode", "metadata", "mode (one of metadata, typecheck, wholeprogram)")
|
||||
private = flag.Bool("private", false, "show non-exported declarations too")
|
||||
depsFlag = flag.Bool("deps", false, "show dependencies too")
|
||||
testFlag = flag.Bool("test", false, "include any tests implied by the patterns")
|
||||
mode = flag.String("mode", "imports", "mode (one of files, imports, types, syntax, allsyntax)")
|
||||
private = flag.Bool("private", false, "show non-exported declarations too")
|
||||
printJSON = flag.Bool("json", false, "print package in JSON form")
|
||||
|
||||
cpuprofile = flag.String("cpuprofile", "", "write CPU profile to this file")
|
||||
memprofile = flag.String("memprofile", "", "write memory profile to this file")
|
||||
traceFlag = flag.String("trace", "", "write trace log to this file")
|
||||
|
||||
buildFlags stringListValue
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.Var(&buildFlags, "buildflag", "pass argument to underlying build system (may be repeated)")
|
||||
}
|
||||
|
||||
func usage() {
|
||||
fmt.Fprintln(os.Stderr, `Usage: gopackages [-deps] [-cgo] [-mode=...] [-private] package...
|
||||
|
||||
@@ -102,25 +110,30 @@ func main() {
|
||||
}()
|
||||
}
|
||||
|
||||
// Load, parse, and type-check the packages named on the command line.
|
||||
cfg := &packages.Config{
|
||||
Mode: packages.LoadSyntax,
|
||||
Tests: *testFlag,
|
||||
BuildFlags: buildFlags,
|
||||
}
|
||||
|
||||
// -mode flag
|
||||
load := packages.TypeCheck
|
||||
switch strings.ToLower(*mode) {
|
||||
case "metadata":
|
||||
load = packages.Metadata
|
||||
case "typecheck":
|
||||
load = packages.TypeCheck
|
||||
case "wholeprogram":
|
||||
load = packages.WholeProgram
|
||||
case "files":
|
||||
cfg.Mode = packages.LoadFiles
|
||||
case "imports":
|
||||
cfg.Mode = packages.LoadImports
|
||||
case "types":
|
||||
cfg.Mode = packages.LoadTypes
|
||||
case "syntax":
|
||||
cfg.Mode = packages.LoadSyntax
|
||||
case "allsyntax":
|
||||
cfg.Mode = packages.LoadAllSyntax
|
||||
default:
|
||||
log.Fatalf("invalid mode: %s", *mode)
|
||||
}
|
||||
|
||||
// Load, parse, and type-check the packages named on the command line.
|
||||
opts := &packages.Options{
|
||||
Error: func(error) {}, // we'll take responsibility for printing errors
|
||||
DisableCgo: !*cgoFlag,
|
||||
}
|
||||
lpkgs, err := load(opts, flag.Args()...)
|
||||
lpkgs, err := packages.Load(cfg, flag.Args()...)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@@ -161,11 +174,15 @@ func main() {
|
||||
}
|
||||
|
||||
func print(lpkg *packages.Package) {
|
||||
if *printJSON {
|
||||
data, _ := json.MarshalIndent(lpkg, "", "\t")
|
||||
os.Stdout.Write(data)
|
||||
return
|
||||
}
|
||||
// title
|
||||
var kind string
|
||||
if lpkg.IsTest {
|
||||
kind = "test "
|
||||
}
|
||||
// TODO(matloob): If IsTest is added back print "test command" or
|
||||
// "test package" for packages with IsTest == true.
|
||||
if lpkg.Name == "main" {
|
||||
kind += "command"
|
||||
} else {
|
||||
@@ -173,24 +190,23 @@ func print(lpkg *packages.Package) {
|
||||
}
|
||||
fmt.Printf("Go %s %q:\n", kind, lpkg.ID) // unique ID
|
||||
fmt.Printf("\tpackage %s\n", lpkg.Name)
|
||||
fmt.Printf("\treflect.Type.PkgPath %q\n", lpkg.PkgPath)
|
||||
|
||||
// characterize type info
|
||||
if lpkg.Type == nil {
|
||||
if lpkg.Types == nil {
|
||||
fmt.Printf("\thas no exported type info\n")
|
||||
} else if !lpkg.Type.Complete() {
|
||||
} else if !lpkg.Types.Complete() {
|
||||
fmt.Printf("\thas incomplete exported type info\n")
|
||||
} else if len(lpkg.Files) == 0 {
|
||||
} else if len(lpkg.Syntax) == 0 {
|
||||
fmt.Printf("\thas complete exported type info\n")
|
||||
} else {
|
||||
fmt.Printf("\thas complete exported type info and typed ASTs\n")
|
||||
}
|
||||
if lpkg.Type != nil && lpkg.IllTyped && len(lpkg.Errors) == 0 {
|
||||
if lpkg.Types != nil && lpkg.IllTyped && len(lpkg.Errors) == 0 {
|
||||
fmt.Printf("\thas an error among its dependencies\n")
|
||||
}
|
||||
|
||||
// source files
|
||||
for _, src := range lpkg.Srcs {
|
||||
for _, src := range lpkg.GoFiles {
|
||||
fmt.Printf("\tfile %s\n", src)
|
||||
}
|
||||
|
||||
@@ -216,9 +232,9 @@ func print(lpkg *packages.Package) {
|
||||
}
|
||||
|
||||
// package members (TypeCheck or WholeProgram mode)
|
||||
if lpkg.Type != nil {
|
||||
qual := types.RelativeTo(lpkg.Type)
|
||||
scope := lpkg.Type.Scope()
|
||||
if lpkg.Types != nil {
|
||||
qual := types.RelativeTo(lpkg.Types)
|
||||
scope := lpkg.Types.Scope()
|
||||
for _, name := range scope.Names() {
|
||||
obj := scope.Lookup(name)
|
||||
if !obj.Exported() && !*private {
|
||||
@@ -239,3 +255,18 @@ func print(lpkg *packages.Package) {
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// stringListValue is a flag.Value that accumulates strings.
|
||||
// e.g. --flag=one --flag=two would produce []string{"one", "two"}.
|
||||
type stringListValue []string
|
||||
|
||||
func newStringListValue(val []string, p *[]string) *stringListValue {
|
||||
*p = val
|
||||
return (*stringListValue)(p)
|
||||
}
|
||||
|
||||
func (ss *stringListValue) Get() interface{} { return []string(*ss) }
|
||||
|
||||
func (ss *stringListValue) String() string { return fmt.Sprintf("%q", *ss) }
|
||||
|
||||
func (ss *stringListValue) Set(s string) error { *ss = append(*ss, s); return nil }
|
||||
|
976
vendor/golang.org/x/tools/go/packages/packages.go
generated
vendored
976
vendor/golang.org/x/tools/go/packages/packages.go
generated
vendored
File diff suppressed because it is too large
Load Diff
11
vendor/golang.org/x/tools/go/packages/packages110_test.go
generated
vendored
Normal file
11
vendor/golang.org/x/tools/go/packages/packages110_test.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !go1.11
|
||||
|
||||
package packages_test
|
||||
|
||||
func init() {
|
||||
usesOldGolist = true
|
||||
}
|
1548
vendor/golang.org/x/tools/go/packages/packages_test.go
generated
vendored
1548
vendor/golang.org/x/tools/go/packages/packages_test.go
generated
vendored
File diff suppressed because it is too large
Load Diff
60
vendor/golang.org/x/tools/go/packages/packagescgo_test.go
generated
vendored
Normal file
60
vendor/golang.org/x/tools/go/packages/packagescgo_test.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build cgo
|
||||
|
||||
package packages_test
|
||||
|
||||
import (
|
||||
"golang.org/x/tools/go/packages"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLoadImportsC(t *testing.T) {
|
||||
// This test checks that when a package depends on the
|
||||
// test variant of "syscall", "unsafe", or "runtime/cgo", that dependency
|
||||
// is not removed when those packages are added when it imports "C".
|
||||
//
|
||||
// For this test to work, the external test of syscall must have a dependency
|
||||
// on net, and net must import "syscall" and "C".
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skipf("skipping on windows; packages on windows do not satisfy conditions for test.")
|
||||
}
|
||||
if runtime.GOOS == "plan9" {
|
||||
// See https://github.com/golang/go/issues/27100.
|
||||
t.Skip(`skipping on plan9; for some reason "net [syscall.test]" is not loaded`)
|
||||
}
|
||||
|
||||
cfg := &packages.Config{
|
||||
Mode: packages.LoadImports,
|
||||
Tests: true,
|
||||
}
|
||||
initial, err := packages.Load(cfg, "syscall", "net")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to load imports: %v", err)
|
||||
}
|
||||
|
||||
_, all := importGraph(initial)
|
||||
|
||||
for _, test := range []struct {
|
||||
pattern string
|
||||
wantImport string // an import to check for
|
||||
}{
|
||||
{"net", "syscall:syscall"},
|
||||
{"net [syscall.test]", "syscall:syscall [syscall.test]"},
|
||||
{"syscall_test [syscall.test]", "net:net [syscall.test]"},
|
||||
} {
|
||||
// Test the import paths.
|
||||
pkg := all[test.pattern]
|
||||
if pkg == nil {
|
||||
t.Errorf("package %q not loaded", test.pattern)
|
||||
continue
|
||||
}
|
||||
if imports := strings.Join(imports(pkg), " "); !strings.Contains(imports, test.wantImport) {
|
||||
t.Errorf("package %q: got \n%s, \nwant to have %s", test.pattern, imports, test.wantImport)
|
||||
}
|
||||
}
|
||||
}
|
328
vendor/golang.org/x/tools/go/packages/packagestest/expect.go
generated
vendored
Normal file
328
vendor/golang.org/x/tools/go/packages/packagestest/expect.go
generated
vendored
Normal file
@@ -0,0 +1,328 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package packagestest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/token"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/go/expect"
|
||||
)
|
||||
|
||||
const (
|
||||
markMethod = "mark"
|
||||
eofIdentifier = "EOF"
|
||||
)
|
||||
|
||||
// Expect invokes the supplied methods for all expectation notes found in
|
||||
// the exported source files.
|
||||
//
|
||||
// All exported go source files are parsed to collect the expectation
|
||||
// notes.
|
||||
// See the documentation for expect.Parse for how the notes are collected
|
||||
// and parsed.
|
||||
//
|
||||
// The methods are supplied as a map of name to function, and those functions
|
||||
// will be matched against the expectations by name.
|
||||
// Notes with no matching function will be skipped, and functions with no
|
||||
// matching notes will not be invoked.
|
||||
// If there are no registered markers yet, a special pass will be run first
|
||||
// which adds any markers declared with @mark(Name, pattern) or @name. These
|
||||
// call the Mark method to add the marker to the global set.
|
||||
// You can register the "mark" method to override these in your own call to
|
||||
// Expect. The bound Mark function is usable directly in your method map, so
|
||||
// exported.Expect(map[string]interface{}{"mark": exported.Mark})
|
||||
// replicates the built in behavior.
|
||||
//
|
||||
// Method invocation
|
||||
//
|
||||
// When invoking a method the expressions in the parameter list need to be
|
||||
// converted to values to be passed to the method.
|
||||
// There are a very limited set of types the arguments are allowed to be.
|
||||
// expect.Comment : passed the Comment instance being evaluated.
|
||||
// string : can be supplied either a string literal or an identifier.
|
||||
// int : can only be supplied an integer literal.
|
||||
// token.Pos : has a file position calculated as described below.
|
||||
// token.Position : has a file position calculated as described below.
|
||||
//
|
||||
// Position calculation
|
||||
//
|
||||
// There is some extra handling when a parameter is being coerced into a
|
||||
// token.Pos, token.Position or Range type argument.
|
||||
//
|
||||
// If the parameter is an identifier, it will be treated as the name of an
|
||||
// marker to look up (as if markers were global variables).
|
||||
//
|
||||
// If it is a string or regular expression, then it will be passed to
|
||||
// expect.MatchBefore to look up a match in the line at which it was declared.
|
||||
//
|
||||
// It is safe to call this repeatedly with different method sets, but it is
|
||||
// not safe to call it concurrently.
|
||||
func (e *Exported) Expect(methods map[string]interface{}) error {
|
||||
if err := e.getNotes(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := e.getMarkers(); err != nil {
|
||||
return err
|
||||
}
|
||||
var err error
|
||||
ms := make(map[string]method, len(methods))
|
||||
for name, f := range methods {
|
||||
mi := method{f: reflect.ValueOf(f)}
|
||||
mi.converters = make([]converter, mi.f.Type().NumIn())
|
||||
for i := 0; i < len(mi.converters); i++ {
|
||||
mi.converters[i], err = e.buildConverter(mi.f.Type().In(i))
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid method %v: %v", name, err)
|
||||
}
|
||||
}
|
||||
ms[name] = mi
|
||||
}
|
||||
for _, n := range e.notes {
|
||||
if n.Args == nil {
|
||||
// simple identifier form, convert to a call to mark
|
||||
n = &expect.Note{
|
||||
Pos: n.Pos,
|
||||
Name: markMethod,
|
||||
Args: []interface{}{n.Name, n.Name},
|
||||
}
|
||||
}
|
||||
mi, ok := ms[n.Name]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
params := make([]reflect.Value, len(mi.converters))
|
||||
args := n.Args
|
||||
for i, convert := range mi.converters {
|
||||
params[i], args, err = convert(n, args)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%v: %v", e.fset.Position(n.Pos), err)
|
||||
}
|
||||
}
|
||||
if len(args) > 0 {
|
||||
return fmt.Errorf("%v: unwanted args got %+v extra", e.fset.Position(n.Pos), args)
|
||||
}
|
||||
//TODO: catch the error returned from the method
|
||||
mi.f.Call(params)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Range struct {
|
||||
Start token.Pos
|
||||
End token.Pos
|
||||
}
|
||||
|
||||
// Mark adds a new marker to the known set.
|
||||
func (e *Exported) Mark(name string, r Range) {
|
||||
if e.markers == nil {
|
||||
e.markers = make(map[string]Range)
|
||||
}
|
||||
e.markers[name] = r
|
||||
}
|
||||
|
||||
func (e *Exported) getNotes() error {
|
||||
if e.notes != nil {
|
||||
return nil
|
||||
}
|
||||
notes := []*expect.Note{}
|
||||
for _, module := range e.written {
|
||||
for _, filename := range module {
|
||||
if !strings.HasSuffix(filename, ".go") {
|
||||
continue
|
||||
}
|
||||
l, err := expect.Parse(e.fset, filename, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to extract expectations: %v", err)
|
||||
}
|
||||
notes = append(notes, l...)
|
||||
}
|
||||
}
|
||||
e.notes = notes
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Exported) getMarkers() error {
|
||||
if e.markers != nil {
|
||||
return nil
|
||||
}
|
||||
// set markers early so that we don't call getMarkers again from Expect
|
||||
e.markers = make(map[string]Range)
|
||||
return e.Expect(map[string]interface{}{
|
||||
markMethod: e.Mark,
|
||||
})
|
||||
}
|
||||
|
||||
var (
|
||||
noteType = reflect.TypeOf((*expect.Note)(nil))
|
||||
identifierType = reflect.TypeOf(expect.Identifier(""))
|
||||
posType = reflect.TypeOf(token.Pos(0))
|
||||
positionType = reflect.TypeOf(token.Position{})
|
||||
rangeType = reflect.TypeOf(Range{})
|
||||
)
|
||||
|
||||
// converter converts from a marker's argument parsed from the comment to
|
||||
// reflect values passed to the method during Invoke.
|
||||
// It takes the args remaining, and returns the args it did not consume.
|
||||
// This allows a converter to consume 0 args for well known types, or multiple
|
||||
// args for compound types.
|
||||
type converter func(*expect.Note, []interface{}) (reflect.Value, []interface{}, error)
|
||||
|
||||
// method is used to track information about Invoke methods that is expensive to
|
||||
// calculate so that we can work it out once rather than per marker.
|
||||
type method struct {
|
||||
f reflect.Value // the reflect value of the passed in method
|
||||
converters []converter // the parameter converters for the method
|
||||
}
|
||||
|
||||
// buildConverter works out what function should be used to go from an ast expressions to a reflect
|
||||
// value of the type expected by a method.
|
||||
// It is called when only the target type is know, it returns converters that are flexible across
|
||||
// all supported expression types for that target type.
|
||||
func (e *Exported) buildConverter(pt reflect.Type) (converter, error) {
|
||||
switch {
|
||||
case pt == noteType:
|
||||
return func(n *expect.Note, args []interface{}) (reflect.Value, []interface{}, error) {
|
||||
return reflect.ValueOf(n), args, nil
|
||||
}, nil
|
||||
case pt == posType:
|
||||
return func(n *expect.Note, args []interface{}) (reflect.Value, []interface{}, error) {
|
||||
r, remains, err := e.rangeConverter(n, args)
|
||||
if err != nil {
|
||||
return reflect.Value{}, nil, err
|
||||
}
|
||||
return reflect.ValueOf(r.Start), remains, nil
|
||||
}, nil
|
||||
case pt == positionType:
|
||||
return func(n *expect.Note, args []interface{}) (reflect.Value, []interface{}, error) {
|
||||
r, remains, err := e.rangeConverter(n, args)
|
||||
if err != nil {
|
||||
return reflect.Value{}, nil, err
|
||||
}
|
||||
return reflect.ValueOf(e.fset.Position(r.Start)), remains, nil
|
||||
}, nil
|
||||
case pt == rangeType:
|
||||
return func(n *expect.Note, args []interface{}) (reflect.Value, []interface{}, error) {
|
||||
r, remains, err := e.rangeConverter(n, args)
|
||||
if err != nil {
|
||||
return reflect.Value{}, nil, err
|
||||
}
|
||||
return reflect.ValueOf(r), remains, nil
|
||||
}, nil
|
||||
case pt == identifierType:
|
||||
return func(n *expect.Note, args []interface{}) (reflect.Value, []interface{}, error) {
|
||||
arg := args[0]
|
||||
args = args[1:]
|
||||
switch arg := arg.(type) {
|
||||
case expect.Identifier:
|
||||
return reflect.ValueOf(arg), args, nil
|
||||
default:
|
||||
return reflect.Value{}, nil, fmt.Errorf("cannot convert %v to string", arg)
|
||||
}
|
||||
}, nil
|
||||
case pt.Kind() == reflect.String:
|
||||
return func(n *expect.Note, args []interface{}) (reflect.Value, []interface{}, error) {
|
||||
arg := args[0]
|
||||
args = args[1:]
|
||||
switch arg := arg.(type) {
|
||||
case expect.Identifier:
|
||||
return reflect.ValueOf(string(arg)), args, nil
|
||||
case string:
|
||||
return reflect.ValueOf(arg), args, nil
|
||||
default:
|
||||
return reflect.Value{}, nil, fmt.Errorf("cannot convert %v to string", arg)
|
||||
}
|
||||
}, nil
|
||||
case pt.Kind() == reflect.Int64:
|
||||
return func(n *expect.Note, args []interface{}) (reflect.Value, []interface{}, error) {
|
||||
arg := args[0]
|
||||
args = args[1:]
|
||||
switch arg := arg.(type) {
|
||||
case int64:
|
||||
return reflect.ValueOf(arg), args, nil
|
||||
default:
|
||||
return reflect.Value{}, nil, fmt.Errorf("cannot convert %v to int", arg)
|
||||
}
|
||||
}, nil
|
||||
case pt.Kind() == reflect.Bool:
|
||||
return func(n *expect.Note, args []interface{}) (reflect.Value, []interface{}, error) {
|
||||
arg := args[0]
|
||||
args = args[1:]
|
||||
b, ok := arg.(bool)
|
||||
if !ok {
|
||||
return reflect.Value{}, nil, fmt.Errorf("cannot convert %v to bool", arg)
|
||||
}
|
||||
return reflect.ValueOf(b), args, nil
|
||||
}, nil
|
||||
case pt.Kind() == reflect.Slice:
|
||||
return func(n *expect.Note, args []interface{}) (reflect.Value, []interface{}, error) {
|
||||
converter, err := e.buildConverter(pt.Elem())
|
||||
if err != nil {
|
||||
return reflect.Value{}, nil, err
|
||||
}
|
||||
result := reflect.MakeSlice(reflect.SliceOf(pt.Elem()), 0, len(args))
|
||||
for range args {
|
||||
value, remains, err := converter(n, args)
|
||||
if err != nil {
|
||||
return reflect.Value{}, nil, err
|
||||
}
|
||||
result = reflect.Append(result, value)
|
||||
args = remains
|
||||
}
|
||||
return result, args, nil
|
||||
}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("param has invalid type %v", pt)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Exported) rangeConverter(n *expect.Note, args []interface{}) (Range, []interface{}, error) {
|
||||
if len(args) < 1 {
|
||||
return Range{}, nil, fmt.Errorf("missing argument")
|
||||
}
|
||||
arg := args[0]
|
||||
args = args[1:]
|
||||
switch arg := arg.(type) {
|
||||
case expect.Identifier:
|
||||
// handle the special identifiers
|
||||
switch arg {
|
||||
case eofIdentifier:
|
||||
// end of file identifier, look up the current file
|
||||
f := e.fset.File(n.Pos)
|
||||
eof := f.Pos(f.Size())
|
||||
return Range{Start: eof, End: token.NoPos}, args, nil
|
||||
default:
|
||||
// look up an marker by name
|
||||
mark, ok := e.markers[string(arg)]
|
||||
if !ok {
|
||||
return Range{}, nil, fmt.Errorf("cannot find marker %v", arg)
|
||||
}
|
||||
return mark, args, nil
|
||||
}
|
||||
case string:
|
||||
start, end, err := expect.MatchBefore(e.fset, e.fileContents, n.Pos, arg)
|
||||
if err != nil {
|
||||
return Range{}, nil, err
|
||||
}
|
||||
if start == token.NoPos {
|
||||
return Range{}, nil, fmt.Errorf("%v: pattern %s did not match", e.fset.Position(n.Pos), arg)
|
||||
}
|
||||
return Range{Start: start, End: end}, args, nil
|
||||
case *regexp.Regexp:
|
||||
start, end, err := expect.MatchBefore(e.fset, e.fileContents, n.Pos, arg)
|
||||
if err != nil {
|
||||
return Range{}, nil, err
|
||||
}
|
||||
if start == token.NoPos {
|
||||
return Range{}, nil, fmt.Errorf("%v: pattern %s did not match", e.fset.Position(n.Pos), arg)
|
||||
}
|
||||
return Range{Start: start, End: end}, args, nil
|
||||
default:
|
||||
return Range{}, nil, fmt.Errorf("cannot convert %v to pos", arg)
|
||||
}
|
||||
}
|
66
vendor/golang.org/x/tools/go/packages/packagestest/expect_test.go
generated
vendored
Normal file
66
vendor/golang.org/x/tools/go/packages/packagestest/expect_test.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package packagestest_test
|
||||
|
||||
import (
|
||||
"go/token"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/tools/go/expect"
|
||||
"golang.org/x/tools/go/packages/packagestest"
|
||||
)
|
||||
|
||||
func TestExpect(t *testing.T) {
|
||||
exported := packagestest.Export(t, packagestest.GOPATH, []packagestest.Module{{
|
||||
Name: "golang.org/fake",
|
||||
Files: packagestest.MustCopyFileTree("testdata"),
|
||||
}})
|
||||
defer exported.Cleanup()
|
||||
count := 0
|
||||
if err := exported.Expect(map[string]interface{}{
|
||||
"check": func(src, target token.Position) {
|
||||
count++
|
||||
},
|
||||
"boolArg": func(n *expect.Note, yes, no bool) {
|
||||
if !yes {
|
||||
t.Errorf("Expected boolArg first param to be true")
|
||||
}
|
||||
if no {
|
||||
t.Errorf("Expected boolArg second param to be false")
|
||||
}
|
||||
},
|
||||
"intArg": func(n *expect.Note, i int64) {
|
||||
if i != 42 {
|
||||
t.Errorf("Expected intarg to be 42")
|
||||
}
|
||||
},
|
||||
"stringArg": func(n *expect.Note, name expect.Identifier, value string) {
|
||||
if string(name) != value {
|
||||
t.Errorf("Got string arg %v expected %v", value, name)
|
||||
}
|
||||
},
|
||||
"directNote": func(n *expect.Note) {},
|
||||
"range": func(r packagestest.Range) {
|
||||
if r.Start == token.NoPos || r.Start == 0 {
|
||||
t.Errorf("Range had no valid starting position")
|
||||
}
|
||||
if r.End == token.NoPos || r.End == 0 {
|
||||
t.Errorf("Range had no valid ending position")
|
||||
} else if r.End <= r.Start {
|
||||
t.Errorf("Range ending was not greater than start")
|
||||
}
|
||||
},
|
||||
"checkEOF": func(n *expect.Note, p token.Pos) {
|
||||
if p <= n.Pos {
|
||||
t.Errorf("EOF was before the checkEOF note")
|
||||
}
|
||||
},
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if count == 0 {
|
||||
t.Fatalf("No tests were run")
|
||||
}
|
||||
}
|
281
vendor/golang.org/x/tools/go/packages/packagestest/export.go
generated
vendored
Normal file
281
vendor/golang.org/x/tools/go/packages/packagestest/export.go
generated
vendored
Normal file
@@ -0,0 +1,281 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
Package packagestest creates temporary projects on disk for testing go tools on.
|
||||
|
||||
By changing the exporter used, you can create projects for multiple build
|
||||
systems from the same description, and run the same tests on them in many
|
||||
cases.
|
||||
*/
|
||||
package packagestest
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/token"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/tools/go/expect"
|
||||
"golang.org/x/tools/go/packages"
|
||||
)
|
||||
|
||||
var (
|
||||
skipCleanup = flag.Bool("skip-cleanup", false, "Do not delete the temporary export folders") // for debugging
|
||||
)
|
||||
|
||||
// Module is a representation of a go module.
|
||||
type Module struct {
|
||||
// Name is the base name of the module as it would be in the go.mod file.
|
||||
Name string
|
||||
// Files is the set of source files for all packages that make up the module.
|
||||
// The keys are the file fragment that follows the module name, the value can
|
||||
// be a string or byte slice, in which case it is the contents of the
|
||||
// file, otherwise it must be a Writer function.
|
||||
Files map[string]interface{}
|
||||
}
|
||||
|
||||
// A Writer is a function that writes out a test file.
|
||||
// It is provided the name of the file to write, and may return an error if it
|
||||
// cannot write the file.
|
||||
// These are used as the content of the Files map in a Module.
|
||||
type Writer func(filename string) error
|
||||
|
||||
// Exported is returned by the Export function to report the structure that was produced on disk.
|
||||
type Exported struct {
|
||||
// Config is a correctly configured packages.Config ready to be passed to packages.Load.
|
||||
// Exactly what it will contain varies depending on the Exporter being used.
|
||||
Config *packages.Config
|
||||
|
||||
temp string // the temporary directory that was exported to
|
||||
primary string // the first non GOROOT module that was exported
|
||||
written map[string]map[string]string // the full set of exported files
|
||||
fset *token.FileSet // The file set used when parsing expectations
|
||||
notes []*expect.Note // The list of expectations extracted from go source files
|
||||
markers map[string]Range // The set of markers extracted from go source files
|
||||
contents map[string][]byte
|
||||
}
|
||||
|
||||
// Exporter implementations are responsible for converting from the generic description of some
|
||||
// test data to a driver specific file layout.
|
||||
type Exporter interface {
|
||||
// Name reports the name of the exporter, used in logging and sub-test generation.
|
||||
Name() string
|
||||
// Filename reports the system filename for test data source file.
|
||||
// It is given the base directory, the module the file is part of and the filename fragment to
|
||||
// work from.
|
||||
Filename(exported *Exported, module, fragment string) string
|
||||
// Finalize is called once all files have been written to write any extra data needed and modify
|
||||
// the Config to match. It is handed the full list of modules that were encountered while writing
|
||||
// files.
|
||||
Finalize(exported *Exported) error
|
||||
}
|
||||
|
||||
// All is the list of known exporters.
|
||||
// This is used by TestAll to run tests with all the exporters.
|
||||
var All []Exporter
|
||||
|
||||
// TestAll invokes the testing function once for each exporter registered in
|
||||
// the All global.
|
||||
// Each exporter will be run as a sub-test named after the exporter being used.
|
||||
func TestAll(t *testing.T, f func(*testing.T, Exporter)) {
|
||||
t.Helper()
|
||||
for _, e := range All {
|
||||
t.Run(e.Name(), func(t *testing.T) {
|
||||
t.Helper()
|
||||
f(t, e)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Export is called to write out a test directory from within a test function.
|
||||
// It takes the exporter and the build system agnostic module descriptions, and
|
||||
// uses them to build a temporary directory.
|
||||
// It returns an Exported with the results of the export.
|
||||
// The Exported.Config is prepared for loading from the exported data.
|
||||
// You must invoke Exported.Cleanup on the returned value to clean up.
|
||||
// The file deletion in the cleanup can be skipped by setting the skip-cleanup
|
||||
// flag when invoking the test, allowing the temporary directory to be left for
|
||||
// debugging tests.
|
||||
func Export(t *testing.T, exporter Exporter, modules []Module) *Exported {
|
||||
t.Helper()
|
||||
dirname := strings.Replace(t.Name(), "/", "_", -1)
|
||||
dirname = strings.Replace(dirname, "#", "_", -1) // duplicate subtests get a #NNN suffix.
|
||||
temp, err := ioutil.TempDir("", dirname)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
exported := &Exported{
|
||||
Config: &packages.Config{
|
||||
Dir: temp,
|
||||
Env: append(os.Environ(), "GOPACKAGESDRIVER=off"),
|
||||
},
|
||||
temp: temp,
|
||||
primary: modules[0].Name,
|
||||
written: map[string]map[string]string{},
|
||||
fset: token.NewFileSet(),
|
||||
contents: map[string][]byte{},
|
||||
}
|
||||
defer func() {
|
||||
if t.Failed() || t.Skipped() {
|
||||
exported.Cleanup()
|
||||
}
|
||||
}()
|
||||
for _, module := range modules {
|
||||
for fragment, value := range module.Files {
|
||||
fullpath := exporter.Filename(exported, module.Name, filepath.FromSlash(fragment))
|
||||
written, ok := exported.written[module.Name]
|
||||
if !ok {
|
||||
written = map[string]string{}
|
||||
exported.written[module.Name] = written
|
||||
}
|
||||
written[fragment] = fullpath
|
||||
if err := os.MkdirAll(filepath.Dir(fullpath), 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
switch value := value.(type) {
|
||||
case Writer:
|
||||
if err := value(fullpath); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
case string:
|
||||
if err := ioutil.WriteFile(fullpath, []byte(value), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
default:
|
||||
t.Fatalf("Invalid type %T in files, must be string or Writer", value)
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := exporter.Finalize(exported); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return exported
|
||||
}
|
||||
|
||||
// Script returns a Writer that writes out contents to the file and sets the
|
||||
// executable bit on the created file.
|
||||
// It is intended for source files that are shell scripts.
|
||||
func Script(contents string) Writer {
|
||||
return func(filename string) error {
|
||||
return ioutil.WriteFile(filename, []byte(contents), 0755)
|
||||
}
|
||||
}
|
||||
|
||||
// Link returns a Writer that creates a hard link from the specified source to
|
||||
// the required file.
|
||||
// This is used to link testdata files into the generated testing tree.
|
||||
func Link(source string) Writer {
|
||||
return func(filename string) error {
|
||||
return os.Link(source, filename)
|
||||
}
|
||||
}
|
||||
|
||||
// Symlink returns a Writer that creates a symlink from the specified source to the
|
||||
// required file.
|
||||
// This is used to link testdata files into the generated testing tree.
|
||||
func Symlink(source string) Writer {
|
||||
if !strings.HasPrefix(source, ".") {
|
||||
if abspath, err := filepath.Abs(source); err == nil {
|
||||
if _, err := os.Stat(source); !os.IsNotExist(err) {
|
||||
source = abspath
|
||||
}
|
||||
}
|
||||
}
|
||||
return func(filename string) error {
|
||||
return os.Symlink(source, filename)
|
||||
}
|
||||
}
|
||||
|
||||
// Copy returns a Writer that copies a file from the specified source to the
|
||||
// required file.
|
||||
// This is used to copy testdata files into the generated testing tree.
|
||||
func Copy(source string) Writer {
|
||||
return func(filename string) error {
|
||||
stat, err := os.Stat(source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !stat.Mode().IsRegular() {
|
||||
// cannot copy non-regular files (e.g., directories,
|
||||
// symlinks, devices, etc.)
|
||||
return fmt.Errorf("Cannot copy non regular file %s", source)
|
||||
}
|
||||
contents, err := ioutil.ReadFile(source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(filename, contents, stat.Mode())
|
||||
}
|
||||
}
|
||||
|
||||
// MustCopyFileTree returns a file set for a module based on a real directory tree.
|
||||
// It scans the directory tree anchored at root and adds a Copy writer to the
|
||||
// map for every file found.
|
||||
// This is to enable the common case in tests where you have a full copy of the
|
||||
// package in your testdata.
|
||||
// This will panic if there is any kind of error trying to walk the file tree.
|
||||
func MustCopyFileTree(root string) map[string]interface{} {
|
||||
result := map[string]interface{}{}
|
||||
if err := filepath.Walk(filepath.FromSlash(root), func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
fragment, err := filepath.Rel(root, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result[fragment] = Copy(path)
|
||||
return nil
|
||||
}); err != nil {
|
||||
log.Panic(fmt.Sprintf("MustCopyFileTree failed: %v", err))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Cleanup removes the temporary directory (unless the --skip-cleanup flag was set)
|
||||
// It is safe to call cleanup multiple times.
|
||||
func (e *Exported) Cleanup() {
|
||||
if e.temp == "" {
|
||||
return
|
||||
}
|
||||
if *skipCleanup {
|
||||
log.Printf("Skipping cleanup of temp dir: %s", e.temp)
|
||||
return
|
||||
}
|
||||
os.RemoveAll(e.temp) // ignore errors
|
||||
e.temp = ""
|
||||
}
|
||||
|
||||
// Temp returns the temporary directory that was generated.
|
||||
func (e *Exported) Temp() string {
|
||||
return e.temp
|
||||
}
|
||||
|
||||
// File returns the full path for the given module and file fragment.
|
||||
func (e *Exported) File(module, fragment string) string {
|
||||
if m := e.written[module]; m != nil {
|
||||
return m[fragment]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (e *Exported) fileContents(filename string) ([]byte, error) {
|
||||
if content, found := e.contents[filename]; found {
|
||||
return content, nil
|
||||
}
|
||||
content, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return content, nil
|
||||
}
|
73
vendor/golang.org/x/tools/go/packages/packagestest/export_test.go
generated
vendored
Normal file
73
vendor/golang.org/x/tools/go/packages/packagestest/export_test.go
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package packagestest_test
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/tools/go/packages/packagestest"
|
||||
)
|
||||
|
||||
var testdata = []packagestest.Module{{
|
||||
Name: "golang.org/fake1",
|
||||
Files: map[string]interface{}{
|
||||
"a.go": packagestest.Symlink("testdata/a.go"),
|
||||
"b.go": "package fake1",
|
||||
},
|
||||
}, {
|
||||
Name: "golang.org/fake2",
|
||||
Files: map[string]interface{}{
|
||||
"other/a.go": "package fake2",
|
||||
},
|
||||
}, {
|
||||
Name: "golang.org/fake2/v2",
|
||||
Files: map[string]interface{}{
|
||||
"other/a.go": "package fake2",
|
||||
},
|
||||
}}
|
||||
|
||||
type fileTest struct {
|
||||
module, fragment, expect string
|
||||
check func(t *testing.T, filename string)
|
||||
}
|
||||
|
||||
func checkFiles(t *testing.T, exported *packagestest.Exported, tests []fileTest) {
|
||||
for _, test := range tests {
|
||||
expect := filepath.Join(exported.Temp(), filepath.FromSlash(test.expect))
|
||||
got := exported.File(test.module, test.fragment)
|
||||
if got == "" {
|
||||
t.Errorf("File %v missing from the output", expect)
|
||||
} else if got != expect {
|
||||
t.Errorf("Got file %v, expected %v", got, expect)
|
||||
}
|
||||
if test.check != nil {
|
||||
test.check(t, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func checkLink(expect string) func(t *testing.T, filename string) {
|
||||
expect = filepath.FromSlash(expect)
|
||||
return func(t *testing.T, filename string) {
|
||||
if target, err := os.Readlink(filename); err != nil {
|
||||
t.Errorf("Error checking link %v: %v", filename, err)
|
||||
} else if target != expect {
|
||||
t.Errorf("Link %v does not match, got %v expected %v", filename, target, expect)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func checkContent(expect string) func(t *testing.T, filename string) {
|
||||
return func(t *testing.T, filename string) {
|
||||
if content, err := ioutil.ReadFile(filename); err != nil {
|
||||
t.Errorf("Error reading %v: %v", filename, err)
|
||||
} else if string(content) != expect {
|
||||
t.Errorf("Content of %v does not match, got %v expected %v", filename, string(content), expect)
|
||||
}
|
||||
}
|
||||
}
|
74
vendor/golang.org/x/tools/go/packages/packagestest/gopath.go
generated
vendored
Normal file
74
vendor/golang.org/x/tools/go/packages/packagestest/gopath.go
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package packagestest
|
||||
|
||||
import (
|
||||
"path"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// GOPATH is the exporter that produces GOPATH layouts.
|
||||
// Each "module" is put in it's own GOPATH entry to help test complex cases.
|
||||
// Given the two files
|
||||
// golang.org/repoa#a/a.go
|
||||
// golang.org/repob#b/b.go
|
||||
// You would get the directory layout
|
||||
// /sometemporarydirectory
|
||||
// ├── repoa
|
||||
// │ └── src
|
||||
// │ └── golang.org
|
||||
// │ └── repoa
|
||||
// │ └── a
|
||||
// │ └── a.go
|
||||
// └── repob
|
||||
// └── src
|
||||
// └── golang.org
|
||||
// └── repob
|
||||
// └── b
|
||||
// └── b.go
|
||||
// GOPATH would be set to
|
||||
// /sometemporarydirectory/repoa;/sometemporarydirectory/repob
|
||||
// and the working directory would be
|
||||
// /sometemporarydirectory/repoa/src
|
||||
var GOPATH = gopath{}
|
||||
|
||||
func init() {
|
||||
All = append(All, GOPATH)
|
||||
}
|
||||
|
||||
type gopath struct{}
|
||||
|
||||
func (gopath) Name() string {
|
||||
return "GOPATH"
|
||||
}
|
||||
|
||||
func (gopath) Filename(exported *Exported, module, fragment string) string {
|
||||
return filepath.Join(gopathDir(exported, module), "src", module, fragment)
|
||||
}
|
||||
|
||||
func (gopath) Finalize(exported *Exported) error {
|
||||
exported.Config.Env = append(exported.Config.Env, "GO111MODULE=off")
|
||||
gopath := ""
|
||||
for module := range exported.written {
|
||||
if gopath != "" {
|
||||
gopath += string(filepath.ListSeparator)
|
||||
}
|
||||
dir := gopathDir(exported, module)
|
||||
gopath += dir
|
||||
if module == exported.primary {
|
||||
exported.Config.Dir = filepath.Join(dir, "src")
|
||||
}
|
||||
}
|
||||
exported.Config.Env = append(exported.Config.Env, "GOPATH="+gopath)
|
||||
return nil
|
||||
}
|
||||
|
||||
func gopathDir(exported *Exported, module string) string {
|
||||
dir := path.Base(module)
|
||||
if versionSuffixRE.MatchString(dir) {
|
||||
dir = path.Base(path.Dir(module)) + "_" + dir
|
||||
}
|
||||
return filepath.Join(exported.temp, dir)
|
||||
}
|
28
vendor/golang.org/x/tools/go/packages/packagestest/gopath_test.go
generated
vendored
Normal file
28
vendor/golang.org/x/tools/go/packages/packagestest/gopath_test.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package packagestest_test
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/tools/go/packages/packagestest"
|
||||
)
|
||||
|
||||
func TestGOPATHExport(t *testing.T) {
|
||||
exported := packagestest.Export(t, packagestest.GOPATH, testdata)
|
||||
defer exported.Cleanup()
|
||||
// Check that the cfg contains all the right bits
|
||||
var expectDir = filepath.Join(exported.Temp(), "fake1", "src")
|
||||
if exported.Config.Dir != expectDir {
|
||||
t.Errorf("Got working directory %v expected %v", exported.Config.Dir, expectDir)
|
||||
}
|
||||
checkFiles(t, exported, []fileTest{
|
||||
{"golang.org/fake1", "a.go", "fake1/src/golang.org/fake1/a.go", checkLink("testdata/a.go")},
|
||||
{"golang.org/fake1", "b.go", "fake1/src/golang.org/fake1/b.go", checkContent("package fake1")},
|
||||
{"golang.org/fake2", "other/a.go", "fake2/src/golang.org/fake2/other/a.go", checkContent("package fake2")},
|
||||
{"golang.org/fake2/v2", "other/a.go", "fake2_v2/src/golang.org/fake2/v2/other/a.go", checkContent("package fake2")},
|
||||
})
|
||||
}
|
210
vendor/golang.org/x/tools/go/packages/packagestest/modules.go
generated
vendored
Normal file
210
vendor/golang.org/x/tools/go/packages/packagestest/modules.go
generated
vendored
Normal file
@@ -0,0 +1,210 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package packagestest
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
|
||||
"golang.org/x/tools/go/packages"
|
||||
)
|
||||
|
||||
// Modules is the exporter that produces module layouts.
|
||||
// Each "repository" is put in it's own module, and the module file generated
|
||||
// will have replace directives for all other modules.
|
||||
// Given the two files
|
||||
// golang.org/repoa#a/a.go
|
||||
// golang.org/repob#b/b.go
|
||||
// You would get the directory layout
|
||||
// /sometemporarydirectory
|
||||
// ├── repoa
|
||||
// │ ├── a
|
||||
// │ │ └── a.go
|
||||
// │ └── go.mod
|
||||
// └── repob
|
||||
// ├── b
|
||||
// │ └── b.go
|
||||
// └── go.mod
|
||||
// and the working directory would be
|
||||
// /sometemporarydirectory/repoa
|
||||
var Modules = modules{}
|
||||
|
||||
type modules struct{}
|
||||
|
||||
func (modules) Name() string {
|
||||
return "Modules"
|
||||
}
|
||||
|
||||
func (modules) Filename(exported *Exported, module, fragment string) string {
|
||||
if module == exported.primary {
|
||||
return filepath.Join(primaryDir(exported), fragment)
|
||||
}
|
||||
return filepath.Join(moduleDir(exported, module), fragment)
|
||||
}
|
||||
|
||||
func (modules) Finalize(exported *Exported) error {
|
||||
// Write out the primary module. This module can use symlinks and
|
||||
// other weird stuff, and will be the working dir for the go command.
|
||||
// It depends on all the other modules.
|
||||
primaryDir := primaryDir(exported)
|
||||
exported.Config.Dir = primaryDir
|
||||
exported.written[exported.primary]["go.mod"] = filepath.Join(primaryDir, "go.mod")
|
||||
primaryGomod := "module " + exported.primary + "\nrequire (\n"
|
||||
for other := range exported.written {
|
||||
if other == exported.primary {
|
||||
continue
|
||||
}
|
||||
primaryGomod += fmt.Sprintf("\t%v %v\n", other, moduleVersion(other))
|
||||
}
|
||||
primaryGomod += ")\n"
|
||||
if err := ioutil.WriteFile(filepath.Join(primaryDir, "go.mod"), []byte(primaryGomod), 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create the mod cache so we can rename it later, even if we don't need it.
|
||||
if err := os.MkdirAll(modCache(exported), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write out the go.mod files for the other modules.
|
||||
for module, files := range exported.written {
|
||||
if module == exported.primary {
|
||||
continue
|
||||
}
|
||||
dir := moduleDir(exported, module)
|
||||
|
||||
modfile := filepath.Join(dir, "go.mod")
|
||||
if err := ioutil.WriteFile(modfile, []byte("module "+module+"\n"), 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
files["go.mod"] = modfile
|
||||
}
|
||||
|
||||
// Zip up all the secondary modules into the proxy dir.
|
||||
proxyDir := filepath.Join(exported.temp, "modproxy")
|
||||
for module, files := range exported.written {
|
||||
if module == exported.primary {
|
||||
continue
|
||||
}
|
||||
dir := filepath.Join(proxyDir, module, "@v")
|
||||
|
||||
if err := writeModuleProxy(dir, module, files); err != nil {
|
||||
return fmt.Errorf("creating module proxy dir for %v: %v", module, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Discard the original mod cache dir, which contained the files written
|
||||
// for us by Export.
|
||||
if err := os.Rename(modCache(exported), modCache(exported)+".orig"); err != nil {
|
||||
return err
|
||||
}
|
||||
exported.Config.Env = append(exported.Config.Env,
|
||||
"GO111MODULE=on",
|
||||
"GOPATH="+filepath.Join(exported.temp, "modcache"),
|
||||
"GOPROXY=file://"+filepath.ToSlash(proxyDir))
|
||||
|
||||
// Run go mod download to recreate the mod cache dir with all the extra
|
||||
// stuff in cache. All the files created by Export should be recreated.
|
||||
if err := invokeGo(exported.Config, "mod", "download"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeModuleProxy creates a directory in the proxy dir for a module.
|
||||
func writeModuleProxy(dir, module string, files map[string]string) error {
|
||||
ver := moduleVersion(module)
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// list file. Just the single version.
|
||||
if err := ioutil.WriteFile(filepath.Join(dir, "list"), []byte(ver+"\n"), 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// go.mod, copied from the file written in Finalize.
|
||||
modContents, err := ioutil.ReadFile(files["go.mod"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(filepath.Join(dir, ver+".mod"), modContents, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// info file, just the bare bones.
|
||||
infoContents := []byte(fmt.Sprintf(`{"Version": "%v", "Time":"2017-12-14T13:08:43Z"}`, ver))
|
||||
if err := ioutil.WriteFile(filepath.Join(dir, ver+".info"), infoContents, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// zip of all the source files.
|
||||
f, err := os.OpenFile(filepath.Join(dir, ver+".zip"), os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
z := zip.NewWriter(f)
|
||||
for name, path := range files {
|
||||
zf, err := z.Create(module + "@" + ver + "/" + name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
contents, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := zf.Write(contents); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := z.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func invokeGo(cfg *packages.Config, args ...string) error {
|
||||
stdout := new(bytes.Buffer)
|
||||
stderr := new(bytes.Buffer)
|
||||
cmd := exec.Command("go", args...)
|
||||
cmd.Env = append(append([]string{}, cfg.Env...), "PWD="+cfg.Dir)
|
||||
cmd.Dir = cfg.Dir
|
||||
cmd.Stdout = stdout
|
||||
cmd.Stderr = stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("go %v: %s: %s", args, err, stderr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func modCache(exported *Exported) string {
|
||||
return filepath.Join(exported.temp, "modcache/pkg/mod")
|
||||
}
|
||||
|
||||
func primaryDir(exported *Exported) string {
|
||||
return filepath.Join(exported.temp, "primarymod", path.Base(exported.primary))
|
||||
}
|
||||
|
||||
func moduleDir(exported *Exported, module string) string {
|
||||
return filepath.Join(modCache(exported), path.Dir(module), path.Base(module)+"@"+moduleVersion(module))
|
||||
}
|
||||
|
||||
var versionSuffixRE = regexp.MustCompile(`v\d+`)
|
||||
|
||||
func moduleVersion(module string) string {
|
||||
if versionSuffixRE.MatchString(path.Base(module)) {
|
||||
return path.Base(module) + ".0.0"
|
||||
}
|
||||
return "v1.0.0"
|
||||
}
|
7
vendor/golang.org/x/tools/go/packages/packagestest/modules_111.go
generated
vendored
Normal file
7
vendor/golang.org/x/tools/go/packages/packagestest/modules_111.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
// +build go1.11
|
||||
|
||||
package packagestest
|
||||
|
||||
func init() {
|
||||
All = append(All, Modules)
|
||||
}
|
32
vendor/golang.org/x/tools/go/packages/packagestest/modules_test.go
generated
vendored
Normal file
32
vendor/golang.org/x/tools/go/packages/packagestest/modules_test.go
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build go1.11
|
||||
|
||||
package packagestest_test
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/tools/go/packages/packagestest"
|
||||
)
|
||||
|
||||
func TestModulesExport(t *testing.T) {
|
||||
exported := packagestest.Export(t, packagestest.Modules, testdata)
|
||||
defer exported.Cleanup()
|
||||
// Check that the cfg contains all the right bits
|
||||
var expectDir = filepath.Join(exported.Temp(), "primarymod/fake1")
|
||||
if exported.Config.Dir != expectDir {
|
||||
t.Errorf("Got working directory %v expected %v", exported.Config.Dir, expectDir)
|
||||
}
|
||||
checkFiles(t, exported, []fileTest{
|
||||
{"golang.org/fake1", "go.mod", "primarymod/fake1/go.mod", nil},
|
||||
{"golang.org/fake1", "a.go", "primarymod/fake1/a.go", checkLink("testdata/a.go")},
|
||||
{"golang.org/fake1", "b.go", "primarymod/fake1/b.go", checkContent("package fake1")},
|
||||
{"golang.org/fake2", "go.mod", "modcache/pkg/mod/golang.org/fake2@v1.0.0/go.mod", nil},
|
||||
{"golang.org/fake2", "other/a.go", "modcache/pkg/mod/golang.org/fake2@v1.0.0/other/a.go", checkContent("package fake2")},
|
||||
{"golang.org/fake2/v2", "other/a.go", "modcache/pkg/mod/golang.org/fake2/v2@v2.0.0/other/a.go", checkContent("package fake2")},
|
||||
})
|
||||
}
|
24
vendor/golang.org/x/tools/go/packages/packagestest/testdata/test.go
generated
vendored
Normal file
24
vendor/golang.org/x/tools/go/packages/packagestest/testdata/test.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package fake1
|
||||
|
||||
// This is a test file for the behaviors in Exported.Expect.
|
||||
|
||||
type AThing string //@AThing,mark(StringThing, "AThing"),mark(REThing,re`.T.*g`)
|
||||
|
||||
type Match string //@check("Match",re`[[:upper:]]`)
|
||||
|
||||
//@check(AThing, StringThing)
|
||||
//@check(AThing, REThing)
|
||||
|
||||
//@boolArg(true, false)
|
||||
//@intArg(42)
|
||||
//@stringArg(PlainString, "PlainString")
|
||||
//@stringArg(IdentAsString,IdentAsString)
|
||||
//@directNote()
|
||||
//@range(AThing)
|
||||
|
||||
// The following test should remain at the bottom of the file
|
||||
//@checkEOF(EOF)
|
84
vendor/golang.org/x/tools/go/packages/stdlib_test.go
generated
vendored
84
vendor/golang.org/x/tools/go/packages/stdlib_test.go
generated
vendored
@@ -30,10 +30,14 @@ func TestStdlibMetadata(t *testing.T) {
|
||||
alloc := memstats.Alloc
|
||||
|
||||
// Load, parse and type-check the program.
|
||||
pkgs, err := packages.Metadata(nil, "std")
|
||||
cfg := &packages.Config{Mode: packages.LoadAllSyntax}
|
||||
pkgs, err := packages.Load(cfg, "std")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to load metadata: %v", err)
|
||||
}
|
||||
if packages.PrintErrors(pkgs) > 0 {
|
||||
t.Fatal("there were errors loading standard library")
|
||||
}
|
||||
|
||||
t1 := time.Now()
|
||||
runtime.GC()
|
||||
@@ -42,7 +46,9 @@ func TestStdlibMetadata(t *testing.T) {
|
||||
|
||||
t.Logf("Loaded %d packages", len(pkgs))
|
||||
numPkgs := len(pkgs)
|
||||
if want := 340; numPkgs < want {
|
||||
|
||||
want := 150 // 186 on linux, 185 on windows.
|
||||
if numPkgs < want {
|
||||
t.Errorf("Loaded only %d packages, want at least %d", numPkgs, want)
|
||||
}
|
||||
|
||||
@@ -90,49 +96,41 @@ func TestCgoOption(t *testing.T) {
|
||||
{"net", "cgoLookupHost", "cgo_stub.go"},
|
||||
{"os/user", "current", "lookup_stubs.go"},
|
||||
} {
|
||||
for i := 0; i < 2; i++ { // !cgo, cgo
|
||||
opts := &packages.Options{
|
||||
DisableCgo: i == 0,
|
||||
Error: func(error) {},
|
||||
}
|
||||
pkgs, err := packages.TypeCheck(opts, test.pkg)
|
||||
if err != nil {
|
||||
t.Errorf("Load failed: %v", err)
|
||||
continue
|
||||
}
|
||||
pkg := pkgs[0]
|
||||
obj := pkg.Type.Scope().Lookup(test.name)
|
||||
if obj == nil {
|
||||
t.Errorf("no object %s.%s", test.pkg, test.name)
|
||||
continue
|
||||
}
|
||||
posn := pkg.Fset.Position(obj.Pos())
|
||||
if false {
|
||||
t.Logf("DisableCgo=%t, obj=%s, posn=%s", opts.DisableCgo, obj, posn)
|
||||
}
|
||||
cfg := &packages.Config{Mode: packages.LoadSyntax}
|
||||
pkgs, err := packages.Load(cfg, test.pkg)
|
||||
if err != nil {
|
||||
t.Errorf("Load failed: %v", err)
|
||||
continue
|
||||
}
|
||||
if packages.PrintErrors(pkgs) > 0 {
|
||||
t.Error("there were errors loading standard library")
|
||||
continue
|
||||
}
|
||||
pkg := pkgs[0]
|
||||
obj := pkg.Types.Scope().Lookup(test.name)
|
||||
if obj == nil {
|
||||
t.Errorf("no object %s.%s", test.pkg, test.name)
|
||||
continue
|
||||
}
|
||||
posn := pkg.Fset.Position(obj.Pos())
|
||||
gotFile := filepath.Base(posn.Filename)
|
||||
filesMatch := gotFile == test.genericFile
|
||||
|
||||
gotFile := filepath.Base(posn.Filename)
|
||||
filesMatch := gotFile == test.genericFile
|
||||
if filesMatch {
|
||||
t.Errorf("!DisableCgo: %s found in %s, want native file",
|
||||
obj, gotFile)
|
||||
}
|
||||
|
||||
if !opts.DisableCgo && filesMatch {
|
||||
t.Errorf("!DisableCgo: %s found in %s, want native file",
|
||||
obj, gotFile)
|
||||
} else if opts.DisableCgo && !filesMatch {
|
||||
t.Errorf("DisableCgo: %s found in %s, want %s",
|
||||
obj, gotFile, test.genericFile)
|
||||
}
|
||||
|
||||
// Load the file and check the object is declared at the right place.
|
||||
b, err := ioutil.ReadFile(posn.Filename)
|
||||
if err != nil {
|
||||
t.Errorf("can't read %s: %s", posn.Filename, err)
|
||||
continue
|
||||
}
|
||||
line := string(bytes.Split(b, []byte("\n"))[posn.Line-1])
|
||||
// Don't assume posn.Column is accurate.
|
||||
if !strings.Contains(line, "func "+test.name) {
|
||||
t.Errorf("%s: %s not declared here (looking at %q)", posn, obj, line)
|
||||
}
|
||||
// Load the file and check the object is declared at the right place.
|
||||
b, err := ioutil.ReadFile(posn.Filename)
|
||||
if err != nil {
|
||||
t.Errorf("can't read %s: %s", posn.Filename, err)
|
||||
continue
|
||||
}
|
||||
line := string(bytes.Split(b, []byte("\n"))[posn.Line-1])
|
||||
// Don't assume posn.Column is accurate.
|
||||
if !strings.Contains(line, "func "+test.name) {
|
||||
t.Errorf("%s: %s not declared here (looking at %q)", posn, obj, line)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
3
vendor/golang.org/x/tools/go/packages/testdata/README
generated
vendored
Normal file
3
vendor/golang.org/x/tools/go/packages/testdata/README
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
Test data directories here were created by running go commands with GOPATH set as such:
|
||||
GOPATH=......./testdata/TestNamed_ModulesDedup go get github.com/heschik/tools-testrepo/v2@v2.0.1
|
||||
and then removing the vcs cache directories, which appear to be unnecessary.
|
1
vendor/golang.org/x/tools/go/packages/testdata/TestName_Modules/pkg/mod/cache/download/github.com/heschik/tools-testrepo/@v/list
generated
vendored
Normal file
1
vendor/golang.org/x/tools/go/packages/testdata/TestName_Modules/pkg/mod/cache/download/github.com/heschik/tools-testrepo/@v/list
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
v1.0.0
|
@@ -0,0 +1 @@
|
||||
{"Version":"v1.0.0","Time":"2018-09-28T22:09:08Z"}
|
@@ -0,0 +1 @@
|
||||
module github.com/heschik/tools-testrepo
|
BIN
vendor/golang.org/x/tools/go/packages/testdata/TestName_Modules/pkg/mod/cache/download/github.com/heschik/tools-testrepo/@v/v1.0.0.zip
generated
vendored
Normal file
BIN
vendor/golang.org/x/tools/go/packages/testdata/TestName_Modules/pkg/mod/cache/download/github.com/heschik/tools-testrepo/@v/v1.0.0.zip
generated
vendored
Normal file
Binary file not shown.
@@ -0,0 +1 @@
|
||||
h1:D2qc+R2eCTCyoT8WAYoExXhPBThJWmlYSfB4coWbfBE=
|
1
vendor/golang.org/x/tools/go/packages/testdata/TestName_Modules/pkg/mod/cache/download/github.com/heschik/tools-testrepo/v2/@v/list
generated
vendored
Normal file
1
vendor/golang.org/x/tools/go/packages/testdata/TestName_Modules/pkg/mod/cache/download/github.com/heschik/tools-testrepo/v2/@v/list
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
v2.0.0
|
@@ -0,0 +1 @@
|
||||
{"Version":"v2.0.0","Time":"2018-09-28T22:12:08Z"}
|
@@ -0,0 +1 @@
|
||||
module github.com/heschik/tools-testrepo/v2
|
BIN
vendor/golang.org/x/tools/go/packages/testdata/TestName_Modules/pkg/mod/cache/download/github.com/heschik/tools-testrepo/v2/@v/v2.0.0.zip
generated
vendored
Normal file
BIN
vendor/golang.org/x/tools/go/packages/testdata/TestName_Modules/pkg/mod/cache/download/github.com/heschik/tools-testrepo/v2/@v/v2.0.0.zip
generated
vendored
Normal file
Binary file not shown.
@@ -0,0 +1 @@
|
||||
h1:Ll4Bx8ZD8zg8lD4idX7CAhx/jh16o9dWC2m9SnT1qu0=
|
1
vendor/golang.org/x/tools/go/packages/testdata/TestName_Modules/pkg/mod/github.com/heschik/tools-testrepo/v2@v2.0.0/go.mod
generated
vendored
Normal file
1
vendor/golang.org/x/tools/go/packages/testdata/TestName_Modules/pkg/mod/github.com/heschik/tools-testrepo/v2@v2.0.0/go.mod
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module github.com/heschik/tools-testrepo/v2
|
1
vendor/golang.org/x/tools/go/packages/testdata/TestName_Modules/pkg/mod/github.com/heschik/tools-testrepo/v2@v2.0.0/pkg/pkg.go
generated
vendored
Normal file
1
vendor/golang.org/x/tools/go/packages/testdata/TestName_Modules/pkg/mod/github.com/heschik/tools-testrepo/v2@v2.0.0/pkg/pkg.go
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package pkg
|
1
vendor/golang.org/x/tools/go/packages/testdata/TestName_Modules/pkg/mod/github.com/heschik/tools-testrepo@v1.0.0/go.mod
generated
vendored
Normal file
1
vendor/golang.org/x/tools/go/packages/testdata/TestName_Modules/pkg/mod/github.com/heschik/tools-testrepo@v1.0.0/go.mod
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module github.com/heschik/tools-testrepo
|
1
vendor/golang.org/x/tools/go/packages/testdata/TestName_Modules/pkg/mod/github.com/heschik/tools-testrepo@v1.0.0/pkg/pkg.go
generated
vendored
Normal file
1
vendor/golang.org/x/tools/go/packages/testdata/TestName_Modules/pkg/mod/github.com/heschik/tools-testrepo@v1.0.0/pkg/pkg.go
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package pkg
|
1
vendor/golang.org/x/tools/go/packages/testdata/TestName_Modules/src/b/pkg/pkg.go
generated
vendored
Normal file
1
vendor/golang.org/x/tools/go/packages/testdata/TestName_Modules/src/b/pkg/pkg.go
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package pkg
|
@@ -0,0 +1 @@
|
||||
v1.0.0
|
@@ -0,0 +1 @@
|
||||
{"Version":"v1.0.0","Time":"2018-09-28T22:09:08Z"}
|
@@ -0,0 +1 @@
|
||||
module github.com/heschik/tools-testrepo
|
BIN
vendor/golang.org/x/tools/go/packages/testdata/TestName_ModulesDedup/pkg/mod/cache/download/github.com/heschik/tools-testrepo/@v/v1.0.0.zip
generated
vendored
Normal file
BIN
vendor/golang.org/x/tools/go/packages/testdata/TestName_ModulesDedup/pkg/mod/cache/download/github.com/heschik/tools-testrepo/@v/v1.0.0.zip
generated
vendored
Normal file
Binary file not shown.
@@ -0,0 +1 @@
|
||||
h1:D2qc+R2eCTCyoT8WAYoExXhPBThJWmlYSfB4coWbfBE=
|
@@ -0,0 +1,2 @@
|
||||
v2.0.1
|
||||
v2.0.2
|
@@ -0,0 +1 @@
|
||||
{"Version":"v2.0.1","Time":"2018-09-28T22:12:08Z"}
|
@@ -0,0 +1 @@
|
||||
module github.com/heschik/tools-testrepo/v2
|
Binary file not shown.
@@ -0,0 +1 @@
|
||||
h1:efPBVdJ45IMcA/KXBOWyOZLo1TETKCXvzrZgfY+gqZk=
|
@@ -0,0 +1 @@
|
||||
{"Version":"v2.0.2","Time":"2018-09-28T22:12:08Z"}
|
@@ -0,0 +1 @@
|
||||
module github.com/heschik/tools-testrepo/v2
|
Binary file not shown.
@@ -0,0 +1 @@
|
||||
h1:vUnR/JOkfEQt/wvMqbT9G2gODHVgVD1saTJ8x2ngAck=
|
1
vendor/golang.org/x/tools/go/packages/testdata/TestName_ModulesDedup/pkg/mod/github.com/heschik/tools-testrepo/v2@v2.0.1/go.mod
generated
vendored
Normal file
1
vendor/golang.org/x/tools/go/packages/testdata/TestName_ModulesDedup/pkg/mod/github.com/heschik/tools-testrepo/v2@v2.0.1/go.mod
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module github.com/heschik/tools-testrepo/v2
|
1
vendor/golang.org/x/tools/go/packages/testdata/TestName_ModulesDedup/pkg/mod/github.com/heschik/tools-testrepo/v2@v2.0.1/pkg/pkg.go
generated
vendored
Normal file
1
vendor/golang.org/x/tools/go/packages/testdata/TestName_ModulesDedup/pkg/mod/github.com/heschik/tools-testrepo/v2@v2.0.1/pkg/pkg.go
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package pkg
|
1
vendor/golang.org/x/tools/go/packages/testdata/TestName_ModulesDedup/pkg/mod/github.com/heschik/tools-testrepo/v2@v2.0.2/go.mod
generated
vendored
Normal file
1
vendor/golang.org/x/tools/go/packages/testdata/TestName_ModulesDedup/pkg/mod/github.com/heschik/tools-testrepo/v2@v2.0.2/go.mod
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module github.com/heschik/tools-testrepo/v2
|
1
vendor/golang.org/x/tools/go/packages/testdata/TestName_ModulesDedup/pkg/mod/github.com/heschik/tools-testrepo/v2@v2.0.2/pkg/pkg.go
generated
vendored
Normal file
1
vendor/golang.org/x/tools/go/packages/testdata/TestName_ModulesDedup/pkg/mod/github.com/heschik/tools-testrepo/v2@v2.0.2/pkg/pkg.go
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package pkg
|
1
vendor/golang.org/x/tools/go/packages/testdata/TestName_ModulesDedup/pkg/mod/github.com/heschik/tools-testrepo@v1.0.0/go.mod
generated
vendored
Normal file
1
vendor/golang.org/x/tools/go/packages/testdata/TestName_ModulesDedup/pkg/mod/github.com/heschik/tools-testrepo@v1.0.0/go.mod
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module github.com/heschik/tools-testrepo
|
1
vendor/golang.org/x/tools/go/packages/testdata/TestName_ModulesDedup/pkg/mod/github.com/heschik/tools-testrepo@v1.0.0/pkg/pkg.go
generated
vendored
Normal file
1
vendor/golang.org/x/tools/go/packages/testdata/TestName_ModulesDedup/pkg/mod/github.com/heschik/tools-testrepo@v1.0.0/pkg/pkg.go
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package pkg
|
55
vendor/golang.org/x/tools/go/packages/visit.go
generated
vendored
Normal file
55
vendor/golang.org/x/tools/go/packages/visit.go
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
package packages
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// Visit visits all the packages in the import graph whose roots are
|
||||
// pkgs, calling the optional pre function the first time each package
|
||||
// is encountered (preorder), and the optional post function after a
|
||||
// package's dependencies have been visited (postorder).
|
||||
// The boolean result of pre(pkg) determines whether
|
||||
// the imports of package pkg are visited.
|
||||
func Visit(pkgs []*Package, pre func(*Package) bool, post func(*Package)) {
|
||||
seen := make(map[*Package]bool)
|
||||
var visit func(*Package)
|
||||
visit = func(pkg *Package) {
|
||||
if !seen[pkg] {
|
||||
seen[pkg] = true
|
||||
|
||||
if pre == nil || pre(pkg) {
|
||||
paths := make([]string, 0, len(pkg.Imports))
|
||||
for path := range pkg.Imports {
|
||||
paths = append(paths, path)
|
||||
}
|
||||
sort.Strings(paths) // Imports is a map, this makes visit stable
|
||||
for _, path := range paths {
|
||||
visit(pkg.Imports[path])
|
||||
}
|
||||
}
|
||||
|
||||
if post != nil {
|
||||
post(pkg)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, pkg := range pkgs {
|
||||
visit(pkg)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintErrors prints to os.Stderr the accumulated errors of all
|
||||
// packages in the import graph rooted at pkgs, dependencies first.
|
||||
// PrintErrors returns the number of errors printed.
|
||||
func PrintErrors(pkgs []*Package) int {
|
||||
var n int
|
||||
Visit(pkgs, nil, func(pkg *Package) {
|
||||
for _, err := range pkg.Errors {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
n++
|
||||
}
|
||||
})
|
||||
return n
|
||||
}
|
Reference in New Issue
Block a user