You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

218 lines
5.8 KiB

  1. // Copyright 2013 com authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License"): you may
  4. // not use this file except in compliance with the License. You may obtain
  5. // a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  11. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  12. // License for the specific language governing permissions and limitations
  13. // under the License.
  14. package com
  15. import (
  16. "errors"
  17. "fmt"
  18. "os"
  19. "path"
  20. "strings"
  21. )
  22. // IsDir returns true if given path is a directory,
  23. // or returns false when it's a file or does not exist.
  24. func IsDir(dir string) bool {
  25. f, e := os.Stat(dir)
  26. if e != nil {
  27. return false
  28. }
  29. return f.IsDir()
  30. }
  31. func statDir(dirPath, recPath string, includeDir, isDirOnly, followSymlinks bool) ([]string, error) {
  32. dir, err := os.Open(dirPath)
  33. if err != nil {
  34. return nil, err
  35. }
  36. defer dir.Close()
  37. fis, err := dir.Readdir(0)
  38. if err != nil {
  39. return nil, err
  40. }
  41. statList := make([]string, 0)
  42. for _, fi := range fis {
  43. if strings.Contains(fi.Name(), ".DS_Store") {
  44. continue
  45. }
  46. relPath := path.Join(recPath, fi.Name())
  47. curPath := path.Join(dirPath, fi.Name())
  48. if fi.IsDir() {
  49. if includeDir {
  50. statList = append(statList, relPath+"/")
  51. }
  52. s, err := statDir(curPath, relPath, includeDir, isDirOnly, followSymlinks)
  53. if err != nil {
  54. return nil, err
  55. }
  56. statList = append(statList, s...)
  57. } else if !isDirOnly {
  58. statList = append(statList, relPath)
  59. } else if followSymlinks && fi.Mode()&os.ModeSymlink != 0 {
  60. link, err := os.Readlink(curPath)
  61. if err != nil {
  62. return nil, err
  63. }
  64. if IsDir(link) {
  65. if includeDir {
  66. statList = append(statList, relPath+"/")
  67. }
  68. s, err := statDir(curPath, relPath, includeDir, isDirOnly, followSymlinks)
  69. if err != nil {
  70. return nil, err
  71. }
  72. statList = append(statList, s...)
  73. }
  74. }
  75. }
  76. return statList, nil
  77. }
  78. // StatDir gathers information of given directory by depth-first.
  79. // It returns slice of file list and includes subdirectories if enabled;
  80. // it returns error and nil slice when error occurs in underlying functions,
  81. // or given path is not a directory or does not exist.
  82. //
  83. // Slice does not include given path itself.
  84. // If subdirectories is enabled, they will have suffix '/'.
  85. func StatDir(rootPath string, includeDir ...bool) ([]string, error) {
  86. if !IsDir(rootPath) {
  87. return nil, errors.New("not a directory or does not exist: " + rootPath)
  88. }
  89. isIncludeDir := false
  90. if len(includeDir) >= 1 {
  91. isIncludeDir = includeDir[0]
  92. }
  93. return statDir(rootPath, "", isIncludeDir, false, false)
  94. }
  95. // LstatDir gathers information of given directory by depth-first.
  96. // It returns slice of file list, follows symbolic links and includes subdirectories if enabled;
  97. // it returns error and nil slice when error occurs in underlying functions,
  98. // or given path is not a directory or does not exist.
  99. //
  100. // Slice does not include given path itself.
  101. // If subdirectories is enabled, they will have suffix '/'.
  102. func LstatDir(rootPath string, includeDir ...bool) ([]string, error) {
  103. if !IsDir(rootPath) {
  104. return nil, errors.New("not a directory or does not exist: " + rootPath)
  105. }
  106. isIncludeDir := false
  107. if len(includeDir) >= 1 {
  108. isIncludeDir = includeDir[0]
  109. }
  110. return statDir(rootPath, "", isIncludeDir, false, true)
  111. }
  112. // GetAllSubDirs returns all subdirectories of given root path.
  113. // Slice does not include given path itself.
  114. func GetAllSubDirs(rootPath string) ([]string, error) {
  115. if !IsDir(rootPath) {
  116. return nil, errors.New("not a directory or does not exist: " + rootPath)
  117. }
  118. return statDir(rootPath, "", true, true, false)
  119. }
  120. // LgetAllSubDirs returns all subdirectories of given root path, including
  121. // following symbolic links, if any.
  122. // Slice does not include given path itself.
  123. func LgetAllSubDirs(rootPath string) ([]string, error) {
  124. if !IsDir(rootPath) {
  125. return nil, errors.New("not a directory or does not exist: " + rootPath)
  126. }
  127. return statDir(rootPath, "", true, true, true)
  128. }
  129. // GetFileListBySuffix returns an ordered list of file paths.
  130. // It recognize if given path is a file, and don't do recursive find.
  131. func GetFileListBySuffix(dirPath, suffix string) ([]string, error) {
  132. if !IsExist(dirPath) {
  133. return nil, fmt.Errorf("given path does not exist: %s", dirPath)
  134. } else if IsFile(dirPath) {
  135. return []string{dirPath}, nil
  136. }
  137. // Given path is a directory.
  138. dir, err := os.Open(dirPath)
  139. if err != nil {
  140. return nil, err
  141. }
  142. fis, err := dir.Readdir(0)
  143. if err != nil {
  144. return nil, err
  145. }
  146. files := make([]string, 0, len(fis))
  147. for _, fi := range fis {
  148. if strings.HasSuffix(fi.Name(), suffix) {
  149. files = append(files, path.Join(dirPath, fi.Name()))
  150. }
  151. }
  152. return files, nil
  153. }
  154. // CopyDir copy files recursively from source to target directory.
  155. //
  156. // The filter accepts a function that process the path info.
  157. // and should return true for need to filter.
  158. //
  159. // It returns error when error occurs in underlying functions.
  160. func CopyDir(srcPath, destPath string, filters ...func(filePath string) bool) error {
  161. // Check if target directory exists.
  162. if IsExist(destPath) {
  163. return errors.New("file or directory alreay exists: " + destPath)
  164. }
  165. err := os.MkdirAll(destPath, os.ModePerm)
  166. if err != nil {
  167. return err
  168. }
  169. // Gather directory info.
  170. infos, err := StatDir(srcPath, true)
  171. if err != nil {
  172. return err
  173. }
  174. var filter func(filePath string) bool
  175. if len(filters) > 0 {
  176. filter = filters[0]
  177. }
  178. for _, info := range infos {
  179. if filter != nil && filter(info) {
  180. continue
  181. }
  182. curPath := path.Join(destPath, info)
  183. if strings.HasSuffix(info, "/") {
  184. err = os.MkdirAll(curPath, os.ModePerm)
  185. } else {
  186. err = Copy(path.Join(srcPath, info), curPath)
  187. }
  188. if err != nil {
  189. return err
  190. }
  191. }
  192. return nil
  193. }