func (d *decoder) decodeInterface(name string, o *hcl.Object, result reflect.Value) error { var set reflect.Value redecode := true switch o.Type { case hcl.ValueTypeObject: // If we're at the root or we're directly within a slice, then we // decode objects into map[string]interface{}, otherwise we decode // them into lists. if len(d.stack) == 0 || d.stack[len(d.stack)-1] == reflect.Slice { var temp map[string]interface{} tempVal := reflect.ValueOf(temp) result := reflect.MakeMap( reflect.MapOf( reflect.TypeOf(""), tempVal.Type().Elem())) set = result } else { var temp []map[string]interface{} tempVal := reflect.ValueOf(temp) result := reflect.MakeSlice( reflect.SliceOf(tempVal.Type().Elem()), 0, int(o.Len())) set = result } case hcl.ValueTypeList: var temp []interface{} tempVal := reflect.ValueOf(temp) result := reflect.MakeSlice( reflect.SliceOf(tempVal.Type().Elem()), 0, 0) set = result case hcl.ValueTypeBool: var result bool set = reflect.Indirect(reflect.New(reflect.TypeOf(result))) case hcl.ValueTypeFloat: var result float64 set = reflect.Indirect(reflect.New(reflect.TypeOf(result))) case hcl.ValueTypeInt: var result int set = reflect.Indirect(reflect.New(reflect.TypeOf(result))) case hcl.ValueTypeString: set = reflect.Indirect(reflect.New(reflect.TypeOf(""))) default: return fmt.Errorf( "%s: cannot decode into interface: %T", name, o) } // Set the result to what its supposed to be, then reset // result so we don't reflect into this method anymore. result.Set(set) if redecode { // Revisit the node so that we can use the newly instantiated // thing and populate it. if err := d.decode(name, o, result); err != nil { return err } } return nil }
func loadProvisionersHcl(os *hclobj.Object, connInfo map[string]interface{}) ([]*Provisioner, error) { pos := make([]*hclobj.Object, 0, int(os.Len())) // Accumulate all the actual provisioner configuration objects. We // have to iterate twice here: // // 1. The first iteration is of the list of `provisioner` blocks. // 2. The second iteration is of the dictionary within the // provisioner which will have only one element which is the // type of provisioner to use along with tis config. // // In JSON it looks kind of like this: // // [ // { // "shell": { // ... // } // } // ] // for _, o1 := range os.Elem(false) { for _, o2 := range o1.Elem(true) { switch o1.Type { case hclobj.ValueTypeList: for _, o3 := range o2.Elem(true) { pos = append(pos, o3) } case hclobj.ValueTypeObject: pos = append(pos, o2) } } } // Short-circuit if there are no items if len(pos) == 0 { return nil, nil } result := make([]*Provisioner, 0, len(pos)) for _, po := range pos { var config map[string]interface{} if err := hcl.DecodeObject(&config, po); err != nil { return nil, err } // Delete the "connection" section, handle seperately delete(config, "connection") rawConfig, err := NewRawConfig(config) if err != nil { return nil, err } // Check if we have a provisioner-level connection // block that overrides the resource-level var subConnInfo map[string]interface{} if o := po.Get("connection", false); o != nil { err := hcl.DecodeObject(&subConnInfo, o) if err != nil { return nil, err } } // Inherit from the resource connInfo any keys // that are not explicitly overriden. if connInfo != nil && subConnInfo != nil { for k, v := range connInfo { if _, ok := subConnInfo[k]; !ok { subConnInfo[k] = v } } } else if subConnInfo == nil { subConnInfo = connInfo } // Parse the connInfo connRaw, err := NewRawConfig(subConnInfo) if err != nil { return nil, err } result = append(result, &Provisioner{ Type: po.Key, RawConfig: rawConfig, ConnInfo: connRaw, }) } return result, nil }