github.com/jpedro/terraform@v0.11.12-beta1/helper/shadow/closer.go (about) 1 package shadow 2 3 import ( 4 "fmt" 5 "io" 6 "reflect" 7 8 "github.com/hashicorp/go-multierror" 9 "github.com/mitchellh/reflectwalk" 10 ) 11 12 // Close will close all shadow values within the given structure. 13 // 14 // This uses reflection to walk the structure, find all shadow elements, 15 // and close them. Currently this will only find struct fields that are 16 // shadow values, and not slice elements, etc. 17 func Close(v interface{}) error { 18 // We require a pointer so we can address the internal fields 19 val := reflect.ValueOf(v) 20 if val.Kind() != reflect.Ptr { 21 return fmt.Errorf("value must be a pointer") 22 } 23 24 // Walk and close 25 var w closeWalker 26 if err := reflectwalk.Walk(v, &w); err != nil { 27 return err 28 } 29 30 return w.Err 31 } 32 33 type closeWalker struct { 34 Err error 35 } 36 37 func (w *closeWalker) Struct(reflect.Value) error { 38 // Do nothing. We implement this for reflectwalk.StructWalker 39 return nil 40 } 41 42 var closerType = reflect.TypeOf((*io.Closer)(nil)).Elem() 43 44 func (w *closeWalker) StructField(f reflect.StructField, v reflect.Value) error { 45 // Not sure why this would be but lets avoid some panics 46 if !v.IsValid() { 47 return nil 48 } 49 50 // Empty for exported, so don't check unexported fields 51 if f.PkgPath != "" { 52 return nil 53 } 54 55 // Verify the io.Closer is in this package 56 typ := v.Type() 57 if typ.PkgPath() != "github.com/hashicorp/terraform/helper/shadow" { 58 return nil 59 } 60 61 var closer io.Closer 62 if v.Type().Implements(closerType) { 63 closer = v.Interface().(io.Closer) 64 } else if v.CanAddr() { 65 // The Close method may require a pointer receiver, but we only have a value. 66 v := v.Addr() 67 if v.Type().Implements(closerType) { 68 closer = v.Interface().(io.Closer) 69 } 70 } 71 72 if closer == nil { 73 return reflectwalk.SkipEntry 74 } 75 76 // Close it 77 if err := closer.Close(); err != nil { 78 w.Err = multierror.Append(w.Err, err) 79 } 80 81 // Don't go into the struct field 82 return reflectwalk.SkipEntry 83 }