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  }