]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/configs/parser_config_dir.go
update vendor and go.mod
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / configs / parser_config_dir.go
1 package configs
2
3 import (
4 "fmt"
5 "os"
6 "path/filepath"
7 "strings"
8
9 "github.com/hashicorp/hcl2/hcl"
10 )
11
12 // LoadConfigDir reads the .tf and .tf.json files in the given directory
13 // as config files (using LoadConfigFile) and then combines these files into
14 // a single Module.
15 //
16 // If this method returns nil, that indicates that the given directory does not
17 // exist at all or could not be opened for some reason. Callers may wish to
18 // detect this case and ignore the returned diagnostics so that they can
19 // produce a more context-aware error message in that case.
20 //
21 // If this method returns a non-nil module while error diagnostics are returned
22 // then the module may be incomplete but can be used carefully for static
23 // analysis.
24 //
25 // This file does not consider a directory with no files to be an error, and
26 // will simply return an empty module in that case. Callers should first call
27 // Parser.IsConfigDir if they wish to recognize that situation.
28 //
29 // .tf files are parsed using the HCL native syntax while .tf.json files are
30 // parsed using the HCL JSON syntax.
31 func (p *Parser) LoadConfigDir(path string) (*Module, hcl.Diagnostics) {
32 primaryPaths, overridePaths, diags := p.dirFiles(path)
33 if diags.HasErrors() {
34 return nil, diags
35 }
36
37 primary, fDiags := p.loadFiles(primaryPaths, false)
38 diags = append(diags, fDiags...)
39 override, fDiags := p.loadFiles(overridePaths, true)
40 diags = append(diags, fDiags...)
41
42 mod, modDiags := NewModule(primary, override)
43 diags = append(diags, modDiags...)
44
45 mod.SourceDir = path
46
47 return mod, diags
48 }
49
50 // ConfigDirFiles returns lists of the primary and override files configuration
51 // files in the given directory.
52 //
53 // If the given directory does not exist or cannot be read, error diagnostics
54 // are returned. If errors are returned, the resulting lists may be incomplete.
55 func (p Parser) ConfigDirFiles(dir string) (primary, override []string, diags hcl.Diagnostics) {
56 return p.dirFiles(dir)
57 }
58
59 // IsConfigDir determines whether the given path refers to a directory that
60 // exists and contains at least one Terraform config file (with a .tf or
61 // .tf.json extension.)
62 func (p *Parser) IsConfigDir(path string) bool {
63 primaryPaths, overridePaths, _ := p.dirFiles(path)
64 return (len(primaryPaths) + len(overridePaths)) > 0
65 }
66
67 func (p *Parser) loadFiles(paths []string, override bool) ([]*File, hcl.Diagnostics) {
68 var files []*File
69 var diags hcl.Diagnostics
70
71 for _, path := range paths {
72 var f *File
73 var fDiags hcl.Diagnostics
74 if override {
75 f, fDiags = p.LoadConfigFileOverride(path)
76 } else {
77 f, fDiags = p.LoadConfigFile(path)
78 }
79 diags = append(diags, fDiags...)
80 if f != nil {
81 files = append(files, f)
82 }
83 }
84
85 return files, diags
86 }
87
88 func (p *Parser) dirFiles(dir string) (primary, override []string, diags hcl.Diagnostics) {
89 infos, err := p.fs.ReadDir(dir)
90 if err != nil {
91 diags = append(diags, &hcl.Diagnostic{
92 Severity: hcl.DiagError,
93 Summary: "Failed to read module directory",
94 Detail: fmt.Sprintf("Module directory %s does not exist or cannot be read.", dir),
95 })
96 return
97 }
98
99 for _, info := range infos {
100 if info.IsDir() {
101 // We only care about files
102 continue
103 }
104
105 name := info.Name()
106 ext := fileExt(name)
107 if ext == "" || IsIgnoredFile(name) {
108 continue
109 }
110
111 baseName := name[:len(name)-len(ext)] // strip extension
112 isOverride := baseName == "override" || strings.HasSuffix(baseName, "_override")
113
114 fullPath := filepath.Join(dir, name)
115 if isOverride {
116 override = append(override, fullPath)
117 } else {
118 primary = append(primary, fullPath)
119 }
120 }
121
122 return
123 }
124
125 // fileExt returns the Terraform configuration extension of the given
126 // path, or a blank string if it is not a recognized extension.
127 func fileExt(path string) string {
128 if strings.HasSuffix(path, ".tf") {
129 return ".tf"
130 } else if strings.HasSuffix(path, ".tf.json") {
131 return ".tf.json"
132 } else {
133 return ""
134 }
135 }
136
137 // IsIgnoredFile returns true if the given filename (which must not have a
138 // directory path ahead of it) should be ignored as e.g. an editor swap file.
139 func IsIgnoredFile(name string) bool {
140 return strings.HasPrefix(name, ".") || // Unix-like hidden files
141 strings.HasSuffix(name, "~") || // vim
142 strings.HasPrefix(name, "#") && strings.HasSuffix(name, "#") // emacs
143 }
144
145 // IsEmptyDir returns true if the given filesystem path contains no Terraform
146 // configuration files.
147 //
148 // Unlike the methods of the Parser type, this function always consults the
149 // real filesystem, and thus it isn't appropriate to use when working with
150 // configuration loaded from a plan file.
151 func IsEmptyDir(path string) (bool, error) {
152 if _, err := os.Stat(path); err != nil && os.IsNotExist(err) {
153 return true, nil
154 }
155
156 p := NewParser(nil)
157 fs, os, err := p.dirFiles(path)
158 if err != nil {
159 return false, err
160 }
161
162 return len(fs) == 0 && len(os) == 0, nil
163 }