github.com/shvar/terraform@v0.6.9-0.20151215234924-3365cd2231df/config/import_tree.go (about) 1 package config 2 3 import ( 4 "fmt" 5 "io" 6 ) 7 8 // configurable is an interface that must be implemented by any configuration 9 // formats of Terraform in order to return a *Config. 10 type configurable interface { 11 Config() (*Config, error) 12 } 13 14 // importTree is the result of the first-pass load of the configuration 15 // files. It is a tree of raw configurables and then any children (their 16 // imports). 17 // 18 // An importTree can be turned into a configTree. 19 type importTree struct { 20 Path string 21 Raw configurable 22 Children []*importTree 23 } 24 25 // This is the function type that must be implemented by the configuration 26 // file loader to turn a single file into a configurable and any additional 27 // imports. 28 type fileLoaderFunc func(path string) (configurable, []string, error) 29 30 // loadTree takes a single file and loads the entire importTree for that 31 // file. This function detects what kind of configuration file it is an 32 // executes the proper fileLoaderFunc. 33 func loadTree(root string) (*importTree, error) { 34 var f fileLoaderFunc 35 switch ext(root) { 36 case ".tf", ".tf.json": 37 f = loadFileHcl 38 default: 39 } 40 41 if f == nil { 42 return nil, fmt.Errorf( 43 "%s: unknown configuration format. Use '.tf' or '.tf.json' extension", 44 root) 45 } 46 47 c, imps, err := f(root) 48 if err != nil { 49 return nil, err 50 } 51 52 children := make([]*importTree, len(imps)) 53 for i, imp := range imps { 54 t, err := loadTree(imp) 55 if err != nil { 56 return nil, err 57 } 58 59 children[i] = t 60 } 61 62 return &importTree{ 63 Path: root, 64 Raw: c, 65 Children: children, 66 }, nil 67 } 68 69 // Close releases any resources we might be holding open for the importTree. 70 // 71 // This can safely be called even while ConfigTree results are alive. The 72 // importTree is not bound to these. 73 func (t *importTree) Close() error { 74 if c, ok := t.Raw.(io.Closer); ok { 75 c.Close() 76 } 77 for _, ct := range t.Children { 78 ct.Close() 79 } 80 81 return nil 82 } 83 84 // ConfigTree traverses the importTree and turns each node into a *Config 85 // object, ultimately returning a *configTree. 86 func (t *importTree) ConfigTree() (*configTree, error) { 87 config, err := t.Raw.Config() 88 if err != nil { 89 return nil, fmt.Errorf( 90 "Error loading %s: %s", 91 t.Path, 92 err) 93 } 94 95 // Build our result 96 result := &configTree{ 97 Path: t.Path, 98 Config: config, 99 } 100 101 // Build the config trees for the children 102 result.Children = make([]*configTree, len(t.Children)) 103 for i, ct := range t.Children { 104 t, err := ct.ConfigTree() 105 if err != nil { 106 return nil, err 107 } 108 109 result.Children[i] = t 110 } 111 112 return result, nil 113 }