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