forked from ebhomengo/niki
1
0
Fork 0
niki/vendor/github.com/KyleBanks/depth/depth.go

211 lines
3.3 KiB
Go
Raw Normal View History

2024-05-14 13:07:09 +00:00
// Package depth provides the ability to traverse and retrieve Go source code dependencies in the form of
2024-05-14 13:07:09 +00:00
// internal and external packages.
2024-05-14 13:07:09 +00:00
//
2024-05-14 13:07:09 +00:00
// For example, the dependencies of the stdlib `strings` package can be resolved like so:
2024-05-14 13:07:09 +00:00
//
2024-06-14 08:41:36 +00:00
// import "github.com/KyleBanks/depth"
2024-05-14 13:07:09 +00:00
//
2024-05-14 13:07:09 +00:00
// var t depth.Tree
2024-06-14 08:41:36 +00:00
// err := t.Resolve("strings")
2024-06-14 08:41:36 +00:00
// if err != nil {
2024-06-14 08:41:36 +00:00
// log.Fatal(err)
2024-06-14 08:41:36 +00:00
// }
2024-05-14 13:07:09 +00:00
//
2024-06-14 08:41:36 +00:00
// // Output: "strings has 4 dependencies."
2024-06-14 08:41:36 +00:00
// log.Printf("%v has %v dependencies.", t.Root.Name, len(t.Root.Deps))
2024-05-14 13:07:09 +00:00
//
2024-05-14 13:07:09 +00:00
// For additional customization, simply set the appropriate flags on the `Tree` before resolving:
2024-05-14 13:07:09 +00:00
//
2024-06-14 08:41:36 +00:00
// import "github.com/KyleBanks/depth"
2024-05-14 13:07:09 +00:00
//
2024-06-14 08:41:36 +00:00
// t := depth.Tree {
2024-06-14 08:41:36 +00:00
// ResolveInternal: true,
2024-06-14 08:41:36 +00:00
// ResolveTest: true,
2024-06-14 08:41:36 +00:00
// MaxDepth: 10,
2024-06-14 08:41:36 +00:00
// }
2024-06-14 08:41:36 +00:00
// err := t.Resolve("strings")
2024-05-14 13:07:09 +00:00
package depth
import (
"errors"
"go/build"
"os"
)
// ErrRootPkgNotResolved is returned when the root Pkg of the Tree cannot be resolved,
2024-05-14 13:07:09 +00:00
// typically because it does not exist.
2024-05-14 13:07:09 +00:00
var ErrRootPkgNotResolved = errors.New("unable to resolve root package")
// Importer defines a type that can import a package and return its details.
2024-05-14 13:07:09 +00:00
type Importer interface {
Import(name, srcDir string, im build.ImportMode) (*build.Package, error)
}
// Tree represents the top level of a Pkg and the configuration used to
2024-05-14 13:07:09 +00:00
// initialize and represent its contents.
2024-05-14 13:07:09 +00:00
type Tree struct {
Root *Pkg
ResolveInternal bool
ResolveTest bool
MaxDepth int
2024-05-14 13:07:09 +00:00
Importer Importer
importCache map[string]struct{}
}
// Resolve recursively finds all dependencies for the root Pkg name provided,
2024-05-14 13:07:09 +00:00
// and the packages it depends on.
2024-05-14 13:07:09 +00:00
func (t *Tree) Resolve(name string) error {
2024-05-14 13:07:09 +00:00
pwd, err := os.Getwd()
2024-05-14 13:07:09 +00:00
if err != nil {
2024-05-14 13:07:09 +00:00
return err
2024-05-14 13:07:09 +00:00
}
t.Root = &Pkg{
Name: name,
Tree: t,
2024-05-14 13:07:09 +00:00
SrcDir: pwd,
Test: false,
2024-05-14 13:07:09 +00:00
}
// Reset the import cache each time to ensure a reused Tree doesn't
2024-05-14 13:07:09 +00:00
// reuse the same cache.
2024-05-14 13:07:09 +00:00
t.importCache = nil
// Allow custom importers, but use build.Default if none is provided.
2024-05-14 13:07:09 +00:00
if t.Importer == nil {
2024-05-14 13:07:09 +00:00
t.Importer = &build.Default
2024-05-14 13:07:09 +00:00
}
t.Root.Resolve(t.Importer)
2024-05-14 13:07:09 +00:00
if !t.Root.Resolved {
2024-05-14 13:07:09 +00:00
return ErrRootPkgNotResolved
2024-05-14 13:07:09 +00:00
}
return nil
2024-05-14 13:07:09 +00:00
}
// shouldResolveInternal determines if internal packages should be further resolved beyond the
2024-05-14 13:07:09 +00:00
// current parent.
2024-05-14 13:07:09 +00:00
//
2024-05-14 13:07:09 +00:00
// For example, if the parent Pkg is `github.com/foo/bar` and true is returned, all the
2024-05-14 13:07:09 +00:00
// internal dependencies it relies on will be resolved. If for example `strings` is one of those
2024-05-14 13:07:09 +00:00
// dependencies, and it is passed as the parent here, false may be returned and its internal
2024-05-14 13:07:09 +00:00
// dependencies will not be resolved.
2024-05-14 13:07:09 +00:00
func (t *Tree) shouldResolveInternal(parent *Pkg) bool {
2024-05-14 13:07:09 +00:00
if t.ResolveInternal {
2024-05-14 13:07:09 +00:00
return true
2024-05-14 13:07:09 +00:00
}
return parent == t.Root
2024-05-14 13:07:09 +00:00
}
// isAtMaxDepth returns true when the depth of the Pkg provided is at or beyond the maximum
2024-05-14 13:07:09 +00:00
// depth allowed by the tree.
2024-05-14 13:07:09 +00:00
//
2024-05-14 13:07:09 +00:00
// If the Tree has a MaxDepth of zero, true is never returned.
2024-05-14 13:07:09 +00:00
func (t *Tree) isAtMaxDepth(p *Pkg) bool {
2024-05-14 13:07:09 +00:00
if t.MaxDepth == 0 {
2024-05-14 13:07:09 +00:00
return false
2024-05-14 13:07:09 +00:00
}
return p.depth() >= t.MaxDepth
2024-05-14 13:07:09 +00:00
}
// hasSeenImport returns true if the import name provided has already been seen within the tree.
2024-05-14 13:07:09 +00:00
// This function only returns false for a name once.
2024-05-14 13:07:09 +00:00
func (t *Tree) hasSeenImport(name string) bool {
2024-05-14 13:07:09 +00:00
if t.importCache == nil {
2024-05-14 13:07:09 +00:00
t.importCache = make(map[string]struct{})
2024-05-14 13:07:09 +00:00
}
if _, ok := t.importCache[name]; ok {
2024-05-14 13:07:09 +00:00
return true
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
t.importCache[name] = struct{}{}
2024-05-14 13:07:09 +00:00
return false
2024-05-14 13:07:09 +00:00
}