// treeFunc returns or accumulates keyPrefix dependencies. func treeFunc(b *Brain, used, missing *dep.Set) func(string) ([]*dep.KeyPair, error) { return func(s string) ([]*dep.KeyPair, error) { result := []*dep.KeyPair{} if len(s) == 0 { return result, nil } d, err := dep.NewKVListQuery(s) if err != nil { return result, err } used.Add(d) // Only return non-empty top-level keys if value, ok := b.Recall(d); ok { for _, pair := range value.([]*dep.KeyPair) { parts := strings.Split(pair.Key, "/") if parts[len(parts)-1] != "" { result = append(result, pair) } } return result, nil } missing.Add(d) return result, nil } }
// ParsePrefix parses a prefix of the format "source@dc:destination" into the // Prefix component. func ParsePrefix(s string) (*Prefix, error) { if len(strings.TrimSpace(s)) < 1 { return nil, fmt.Errorf("cannot specify empty prefix declaration") } parts := strings.SplitN(s, ":", 2) var source, destination string switch len(parts) { case 1: source, destination = parts[0], "" case 2: source, destination = parts[0], parts[1] default: return nil, fmt.Errorf("invalid format: %q", s) } if source == "" || !dep.KVListQueryRe.MatchString(source) { return nil, fmt.Errorf("invalid format: %q", s) } m := regexpMatch(dep.KVListQueryRe, source) prefix := m["prefix"] dc := m["dc"] d, err := dep.NewKVListQuery(source) if err != nil { return nil, err } if destination == "" { destination = prefix } return &Prefix{ Dependency: d, Source: prefix, DataCenter: dc, Destination: destination, }, nil }
// g reads the configuration file at the given path and returns a new // Config struct with the data populated. func ParseConfig(path string) (*Config, error) { var errs *multierror.Error // Read the contents of the file contents, err := ioutil.ReadFile(path) if err != nil { return nil, fmt.Errorf("error reading config at %q: %s", path, err) } // Parse the file (could be HCL or JSON) var shadow interface{} if err := hcl.Decode(&shadow, string(contents)); err != nil { return nil, fmt.Errorf("error decoding config at %q: %s", path, err) } // Convert to a map and flatten the keys we want to flatten parsed, ok := shadow.(map[string]interface{}) if !ok { return nil, fmt.Errorf("error converting config at %q", path) } flattenKeys(parsed, []string{"auth", "ssl", "syslog"}) // Create a new, empty config c := new(Config) // Use mapstructure to populate the basic config fields metadata := new(mapstructure.Metadata) decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ DecodeHook: mapstructure.ComposeDecodeHookFunc( config.StringToWaitDurationHookFunc(), mapstructure.StringToSliceHookFunc(","), mapstructure.StringToTimeDurationHookFunc(), ), ErrorUnused: true, Metadata: metadata, Result: c, }) if err != nil { errs = multierror.Append(errs, err) return nil, errs.ErrorOrNil() } if err := decoder.Decode(parsed); err != nil { errs = multierror.Append(errs, err) return nil, errs.ErrorOrNil() } // Store a reference to the path where this config was read from c.Path = path // Parse the prefix sources for _, prefix := range c.Prefixes { parsed, err := dep.NewKVListQuery(prefix.Source) if err != nil { errs = multierror.Append(errs, err) continue } prefix.Dependency = parsed // If no destination was given, default to the prefix if prefix.Destination == "" { prefix.Destination = prefix.Source } } // Update the list of set keys if c.setKeys == nil { c.setKeys = make(map[string]struct{}) } for _, key := range metadata.Keys { if _, ok := c.setKeys[key]; !ok { c.setKeys[key] = struct{}{} } } c.setKeys["path"] = struct{}{} d := DefaultConfig() d.Merge(c) c = d return c, errs.ErrorOrNil() }