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