github.com/haklop/terraform@v0.3.6/config/loader.go (about) 1 package config 2 3 import ( 4 "fmt" 5 "io" 6 "os" 7 "path/filepath" 8 "sort" 9 "strings" 10 ) 11 12 // Load loads the Terraform configuration from a given file. 13 // 14 // This file can be any format that Terraform recognizes, and import any 15 // other format that Terraform recognizes. 16 func Load(path string) (*Config, error) { 17 importTree, err := loadTree(path) 18 if err != nil { 19 return nil, err 20 } 21 22 configTree, err := importTree.ConfigTree() 23 24 // Close the importTree now so that we can clear resources as quickly 25 // as possible. 26 importTree.Close() 27 28 if err != nil { 29 return nil, err 30 } 31 32 return configTree.Flatten() 33 } 34 35 // LoadDir loads all the Terraform configuration files in a single 36 // directory and appends them together. 37 // 38 // Special files known as "override files" can also be present, which 39 // are merged into the loaded configuration. That is, the non-override 40 // files are loaded first to create the configuration. Then, the overrides 41 // are merged into the configuration to create the final configuration. 42 // 43 // Files are loaded in lexical order. 44 func LoadDir(root string) (*Config, error) { 45 files, overrides, err := dirFiles(root) 46 if err != nil { 47 return nil, err 48 } 49 if len(files) == 0 { 50 return nil, fmt.Errorf( 51 "No Terraform configuration files found in directory: %s", 52 root) 53 } 54 55 // Determine the absolute path to the directory. 56 rootAbs, err := filepath.Abs(root) 57 if err != nil { 58 return nil, err 59 } 60 61 var result *Config 62 63 // Sort the files and overrides so we have a deterministic order 64 sort.Strings(files) 65 sort.Strings(overrides) 66 67 // Load all the regular files, append them to each other. 68 for _, f := range files { 69 c, err := Load(f) 70 if err != nil { 71 return nil, err 72 } 73 74 if result != nil { 75 result, err = Append(result, c) 76 if err != nil { 77 return nil, err 78 } 79 } else { 80 result = c 81 } 82 } 83 84 // Load all the overrides, and merge them into the config 85 for _, f := range overrides { 86 c, err := Load(f) 87 if err != nil { 88 return nil, err 89 } 90 91 result, err = Merge(result, c) 92 if err != nil { 93 return nil, err 94 } 95 } 96 97 // Mark the directory 98 result.Dir = rootAbs 99 100 return result, nil 101 } 102 103 // IsEmptyDir returns true if the directory given has no Terraform 104 // configuration files. 105 func IsEmptyDir(root string) (bool, error) { 106 if _, err := os.Stat(root); err != nil && os.IsNotExist(err) { 107 return true, nil 108 } 109 110 fs, os, err := dirFiles(root) 111 if err != nil { 112 return false, err 113 } 114 115 return len(fs) == 0 && len(os) == 0, nil 116 } 117 118 // Ext returns the Terraform configuration extension of the given 119 // path, or a blank string if it is an invalid function. 120 func ext(path string) string { 121 if strings.HasSuffix(path, ".tf") { 122 return ".tf" 123 } else if strings.HasSuffix(path, ".tf.json") { 124 return ".tf.json" 125 } else { 126 return "" 127 } 128 } 129 130 func dirFiles(dir string) ([]string, []string, error) { 131 f, err := os.Open(dir) 132 if err != nil { 133 return nil, nil, err 134 } 135 defer f.Close() 136 137 fi, err := f.Stat() 138 if err != nil { 139 return nil, nil, err 140 } 141 if !fi.IsDir() { 142 return nil, nil, fmt.Errorf( 143 "configuration path must be a directory: %s", 144 dir) 145 } 146 147 var files, overrides []string 148 err = nil 149 for err != io.EOF { 150 var fis []os.FileInfo 151 fis, err = f.Readdir(128) 152 if err != nil && err != io.EOF { 153 return nil, nil, err 154 } 155 156 for _, fi := range fis { 157 // Ignore directories 158 if fi.IsDir() { 159 continue 160 } 161 162 // Only care about files that are valid to load 163 name := fi.Name() 164 extValue := ext(name) 165 if extValue == "" || isTemporaryFile(name) { 166 continue 167 } 168 169 // Determine if we're dealing with an override 170 nameNoExt := name[:len(name)-len(extValue)] 171 override := nameNoExt == "override" || 172 strings.HasSuffix(nameNoExt, "_override") 173 174 path := filepath.Join(dir, name) 175 if override { 176 overrides = append(overrides, path) 177 } else { 178 files = append(files, path) 179 } 180 } 181 } 182 183 return files, overrides, nil 184 } 185 186 // isTemporaryFile returns true or false depending on whether the 187 // provided file name is a temporary file for the following editors: 188 // emacs or vim. 189 func isTemporaryFile(name string) bool { 190 return strings.HasSuffix(name, "~") || // vim 191 strings.HasPrefix(name, ".#") || // emacs 192 (strings.HasPrefix(name, "#") && strings.HasSuffix(name, "#")) // emacs 193 }