1package common 2 3import ( 4 "errors" 5 "fmt" 6 "os" 7 "path" 8 "strings" 9) 10 11// IsDir returns true if given path is a directory, 12// or returns false when it's a file or does not exist. 13func IsDir(dir string) bool { 14 f, e := os.Stat(dir) 15 if e != nil { 16 return false 17 } 18 return f.IsDir() 19} 20 21func statDir(dirPath, recPath string, includeDir, isDirOnly bool) ([]string, error) { 22 dir, err := os.Open(dirPath) 23 if err != nil { 24 return nil, err 25 } 26 defer dir.Close() 27 28 fis, err := dir.Readdir(0) 29 if err != nil { 30 return nil, err 31 } 32 33 var statList []string 34 35 for _, fi := range fis { 36 if strings.Contains(fi.Name(), ".DS_Store") { 37 continue 38 } 39 40 relPath := path.Join(recPath, fi.Name()) 41 curPath := path.Join(dirPath, fi.Name()) 42 if fi.IsDir() { 43 if includeDir { 44 statList = append(statList, relPath+"/") 45 } 46 s, err := statDir(curPath, relPath, includeDir, isDirOnly) 47 if err != nil { 48 return nil, err 49 } 50 statList = append(statList, s...) 51 } else if !isDirOnly { 52 statList = append(statList, relPath) 53 } 54 } 55 return statList, nil 56} 57 58// StatDir gathers information of given directory by depth-first. 59// It returns slice of file list and includes subdirectories if enabled; 60// it returns error and nil slice when error occurs in underlying functions, 61// or given path is not a directory or does not exist. 62// 63// Slice does not include given path itself. 64// If subdirectories is enabled, they will have suffix '/'. 65func StatDir(rootPath string, includeDir ...bool) ([]string, error) { 66 if !IsDir(rootPath) { 67 return nil, errors.New("not a directory or does not exist: " + rootPath) 68 } 69 70 isIncludeDir := false 71 if len(includeDir) >= 1 { 72 isIncludeDir = includeDir[0] 73 } 74 return statDir(rootPath, "", isIncludeDir, false) 75} 76 77// GetAllSubDirs returns all subdirectories of given root path. 78// Slice does not include given path itself. 79func GetAllSubDirs(rootPath string) ([]string, error) { 80 if !IsDir(rootPath) { 81 return nil, errors.New("not a directory or does not exist: " + rootPath) 82 } 83 return statDir(rootPath, "", true, true) 84} 85 86// GetFileListBySuffix returns an ordered list of file paths. 87// It recognize if given path is a file, and don't do recursive find. 88func GetFileListBySuffix(dirPath, suffix string) ([]string, error) { 89 if !IsExist(dirPath) { 90 return nil, fmt.Errorf("given path does not exist: %s", dirPath) 91 } else if IsFile(dirPath) { 92 return []string{dirPath}, nil 93 } 94 95 // Given path is a directory. 96 dir, err := os.Open(dirPath) 97 if err != nil { 98 return nil, err 99 } 100 101 fis, err := dir.Readdir(0) 102 if err != nil { 103 return nil, err 104 } 105 106 files := make([]string, 0, len(fis)) 107 for _, fi := range fis { 108 if strings.HasSuffix(fi.Name(), suffix) { 109 files = append(files, path.Join(dirPath, fi.Name())) 110 } 111 } 112 113 return files, nil 114} 115 116// CopyDir copy files recursively from source to target directory. 117// 118// The filter accepts a function that process the path info. 119// and should return true for need to filter. 120// 121// It returns error when error occurs in underlying functions. 122func CopyDir(srcPath, destPath string, filters ...func(filePath string) bool) error { 123 // Check if target directory exists. 124 if IsExist(destPath) { 125 return errors.New("file or directory alreay exists: " + destPath) 126 } 127 128 err := os.MkdirAll(destPath, os.ModePerm) 129 if err != nil { 130 return err 131 } 132 133 // Gather directory info. 134 infos, err := StatDir(srcPath, true) 135 if err != nil { 136 return err 137 } 138 139 var filter func(filePath string) bool 140 if len(filters) > 0 { 141 filter = filters[0] 142 } 143 144 for _, info := range infos { 145 if filter != nil && filter(info) { 146 continue 147 } 148 149 curPath := path.Join(destPath, info) 150 if strings.HasSuffix(info, "/") { 151 err = os.MkdirAll(curPath, os.ModePerm) 152 } else { 153 err = Copy(path.Join(srcPath, info), curPath) 154 } 155 if err != nil { 156 return err 157 } 158 } 159 return nil 160} 161