]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/go/internal/fsys: move glob, walk code into new files
authorRuss Cox <rsc@golang.org>
Fri, 15 Nov 2024 17:52:10 +0000 (12:52 -0500)
committerGopher Robot <gobot@golang.org>
Tue, 19 Nov 2024 05:07:37 +0000 (05:07 +0000)
The Glob and Walk code does not depend on any of the fsys internals;
it simply uses ReadDir as an opaque abstraction.
Move it to separate files so that when working on the
actual overlay abstraction, it is out of sight, out of mind.

Change-Id: Ifa98feaaaafe5c1d8d8edce82de4fd0c78f599c4
Reviewed-on: https://go-review.googlesource.com/c/go/+/628696
Auto-Submit: Russ Cox <rsc@golang.org>
Reviewed-by: Sam Thanawalla <samthanawalla@google.com>
TryBot-Bypass: Russ Cox <rsc@golang.org>
Reviewed-by: Michael Matloob <matloob@golang.org>
src/cmd/go/internal/fsys/fsys.go
src/cmd/go/internal/fsys/glob.go [new file with mode: 0644]
src/cmd/go/internal/fsys/walk.go [new file with mode: 0644]

index 11293120f68ef4f2740848c385f5fb9a4a4a0a02..7c2e997bdaef6674d57f7c8eb6ab8139c7b1b278 100644 (file)
@@ -17,7 +17,6 @@ import (
        "os"
        pathpkg "path"
        "path/filepath"
-       "runtime"
        "runtime/debug"
        "sort"
        "strings"
@@ -487,45 +486,6 @@ func IsDirWithGoFiles(dir string) (bool, error) {
        return false, firstErr
 }
 
-// walk recursively descends path, calling walkFn. Copied, with some
-// modifications from path/filepath.walk.
-func walk(path string, info fs.FileInfo, walkFn filepath.WalkFunc) error {
-       if err := walkFn(path, info, nil); err != nil || !info.IsDir() {
-               return err
-       }
-
-       fis, err := ReadDir(path)
-       if err != nil {
-               return walkFn(path, info, err)
-       }
-
-       for _, fi := range fis {
-               filename := filepath.Join(path, fi.Name())
-               if err := walk(filename, fi, walkFn); err != nil {
-                       if !fi.IsDir() || err != filepath.SkipDir {
-                               return err
-                       }
-               }
-       }
-       return nil
-}
-
-// Walk walks the file tree rooted at root, calling walkFn for each file or
-// directory in the tree, including root.
-func Walk(root string, walkFn filepath.WalkFunc) error {
-       Trace("Walk", root)
-       info, err := Lstat(root)
-       if err != nil {
-               err = walkFn(root, nil, err)
-       } else {
-               err = walk(root, info, walkFn)
-       }
-       if err == filepath.SkipDir {
-               return nil
-       }
-       return err
-}
-
 // Lstat implements a version of os.Lstat that operates on the overlay filesystem.
 func Lstat(path string) (fs.FileInfo, error) {
        Trace("Lstat", path)
@@ -625,166 +585,3 @@ func (f fakeDir) Sys() any           { return nil }
 func (f fakeDir) String() string {
        return fs.FormatFileInfo(f)
 }
-
-// Glob is like filepath.Glob but uses the overlay file system.
-func Glob(pattern string) (matches []string, err error) {
-       Trace("Glob", pattern)
-       // Check pattern is well-formed.
-       if _, err := filepath.Match(pattern, ""); err != nil {
-               return nil, err
-       }
-       if !hasMeta(pattern) {
-               if _, err = Lstat(pattern); err != nil {
-                       return nil, nil
-               }
-               return []string{pattern}, nil
-       }
-
-       dir, file := filepath.Split(pattern)
-       volumeLen := 0
-       if runtime.GOOS == "windows" {
-               volumeLen, dir = cleanGlobPathWindows(dir)
-       } else {
-               dir = cleanGlobPath(dir)
-       }
-
-       if !hasMeta(dir[volumeLen:]) {
-               return glob(dir, file, nil)
-       }
-
-       // Prevent infinite recursion. See issue 15879.
-       if dir == pattern {
-               return nil, filepath.ErrBadPattern
-       }
-
-       var m []string
-       m, err = Glob(dir)
-       if err != nil {
-               return
-       }
-       for _, d := range m {
-               matches, err = glob(d, file, matches)
-               if err != nil {
-                       return
-               }
-       }
-       return
-}
-
-// cleanGlobPath prepares path for glob matching.
-func cleanGlobPath(path string) string {
-       switch path {
-       case "":
-               return "."
-       case string(filepath.Separator):
-               // do nothing to the path
-               return path
-       default:
-               return path[0 : len(path)-1] // chop off trailing separator
-       }
-}
-
-func volumeNameLen(path string) int {
-       isSlash := func(c uint8) bool {
-               return c == '\\' || c == '/'
-       }
-       if len(path) < 2 {
-               return 0
-       }
-       // with drive letter
-       c := path[0]
-       if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') {
-               return 2
-       }
-       // is it UNC? https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file
-       if l := len(path); l >= 5 && isSlash(path[0]) && isSlash(path[1]) &&
-               !isSlash(path[2]) && path[2] != '.' {
-               // first, leading `\\` and next shouldn't be `\`. its server name.
-               for n := 3; n < l-1; n++ {
-                       // second, next '\' shouldn't be repeated.
-                       if isSlash(path[n]) {
-                               n++
-                               // third, following something characters. its share name.
-                               if !isSlash(path[n]) {
-                                       if path[n] == '.' {
-                                               break
-                                       }
-                                       for ; n < l; n++ {
-                                               if isSlash(path[n]) {
-                                                       break
-                                               }
-                                       }
-                                       return n
-                               }
-                               break
-                       }
-               }
-       }
-       return 0
-}
-
-// cleanGlobPathWindows is windows version of cleanGlobPath.
-func cleanGlobPathWindows(path string) (prefixLen int, cleaned string) {
-       vollen := volumeNameLen(path)
-       switch {
-       case path == "":
-               return 0, "."
-       case vollen+1 == len(path) && os.IsPathSeparator(path[len(path)-1]): // /, \, C:\ and C:/
-               // do nothing to the path
-               return vollen + 1, path
-       case vollen == len(path) && len(path) == 2: // C:
-               return vollen, path + "." // convert C: into C:.
-       default:
-               if vollen >= len(path) {
-                       vollen = len(path) - 1
-               }
-               return vollen, path[0 : len(path)-1] // chop off trailing separator
-       }
-}
-
-// glob searches for files matching pattern in the directory dir
-// and appends them to matches. If the directory cannot be
-// opened, it returns the existing matches. New matches are
-// added in lexicographical order.
-func glob(dir, pattern string, matches []string) (m []string, e error) {
-       m = matches
-       fi, err := Stat(dir)
-       if err != nil {
-               return // ignore I/O error
-       }
-       if !fi.IsDir() {
-               return // ignore I/O error
-       }
-
-       list, err := ReadDir(dir)
-       if err != nil {
-               return // ignore I/O error
-       }
-
-       names := make([]string, 0, len(list))
-       for _, info := range list {
-               names = append(names, info.Name())
-       }
-       sort.Strings(names)
-
-       for _, n := range names {
-               matched, err := filepath.Match(pattern, n)
-               if err != nil {
-                       return m, err
-               }
-               if matched {
-                       m = append(m, filepath.Join(dir, n))
-               }
-       }
-       return
-}
-
-// hasMeta reports whether path contains any of the magic characters
-// recognized by filepath.Match.
-func hasMeta(path string) bool {
-       magicChars := `*?[`
-       if runtime.GOOS != "windows" {
-               magicChars = `*?[\`
-       }
-       return strings.ContainsAny(path, magicChars)
-}
diff --git a/src/cmd/go/internal/fsys/glob.go b/src/cmd/go/internal/fsys/glob.go
new file mode 100644 (file)
index 0000000..082adc7
--- /dev/null
@@ -0,0 +1,178 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fsys
+
+import (
+       "os"
+       "path/filepath"
+       "runtime"
+       "sort"
+       "strings"
+)
+
+// Copied from path/filepath.
+
+// Glob is like filepath.Glob but uses the overlay file system.
+func Glob(pattern string) (matches []string, err error) {
+       Trace("Glob", pattern)
+       // Check pattern is well-formed.
+       if _, err := filepath.Match(pattern, ""); err != nil {
+               return nil, err
+       }
+       if !hasMeta(pattern) {
+               if _, err = Lstat(pattern); err != nil {
+                       return nil, nil
+               }
+               return []string{pattern}, nil
+       }
+
+       dir, file := filepath.Split(pattern)
+       volumeLen := 0
+       if runtime.GOOS == "windows" {
+               volumeLen, dir = cleanGlobPathWindows(dir)
+       } else {
+               dir = cleanGlobPath(dir)
+       }
+
+       if !hasMeta(dir[volumeLen:]) {
+               return glob(dir, file, nil)
+       }
+
+       // Prevent infinite recursion. See issue 15879.
+       if dir == pattern {
+               return nil, filepath.ErrBadPattern
+       }
+
+       var m []string
+       m, err = Glob(dir)
+       if err != nil {
+               return
+       }
+       for _, d := range m {
+               matches, err = glob(d, file, matches)
+               if err != nil {
+                       return
+               }
+       }
+       return
+}
+
+// cleanGlobPath prepares path for glob matching.
+func cleanGlobPath(path string) string {
+       switch path {
+       case "":
+               return "."
+       case string(filepath.Separator):
+               // do nothing to the path
+               return path
+       default:
+               return path[0 : len(path)-1] // chop off trailing separator
+       }
+}
+
+func volumeNameLen(path string) int {
+       isSlash := func(c uint8) bool {
+               return c == '\\' || c == '/'
+       }
+       if len(path) < 2 {
+               return 0
+       }
+       // with drive letter
+       c := path[0]
+       if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') {
+               return 2
+       }
+       // is it UNC? https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file
+       if l := len(path); l >= 5 && isSlash(path[0]) && isSlash(path[1]) &&
+               !isSlash(path[2]) && path[2] != '.' {
+               // first, leading `\\` and next shouldn't be `\`. its server name.
+               for n := 3; n < l-1; n++ {
+                       // second, next '\' shouldn't be repeated.
+                       if isSlash(path[n]) {
+                               n++
+                               // third, following something characters. its share name.
+                               if !isSlash(path[n]) {
+                                       if path[n] == '.' {
+                                               break
+                                       }
+                                       for ; n < l; n++ {
+                                               if isSlash(path[n]) {
+                                                       break
+                                               }
+                                       }
+                                       return n
+                               }
+                               break
+                       }
+               }
+       }
+       return 0
+}
+
+// cleanGlobPathWindows is windows version of cleanGlobPath.
+func cleanGlobPathWindows(path string) (prefixLen int, cleaned string) {
+       vollen := volumeNameLen(path)
+       switch {
+       case path == "":
+               return 0, "."
+       case vollen+1 == len(path) && os.IsPathSeparator(path[len(path)-1]): // /, \, C:\ and C:/
+               // do nothing to the path
+               return vollen + 1, path
+       case vollen == len(path) && len(path) == 2: // C:
+               return vollen, path + "." // convert C: into C:.
+       default:
+               if vollen >= len(path) {
+                       vollen = len(path) - 1
+               }
+               return vollen, path[0 : len(path)-1] // chop off trailing separator
+       }
+}
+
+// glob searches for files matching pattern in the directory dir
+// and appends them to matches. If the directory cannot be
+// opened, it returns the existing matches. New matches are
+// added in lexicographical order.
+func glob(dir, pattern string, matches []string) (m []string, e error) {
+       m = matches
+       fi, err := Stat(dir)
+       if err != nil {
+               return // ignore I/O error
+       }
+       if !fi.IsDir() {
+               return // ignore I/O error
+       }
+
+       list, err := ReadDir(dir)
+       if err != nil {
+               return // ignore I/O error
+       }
+
+       names := make([]string, 0, len(list))
+       for _, info := range list {
+               names = append(names, info.Name())
+       }
+       sort.Strings(names)
+
+       for _, n := range names {
+               matched, err := filepath.Match(pattern, n)
+               if err != nil {
+                       return m, err
+               }
+               if matched {
+                       m = append(m, filepath.Join(dir, n))
+               }
+       }
+       return
+}
+
+// hasMeta reports whether path contains any of the magic characters
+// recognized by filepath.Match.
+func hasMeta(path string) bool {
+       magicChars := `*?[`
+       if runtime.GOOS != "windows" {
+               magicChars = `*?[\`
+       }
+       return strings.ContainsAny(path, magicChars)
+}
diff --git a/src/cmd/go/internal/fsys/walk.go b/src/cmd/go/internal/fsys/walk.go
new file mode 100644 (file)
index 0000000..23d7395
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fsys
+
+import (
+       "io/fs"
+       "path/filepath"
+)
+
+// Walk walks the file tree rooted at root, calling walkFn for each file or
+// directory in the tree, including root.
+func Walk(root string, walkFn filepath.WalkFunc) error {
+       Trace("Walk", root)
+       info, err := Lstat(root)
+       if err != nil {
+               err = walkFn(root, nil, err)
+       } else {
+               err = walk(root, info, walkFn)
+       }
+       if err == filepath.SkipDir {
+               return nil
+       }
+       return err
+}
+
+// walk recursively descends path, calling walkFn. Copied, with some
+// modifications from path/filepath.walk.
+func walk(path string, info fs.FileInfo, walkFn filepath.WalkFunc) error {
+       if err := walkFn(path, info, nil); err != nil || !info.IsDir() {
+               return err
+       }
+
+       fis, err := ReadDir(path)
+       if err != nil {
+               return walkFn(path, info, err)
+       }
+
+       for _, fi := range fis {
+               filename := filepath.Join(path, fi.Name())
+               if err := walk(filename, fi, walkFn); err != nil {
+                       if !fi.IsDir() || err != filepath.SkipDir {
+                               return err
+                       }
+               }
+       }
+       return nil
+}