package storage import ( "bytes" "errors" "io" "io/ioutil" "os" "path" "path/filepath" yaml "gopkg.in/yaml.v2" ) const ( yamlExt = ".yaml" ) type Yaml struct { path string } func NewYaml(p string) (*Yaml, error) { _, err := os.Stat(path.Dir(p)) if err != nil { return nil, err } p, err = filepath.Abs(p) if err != nil { return nil, err } return &Yaml{ path: p, }, os.MkdirAll(path.Dir(p), os.ModePerm) } func (y *Yaml) Namespaces() ([][]string, error) { m, err := y.getMap() if err != nil { return nil, err } return keysDFS(m) } func (y *Yaml) List(ns []string, limits ...string) ([]string, error) { return nil, errors.New("not impl") } func (y *Yaml) Get(key string, ns ...string) ([]byte, error) { r, err := y.GetStream(key, ns...) if err != nil { return nil, err } return ioutil.ReadAll(r) } func (y *Yaml) GetStream(key string, ns ...string) (io.Reader, error) { return nil, errors.New("not impl") } func (y *Yaml) Set(key string, value []byte, ns ...string) error { r := bytes.NewReader(value) if value == nil { return y.Del(key, ns...) } return y.SetStream(key, r, ns...) } func (y *Yaml) Del(key string, ns ...string) error { return errors.New("not impl") } func (y *Yaml) SetStream(key string, r io.Reader, ns ...string) error { return errors.New("not impl") } func (y *Yaml) Close() error { return nil } func (y *Yaml) getMap() (map[string]interface{}, error) { b, err := y.get() if err != nil { return nil, err } var m map[string]interface{} err = yaml.Unmarshal(b, &m) return m, err } func (y *Yaml) get() ([]byte, error) { b, err := ioutil.ReadFile(y.path) if err == os.ErrNotExist { return []byte{}, nil } return b, err } func (y *Yaml) set(b []byte) error { return ioutil.WriteFile(y.path, b, os.ModePerm) } func keysDFS(m map[string]interface{}) ([][]string, error) { keys, _, err := _keysDFS(m) return keys, err } func _keysDFS(m map[string]interface{}) ([][]string, bool, error) { keys := make([][]string, 0) hasNonMaps := false for k, v := range m { if subm, ok := v.(map[string]interface{}); ok { subkeys, hasElements, err := _keysDFS(subm) if err != nil { return nil, false, err } if hasElements { subkeys = append(subkeys, []string{}) } for i := range subkeys { subkeys[i] = append([]string{k}, subkeys[i]...) keys = append(keys, subkeys[i]) } } else { hasNonMaps = true } } return keys, hasNonMaps, nil }