]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/helper/shadow/closer.go
vendor: github.com/hashicorp/terraform/...@v0.10.0
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / helper / shadow / closer.go
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 }