add yaml
This commit is contained in:
132
yaml.go
132
yaml.go
@@ -2,9 +2,12 @@ package storage
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"local/storage/resolve"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
@@ -43,7 +46,19 @@ func (y *Yaml) Namespaces() ([][]string, error) {
|
||||
}
|
||||
|
||||
func (y *Yaml) List(ns []string, limits ...string) ([]string, error) {
|
||||
return nil, errors.New("not impl")
|
||||
namespace := resolve.Namespace(ns)
|
||||
m, err := y.getMap(namespace)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
limits = resolve.Limits(limits)
|
||||
ks := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
if k >= limits[0] && k <= limits[1] {
|
||||
ks = append(ks, k)
|
||||
}
|
||||
}
|
||||
return ks, nil
|
||||
}
|
||||
|
||||
func (y *Yaml) Get(key string, ns ...string) ([]byte, error) {
|
||||
@@ -55,7 +70,21 @@ func (y *Yaml) Get(key string, ns ...string) ([]byte, error) {
|
||||
}
|
||||
|
||||
func (y *Yaml) GetStream(key string, ns ...string) (io.Reader, error) {
|
||||
return nil, errors.New("not impl")
|
||||
namespace := resolve.Namespace(ns)
|
||||
m, err := y.getMap(namespace)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v, ok := m[key]
|
||||
if !ok {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
s, ok := v.(string)
|
||||
if !ok {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
b, err := base64.StdEncoding.DecodeString(s)
|
||||
return bytes.NewReader(b), err
|
||||
}
|
||||
|
||||
func (y *Yaml) Set(key string, value []byte, ns ...string) error {
|
||||
@@ -67,30 +96,98 @@ func (y *Yaml) Set(key string, value []byte, ns ...string) error {
|
||||
}
|
||||
|
||||
func (y *Yaml) Del(key string, ns ...string) error {
|
||||
return errors.New("not impl")
|
||||
return y.SetStream(key, nil, ns...)
|
||||
}
|
||||
|
||||
func (y *Yaml) SetStream(key string, r io.Reader, ns ...string) error {
|
||||
return errors.New("not impl")
|
||||
namespace := resolve.Namespace(ns)
|
||||
var v interface{} = nil
|
||||
if r != nil {
|
||||
b, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v = base64.StdEncoding.EncodeToString(b)
|
||||
}
|
||||
m, err := y.getMap()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := setInMap(m, []string{namespace}, key, v); err != nil {
|
||||
return err
|
||||
}
|
||||
return y.setMap(m)
|
||||
}
|
||||
|
||||
func (y *Yaml) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (y *Yaml) getMap() (map[string]interface{}, error) {
|
||||
func (y *Yaml) getMap(keys ...string) (map[string]interface{}, error) {
|
||||
b, err := y.get()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var m map[string]interface{}
|
||||
err = yaml.Unmarshal(b, &m)
|
||||
var mBad map[interface{}]interface{}
|
||||
if err := yaml.Unmarshal(b, &mBad); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m, err := mbadToM(mBad)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if m == nil {
|
||||
m = map[string]interface{}{}
|
||||
}
|
||||
for _, k := range keys {
|
||||
subv, ok := m[k]
|
||||
if !ok {
|
||||
subv = map[string]interface{}{}
|
||||
m[k] = subv
|
||||
}
|
||||
subm, ok := subv.(map[string]interface{})
|
||||
if !ok {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
m = subm
|
||||
}
|
||||
return m, err
|
||||
}
|
||||
|
||||
func (y *Yaml) setMap(m map[string]interface{}) error {
|
||||
b, err := yaml.Marshal(m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return y.set(b)
|
||||
}
|
||||
|
||||
func setInMap(m map[string]interface{}, keys []string, key string, v interface{}) error {
|
||||
if len(keys) == 0 {
|
||||
m[key] = v
|
||||
if v == nil {
|
||||
delete(m, key)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
subv, ok := m[keys[0]]
|
||||
if !ok {
|
||||
subv = map[string]interface{}{}
|
||||
}
|
||||
subm, ok := subv.(map[string]interface{})
|
||||
if !ok {
|
||||
return errors.New("clobber")
|
||||
}
|
||||
if err := setInMap(subm, keys[1:], key, v); err != nil {
|
||||
return err
|
||||
}
|
||||
m[keys[0]] = subm
|
||||
return nil
|
||||
}
|
||||
|
||||
func (y *Yaml) get() ([]byte, error) {
|
||||
b, err := ioutil.ReadFile(y.path)
|
||||
if err == os.ErrNotExist {
|
||||
if os.IsNotExist(err) {
|
||||
return []byte{}, nil
|
||||
}
|
||||
return b, err
|
||||
@@ -127,3 +224,22 @@ func _keysDFS(m map[string]interface{}) ([][]string, bool, error) {
|
||||
}
|
||||
return keys, hasNonMaps, nil
|
||||
}
|
||||
|
||||
func mbadToM(mBad map[interface{}]interface{}) (map[string]interface{}, error) {
|
||||
m := map[string]interface{}{}
|
||||
for k, v := range mBad {
|
||||
s, ok := k.(string)
|
||||
if !ok {
|
||||
s = fmt.Sprint(k)
|
||||
}
|
||||
m[s] = v
|
||||
if m2, ok := v.(map[interface{}]interface{}); ok {
|
||||
v2, err := mbadToM(m2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m[s] = v2
|
||||
}
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user