github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/utils/path/marshal.go (about) 1 package path 2 3 import ( 4 "fmt" 5 "os" 6 "path" 7 "strings" 8 9 "github.com/lmorg/murex/lang/types" 10 "github.com/lmorg/murex/utils/consts" 11 ) 12 13 const ( 14 IS_RELATIVE = "IsRelative" 15 IS_DIR = "IsDir" 16 VALUE = "Value" 17 EXISTS = "Exists" 18 ) 19 20 func Marshal(v interface{}) ([]byte, error) { 21 switch t := v.(type) { 22 case string: 23 return []byte(t), nil 24 25 case []string: 26 s := Join(t) 27 return []byte(s), nil 28 29 case map[string]interface{}: 30 name, err := types.ConvertGoType(t[VALUE], types.String) 31 if err != nil { 32 return nil, fmt.Errorf("unable to get '%s' from %v", VALUE, t) 33 } 34 return []byte(name.(string)), nil 35 36 case []interface{}: 37 if len(t) == 0 { 38 return nil, nil 39 } 40 return marshalPathInterface(t) 41 42 default: 43 return nil, fmt.Errorf("%s can only marshal arrays. Instead got %T", types.Path, t) 44 } 45 } 46 47 func marshalPathInterface(v []interface{}) ([]byte, error) { 48 a := make([]string, len(v)) 49 50 for i := range v { 51 switch v[i].(type) { 52 case map[string]interface{}: 53 name, err := types.ConvertGoType(v[i].(map[string]interface{})[VALUE], types.String) 54 if err != nil { 55 return nil, fmt.Errorf("unable to get '%s' from %v", VALUE, v[i]) 56 } 57 a[i] = name.(string) 58 59 default: 60 name, err := types.ConvertGoType(v[i], types.String) 61 if err != nil { 62 return nil, err 63 } 64 a[i] = name.(string) 65 } 66 } 67 68 s := Join(a) 69 s = path.Clean(s) 70 71 return []byte(s), nil 72 } 73 74 var pathSlashByte = consts.PathSlash[0] 75 76 func Unmarshal(b []byte) (interface{}, error) { 77 if len(b) == 0 { 78 b = []byte{'.'} 79 } 80 81 relative := b[0] != pathSlashByte 82 path := string(b) 83 84 f, err := os.Stat(path) 85 dir := err == nil && f.IsDir() 86 87 split := Split(path) 88 89 notExists := make([]bool, len(split)) 90 for i := len(split) - 1; i > -1; i-- { 91 notExists[i] = os.IsNotExist(err) 92 if !notExists[i] { 93 break 94 } 95 _, err = os.Stat(strings.Join(split[:i], consts.PathSlash)) 96 } 97 98 v := make([]interface{}, len(split)) 99 100 for i := range split { 101 v[i] = map[string]interface{}{ 102 IS_RELATIVE: relative && i == 0, 103 IS_DIR: (dir && i == len(split)-1) || i < len(split)-1, 104 VALUE: split[i], 105 EXISTS: !notExists[i], 106 } 107 } 108 109 return v, nil 110 }