github.com/oweisse/u-root@v0.0.0-20181109060735-d005ad25fef1/cmds/elvish/eval/env_list.go (about)

     1  package eval
     2  
     3  import (
     4  	"errors"
     5  	"os"
     6  	"strings"
     7  	"sync"
     8  
     9  	"github.com/u-root/u-root/cmds/elvish/eval/vals"
    10  	"github.com/u-root/u-root/cmds/elvish/eval/vars"
    11  	"github.com/u-root/u-root/cmds/elvish/util"
    12  	"github.com/u-root/u-root/cmds/elvish/vector"
    13  )
    14  
    15  var (
    16  	pathListSeparator = string(os.PathListSeparator)
    17  	forbiddenInPath   = pathListSeparator + "\x00"
    18  )
    19  
    20  // Errors
    21  var (
    22  	ErrCanOnlyAssignList          = errors.New("can only assign compatible values")
    23  	ErrPathMustBeString           = errors.New("path must be string")
    24  	ErrPathCannotContainColonZero = errors.New(`path cannot contain colon or \0`)
    25  )
    26  
    27  // EnvList is a variable whose value is constructed from an environment variable
    28  // by splitting at pathListSeparator. Changes to it are also propagated to the
    29  // corresponding environment variable. Its elements cannot contain
    30  // pathListSeparator or \0; attempting to put any in its elements will result in
    31  // an error.
    32  type EnvList struct {
    33  	sync.RWMutex
    34  	envName    string
    35  	cacheFor   string
    36  	cacheValue interface{}
    37  }
    38  
    39  var (
    40  	_ vars.Var = (*EnvList)(nil)
    41  )
    42  
    43  // Get returns a Value for an EnvPathList.
    44  func (envli *EnvList) Get() interface{} {
    45  	envli.Lock()
    46  	defer envli.Unlock()
    47  
    48  	value := os.Getenv(envli.envName)
    49  	if value == envli.cacheFor {
    50  		return envli.cacheValue
    51  	}
    52  	envli.cacheFor = value
    53  	v := vector.Empty
    54  	for _, path := range strings.Split(value, pathListSeparator) {
    55  		v = v.Cons(path)
    56  	}
    57  	envli.cacheValue = v
    58  	return envli.cacheValue
    59  }
    60  
    61  // Set sets an EnvPathList. The underlying environment variable is set.
    62  func (envli *EnvList) Set(v interface{}) error {
    63  	var (
    64  		paths      []string
    65  		errElement error
    66  	)
    67  	errIterate := vals.Iterate(v, func(v interface{}) bool {
    68  		s, ok := v.(string)
    69  		if !ok {
    70  			errElement = ErrPathMustBeString
    71  			return false
    72  		}
    73  		path := s
    74  		if strings.ContainsAny(path, forbiddenInPath) {
    75  			errElement = ErrPathCannotContainColonZero
    76  			return false
    77  		}
    78  		paths = append(paths, s)
    79  		return true
    80  	})
    81  
    82  	if errElement != nil || errIterate != nil {
    83  		return util.Errors(errElement, errIterate)
    84  	}
    85  
    86  	envli.Lock()
    87  	defer envli.Unlock()
    88  	os.Setenv(envli.envName, strings.Join(paths, pathListSeparator))
    89  	return nil
    90  }