github.com/getgauge/gauge@v1.6.9/util/fileUtils.go (about) 1 /*---------------------------------------------------------------- 2 * Copyright (c) ThoughtWorks, Inc. 3 * Licensed under the Apache License, Version 2.0 4 * See LICENSE in the project root for license information. 5 *----------------------------------------------------------------*/ 6 7 package util 8 9 import ( 10 "fmt" 11 "io" 12 "os" 13 "path/filepath" 14 "strings" 15 16 "github.com/getgauge/common" 17 "github.com/getgauge/gauge/config" 18 "github.com/getgauge/gauge/env" 19 "github.com/getgauge/gauge/logger" 20 ) 21 22 const ( 23 gaugeExcludeDirectories = "gauge_exclude_dirs" 24 cptFileExtension = ".cpt" 25 ) 26 27 var ignoredDirectories = make(map[string]bool) 28 29 func add(value string) { 30 value = strings.TrimSpace(value) 31 if !filepath.IsAbs(value) { 32 path, err := filepath.Abs(filepath.Join(config.ProjectRoot, value)) 33 if err != nil { 34 logger.Errorf(true, "Error getting absolute path. %v", err) 35 return 36 } 37 value = path 38 } 39 ignoredDirectories[value] = true 40 } 41 42 func addDirectories(value string) { 43 for _, dir := range strings.Split(value, ",") { 44 add(dir) 45 } 46 } 47 48 func addIgnoredDirectories() { 49 ignoredDirectories[filepath.Join(config.ProjectRoot, "gauge_bin")] = true 50 ignoredDirectories[filepath.Join(config.ProjectRoot, "reports")] = true 51 ignoredDirectories[filepath.Join(config.ProjectRoot, "logs")] = true 52 ignoredDirectories[filepath.Join(config.ProjectRoot, common.EnvDirectoryName)] = true 53 addDirFromEnv(env.GaugeReportsDir, add) 54 addDirFromEnv(env.LogsDirectory, add) 55 addDirFromEnv(gaugeExcludeDirectories, addDirectories) 56 } 57 58 func addDirFromEnv(name string, add func(value string)) { 59 value := os.Getenv(name) 60 if value != "" { 61 add(value) 62 } 63 } 64 65 // findFilesIn Finds all the files in the directory of a given extension 66 func findFilesIn(dirRoot string, isValidFile func(path string) bool, shouldSkip func(path string, f os.FileInfo) bool) []string { 67 absRoot, _ := filepath.Abs(dirRoot) 68 files := common.FindFilesInDir(absRoot, isValidFile, shouldSkip) 69 return files 70 } 71 72 // FindSpecFilesIn Finds spec files in the given directory 73 var FindSpecFilesIn = func(dir string) []string { 74 return findFilesIn(dir, IsValidSpecExtension, func(path string, f os.FileInfo) bool { 75 return false 76 }) 77 } 78 79 // IsValidSpecExtension Checks if the path has a spec file extension 80 func IsValidSpecExtension(path string) bool { 81 for _, ext := range env.GaugeSpecFileExtensions() { 82 if ext == strings.ToLower(filepath.Ext(path)) { 83 return true 84 } 85 } 86 return false 87 } 88 89 // FindConceptFilesIn Finds the concept files in specified directory 90 func FindConceptFilesIn(dir string) []string { 91 addIgnoredDirectories() 92 return findFilesIn(dir, IsValidConceptExtension, func(path string, f os.FileInfo) bool { 93 if !f.IsDir() { 94 return false 95 } 96 _, ok := ignoredDirectories[path] 97 return strings.HasPrefix(f.Name(), ".") || ok 98 }) 99 } 100 101 // IsValidConceptExtension Checks if the path has a concept file extension 102 func IsValidConceptExtension(path string) bool { 103 return strings.ToLower(filepath.Ext(path)) == cptFileExtension 104 } 105 106 // IsConcept Returns true if concept file 107 func IsConcept(path string) bool { 108 return IsValidConceptExtension(path) 109 } 110 111 // IsSpec Returns true if spec file file 112 func IsSpec(path string) bool { 113 return IsValidSpecExtension(path) 114 } 115 116 // IsGaugeFile Returns true if spec file or concept file 117 func IsGaugeFile(path string) bool { 118 return IsConcept(path) || IsSpec(path) 119 } 120 121 // IsGaugeFile Returns true if spec file or concept file 122 func GaugeFileExtensions() []string { 123 return append(env.GaugeSpecFileExtensions(), cptFileExtension) 124 } 125 126 // FindAllNestedDirs returns list of all nested directories in given path 127 func FindAllNestedDirs(dir string) []string { 128 var nestedDirs []string 129 err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { 130 if err == nil && info.IsDir() && !(path == dir) { 131 nestedDirs = append(nestedDirs, path) 132 } 133 return nil 134 }) 135 if err != nil { 136 logger.Errorf(false, "Failed to find nested directories for %s: %s", dir, err.Error()) 137 } 138 return nestedDirs 139 } 140 141 // IsDir reports whether path describes a directory. 142 func IsDir(path string) bool { 143 fileInfo, err := os.Stat(path) 144 if err != nil { 145 return false 146 } 147 return fileInfo.IsDir() 148 } 149 150 var exitWithMessage = func(message string) { 151 logger.Error(true, message) 152 os.Exit(1) 153 } 154 155 // GetSpecFiles returns the list of spec files present at the given path. 156 // If the path itself represents a spec file, it returns the same. 157 var GetSpecFiles = func(paths []string) []string { 158 var specFiles []string 159 for _, path := range paths { 160 if !common.FileExists(path) { 161 exitWithMessage(fmt.Sprintf("Specs directory %s does not exist.", path)) 162 } 163 if common.DirExists(path) { 164 specFilesInpath := FindSpecFilesIn(path) 165 if len(specFilesInpath) < 1 { 166 exitWithMessage(fmt.Sprintf("No specifications found in %s.", path)) 167 } 168 specFiles = append(specFiles, specFilesInpath...) 169 } else if IsValidSpecExtension(path) { 170 f, _ := filepath.Abs(path) 171 specFiles = append(specFiles, f) 172 } 173 } 174 return specFiles 175 } 176 177 func findConceptFiles(paths []string) []string { 178 var conceptFiles []string 179 for _, path := range paths { 180 var conceptPath = strings.TrimSpace(path) 181 if !filepath.IsAbs(conceptPath) { 182 conceptPath = filepath.Join(config.ProjectRoot, conceptPath) 183 } 184 absPath, err := filepath.Abs(conceptPath) 185 if err != nil { 186 logger.Fatalf(true, "Error getting absolute concept path. %v", err) 187 } 188 if !common.FileExists(absPath) { 189 exitWithMessage(fmt.Sprintf("No such file or diretory: %s", absPath)) 190 } 191 conceptFiles = append(conceptFiles, FindConceptFilesIn(absPath)...) 192 } 193 return conceptFiles 194 } 195 196 // GetConceptFiles It returns the list of concept files 197 // It returns concept files from gauge_concepts_dir if present 198 // It returns concept files from projectRoot otherwise 199 var GetConceptFiles = func() []string { 200 conceptPaths := GetConceptsPaths() 201 if len(conceptPaths) > 0 { 202 return removeDuplicateValues(findConceptFiles(conceptPaths)) 203 } 204 projRoot := config.ProjectRoot 205 if projRoot == "" { 206 logger.Fatalf(true, "Failed to get project root.") 207 } 208 absProjRoot, _ := filepath.Abs(projRoot) 209 files := findConceptFiles([]string{absProjRoot}) 210 specDirFromProperties := os.Getenv(env.SpecsDir) 211 if specDirFromProperties != "" { 212 specDirectories := strings.Split(specDirFromProperties, ",") 213 files = append(files, findConceptFiles(specDirectories)...) 214 } 215 return removeDuplicateValues(files) 216 } 217 218 func removeDuplicateValues(slice []string) []string { 219 keys := make(map[string]bool) 220 list := []string{} 221 for _, entry := range slice { 222 if _, value := keys[entry]; !value { 223 keys[entry] = true 224 list = append(list, entry) 225 } 226 } 227 return list 228 } 229 230 // SaveFile saves contents at the given path 231 func SaveFile(fileName string, content string, backup bool) { 232 err := common.SaveFile(fileName, content, backup) 233 if err != nil { 234 logger.Errorf(true, "Failed to refactor '%s': %s\n", fileName, err.Error()) 235 } 236 } 237 238 func RelPathToProjectRoot(path string) string { 239 return strings.TrimPrefix(path, config.ProjectRoot+string(filepath.Separator)) 240 } 241 242 // GetPathToFile returns the path to a given file from the Project root 243 func GetPathToFile(path string) string { 244 if filepath.IsAbs(path) { 245 return path 246 } 247 248 gaugeDataDir := env.GaugeDataDir() 249 if gaugeDataDir != "." && filepath.IsAbs(env.GaugeDataDir()) { 250 logger.Warningf(true, "'gauge_data_dir' property must be relative to Project Root. Found absolute path: %s", gaugeDataDir) 251 } 252 253 pathToFile := filepath.Join(config.ProjectRoot, gaugeDataDir, path) 254 logger.Debugf(true, "Reading data file: %s", pathToFile) 255 return pathToFile 256 } 257 258 // Remove removes all the files and directories recursively for the given path 259 func Remove(dir string) { 260 err := common.Remove(dir) 261 if err != nil { 262 logger.Warningf(true, "Failed to remove directory %s. Remove it manually. %s", dir, err.Error()) 263 } 264 } 265 266 // RemoveTempDir removes the temp dir 267 func RemoveTempDir() { 268 Remove(common.GetTempDir()) 269 } 270 271 // GetLinesFromText gets lines of a text in an array 272 func GetLinesFromText(text string) []string { 273 text = strings.Replace(text, "\r\n", "\n", -1) 274 return strings.Split(text, "\n") 275 } 276 277 // GetLineCount give no of lines in given text 278 func GetLineCount(text string) int { 279 return len(GetLinesFromText(text)) 280 } 281 282 func OpenFile(fileName string) (io.Writer, error) { 283 return os.OpenFile(fileName, os.O_APPEND|os.O_WRONLY, 0600) 284 }