github.com/alexissmirnov/terraform@v0.4.3-0.20150423153700-1ef9731a2f14/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": 37 fallthrough 38 case ".tf.json": 39 f = loadFileHcl 40 default: 41 } 42 43 if f == nil { 44 return nil, fmt.Errorf( 45 "%s: unknown configuration format. Use '.tf' or '.tf.json' extension", 46 root) 47 } 48 49 c, imps, err := f(root) 50 if err != nil { 51 return nil, err 52 } 53 54 children := make([]*importTree, len(imps)) 55 for i, imp := range imps { 56 t, err := loadTree(imp) 57 if err != nil { 58 return nil, err 59 } 60 61 children[i] = t 62 } 63 64 return &importTree{ 65 Path: root, 66 Raw: c, 67 Children: children, 68 }, nil 69 } 70 71 // Close releases any resources we might be holding open for the importTree. 72 // 73 // This can safely be called even while ConfigTree results are alive. The 74 // importTree is not bound to these. 75 func (t *importTree) Close() error { 76 if c, ok := t.Raw.(io.Closer); ok { 77 c.Close() 78 } 79 for _, ct := range t.Children { 80 ct.Close() 81 } 82 83 return nil 84 } 85 86 // ConfigTree traverses the importTree and turns each node into a *Config 87 // object, ultimately returning a *configTree. 88 func (t *importTree) ConfigTree() (*configTree, error) { 89 config, err := t.Raw.Config() 90 if err != nil { 91 return nil, fmt.Errorf( 92 "Error loading %s: %s", 93 t.Path, 94 err) 95 } 96 97 // Build our result 98 result := &configTree{ 99 Path: t.Path, 100 Config: config, 101 } 102 103 // Build the config trees for the children 104 result.Children = make([]*configTree, len(t.Children)) 105 for i, ct := range t.Children { 106 t, err := ct.ConfigTree() 107 if err != nil { 108 return nil, err 109 } 110 111 result.Children[i] = t 112 } 113 114 return result, nil 115 }