github.com/tooploox/oya@v0.0.21-0.20230524103240-1cda1861aad6/pkg/deptree/deptree.go (about) 1 package deptree 2 3 import ( 4 "fmt" 5 6 "github.com/tooploox/oya/pkg/deptree/internal" 7 "github.com/tooploox/oya/pkg/errors" 8 "github.com/tooploox/oya/pkg/mvs" 9 "github.com/tooploox/oya/pkg/oyafile" 10 "github.com/tooploox/oya/pkg/pack" 11 "github.com/tooploox/oya/pkg/types" 12 ) 13 14 type ErrResolvingDeps struct { 15 } 16 17 func (e ErrResolvingDeps) Error() string { 18 return "error resolving dependencies" 19 } 20 21 // DependencyTree defines a project's dependencies, allowing for loading them. 22 type DependencyTree struct { 23 installDirs []string 24 dependencies []pack.Pack 25 reqs *internal.Reqs 26 rootDir string 27 } 28 29 // New returns a new dependency tree. 30 // BUG(bilus): It's called a 'tree' but it currently does not take into account inter-pack 31 // dependencies. This will likely change and then the name will fit like a glove. ;) 32 func New(rootDir string, installDirs []string, dependencies []pack.Pack) (*DependencyTree, error) { 33 return &DependencyTree{ 34 installDirs: installDirs, 35 dependencies: dependencies, 36 reqs: internal.NewReqs(rootDir, installDirs), 37 rootDir: rootDir, 38 }, nil 39 } 40 41 // Explode takes the initial list of dependencies and builds the full list, 42 // taking into account packs' dependencies and using Minimal Version Selection. 43 func (dt *DependencyTree) Explode() error { 44 list, err := mvs.List(dt.dependencies, dt.reqs) 45 if err != nil { 46 return errors.Wrap( 47 err, 48 ErrResolvingDeps{}, 49 errors.Location{ 50 Name: dt.rootDir, 51 VerboseName: fmt.Sprintf("project at %q", dt.rootDir), 52 }, 53 ) 54 } 55 dt.dependencies = list 56 return nil 57 } 58 59 // Load loads an pack's Oyafile based on its import path. 60 // It supports two types of import paths: 61 // - referring to the project's Require: section (e.g. github.com/tooploox/oya-packs/docker), in this case it will load, the required version; 62 // - path relative to the project's root (e.g. /) -- does not support versioning, loads Oyafile directly from the path (<root dir>/<import path>). 63 func (dt *DependencyTree) Load(importPath types.ImportPath) (*oyafile.Oyafile, bool, error) { 64 pack, found, err := dt.findRequiredPack(importPath) 65 if err != nil { 66 return nil, false, err 67 } 68 if found { 69 return dt.reqs.LoadLocalOyafile(pack) 70 } 71 return nil, false, nil 72 } 73 74 // Find lookups pack by its import path. 75 func (dt *DependencyTree) Find(importPath types.ImportPath) (pack.Pack, bool, error) { 76 for _, pack := range dt.dependencies { 77 if pack.ImportPath() == importPath { 78 return pack, true, nil 79 } 80 } 81 return pack.Pack{}, false, nil 82 } 83 84 // ForEach iterates through the packs. 85 func (dt *DependencyTree) ForEach(f func(pack.Pack) error) error { 86 for _, pack := range dt.dependencies { 87 if err := f(pack); err != nil { 88 return err 89 } 90 } 91 return nil 92 } 93 94 func (dt *DependencyTree) findRequiredPack(importPath types.ImportPath) (pack.Pack, bool, error) { 95 for _, pack := range dt.dependencies { 96 if pack.ImportPath() == importPath { 97 return pack, true, nil 98 } 99 } 100 return pack.Pack{}, false, nil 101 }