]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blame - vendor/github.com/hashicorp/terraform/config/import_tree.go
Merge branch 'fix_read_test' of github.com:alexandreFre/terraform-provider-statuscake
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / config / import_tree.go
CommitLineData
bae9f6d2
JC
1package config
2
3import (
15c0b25d 4 "bufio"
bae9f6d2
JC
5 "fmt"
6 "io"
15c0b25d
AP
7 "os"
8
9 "github.com/hashicorp/errwrap"
bae9f6d2
JC
10)
11
12// configurable is an interface that must be implemented by any configuration
13// formats of Terraform in order to return a *Config.
14type configurable interface {
15 Config() (*Config, error)
16}
17
18// importTree is the result of the first-pass load of the configuration
19// files. It is a tree of raw configurables and then any children (their
20// imports).
21//
22// An importTree can be turned into a configTree.
23type importTree struct {
24 Path string
25 Raw configurable
26 Children []*importTree
27}
28
29// This is the function type that must be implemented by the configuration
30// file loader to turn a single file into a configurable and any additional
31// imports.
32type fileLoaderFunc func(path string) (configurable, []string, error)
33
15c0b25d
AP
34// Set this to a non-empty value at link time to enable the HCL2 experiment.
35// This is not currently enabled for release builds.
36//
37// For example:
38// go install -ldflags="-X github.com/hashicorp/terraform/config.enableHCL2Experiment=true" github.com/hashicorp/terraform
39var enableHCL2Experiment = ""
40
bae9f6d2
JC
41// loadTree takes a single file and loads the entire importTree for that
42// file. This function detects what kind of configuration file it is an
43// executes the proper fileLoaderFunc.
44func loadTree(root string) (*importTree, error) {
45 var f fileLoaderFunc
15c0b25d
AP
46
47 // HCL2 experiment is currently activated at build time via the linker.
48 // See the comment on this variable for more information.
49 if enableHCL2Experiment == "" {
50 // Main-line behavior: always use the original HCL parser
51 switch ext(root) {
52 case ".tf", ".tf.json":
53 f = loadFileHcl
54 default:
55 }
56 } else {
57 // Experimental behavior: use the HCL2 parser if the opt-in comment
58 // is present.
59 switch ext(root) {
60 case ".tf":
61 // We need to sniff the file for the opt-in comment line to decide
62 // if the file is participating in the HCL2 experiment.
63 cf, err := os.Open(root)
64 if err != nil {
65 return nil, err
66 }
67 sc := bufio.NewScanner(cf)
68 for sc.Scan() {
69 if sc.Text() == "#terraform:hcl2" {
70 f = globalHCL2Loader.loadFile
71 }
72 }
73 if f == nil {
74 f = loadFileHcl
75 }
76 case ".tf.json":
77 f = loadFileHcl
78 default:
79 }
bae9f6d2
JC
80 }
81
82 if f == nil {
83 return nil, fmt.Errorf(
84 "%s: unknown configuration format. Use '.tf' or '.tf.json' extension",
85 root)
86 }
87
88 c, imps, err := f(root)
89 if err != nil {
90 return nil, err
91 }
92
93 children := make([]*importTree, len(imps))
94 for i, imp := range imps {
95 t, err := loadTree(imp)
96 if err != nil {
97 return nil, err
98 }
99
100 children[i] = t
101 }
102
103 return &importTree{
104 Path: root,
105 Raw: c,
106 Children: children,
107 }, nil
108}
109
110// Close releases any resources we might be holding open for the importTree.
111//
112// This can safely be called even while ConfigTree results are alive. The
113// importTree is not bound to these.
114func (t *importTree) Close() error {
115 if c, ok := t.Raw.(io.Closer); ok {
116 c.Close()
117 }
118 for _, ct := range t.Children {
119 ct.Close()
120 }
121
122 return nil
123}
124
125// ConfigTree traverses the importTree and turns each node into a *Config
126// object, ultimately returning a *configTree.
127func (t *importTree) ConfigTree() (*configTree, error) {
128 config, err := t.Raw.Config()
129 if err != nil {
15c0b25d 130 return nil, errwrap.Wrapf(fmt.Sprintf("Error loading %s: {{err}}", t.Path), err)
bae9f6d2
JC
131 }
132
133 // Build our result
134 result := &configTree{
135 Path: t.Path,
136 Config: config,
137 }
138
139 // Build the config trees for the children
140 result.Children = make([]*configTree, len(t.Children))
141 for i, ct := range t.Children {
142 t, err := ct.ConfigTree()
143 if err != nil {
144 return nil, err
145 }
146
147 result.Children[i] = t
148 }
149
150 return result, nil
151}