github.com/dougm/docker@v1.5.0/engine/env.go (about) 1 package engine 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io" 8 "strconv" 9 "strings" 10 ) 11 12 type Env []string 13 14 // Get returns the last value associated with the given key. If there are no 15 // values associated with the key, Get returns the empty string. 16 func (env *Env) Get(key string) (value string) { 17 // not using Map() because of the extra allocations https://github.com/docker/docker/pull/7488#issuecomment-51638315 18 for _, kv := range *env { 19 if strings.Index(kv, "=") == -1 { 20 continue 21 } 22 parts := strings.SplitN(kv, "=", 2) 23 if parts[0] != key { 24 continue 25 } 26 if len(parts) < 2 { 27 value = "" 28 } else { 29 value = parts[1] 30 } 31 } 32 return 33 } 34 35 func (env *Env) Exists(key string) bool { 36 _, exists := env.Map()[key] 37 return exists 38 } 39 40 // Len returns the number of keys in the environment. 41 // Note that len(env) might be different from env.Len(), 42 // because the same key might be set multiple times. 43 func (env *Env) Len() int { 44 return len(env.Map()) 45 } 46 47 func (env *Env) Init(src *Env) { 48 (*env) = make([]string, 0, len(*src)) 49 for _, val := range *src { 50 (*env) = append((*env), val) 51 } 52 } 53 54 func (env *Env) GetBool(key string) (value bool) { 55 s := strings.ToLower(strings.Trim(env.Get(key), " \t")) 56 if s == "" || s == "0" || s == "no" || s == "false" || s == "none" { 57 return false 58 } 59 return true 60 } 61 62 func (env *Env) SetBool(key string, value bool) { 63 if value { 64 env.Set(key, "1") 65 } else { 66 env.Set(key, "0") 67 } 68 } 69 70 func (env *Env) GetInt(key string) int { 71 return int(env.GetInt64(key)) 72 } 73 74 func (env *Env) GetInt64(key string) int64 { 75 s := strings.Trim(env.Get(key), " \t") 76 val, err := strconv.ParseInt(s, 10, 64) 77 if err != nil { 78 return 0 79 } 80 return val 81 } 82 83 func (env *Env) SetInt(key string, value int) { 84 env.Set(key, fmt.Sprintf("%d", value)) 85 } 86 87 func (env *Env) SetInt64(key string, value int64) { 88 env.Set(key, fmt.Sprintf("%d", value)) 89 } 90 91 // Returns nil if key not found 92 func (env *Env) GetList(key string) []string { 93 sval := env.Get(key) 94 if sval == "" { 95 return nil 96 } 97 l := make([]string, 0, 1) 98 if err := json.Unmarshal([]byte(sval), &l); err != nil { 99 l = append(l, sval) 100 } 101 return l 102 } 103 104 func (env *Env) GetSubEnv(key string) *Env { 105 sval := env.Get(key) 106 if sval == "" { 107 return nil 108 } 109 buf := bytes.NewBufferString(sval) 110 var sub Env 111 if err := sub.Decode(buf); err != nil { 112 return nil 113 } 114 return &sub 115 } 116 117 func (env *Env) SetSubEnv(key string, sub *Env) error { 118 var buf bytes.Buffer 119 if err := sub.Encode(&buf); err != nil { 120 return err 121 } 122 env.Set(key, string(buf.Bytes())) 123 return nil 124 } 125 126 func (env *Env) GetJson(key string, iface interface{}) error { 127 sval := env.Get(key) 128 if sval == "" { 129 return nil 130 } 131 return json.Unmarshal([]byte(sval), iface) 132 } 133 134 func (env *Env) SetJson(key string, value interface{}) error { 135 sval, err := json.Marshal(value) 136 if err != nil { 137 return err 138 } 139 env.Set(key, string(sval)) 140 return nil 141 } 142 143 func (env *Env) SetList(key string, value []string) error { 144 return env.SetJson(key, value) 145 } 146 147 func (env *Env) Set(key, value string) { 148 *env = append(*env, key+"="+value) 149 } 150 151 func NewDecoder(src io.Reader) *Decoder { 152 return &Decoder{ 153 json.NewDecoder(src), 154 } 155 } 156 157 type Decoder struct { 158 *json.Decoder 159 } 160 161 func (decoder *Decoder) Decode() (*Env, error) { 162 m := make(map[string]interface{}) 163 if err := decoder.Decoder.Decode(&m); err != nil { 164 return nil, err 165 } 166 env := &Env{} 167 for key, value := range m { 168 env.SetAuto(key, value) 169 } 170 return env, nil 171 } 172 173 // DecodeEnv decodes `src` as a json dictionary, and adds 174 // each decoded key-value pair to the environment. 175 // 176 // If `src` cannot be decoded as a json dictionary, an error 177 // is returned. 178 func (env *Env) Decode(src io.Reader) error { 179 m := make(map[string]interface{}) 180 if err := json.NewDecoder(src).Decode(&m); err != nil { 181 return err 182 } 183 for k, v := range m { 184 env.SetAuto(k, v) 185 } 186 return nil 187 } 188 189 func (env *Env) SetAuto(k string, v interface{}) { 190 // Issue 7941 - if the value in the incoming JSON is null then treat it 191 // as if they never specified the property at all. 192 if v == nil { 193 return 194 } 195 196 // FIXME: we fix-convert float values to int, because 197 // encoding/json decodes integers to float64, but cannot encode them back. 198 // (See http://golang.org/src/pkg/encoding/json/decode.go#L46) 199 if fval, ok := v.(float64); ok { 200 env.SetInt64(k, int64(fval)) 201 } else if sval, ok := v.(string); ok { 202 env.Set(k, sval) 203 } else if val, err := json.Marshal(v); err == nil { 204 env.Set(k, string(val)) 205 } else { 206 env.Set(k, fmt.Sprintf("%v", v)) 207 } 208 } 209 210 func changeFloats(v interface{}) interface{} { 211 switch v := v.(type) { 212 case float64: 213 return int(v) 214 case map[string]interface{}: 215 for key, val := range v { 216 v[key] = changeFloats(val) 217 } 218 case []interface{}: 219 for idx, val := range v { 220 v[idx] = changeFloats(val) 221 } 222 } 223 return v 224 } 225 226 func (env *Env) Encode(dst io.Writer) error { 227 m := make(map[string]interface{}) 228 for k, v := range env.Map() { 229 var val interface{} 230 if err := json.Unmarshal([]byte(v), &val); err == nil { 231 // FIXME: we fix-convert float values to int, because 232 // encoding/json decodes integers to float64, but cannot encode them back. 233 // (See http://golang.org/src/pkg/encoding/json/decode.go#L46) 234 m[k] = changeFloats(val) 235 } else { 236 m[k] = v 237 } 238 } 239 if err := json.NewEncoder(dst).Encode(&m); err != nil { 240 return err 241 } 242 return nil 243 } 244 245 func (env *Env) WriteTo(dst io.Writer) (n int64, err error) { 246 // FIXME: return the number of bytes written to respect io.WriterTo 247 return 0, env.Encode(dst) 248 } 249 250 func (env *Env) Import(src interface{}) (err error) { 251 defer func() { 252 if err != nil { 253 err = fmt.Errorf("ImportEnv: %s", err) 254 } 255 }() 256 var buf bytes.Buffer 257 if err := json.NewEncoder(&buf).Encode(src); err != nil { 258 return err 259 } 260 if err := env.Decode(&buf); err != nil { 261 return err 262 } 263 return nil 264 } 265 266 func (env *Env) Map() map[string]string { 267 m := make(map[string]string) 268 for _, kv := range *env { 269 parts := strings.SplitN(kv, "=", 2) 270 m[parts[0]] = parts[1] 271 } 272 return m 273 } 274 275 // MultiMap returns a representation of env as a 276 // map of string arrays, keyed by string. 277 // This is the same structure as http headers for example, 278 // which allow each key to have multiple values. 279 func (env *Env) MultiMap() map[string][]string { 280 m := make(map[string][]string) 281 for _, kv := range *env { 282 parts := strings.SplitN(kv, "=", 2) 283 m[parts[0]] = append(m[parts[0]], parts[1]) 284 } 285 return m 286 } 287 288 // InitMultiMap removes all values in env, then initializes 289 // new values from the contents of m. 290 func (env *Env) InitMultiMap(m map[string][]string) { 291 (*env) = make([]string, 0, len(m)) 292 for k, vals := range m { 293 for _, v := range vals { 294 env.Set(k, v) 295 } 296 } 297 }