github.com/yanndegat/hiera@v0.6.8/config/entry.go (about) 1 package config 2 3 import ( 4 "fmt" 5 "path/filepath" 6 "strings" 7 8 "github.com/lyraproj/dgo/vf" 9 10 "github.com/lyraproj/dgo/dgo" 11 "github.com/lyraproj/dgo/util" 12 "github.com/yanndegat/hiera/api" 13 ) 14 15 type ( 16 entry struct { 17 cfg *hieraCfg 18 dataDir string 19 pluginDir string 20 pluginFile string 21 options dgo.Map 22 function api.Function 23 name string 24 locations []api.Location 25 } 26 ) 27 28 // FunctionKeys are the valid keys to use when defining a function in a hierarchy entry 29 var FunctionKeys = []string{string(api.KindDataDig), string(api.KindDataHash), string(api.KindLookupKey)} 30 31 // LocationKeys are the valid keys to use when defining locations in a hierarchy entry 32 var LocationKeys = []string{ 33 string(api.LcPath), `paths`, 34 string(api.LcGlob), `globs`, 35 string(api.LcURI), `uris`, 36 string(api.LcMappedPaths)} 37 38 // ReservedOptionKeys are the option keys that are reserved by Hiera 39 var ReservedOptionKeys = []string{string(api.LcPath), string(api.LcURI)} 40 41 func (e *entry) Options() dgo.Map { 42 return e.options 43 } 44 45 func (e *entry) DataDir() string { 46 return e.dataDir 47 } 48 49 func (e *entry) PluginDir() string { 50 return e.pluginDir 51 } 52 53 func (e *entry) PluginFile() string { 54 return e.pluginFile 55 } 56 57 func (e *entry) Function() api.Function { 58 return e.function 59 } 60 61 func (e *entry) initialize(name string, entryHash dgo.Map) { 62 entryHash.EachEntry(func(me dgo.MapEntry) { 63 ks := me.Key().String() 64 v := me.Value() 65 if ks == `options` { 66 e.options = v.(dgo.Map) 67 e.options.EachKey(func(optKey dgo.Value) { 68 if util.ContainsString(ReservedOptionKeys, optKey.String()) { 69 panic( 70 fmt.Errorf(`option key '%s' used in hierarchy '%s' is reserved by Hiera`, optKey.String(), name)) 71 } 72 }) 73 } else if util.ContainsString(FunctionKeys, ks) { 74 if e.function != nil { 75 panic(fmt.Errorf(`only one of %s can be defined in hierarchy '%s'`, strings.Join(FunctionKeys, `, `), name)) 76 } 77 e.function = &function{api.FunctionKind(ks), v.String()} 78 } 79 }) 80 } 81 82 func (e *entry) Copy(cfg api.Config) api.Entry { 83 c := *e 84 c.cfg = cfg.(*hieraCfg) 85 return &c 86 } 87 88 func (e *entry) Name() string { 89 return e.name 90 } 91 92 func (e *entry) Locations() []api.Location { 93 return e.locations 94 } 95 96 func (e *entry) resolveFunction(ic api.Invocation, defaults api.Entry) { 97 if e.function == nil { 98 if defaults == nil { 99 e.function = &function{kind: api.KindDataHash, name: `yaml_data`} 100 } else { 101 e.function = defaults.Function() 102 } 103 } else if f, fc := e.function.Resolve(ic); fc { 104 e.function = f 105 } 106 107 if e.function == nil { 108 panic(fmt.Errorf(`one of %s must be defined in hierarchy '%s'`, strings.Join(FunctionKeys, `, `), e.name)) 109 } 110 } 111 112 func (e *entry) resolveDataDir(ic api.Invocation, defaults api.Entry) { 113 e.resolveFunction(ic, defaults) 114 if e.dataDir == `` { 115 if defaults == nil { 116 e.dataDir = defaultDataDir() 117 } else { 118 e.dataDir = defaults.DataDir() 119 } 120 } else { 121 if d, dc := ic.InterpolateString(e.dataDir, false); dc { 122 e.dataDir = d.String() 123 } 124 } 125 } 126 127 func (e *entry) resolvePluginDir(ic api.Invocation, defaults api.Entry) { 128 if e.pluginDir == `` { 129 if defaults == nil { 130 e.pluginDir = defaultPluginDir() 131 } else { 132 e.pluginDir = defaults.PluginDir() 133 } 134 } else { 135 if d, dc := ic.InterpolateString(e.pluginDir, false); dc { 136 e.pluginDir = d.String() 137 } 138 } 139 if !filepath.IsAbs(e.pluginDir) { 140 e.pluginDir = filepath.Join(e.cfg.root, e.pluginDir) 141 } 142 } 143 144 func (e *entry) resolveOptions(ic api.Invocation, defaults api.Entry) { 145 if e.options == nil { 146 if defaults != nil { 147 e.options = defaults.Options() 148 } 149 } else if e.options.Len() > 0 { 150 e.options = ic.Interpolate(e.options, false).(dgo.Map) 151 } 152 if e.options == nil { 153 e.options = vf.Map() 154 } 155 } 156 157 func (e *entry) resolveLocations(ic api.Invocation) { 158 var dataRoot string 159 if filepath.IsAbs(e.dataDir) { 160 dataRoot = e.dataDir 161 } else { 162 dataRoot = filepath.Join(e.cfg.root, e.dataDir) 163 } 164 if e.locations != nil { 165 ne := make([]api.Location, 0, len(e.locations)) 166 for _, l := range e.locations { 167 ne = append(ne, l.Resolve(ic, dataRoot)...) 168 } 169 e.locations = ne 170 } 171 } 172 173 func (e *entry) Resolve(ic api.Invocation, defaults api.Entry) api.Entry { 174 // Resolve interpolated strings and locations 175 ce := *e 176 177 ce.resolveFunction(ic, defaults) 178 ce.resolveDataDir(ic, defaults) 179 ce.resolvePluginDir(ic, defaults) 180 ce.resolveOptions(ic, defaults) 181 ce.resolveLocations(ic) 182 183 return &ce 184 }