本站源代码
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.

107 lines
2.9KB

  1. // Copyright ©2015 The Go Authors
  2. // Copyright ©2015 Steve Francia <spf@spf13.com>
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. package afero
  16. import (
  17. "os"
  18. "path/filepath"
  19. "sort"
  20. )
  21. // readDirNames reads the directory named by dirname and returns
  22. // a sorted list of directory entries.
  23. // adapted from https://golang.org/src/path/filepath/path.go
  24. func readDirNames(fs Fs, dirname string) ([]string, error) {
  25. f, err := fs.Open(dirname)
  26. if err != nil {
  27. return nil, err
  28. }
  29. names, err := f.Readdirnames(-1)
  30. f.Close()
  31. if err != nil {
  32. return nil, err
  33. }
  34. sort.Strings(names)
  35. return names, nil
  36. }
  37. // walk recursively descends path, calling walkFn
  38. // adapted from https://golang.org/src/path/filepath/path.go
  39. func walk(fs Fs, path string, info os.FileInfo, walkFn filepath.WalkFunc) error {
  40. err := walkFn(path, info, nil)
  41. if err != nil {
  42. if info.IsDir() && err == filepath.SkipDir {
  43. return nil
  44. }
  45. return err
  46. }
  47. if !info.IsDir() {
  48. return nil
  49. }
  50. names, err := readDirNames(fs, path)
  51. if err != nil {
  52. return walkFn(path, info, err)
  53. }
  54. for _, name := range names {
  55. filename := filepath.Join(path, name)
  56. fileInfo, err := lstatIfPossible(fs, filename)
  57. if err != nil {
  58. if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir {
  59. return err
  60. }
  61. } else {
  62. err = walk(fs, filename, fileInfo, walkFn)
  63. if err != nil {
  64. if !fileInfo.IsDir() || err != filepath.SkipDir {
  65. return err
  66. }
  67. }
  68. }
  69. }
  70. return nil
  71. }
  72. // if the filesystem supports it, use Lstat, else use fs.Stat
  73. func lstatIfPossible(fs Fs, path string) (os.FileInfo, error) {
  74. if lfs, ok := fs.(Lstater); ok {
  75. fi, _, err := lfs.LstatIfPossible(path)
  76. return fi, err
  77. }
  78. return fs.Stat(path)
  79. }
  80. // Walk walks the file tree rooted at root, calling walkFn for each file or
  81. // directory in the tree, including root. All errors that arise visiting files
  82. // and directories are filtered by walkFn. The files are walked in lexical
  83. // order, which makes the output deterministic but means that for very
  84. // large directories Walk can be inefficient.
  85. // Walk does not follow symbolic links.
  86. func (a Afero) Walk(root string, walkFn filepath.WalkFunc) error {
  87. return Walk(a.Fs, root, walkFn)
  88. }
  89. func Walk(fs Fs, root string, walkFn filepath.WalkFunc) error {
  90. info, err := lstatIfPossible(fs, root)
  91. if err != nil {
  92. return walkFn(root, nil, err)
  93. }
  94. return walk(fs, root, info, walkFn)
  95. }
上海开阖软件有限公司 沪ICP备12045867号-1