github.com/clusterize-io/tusk@v0.6.3-0.20211001020217-cfe8a8cd0d4a/runner/dependencies.go (about) 1 package runner 2 3 import ( 4 "encoding/json" 5 6 "github.com/clusterize-io/tusk/marshal" 7 ) 8 9 // FindAllOptions returns a list of options relevant for a given config. 10 func FindAllOptions(t *Task, cfg *Config) ([]*Option, error) { 11 names, err := getDependencies(t) 12 if err != nil { 13 return nil, err 14 } 15 16 candidates := make(map[string]*Option) 17 for _, opt := range cfg.Options { 18 // Args that share a name with global options take priority 19 if _, ok := t.Args.Lookup(opt.Name); ok { 20 continue 21 } 22 23 candidates[opt.Name] = opt 24 } 25 26 required := make([]*Option, 0, len(t.Options)) 27 for _, opt := range t.Options { 28 candidates[opt.Name] = opt 29 required = append(required, opt) 30 } 31 32 required, err = findRequiredOptionsRecursively(names, candidates, required) 33 if err != nil { 34 return nil, err 35 } 36 37 return required, nil 38 } 39 40 func findRequiredOptionsRecursively( 41 entry []string, candidates map[string]*Option, found []*Option, 42 ) ([]*Option, error) { 43 for _, item := range entry { 44 candidate, ok := candidates[item] 45 if !ok || optionsContains(found, candidate) { 46 continue 47 } 48 49 found = append(found, candidate) 50 var dependencies []string 51 for _, opt := range found { 52 nested, err := getDependencies(opt) 53 if err != nil { 54 return nil, err 55 } 56 dependencies = append(dependencies, nested...) 57 } 58 59 var err error 60 found, err = findRequiredOptionsRecursively(dependencies, candidates, found) 61 if err != nil { 62 return nil, err 63 } 64 } 65 66 return found, nil 67 } 68 69 func optionsContains(items []*Option, item *Option) bool { 70 for _, want := range items { 71 if item == want { 72 return true 73 } 74 } 75 76 return false 77 } 78 79 type dependencyGetter interface { 80 Dependencies() []string 81 } 82 83 func getDependencies(item dependencyGetter) ([]string, error) { 84 // TODO: Remove json dependency by implementing stringer interface 85 // json is used to print computed fields that should not be yaml parseable 86 marshaled, err := json.Marshal(item) 87 if err != nil { 88 return nil, err 89 } 90 91 names := marshal.FindPotentialVariables(marshaled) 92 names = append(names, item.Dependencies()...) 93 94 return names, nil 95 }