golang

package
v0.7.0-beta.6 Latest Latest
Warning

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

Go to latest
Published: Jul 25, 2018 License: MPL-2.0 Imports: 20 Imported by: 0

Documentation

Overview

Package golang implements the analyzer for Go.

A `BuildTarget` in Go is defined as an import path (see `go help importpath` for details).

This package is implemented by externally calling both the `go` tool and any external build tools.

FAQ

Why not use `go/build`, or a library like `KyleBanks/depth`?

The `go` tool's interface is incredibly stable over different releases, but the internals are not. Using these libraries causes crashes when analyzing code that is compiled using a different version of Go. (This was how the analyzer was originally implemented.)

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNoLockfileInDir   = errors.New("could not find lockfile in directory")
	ErrNoNearestLockfile = errors.New("could not find nearest lockfile of directory")
)

Errors that occur while finding lockfiles.

View Source
var (
	ErrNoVCSInDir   = errors.New("could not find VCS repository in directory")
	ErrNoNearestVCS = errors.New("could not find nearest VCS repository in directory")
)

Errors that occur when finding VCS repositories.

View Source
var (
	ErrNoGOPATH = errors.New("no $GOPATH set")
)

Errors that occur while running utilities.

Functions

func ImportPath

func ImportPath(dir string) (string, error)

ImportPath returns the import path of a package located at the directory.

func LockfileIn

func LockfileIn(dirname string) (resolver.Type, error)

LockfileIn returns the type of lockfile within a directory, or ErrNoLockfileInDir if none is found.

func NearestLockfile

func NearestLockfile(dirname string) (resolver.Type, string, error)

NearestLockfile returns the type and directory of the nearest lockfile in an ancestor directory, or ErrNoNearestLockfile if none is found.

func NearestVCS

func NearestVCS(dirname string) (vcsName string, vcsDir string, err error)

NearestVCS returns the type and directory of the nearest VCS repository containing the directory, or ErrNoNearestVCS if none is found.

func UnresolvedImport

func UnresolvedImport(gopkg gocmd.Package) pkg.Import

UnresolvedImport returns the default (non-zero) pkg.Import for an unresolved gocmd.Package.

func Unvendor

func Unvendor(importpath string) string

Unvendor takes a vendorized import path and strips all vendor folder prefixes.

func VCSIn

func VCSIn(dirname string) (string, error)

VCSIn returns the type of VCS repository rooted at a directory, or ErrNoVCSInDir if none is found.

func VendorParent

func VendorParent(dirname string) string

VendorParent returns the directory that contains a vendored directory, or "." if none exists.

Types

type Analyzer

type Analyzer struct {
	Go        gocmd.Go
	GoVersion string

	Options Options
	// contains filtered or unexported fields
}

An Analyzer contains structs used in the analysis of Go packages. It implements analyzer.Analyzer.

func New

func New(opts map[string]interface{}) (*Analyzer, error)

New constructs an Analyzer.

func (*Analyzer) Analyze

func (a *Analyzer) Analyze(m module.Module) (module.Module, error)

Analyze builds a dependency graph using go list and then looks up revisions using tool-specific lockfiles.

func (*Analyzer) Build

func (a *Analyzer) Build(m module.Module) error

Build runs `go build $PKG`.

func (*Analyzer) Clean

func (a *Analyzer) Clean(m module.Module) error

Clean runs `go clean $PKG`.

func (*Analyzer) Dir

func (a *Analyzer) Dir(importpath string) (string, error)

Dir returns the absolute path to a Go package.

func (*Analyzer) Discover

func (a *Analyzer) Discover(dir string) ([]module.Module, error)

Discover runs `go list ./...`.

func (*Analyzer) IsBuilt

func (a *Analyzer) IsBuilt(m module.Module) (bool, error)

IsBuilt runs `go list $PKG` and checks for errors.

func (*Analyzer) ParentOK

func (a *Analyzer) ParentOK(project Project, gopkg gocmd.Package, dir string) bool

ParentOK returns true if looking up the lockfile of gopkg in dir is allowed.

A package may be looked up in a directory if:

  1. The directory is within the main project.
  2. The directory is not within the main project, but we allow external project vendoring.
  3. The directory is not within the main project, but an allowed external vendoring import path prefix is a prefix of the import path that a package at the directory would have.

func (*Analyzer) Project

func (a *Analyzer) Project(pkg string) (Project, error)

Project calculates the project containing any Go package.

This function searches upwards from the Go package's directory, looking for lockfiles of supported dependency management tools. If none are found, it fails.

The rationale for this design is that the packages in a "project" are versioned together. There are two reasonable ways to capture the notion of "versioned together":

  1. The nearest lockfile. The nearest lockfile to the package probably locks the dependencies of the package.
  2. The nearest VCS repository. The nearest VCS repository probably contains the current "project" being worked on. The only common exception to this is monorepos, in which case all the contents of the repository are probably internal, so allowing packages within the repository to be unresolved is probably acceptable.

There are a couple issues with both of these:

  1. The nearest lockfile is not guaranteed to exist. When it does, it's not guaranteed to be _the_ semantic lockfile for the package -- this is merely a very common convention, not a requirement.
  2. The package is not guaranteed to be in a VCS repository. When it is, the repository might be extremely weird. One example of this is a repository containing the entire $GOPATH (which is a reasonable convention that some early adopters of Go used).

This function tries its best to mitigate both of these issues:

  1. The nearest lockfile is used for resolving versions. This is a very strong convention.
  2. The nearest VCS repository is used for determining allowed unresolved import paths. This is also a very strong convention.

Both of these assumptions can be overridden by the user.

func (*Analyzer) ResolverFromLockfile

func (a *Analyzer) ResolverFromLockfile(tool resolver.Type, dir string) (resolver.Resolver, error)

ResolverFromLockfile loads and caches lockfile resolvers.

func (*Analyzer) Revision

func (a *Analyzer) Revision(project Project, r resolver.Resolver, gopkg gocmd.Package) (pkg.Import, error)

Revision resolves a revision, returning errutil.ErrNoRevisionForPackage when no revision is found (unless a revision is not required).

func (*Analyzer) RevisionContextual

func (a *Analyzer) RevisionContextual(project Project, gopkg gocmd.Package) (pkg.Import, error)

RevisionContextual resolve a revision by looking up its revision in the lockfile of a vendoring parent. This supports complex use cases, such as multi-project vendoring (Docker), and nested vendor folders (Hashicorp):

  1. Multi-project example: docker/docker-ce does not vendor all of its dependencies within the project. Instead, it uses unvendored imports of docker/docker, which vendors imports of its own set of dependencies. This means that we need to do a lookup in docker/docker's lockfile to resolve a transitive dependency of docker/docker-ce.
  2. Nested vendor folder example: hashicorp/consul has nested vendor folders. This means that resolving a transitive dependency may require looking at the lockfile of the dependency that vendors it, or looking further up at any of the ancestors in the vendoring chain.

In theory, this is only used for setups that _build very carefully_, but are otherwise prone to exploding. In practice, this seems to be required a lot.

func (*Analyzer) RevisionContextualLookup

func (a *Analyzer) RevisionContextualLookup(project Project, gopkg gocmd.Package, dir string) (pkg.Import, error)

RevisionContextualLookup attempts to resolve a revision of a package using the lockfile in a specific directory.

func (*Analyzer) RevisionDirect

func (a *Analyzer) RevisionDirect(project Project, r resolver.Resolver, gopkg gocmd.Package) (pkg.Import, error)

RevisionDirect resolves a revision by looking up its revision in the project's lockfile. This works for most conventional projects.

func (*Analyzer) UnresolvedOK

func (a *Analyzer) UnresolvedOK(project Project, gopkg gocmd.Package) bool

UnresolvedOK returns true if failing to resolve the revision of a package is a non-fatal (rather than fatal) error.

Packages require a resolved revision unless any of the following are true:

  1. The package is part of the standard library.
  2. The package is internal.
  3. The package is within the project folder, but not under the vendor folder.
  4. A package at the project's folder would have an import path that is a prefix of the package path.
  5. Options.AllowUnresolved is true.
  6. Options.AllowUnresolvedPrefix is set one of its paths is a prefix of the package's import path.

These exceptions are generally either "part of" (i.e. versioned as a unit with) the project, or otherwise don't have revisions.

type Options

type Options struct {
	BuildOS                   string `mapstructure:"os"`                           // Target build OS (for build tags).
	BuildArch                 string `mapstructure:"arch"`                         // Target build architecture (for build tags).
	Strategy                  string `mapstructure:"strategy"`                     // See the Go analyzer documentation.
	LockfilePath              string `mapstructure:"lockfile"`                     // For non-standard lockfile locations with strategies `manifest:*`.
	AllowUnresolved           bool   `mapstructure:"allow-unresolved"`             // Allow unresolved revisions.
	AllowUnresolvedPrefix     string `mapstructure:"allow-unresolved-prefix"`      // If set, allows unresolved revisions for packages whose import path's prefix matches. Multiple space-delimited prefixes can be specified.
	AllowNestedVendor         bool   `mapstructure:"allow-nested-vendor"`          // Allows vendor folders to be nested and attempts to resolve using parent lockfile lookup.
	AllowDeepVendor           bool   `mapstructure:"allow-deep-vendor"`            // Allows nested vendored dependencies to be resolved using ancestor lockfiles farther than their direct parent.
	AllowExternalVendor       bool   `mapstructure:"allow-external-vendor"`        // Allows reading vendor lockfiles of other projects.
	AllowExternalVendorPrefix string `mapstructure:"allow-external-vendor-prefix"` // If set, allow reading vendor lockfiles of projects whose import path's prefix matches. Multiple space-delimited prefixes can be specified.
	SkipImportTracing         bool   `mapstructure:"skip-tracing"`                 // Skips dependency tracing.
	SkipProject               bool   `mapstructure:"skip-project"`                 // Skips project detection.
}

Options set analyzer options for Go modules.

type Project

type Project struct {
	Tool       resolver.Type // Name of the dependency management tool used by the project, if any.
	Manifest   string        // Absolute path to the tool's manifest file for this project, if any.
	Dir        string        // Absolute path of the first-party code folder, if any.
	ImportPath string        // Import path prefix of project code.
}

A Project is a single folder that forms a coherent "project" for a developer and is versioned as a single unit. It may contain multiple Go packages.

Directories

Path Synopsis
Package resolver provides Go resolvers.
Package resolver provides Go resolvers.

Jump to

Keyboard shortcuts

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