diff options
Diffstat (limited to 'cli/internal/globby')
| -rw-r--r-- | cli/internal/globby/globby.go | 187 | ||||
| -rw-r--r-- | cli/internal/globby/globby_test.go | 832 |
2 files changed, 0 insertions, 1019 deletions
diff --git a/cli/internal/globby/globby.go b/cli/internal/globby/globby.go deleted file mode 100644 index 14c40d9..0000000 --- a/cli/internal/globby/globby.go +++ /dev/null @@ -1,187 +0,0 @@ -package globby - -import ( - "fmt" - "path/filepath" - "sort" - "strings" - - iofs "io/fs" - - "github.com/vercel/turbo/cli/internal/fs" - - "github.com/vercel/turbo/cli/internal/doublestar" - "github.com/vercel/turbo/cli/internal/util" -) - -// GlobAll returns an array of files and folders that match the specified set of glob patterns. -// The returned files and folders are absolute paths, assuming that basePath is an absolute path. -func GlobAll(basePath string, includePatterns []string, excludePatterns []string) ([]string, error) { - fsys := fs.CreateDirFSAtRoot(basePath) - fsysRoot := fs.GetDirFSRootPath(fsys) - output, err := globAllFs(fsys, fsysRoot, basePath, includePatterns, excludePatterns) - - // Because this is coming out of a map output is in no way ordered. - // Sorting will put the files in a depth-first order. - sort.Strings(output) - return output, err -} - -// GlobFiles returns an array of files that match the specified set of glob patterns. -// The return files are absolute paths, assuming that basePath is an absolute path. -func GlobFiles(basePath string, includePatterns []string, excludePatterns []string) ([]string, error) { - fsys := fs.CreateDirFSAtRoot(basePath) - fsysRoot := fs.GetDirFSRootPath(fsys) - output, err := globFilesFs(fsys, fsysRoot, basePath, includePatterns, excludePatterns) - - // Because this is coming out of a map output is in no way ordered. - // Sorting will put the files in a depth-first order. - sort.Strings(output) - return output, err -} - -// checkRelativePath ensures that the the requested file path is a child of `from`. -func checkRelativePath(from string, to string) error { - relativePath, err := filepath.Rel(from, to) - - if err != nil { - return err - } - - if strings.HasPrefix(relativePath, "..") { - return fmt.Errorf("the path you are attempting to specify (%s) is outside of the root", to) - } - - return nil -} - -// globFilesFs searches the specified file system to enumerate all files to include. -func globFilesFs(fsys iofs.FS, fsysRoot string, basePath string, includePatterns []string, excludePatterns []string) ([]string, error) { - return globWalkFs(fsys, fsysRoot, basePath, includePatterns, excludePatterns, false) -} - -// globAllFs searches the specified file system to enumerate all files to include. -func globAllFs(fsys iofs.FS, fsysRoot string, basePath string, includePatterns []string, excludePatterns []string) ([]string, error) { - return globWalkFs(fsys, fsysRoot, basePath, includePatterns, excludePatterns, true) -} - -// globWalkFs searches the specified file system to enumerate all files and folders to include. -func globWalkFs(fsys iofs.FS, fsysRoot string, basePath string, includePatterns []string, excludePatterns []string, includeDirs bool) ([]string, error) { - var processedIncludes []string - var processedExcludes []string - result := make(util.Set) - - for _, includePattern := range includePatterns { - includePath := filepath.Join(basePath, includePattern) - err := checkRelativePath(basePath, includePath) - - if err != nil { - return nil, err - } - - // fs.FS paths may not include leading separators. Calculate the - // correct path for this relative to the filesystem root. - // This will not error as it follows the call to checkRelativePath. - iofsRelativePath, _ := fs.IofsRelativePath(fsysRoot, includePath) - - // Includes only operate on files. - processedIncludes = append(processedIncludes, iofsRelativePath) - } - - for _, excludePattern := range excludePatterns { - excludePath := filepath.Join(basePath, excludePattern) - err := checkRelativePath(basePath, excludePath) - - if err != nil { - return nil, err - } - - // fs.FS paths may not include leading separators. Calculate the - // correct path for this relative to the filesystem root. - // This will not error as it follows the call to checkRelativePath. - iofsRelativePath, _ := fs.IofsRelativePath(fsysRoot, excludePath) - - // In case this is a file pattern and not a directory, add the exact pattern. - // In the event that the user has already specified /**, - if !strings.HasSuffix(iofsRelativePath, string(filepath.Separator)+"**") { - processedExcludes = append(processedExcludes, iofsRelativePath) - } - // TODO: we need to either document or change this behavior - // Excludes operate on entire folders, so we also exclude everything under this in case it represents a directory - processedExcludes = append(processedExcludes, filepath.Join(iofsRelativePath, "**")) - } - - // We start from a naive includePattern - includePattern := "" - includeCount := len(processedIncludes) - - // Do not use alternation if unnecessary. - if includeCount == 1 { - includePattern = processedIncludes[0] - } else if includeCount > 1 { - // We use alternation from the very root of the path. This avoids fs.Stat of the basePath. - includePattern = "{" + strings.Join(processedIncludes, ",") + "}" - } - - // We start with an empty string excludePattern which we only use if excludeCount > 0. - excludePattern := "" - excludeCount := len(processedExcludes) - - // Do not use alternation if unnecessary. - if excludeCount == 1 { - excludePattern = processedExcludes[0] - } else if excludeCount > 1 { - // We use alternation from the very root of the path. This avoids fs.Stat of the basePath. - excludePattern = "{" + strings.Join(processedExcludes, ",") + "}" - } - - // GlobWalk expects that everything uses Unix path conventions. - includePattern = filepath.ToSlash(includePattern) - excludePattern = filepath.ToSlash(excludePattern) - - err := doublestar.GlobWalk(fsys, includePattern, func(path string, dirEntry iofs.DirEntry) error { - if !includeDirs && dirEntry.IsDir() { - return nil - } - - // All files that are returned by doublestar.GlobWalk are relative to - // the fsys root. Go, however, has decided that `fs.FS` filesystems do - // not address the root of the file system using `/` and instead use - // paths without leading separators. - // - // We need to track where the `fsys` root is so that when we hand paths back - // we hand them back as the path addressable in the actual OS filesystem. - // - // As a consequence, when processing, we need to *restore* the original - // root to the file path after returning. This works because when we create - // the `os.dirFS` filesystem we do so at the root of the current volume. - if excludeCount == 0 { - // Reconstruct via string concatenation since the root is already pre-composed. - result.Add(fsysRoot + path) - return nil - } - - isExcluded, err := doublestar.Match(excludePattern, filepath.ToSlash(path)) - if err != nil { - return err - } - - if !isExcluded { - // Reconstruct via string concatenation since the root is already pre-composed. - result.Add(fsysRoot + path) - } - - return nil - }) - - // GlobWalk threw an error. - if err != nil { - return nil, err - } - - // Never actually capture the root folder. - // This is a risk because of how we rework the globs. - result.Delete(strings.TrimSuffix(basePath, "/")) - - return result.UnsafeListOfStrings(), nil -} diff --git a/cli/internal/globby/globby_test.go b/cli/internal/globby/globby_test.go deleted file mode 100644 index 2fdd613..0000000 --- a/cli/internal/globby/globby_test.go +++ /dev/null @@ -1,832 +0,0 @@ -package globby - -import ( - "io/fs" - "path/filepath" - "reflect" - "sort" - "testing" - - "testing/fstest" -) - -// setup prepares the test file system contents and returns the file system. -func setup(fsysRoot string, files []string) fs.FS { - fsys := fstest.MapFS{} - for _, file := range files { - // We're populating a `fs.FS` filesytem which requires paths to have no - // leading slash. As a consequence we strip it during creation. - iofsRelativePath := file[1:] - - fsys[iofsRelativePath] = &fstest.MapFile{Mode: 0666} - } - - return fsys -} - -func TestGlobFilesFs(t *testing.T) { - type args struct { - basePath string - includePatterns []string - excludePatterns []string - } - tests := []struct { - name string - files []string - args args - wantAll []string - wantFiles []string - wantErr bool - }{ - { - name: "hello world", - files: []string{"/test.txt"}, - args: args{ - basePath: "/", - includePatterns: []string{"*.txt"}, - excludePatterns: []string{}, - }, - wantAll: []string{"/test.txt"}, - wantFiles: []string{"/test.txt"}, - }, - { - name: "bullet files", - files: []string{ - "/test.txt", - "/subdir/test.txt", - "/other/test.txt", - }, - args: args{ - basePath: "/", - includePatterns: []string{"subdir/test.txt", "test.txt"}, - excludePatterns: []string{}, - }, - wantAll: []string{ - "/subdir/test.txt", - "/test.txt", - }, - wantFiles: []string{ - "/subdir/test.txt", - "/test.txt", - }, - }, - { - name: "finding workspace package.json files", - files: []string{ - "/external/file.txt", - "/repos/some-app/apps/docs/package.json", - "/repos/some-app/apps/web/package.json", - "/repos/some-app/bower_components/readline/package.json", - "/repos/some-app/examples/package.json", - "/repos/some-app/node_modules/gulp/bower_components/readline/package.json", - "/repos/some-app/node_modules/react/package.json", - "/repos/some-app/package.json", - "/repos/some-app/packages/colors/package.json", - "/repos/some-app/packages/faker/package.json", - "/repos/some-app/packages/left-pad/package.json", - "/repos/some-app/test/mocks/kitchen-sink/package.json", - "/repos/some-app/tests/mocks/kitchen-sink/package.json", - }, - args: args{ - basePath: "/repos/some-app/", - includePatterns: []string{"packages/*/package.json", "apps/*/package.json"}, - excludePatterns: []string{"**/node_modules/", "**/bower_components/", "**/test/", "**/tests/"}, - }, - wantAll: []string{ - "/repos/some-app/apps/docs/package.json", - "/repos/some-app/apps/web/package.json", - "/repos/some-app/packages/colors/package.json", - "/repos/some-app/packages/faker/package.json", - "/repos/some-app/packages/left-pad/package.json", - }, - wantFiles: []string{ - "/repos/some-app/apps/docs/package.json", - "/repos/some-app/apps/web/package.json", - "/repos/some-app/packages/colors/package.json", - "/repos/some-app/packages/faker/package.json", - "/repos/some-app/packages/left-pad/package.json", - }, - }, - { - name: "excludes unexpected workspace package.json files", - files: []string{ - "/external/file.txt", - "/repos/some-app/apps/docs/package.json", - "/repos/some-app/apps/web/package.json", - "/repos/some-app/bower_components/readline/package.json", - "/repos/some-app/examples/package.json", - "/repos/some-app/node_modules/gulp/bower_components/readline/package.json", - "/repos/some-app/node_modules/react/package.json", - "/repos/some-app/package.json", - "/repos/some-app/packages/colors/package.json", - "/repos/some-app/packages/faker/package.json", - "/repos/some-app/packages/left-pad/package.json", - "/repos/some-app/test/mocks/spanish-inquisition/package.json", - "/repos/some-app/tests/mocks/spanish-inquisition/package.json", - }, - args: args{ - basePath: "/repos/some-app/", - includePatterns: []string{"**/package.json"}, - excludePatterns: []string{"**/node_modules/", "**/bower_components/", "**/test/", "**/tests/"}, - }, - wantAll: []string{ - "/repos/some-app/apps/docs/package.json", - "/repos/some-app/apps/web/package.json", - "/repos/some-app/examples/package.json", - "/repos/some-app/package.json", - "/repos/some-app/packages/colors/package.json", - "/repos/some-app/packages/faker/package.json", - "/repos/some-app/packages/left-pad/package.json", - }, - wantFiles: []string{ - "/repos/some-app/apps/docs/package.json", - "/repos/some-app/apps/web/package.json", - "/repos/some-app/examples/package.json", - "/repos/some-app/package.json", - "/repos/some-app/packages/colors/package.json", - "/repos/some-app/packages/faker/package.json", - "/repos/some-app/packages/left-pad/package.json", - }, - }, - { - name: "nested packages work", - files: []string{ - "/external/file.txt", - "/repos/some-app/apps/docs/package.json", - "/repos/some-app/apps/web/package.json", - "/repos/some-app/bower_components/readline/package.json", - "/repos/some-app/examples/package.json", - "/repos/some-app/node_modules/gulp/bower_components/readline/package.json", - "/repos/some-app/node_modules/react/package.json", - "/repos/some-app/package.json", - "/repos/some-app/packages/xzibit/package.json", - "/repos/some-app/packages/xzibit/node_modules/street-legal/package.json", - "/repos/some-app/packages/xzibit/node_modules/paint-colors/package.json", - "/repos/some-app/packages/xzibit/packages/yo-dawg/package.json", - "/repos/some-app/packages/xzibit/packages/yo-dawg/node_modules/meme/package.json", - "/repos/some-app/packages/xzibit/packages/yo-dawg/node_modules/yo-dawg/package.json", - "/repos/some-app/packages/colors/package.json", - "/repos/some-app/packages/faker/package.json", - "/repos/some-app/packages/left-pad/package.json", - "/repos/some-app/test/mocks/spanish-inquisition/package.json", - "/repos/some-app/tests/mocks/spanish-inquisition/package.json", - }, - args: args{ - basePath: "/repos/some-app/", - includePatterns: []string{"packages/**/package.json"}, - excludePatterns: []string{"**/node_modules/", "**/bower_components/", "**/test/", "**/tests/"}, - }, - wantAll: []string{ - "/repos/some-app/packages/colors/package.json", - "/repos/some-app/packages/faker/package.json", - "/repos/some-app/packages/left-pad/package.json", - "/repos/some-app/packages/xzibit/package.json", - "/repos/some-app/packages/xzibit/packages/yo-dawg/package.json", - }, - wantFiles: []string{ - "/repos/some-app/packages/colors/package.json", - "/repos/some-app/packages/faker/package.json", - "/repos/some-app/packages/left-pad/package.json", - "/repos/some-app/packages/xzibit/package.json", - "/repos/some-app/packages/xzibit/packages/yo-dawg/package.json", - }, - }, - { - name: "includes do not override excludes", - files: []string{ - "/external/file.txt", - "/repos/some-app/apps/docs/package.json", - "/repos/some-app/apps/web/package.json", - "/repos/some-app/bower_components/readline/package.json", - "/repos/some-app/examples/package.json", - "/repos/some-app/node_modules/gulp/bower_components/readline/package.json", - "/repos/some-app/node_modules/react/package.json", - "/repos/some-app/package.json", - "/repos/some-app/packages/xzibit/package.json", - "/repos/some-app/packages/xzibit/node_modules/street-legal/package.json", - "/repos/some-app/packages/xzibit/node_modules/paint-colors/package.json", - "/repos/some-app/packages/xzibit/packages/yo-dawg/package.json", - "/repos/some-app/packages/xzibit/packages/yo-dawg/node_modules/meme/package.json", - "/repos/some-app/packages/xzibit/packages/yo-dawg/node_modules/yo-dawg/package.json", - "/repos/some-app/packages/colors/package.json", - "/repos/some-app/packages/faker/package.json", - "/repos/some-app/packages/left-pad/package.json", - "/repos/some-app/test/mocks/spanish-inquisition/package.json", - "/repos/some-app/tests/mocks/spanish-inquisition/package.json", - }, - args: args{ - basePath: "/repos/some-app/", - includePatterns: []string{"packages/**/package.json", "tests/mocks/*/package.json"}, - excludePatterns: []string{"**/node_modules/", "**/bower_components/", "**/test/", "**/tests/"}, - }, - wantAll: []string{ - "/repos/some-app/packages/colors/package.json", - "/repos/some-app/packages/faker/package.json", - "/repos/some-app/packages/left-pad/package.json", - "/repos/some-app/packages/xzibit/package.json", - "/repos/some-app/packages/xzibit/packages/yo-dawg/package.json", - }, - wantFiles: []string{ - "/repos/some-app/packages/colors/package.json", - "/repos/some-app/packages/faker/package.json", - "/repos/some-app/packages/left-pad/package.json", - "/repos/some-app/packages/xzibit/package.json", - "/repos/some-app/packages/xzibit/packages/yo-dawg/package.json", - }, - }, - { - name: "output globbing grabs the desired content", - files: []string{ - "/external/file.txt", - "/repos/some-app/src/index.js", - "/repos/some-app/public/src/css/index.css", - "/repos/some-app/.turbo/turbo-build.log", - "/repos/some-app/.turbo/somebody-touched-this-file-into-existence.txt", - "/repos/some-app/.next/log.txt", - "/repos/some-app/.next/cache/db6a76a62043520e7aaadd0bb2104e78.txt", - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules/browserify.js", - "/repos/some-app/public/dist/css/index.css", - "/repos/some-app/public/dist/images/rick_astley.jpg", - }, - args: args{ - basePath: "/repos/some-app/", - includePatterns: []string{".turbo/turbo-build.log", "dist/**", ".next/**", "public/dist/**"}, - excludePatterns: []string{}, - }, - wantAll: []string{ - "/repos/some-app/.next", - "/repos/some-app/.next/cache", - "/repos/some-app/.next/cache/db6a76a62043520e7aaadd0bb2104e78.txt", - "/repos/some-app/.next/log.txt", - "/repos/some-app/.turbo/turbo-build.log", - "/repos/some-app/dist", - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules", - "/repos/some-app/dist/js/node_modules/browserify.js", - "/repos/some-app/public/dist", - "/repos/some-app/public/dist/css", - "/repos/some-app/public/dist/css/index.css", - "/repos/some-app/public/dist/images", - "/repos/some-app/public/dist/images/rick_astley.jpg", - }, - wantFiles: []string{ - "/repos/some-app/.next/cache/db6a76a62043520e7aaadd0bb2104e78.txt", - "/repos/some-app/.next/log.txt", - "/repos/some-app/.turbo/turbo-build.log", - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules/browserify.js", - "/repos/some-app/public/dist/css/index.css", - "/repos/some-app/public/dist/images/rick_astley.jpg", - }, - }, - { - name: "passing ** captures all children", - files: []string{ - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules/browserify.js", - }, - args: args{ - basePath: "/repos/some-app/", - includePatterns: []string{"dist/**"}, - excludePatterns: []string{}, - }, - wantAll: []string{ - "/repos/some-app/dist", - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules", - "/repos/some-app/dist/js/node_modules/browserify.js", - }, - wantFiles: []string{ - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules/browserify.js", - }, - }, - { - name: "passing just a directory captures no children", - files: []string{ - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules/browserify.js", - }, - args: args{ - basePath: "/repos/some-app/", - includePatterns: []string{"dist"}, - excludePatterns: []string{}, - }, - wantAll: []string{"/repos/some-app/dist"}, - wantFiles: []string{}, - }, - { - name: "redundant includes do not duplicate", - files: []string{ - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules/browserify.js", - }, - args: args{ - basePath: "/repos/some-app/", - includePatterns: []string{"**/*", "dist/**"}, - excludePatterns: []string{}, - }, - wantAll: []string{ - "/repos/some-app/dist", - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules", - "/repos/some-app/dist/js/node_modules/browserify.js", - }, - wantFiles: []string{ - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules/browserify.js", - }, - }, - { - name: "exclude everything, include everything", - files: []string{ - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules/browserify.js", - }, - args: args{ - basePath: "/repos/some-app/", - includePatterns: []string{"**"}, - excludePatterns: []string{"**"}, - }, - wantAll: []string{}, - wantFiles: []string{}, - }, - { - name: "passing just a directory to exclude prevents capture of children", - files: []string{ - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules/browserify.js", - }, - args: args{ - basePath: "/repos/some-app/", - includePatterns: []string{"dist/**"}, - excludePatterns: []string{"dist/js"}, - }, - wantAll: []string{ - "/repos/some-app/dist", - "/repos/some-app/dist/index.html", - }, - wantFiles: []string{ - "/repos/some-app/dist/index.html", - }, - }, - { - name: "passing ** to exclude prevents capture of children", - files: []string{ - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules/browserify.js", - }, - args: args{ - basePath: "/repos/some-app/", - includePatterns: []string{"dist/**"}, - excludePatterns: []string{"dist/js/**"}, - }, - wantAll: []string{ - "/repos/some-app/dist", - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js", - }, - wantFiles: []string{ - "/repos/some-app/dist/index.html", - }, - }, - { - name: "exclude everything with folder . applies at base path", - files: []string{ - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules/browserify.js", - }, - args: args{ - basePath: "/repos/some-app/", - includePatterns: []string{"**"}, - excludePatterns: []string{"./"}, - }, - wantAll: []string{}, - wantFiles: []string{}, - }, - { - name: "exclude everything with traversal applies at a non-base path", - files: []string{ - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules/browserify.js", - }, - args: args{ - basePath: "/repos/some-app/", - includePatterns: []string{"**"}, - excludePatterns: []string{"./dist"}, - }, - wantAll: []string{}, - wantFiles: []string{}, - }, - { - name: "exclude everything with folder traversal (..) applies at base path", - files: []string{ - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules/browserify.js", - }, - args: args{ - basePath: "/repos/some-app/", - includePatterns: []string{"**"}, - excludePatterns: []string{"dist/../"}, - }, - wantAll: []string{}, - wantFiles: []string{}, - }, - { - name: "how do globs even work bad glob microformat", - files: []string{ - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules/browserify.js", - }, - args: args{ - basePath: "/repos/some-app/", - includePatterns: []string{"**/**/**"}, - excludePatterns: []string{}, - }, - wantAll: []string{ - "/repos/some-app/dist", - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules", - "/repos/some-app/dist/js/node_modules/browserify.js", - }, - wantFiles: []string{ - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules/browserify.js", - }, - }, - { - name: "directory traversal stops at base path", - files: []string{ - "/repos/spanish-inquisition/index.html", - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules/browserify.js", - }, - args: args{ - basePath: "/repos/some-app/", - includePatterns: []string{"../spanish-inquisition/**", "dist/**"}, - excludePatterns: []string{}, - }, - wantAll: []string{}, - wantFiles: []string{}, - wantErr: true, - }, - { - name: "globs and traversal and globs do not cross base path", - files: []string{ - "/repos/spanish-inquisition/index.html", - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules/browserify.js", - }, - args: args{ - basePath: "/repos/some-app/", - includePatterns: []string{"**/../../spanish-inquisition/**"}, - excludePatterns: []string{}, - }, - wantAll: []string{}, - wantFiles: []string{}, - wantErr: true, - }, - { - name: "traversal works within base path", - files: []string{ - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules/browserify.js", - }, - args: args{ - basePath: "/repos/some-app/", - includePatterns: []string{"dist/js/../**"}, - excludePatterns: []string{}, - }, - wantAll: []string{ - "/repos/some-app/dist", - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules", - "/repos/some-app/dist/js/node_modules/browserify.js", - }, - wantFiles: []string{ - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules/browserify.js", - }, - }, - { - name: "self-references (.) work", - files: []string{ - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules/browserify.js", - }, - args: args{ - basePath: "/repos/some-app/", - includePatterns: []string{"dist/./././**"}, - excludePatterns: []string{}, - }, - wantAll: []string{ - "/repos/some-app/dist", - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules", - "/repos/some-app/dist/js/node_modules/browserify.js", - }, - wantFiles: []string{ - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules/browserify.js", - }, - }, - { - name: "depth of 1 includes handles folders properly", - files: []string{ - "/repos/some-app/package.json", - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules/browserify.js", - }, - args: args{ - basePath: "/repos/some-app/", - includePatterns: []string{"*"}, - excludePatterns: []string{}, - }, - wantAll: []string{ - "/repos/some-app/dist", - "/repos/some-app/package.json", - }, - wantFiles: []string{"/repos/some-app/package.json"}, - }, - { - name: "depth of 1 excludes prevents capturing folders", - files: []string{ - "/repos/some-app/package.json", - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules/browserify.js", - }, - args: args{ - basePath: "/repos/some-app/", - includePatterns: []string{"**"}, - excludePatterns: []string{"dist/*"}, - }, - wantAll: []string{ - "/repos/some-app/dist", - "/repos/some-app/package.json", - }, - wantFiles: []string{"/repos/some-app/package.json"}, - }, - { - name: "No-trailing slash basePath works", - files: []string{ - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules/browserify.js", - }, - args: args{ - basePath: "/repos/some-app", - includePatterns: []string{"dist/**"}, - excludePatterns: []string{}, - }, - wantAll: []string{ - "/repos/some-app/dist", - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules", - "/repos/some-app/dist/js/node_modules/browserify.js", - }, - wantFiles: []string{ - "/repos/some-app/dist/index.html", - "/repos/some-app/dist/js/index.js", - "/repos/some-app/dist/js/lib.js", - "/repos/some-app/dist/js/node_modules/browserify.js", - }, - }, - { - name: "exclude single file", - files: []string{ - "/repos/some-app/included.txt", - "/repos/some-app/excluded.txt", - }, - args: args{ - basePath: "/repos/some-app", - includePatterns: []string{"*.txt"}, - excludePatterns: []string{"excluded.txt"}, - }, - wantAll: []string{ - "/repos/some-app/included.txt", - }, - wantFiles: []string{ - "/repos/some-app/included.txt", - }, - }, - { - name: "exclude nested single file", - files: []string{ - "/repos/some-app/one/included.txt", - "/repos/some-app/one/two/included.txt", - "/repos/some-app/one/two/three/included.txt", - "/repos/some-app/one/excluded.txt", - "/repos/some-app/one/two/excluded.txt", - "/repos/some-app/one/two/three/excluded.txt", - }, - args: args{ - basePath: "/repos/some-app", - includePatterns: []string{"**"}, - excludePatterns: []string{"**/excluded.txt"}, - }, - wantAll: []string{ - "/repos/some-app/one/included.txt", - "/repos/some-app/one/two/included.txt", - "/repos/some-app/one/two/three/included.txt", - "/repos/some-app/one", - "/repos/some-app/one/two", - "/repos/some-app/one/two/three", - }, - wantFiles: []string{ - "/repos/some-app/one/included.txt", - "/repos/some-app/one/two/included.txt", - "/repos/some-app/one/two/three/included.txt", - }, - }, - { - name: "exclude everything", - files: []string{ - "/repos/some-app/one/included.txt", - "/repos/some-app/one/two/included.txt", - "/repos/some-app/one/two/three/included.txt", - "/repos/some-app/one/excluded.txt", - "/repos/some-app/one/two/excluded.txt", - "/repos/some-app/one/two/three/excluded.txt", - }, - args: args{ - basePath: "/repos/some-app", - includePatterns: []string{"**"}, - excludePatterns: []string{"**"}, - }, - wantAll: []string{}, - wantFiles: []string{}, - }, - { - name: "exclude everything with slash", - files: []string{ - "/repos/some-app/one/included.txt", - "/repos/some-app/one/two/included.txt", - "/repos/some-app/one/two/three/included.txt", - "/repos/some-app/one/excluded.txt", - "/repos/some-app/one/two/excluded.txt", - "/repos/some-app/one/two/three/excluded.txt", - }, - args: args{ - basePath: "/repos/some-app", - includePatterns: []string{"**"}, - excludePatterns: []string{"**/"}, - }, - wantAll: []string{}, - wantFiles: []string{}, - }, - { - name: "exclude everything with leading **", - files: []string{ - "/repos/some-app/foo/bar", - "/repos/some-app/some-foo", - "/repos/some-app/some-foo/bar", - "/repos/some-app/included", - }, - args: args{ - basePath: "/repos/some-app", - includePatterns: []string{"**"}, - excludePatterns: []string{"**foo"}, - }, - wantAll: []string{ - "/repos/some-app/included", - }, - wantFiles: []string{ - "/repos/some-app/included", - }, - }, - { - name: "exclude everything with trailing **", - files: []string{ - "/repos/some-app/foo/bar", - "/repos/some-app/foo-file", - "/repos/some-app/foo-dir/bar", - "/repos/some-app/included", - }, - args: args{ - basePath: "/repos/some-app", - includePatterns: []string{"**"}, - excludePatterns: []string{"foo**"}, - }, - wantAll: []string{ - "/repos/some-app/included", - }, - wantFiles: []string{ - "/repos/some-app/included", - }, - }, - } - for _, tt := range tests { - fsysRoot := "/" - fsys := setup(fsysRoot, tt.files) - - t.Run(tt.name, func(t *testing.T) { - got, err := globFilesFs(fsys, fsysRoot, tt.args.basePath, tt.args.includePatterns, tt.args.excludePatterns) - - if (err != nil) != tt.wantErr { - t.Errorf("globFilesFs() error = %v, wantErr %v", err, tt.wantErr) - return - } - - gotToSlash := make([]string, len(got)) - for index, path := range got { - gotToSlash[index] = filepath.ToSlash(path) - } - - sort.Strings(gotToSlash) - - if !reflect.DeepEqual(gotToSlash, tt.wantFiles) { - t.Errorf("globFilesFs() = %v, want %v", gotToSlash, tt.wantFiles) - } - }) - - t.Run(tt.name, func(t *testing.T) { - got, err := globAllFs(fsys, fsysRoot, tt.args.basePath, tt.args.includePatterns, tt.args.excludePatterns) - - if (err != nil) != tt.wantErr { - t.Errorf("globAllFs() error = %v, wantErr %v", err, tt.wantErr) - return - } - - gotToSlash := make([]string, len(got)) - for index, path := range got { - gotToSlash[index] = filepath.ToSlash(path) - } - - sort.Strings(gotToSlash) - sort.Strings(tt.wantAll) - - if !reflect.DeepEqual(gotToSlash, tt.wantAll) { - t.Errorf("globAllFs() = %v, want %v", gotToSlash, tt.wantAll) - } - }) - } -} |
