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