From c38395490d1ebd0ea2a51ef85b34f029f72e17b0 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Thu, 28 Dec 2017 13:10:50 -0800 Subject: [PATCH] allow setting nested metadata --- file.go | 7 +++--- goldsmith.go | 2 +- util.go | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 5 deletions(-) diff --git a/file.go b/file.go index 6e12532..3145986 100644 --- a/file.go +++ b/file.go @@ -127,12 +127,11 @@ func (f *file) ModTime() time.Time { } func (f *file) Value(key string) (interface{}, bool) { - value, ok := f.Meta[key] - return value, ok + return getDelimValue(f.Meta, key) } -func (f *file) SetValue(key string, value interface{}) { - f.Meta[key] = value +func (f *file) SetValue(key string, value interface{}) bool { + return setDelimValue(f.Meta, key, value) } func (f *file) CopyValues(src File) { diff --git a/goldsmith.go b/goldsmith.go index 407cc7a..ce49920 100644 --- a/goldsmith.go +++ b/goldsmith.go @@ -51,7 +51,7 @@ type File interface { ModTime() time.Time Value(key string) (interface{}, bool) - SetValue(key string, value interface{}) + SetValue(key string, value interface{}) bool CopyValues(src File) Read(p []byte) (int, error) diff --git a/util.go b/util.go index f5d0164..5c0d91c 100644 --- a/util.go +++ b/util.go @@ -25,6 +25,8 @@ package goldsmith import ( "os" "path/filepath" + "reflect" + "strings" ) type fileInfo struct { @@ -55,3 +57,67 @@ func scanDir(root string, infos chan fileInfo) { return nil }) } + +func setDelimValue(container interface{}, path string, data interface{}) bool { + containerVal := reflect.Indirect(reflect.ValueOf(container)) + + segments := strings.Split(path, ".") + segmentHead := segments[0] + + if len(segments) > 1 { + var fieldVal reflect.Value + switch containerVal.Kind() { + case reflect.Map: + fieldVal = containerVal.MapIndex(reflect.ValueOf(segmentHead)) + case reflect.Struct: + fieldVal = containerVal.FieldByName(segmentHead) + if fieldVal.CanAddr() { + fieldVal = fieldVal.Addr() + } + } + + if fieldVal.IsValid() && fieldVal.CanInterface() { + pathRest := strings.Join(segments[1:], ".") + return setDelimValue(fieldVal.Interface(), pathRest, data) + } + } else { + switch containerVal.Kind() { + case reflect.Map: + containerVal.SetMapIndex(reflect.ValueOf(segmentHead), reflect.ValueOf(data)) + return true + case reflect.Struct: + fieldVal := containerVal.FieldByName(segmentHead) + if fieldVal.CanSet() { + fieldVal.Set(reflect.ValueOf(data)) + return true + } + } + } + + return false +} + +func getDelimValue(container interface{}, path string) (interface{}, bool) { + containerVal := reflect.Indirect(reflect.ValueOf(container)) + + segments := strings.Split(path, ".") + segmentHead := segments[0] + + var fieldVal reflect.Value + switch containerVal.Kind() { + case reflect.Map: + fieldVal = containerVal.MapIndex(reflect.ValueOf(segmentHead)) + case reflect.Struct: + fieldVal = containerVal.FieldByName(segmentHead) + } + + if fieldVal.IsValid() && fieldVal.CanInterface() { + if len(segments) > 1 { + return getDelimValue(fieldVal.Interface(), strings.Join(segments[1:], ".")) + } + + return fieldVal.Interface(), true + } + + return nil, false +}