list

package
v0.36.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 21, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

Documentation

Overview

Package list answers the question `go list` answers: given a pattern or an import path, which directory holds that package, and what is it called.

It is separate from the loader above it because the two are inherited from different places and age differently. The loader is a simplified golang.org/x/tools/go/packages — a small, stable shape that codescan owns. This package is cmd/go: module boundaries, workspaces, vendoring, the module cache, and a wildcard grammar with documented exceptions to its own rules.

That is not a design anyone would arrive at; it is a set of behaviours the go command has and every consumer must reproduce exactly. Keeping them apart means the quirks are quarantined where they can be checked against upstream rather than diffused through the loader.

The parts, roughly in the order a scan meets them:

  • resolve.go — the Resolver: patterns to directories, import paths to directories, the main module, the module cache, `replace`, and a vendor directory when one is authoritative.
  • workspace.go — go.work, whose `use` directives place a sibling module at the copy being worked on rather than at whatever the cache holds.
  • pattern.go — where a `...` walk starts, and which walked directories a pattern matches.
  • pkgpattern.go — the wildcard matcher, copied verbatim from the Go distribution under its own licence. See its header, and NOTICE at the repository root.

What it deliberately does not do

No GOPATH mode, no module-graph walk (versions are read already-selected out of the main go.mod), no `internal/` visibility enforcement, and no query syntax (`all`, `std`, `pattern=`). Two of those omissions let codescan read a tree the go command refuses; the rest are documented limits.

Some extra tooling in hack/go-loader is available to help maintainers verify the behavior against changes in the go toolchain.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrUnresolvedPattern reports a scan pattern that names no directory the resolver can reach — most often a virtual
	// filesystem mounted narrower than the pattern reaches.
	ErrUnresolvedPattern = errors.New("cannot resolve pattern")

	// ErrInvalidGoMod reports a go.mod whose requirements could not be read.
	//
	// It is fatal rather than degraded because the alternative is placing no dependency at all and synthesizing the lot,
	// which buries the real fault under a wall of unrelated warnings.
	ErrInvalidGoMod = errors.New("cannot read go.mod")
)

Sentinels for the conditions a caller might reasonably branch on.

The detail — which pattern, which file — goes in the wrapping message; errors.Is matches the sentinel.

Functions

func IsStdlibPath

func IsStdlibPath(importPath string) bool

IsStdlibPath reports whether an import path names a standard-library package: its first segment carries no dot, so it can never be a module path.

func MatchPattern

func MatchPattern(pattern string) func(name string) bool

MatchPattern(pattern)(name) reports whether name matches pattern.

Pattern is a limited glob pattern in which '...' means 'any string' and there is no other special syntax. Unfortunately, there are two special cases. Quoting "go help packages":

First, /... at the end of the pattern can match an empty string, so that net/... matches both net and packages in its subdirectories, like net/http.

Second, any slash-separated pattern element containing a wildcard never participates in a match of the "vendor" element in the path of a vendored package, so that ./... does not match packages in subdirectories of ./vendor or ./mycode/vendor, but ./vendor/... and ./mycode/vendor/... do.

Note, however, that a directory named vendor that itself contains code is not a vendored package: cmd/vendor would be a command named vendor, and the pattern cmd/... matches it.

Types

type Config

type Config struct {
	// FS is the filesystem every read goes through.
	FS *vfs.FS

	// Context carries the build target and the go/build hooks bound to FS.
	Context *build.Context

	// Dir is the directory patterns are relative to.
	Dir string

	// Env is the effective go environment, for GOMODCACHE and GOPATH.
	Env map[string]string

	// GOWORK selects the workspace: "off", a path, or "" to search upwards.
	GOWORK string

	// ModFlag is the -mod setting, which decides whether a vendor directory is authoritative.
	ModFlag string

	// StubStdlib withholds the standard library from resolution.
	StubStdlib bool
}

Config holds what a Resolver needs to know before it can place anything.

type Resolver

type Resolver struct {
	// contains filtered or unexported fields
}

Resolver turns patterns and import paths into directories.

This is the half of `go list` we have to own: mapping "./..." or "example.com/x/y" onto a place on the filesystem. It is deliberately narrow — main module, workspace members, the module cache, a vendor directory, and GOROOT — because those are the trees whose layout is knowable without running the go command.

func NewResolver

func NewResolver(cfg Config) (*Resolver, error)

NewResolver builds a Resolver and reads the module context around Config.Dir.

It fails only when go.mod exists and cannot be read: with no requirement placed, every dependency would fall through to synthesis and the real fault would vanish behind a wall of warnings.

func (*Resolver) InMainModule

func (r *Resolver) InMainModule(importPath string) bool

InMainModule reports whether an import path names a package of the module being scanned.

It decides where a package's types may come from. The code under scan must always be read from source: its comments are the annotations, and export data carries none. Everything else is a dependency, whose types are all that is wanted from it.

func (*Resolver) ResolveImport

func (r *Resolver) ResolveImport(importPath string) (dir, pkgPath string, ok bool)

ResolveImport maps an import path onto a directory.

It answers for an import from anywhere in the main module, which is every caller that has no importer to name. Use Resolver.ResolveImportFrom where the importer is known: it is the only way the standard library's own vendor tree can be reached.

func (*Resolver) ResolveImportFrom

func (r *Resolver) ResolveImportFrom(importPath, fromDir string) (dir, pkgPath string, ok bool)

ResolveImportFrom maps an import path onto a directory, for an import made from fromDir.

The importing directory decides one thing only, and it is the thing Resolver.ResolveImport cannot know: whether the standard library's own vendor tree is in scope. It is in scope for a package inside GOROOT/src and for nothing else, which is what keeps a user package importing golang.org/x/crypto from silently picking up the copy pinned inside the Go installation.

Vendor first, as the go command has it: for an importer under the source root the vendored copy IS the package, and the flat GOROOT/src lookup would miss it anyway.

func (*Resolver) ResolvePatterns

func (r *Resolver) ResolvePatterns(patterns []string) ([]Target, error)

ResolvePatterns expands the caller's patterns into concrete package directories.

Supported: "./dir", "./dir/...", "dir", "all"-free import paths, and bare "...". Anything the go command supports beyond that (query syntax, "std", test patterns) is out of scope.

func (*Resolver) UnderGoroot

func (r *Resolver) UnderGoroot(dir string) bool

UnderGoroot reports whether an import made from dir can see the standard library's own vendor tree.

Exported for the loader's stub memo, which must not give one importer's answer to another.

type Target

type Target struct {
	Dir     string
	PkgPath string
}

Target is a package the caller asked for: where it is, and what it is called.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL