diff --git a/go.mod b/go.mod index f6914f986..d27e7bb41 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ require ( github.com/99designs/gqlgen v0.12.2 github.com/Yamashou/gqlgenc v0.0.0-20200902035953-4dbef3551953 github.com/antchfx/htmlquery v1.2.3 - github.com/bmatcuk/doublestar/v2 v2.0.1 github.com/chromedp/cdproto v0.0.0-20200608134039-8a80cdaf865c github.com/chromedp/chromedp v0.5.3 github.com/disintegration/imaging v1.6.0 diff --git a/go.sum b/go.sum index 03e52adfe..ba64d66f2 100644 --- a/go.sum +++ b/go.sum @@ -62,8 +62,6 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= -github.com/bmatcuk/doublestar/v2 v2.0.1 h1:EFT91DmIMRcrUEcYUW7AqSAwKvNzP5+CoDmNVBbcQOU= -github.com/bmatcuk/doublestar/v2 v2.0.1/go.mod h1:QMmcs3H2AUQICWhfzLXz+IYln8lRQmTZRptLie8RgRw= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= diff --git a/pkg/manager/generator_sprite.go b/pkg/manager/generator_sprite.go index 308b85714..7bbc780c4 100644 --- a/pkg/manager/generator_sprite.go +++ b/pkg/manager/generator_sprite.go @@ -11,9 +11,9 @@ import ( "sort" "strings" - "github.com/bmatcuk/doublestar/v2" "github.com/disintegration/imaging" "github.com/fvbommel/sortorder" + "github.com/stashapp/stash/pkg/ffmpeg" "github.com/stashapp/stash/pkg/logger" "github.com/stashapp/stash/pkg/utils" @@ -89,8 +89,11 @@ func (g *SpriteGenerator) generateSpriteImage(encoder *ffmpeg.Encoder) error { } // Combine all of the thumbnails into a sprite image - globPath := filepath.Join(instance.Paths.Generated.Tmp, fmt.Sprintf("thumbnail_%s_*.jpg", g.VideoChecksum)) - imagePaths, _ := doublestar.Glob(globPath) + pattern := fmt.Sprintf("thumbnail_%s_.+\\.jpg$", g.VideoChecksum) + imagePaths, err := utils.MatchEntries(instance.Paths.Generated.Tmp, pattern) + if err != nil { + return err + } sort.Sort(sortorder.Natural(imagePaths)) var images []image.Image for _, imagePath := range imagePaths { diff --git a/pkg/utils/file.go b/pkg/utils/file.go index 196f0d047..072bdbc82 100644 --- a/pkg/utils/file.go +++ b/pkg/utils/file.go @@ -9,6 +9,7 @@ import ( "os" "os/user" "path/filepath" + "regexp" "github.com/h2non/filetype" "github.com/h2non/filetype/types" @@ -198,8 +199,8 @@ func WriteFile(path string, file []byte) error { } // GetIntraDir returns a string that can be added to filepath.Join to implement directory depth, "" on error -//eg given a pattern of 0af63ce3c99162e9df23a997f62621c5 and a depth of 2 length of 3 -//returns 0af/63c or 0af\63c ( dependin on os) that can be later used like this filepath.Join(directory, intradir, basename) +// eg given a pattern of 0af63ce3c99162e9df23a997f62621c5 and a depth of 2 length of 3 +// returns 0af/63c or 0af\63c ( dependin on os) that can be later used like this filepath.Join(directory, intradir, basename) func GetIntraDir(pattern string, depth, length int) string { if depth < 1 || length < 1 || (depth*length > len(pattern)) { return "" @@ -236,3 +237,35 @@ func ServeFileNoCache(w http.ResponseWriter, r *http.Request, filepath string) { http.ServeFile(w, r, filepath) } + +// MatchEntries returns a string slice of the entries in directory dir which +// match the regexp pattern. On error an empty slice is returned +// MatchEntries isn't recursive, only the specific 'dir' is searched +// without being expanded. +func MatchEntries(dir, pattern string) ([]string, error) { + var res []string + var err error + + re, err := regexp.Compile(pattern) + if err != nil { + return nil, err + } + + f, err := os.Open(dir) + if err != nil { + return nil, err + } + defer f.Close() + + files, err := f.Readdirnames(-1) + if err != nil { + return nil, err + } + + for _, file := range files { + if re.Match([]byte(file)) { + res = append(res, filepath.Join(dir, file)) + } + } + return res, err +} diff --git a/ui/v2.5/src/components/Changelog/versions/v050.md b/ui/v2.5/src/components/Changelog/versions/v050.md index f9f0d911e..9cdcadf85 100644 --- a/ui/v2.5/src/components/Changelog/versions/v050.md +++ b/ui/v2.5/src/components/Changelog/versions/v050.md @@ -22,6 +22,7 @@ * Support configurable number of threads for scanning and generation. ### 🐛 Bug fixes +* Fix sprite generation when generated path has special characters. * Prevent studio from being set as its own parent * Fixed performer scraper select overlapping search results * Fix tag/studio images not being changed after update. diff --git a/vendor/github.com/bmatcuk/doublestar/v2/.gitignore b/vendor/github.com/bmatcuk/doublestar/v2/.gitignore deleted file mode 100644 index af212ecc2..000000000 --- a/vendor/github.com/bmatcuk/doublestar/v2/.gitignore +++ /dev/null @@ -1,32 +0,0 @@ -# vi -*~ -*.swp -*.swo - -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test -*.prof - -# test directory -test/ diff --git a/vendor/github.com/bmatcuk/doublestar/v2/.travis.yml b/vendor/github.com/bmatcuk/doublestar/v2/.travis.yml deleted file mode 100644 index 78a90e7b5..000000000 --- a/vendor/github.com/bmatcuk/doublestar/v2/.travis.yml +++ /dev/null @@ -1,20 +0,0 @@ -language: go - -go: - - 1.12 - - 1.13 - - 1.14 - -os: - - linux - - windows - -before_install: - - go get -t -v ./... - -script: - - go test -race -coverprofile=coverage.txt -covermode=atomic - -after_success: - - bash <(curl -s https://codecov.io/bash) - diff --git a/vendor/github.com/bmatcuk/doublestar/v2/LICENSE b/vendor/github.com/bmatcuk/doublestar/v2/LICENSE deleted file mode 100644 index 309c9d1d1..000000000 --- a/vendor/github.com/bmatcuk/doublestar/v2/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Bob Matcuk - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/vendor/github.com/bmatcuk/doublestar/v2/README.md b/vendor/github.com/bmatcuk/doublestar/v2/README.md deleted file mode 100644 index 44631dcfe..000000000 --- a/vendor/github.com/bmatcuk/doublestar/v2/README.md +++ /dev/null @@ -1,142 +0,0 @@ -# doublestar - -Path pattern matching and globbing supporting `doublestar` (`**`) patterns. - -![Release](https://img.shields.io/github/release/bmatcuk/doublestar.svg?branch=master) -[![Build Status](https://travis-ci.org/bmatcuk/doublestar.svg?branch=master)](https://travis-ci.org/bmatcuk/doublestar) -[![codecov.io](https://img.shields.io/codecov/c/github/bmatcuk/doublestar.svg?branch=master)](https://codecov.io/github/bmatcuk/doublestar?branch=master) - -## About - -#### [Updating from v1 to v2?](UPGRADING.md) - -**doublestar** is a [golang](http://golang.org/) implementation of path pattern -matching and globbing with support for "doublestar" (aka globstar: `**`) -patterns. - -doublestar patterns match files and directories recursively. For example, if -you had the following directory structure: - -```bash -grandparent -`-- parent - |-- child1 - `-- child2 -``` - -You could find the children with patterns such as: `**/child*`, -`grandparent/**/child?`, `**/parent/*`, or even just `**` by itself (which will -return all files and directories recursively). - -Bash's globstar is doublestar's inspiration and, as such, works similarly. -Note that the doublestar must appear as a path component by itself. A pattern -such as `/path**` is invalid and will be treated the same as `/path*`, but -`/path*/**` should achieve the desired result. Additionally, `/path/**` will -match all directories and files under the path directory, but `/path/**/` will -only match directories. - -## Installation - -**doublestar** can be installed via `go get`: - -```bash -go get github.com/bmatcuk/doublestar/v2 -``` - -To use it in your code, you must import it: - -```go -import "github.com/bmatcuk/doublestar/v2" -``` - -## Usage - -### Match - -```go -func Match(pattern, name string) (bool, error) -``` - -Match returns true if `name` matches the file name `pattern` -([see below](#patterns)). `name` and `pattern` are split on forward slash (`/`) -characters and may be relative or absolute. - -Note: `Match()` is meant to be a drop-in replacement for `path.Match()`. As -such, it always uses `/` as the path separator. If you are writing code that -will run on systems where `/` is not the path separator (such as Windows), you -want to use `PathMatch()` (below) instead. - - -### PathMatch - -```go -func PathMatch(pattern, name string) (bool, error) -``` - -PathMatch returns true if `name` matches the file name `pattern` -([see below](#patterns)). The difference between Match and PathMatch is that -PathMatch will automatically use your system's path separator to split `name` -and `pattern`. - -`PathMatch()` is meant to be a drop-in replacement for `filepath.Match()`. - -### Glob - -```go -func Glob(pattern string) ([]string, error) -``` - -Glob finds all files and directories in the filesystem that match `pattern` -([see below](#patterns)). `pattern` may be relative (to the current working -directory), or absolute. - -`Glob()` is meant to be a drop-in replacement for `filepath.Glob()`. - -### Patterns - -**doublestar** supports the following special terms in the patterns: - -Special Terms | Meaning -------------- | ------- -`*` | matches any sequence of non-path-separators -`**` | matches any sequence of characters, including path separators -`?` | matches any single non-path-separator character -`[class]` | matches any single non-path-separator character against a class of characters ([see below](#character-classes)) -`{alt1,...}` | matches a sequence of characters if one of the comma-separated alternatives matches - -Any character with a special meaning can be escaped with a backslash (`\`). - -#### Character Classes - -Character classes support the following: - -Class | Meaning ----------- | ------- -`[abc]` | matches any single character within the set -`[a-z]` | matches any single character in the range -`[^class]` | matches any single character which does *not* match the class - -### Abstracting the `os` package - -**doublestar** by default uses the `Open`, `Stat`, and `Lstat`, functions and -`PathSeparator` value from the standard library's `os` package. To abstract -this, for example to be able to perform tests of Windows paths on Linux, or to -interoperate with your own filesystem code, it includes the functions `GlobOS` -and `PathMatchOS` which are identical to `Glob` and `PathMatch` except that they -operate on an `OS` interface: - -```go -type OS interface { - Lstat(name string) (os.FileInfo, error) - Open(name string) (*os.File, error) - PathSeparator() rune - Stat(name string) (os.FileInfo, error) -} -``` - -`StandardOS` is a value that implements this interface by calling functions in -the standard library's `os` package. - -## License - -[MIT License](LICENSE) diff --git a/vendor/github.com/bmatcuk/doublestar/v2/UPGRADING.md b/vendor/github.com/bmatcuk/doublestar/v2/UPGRADING.md deleted file mode 100644 index 8193544fe..000000000 --- a/vendor/github.com/bmatcuk/doublestar/v2/UPGRADING.md +++ /dev/null @@ -1,13 +0,0 @@ -# Upgrading from v1 to v2 - -The change from v1 to v2 was fairly minor: the return type of the `Open` method -on the `OS` interface was changed from `*os.File` to `File`, a new interface -exported by doublestar. The new `File` interface only defines the functionality -doublestar actually needs (`io.Closer` and `Readdir`), making it easier to use -doublestar with [go-billy](https://github.com/src-d/go-billy), -[afero](https://github.com/spf13/afero), or something similar. If you were -using this functionality, updating should be as easy as updating `Open's` -return type, since `os.File` already implements `doublestar.File`. - -If you weren't using this functionality, updating should be as easy as changing -your dependencies to point to v2. diff --git a/vendor/github.com/bmatcuk/doublestar/v2/doublestar.go b/vendor/github.com/bmatcuk/doublestar/v2/doublestar.go deleted file mode 100644 index 10ce4d404..000000000 --- a/vendor/github.com/bmatcuk/doublestar/v2/doublestar.go +++ /dev/null @@ -1,681 +0,0 @@ -package doublestar - -import ( - "fmt" - "io" - "os" - "path" - "path/filepath" - "sort" - "strings" - "unicode/utf8" -) - -// File defines a subset of file operations -type File interface { - io.Closer - Readdir(count int) ([]os.FileInfo, error) -} - -// An OS abstracts functions in the standard library's os package. -type OS interface { - Lstat(name string) (os.FileInfo, error) - Open(name string) (File, error) - PathSeparator() rune - Stat(name string) (os.FileInfo, error) -} - -// A standardOS implements OS by calling functions in the standard library's os -// package. -type standardOS struct{} - -func (standardOS) Lstat(name string) (os.FileInfo, error) { return os.Lstat(name) } -func (standardOS) Open(name string) (File, error) { return os.Open(name) } -func (standardOS) PathSeparator() rune { return os.PathSeparator } -func (standardOS) Stat(name string) (os.FileInfo, error) { return os.Stat(name) } - -// StandardOS is a value that implements the OS interface by calling functions -// in the standard libray's os package. -var StandardOS OS = standardOS{} - -// ErrBadPattern indicates a pattern was malformed. -var ErrBadPattern = path.ErrBadPattern - -// Split a path on the given separator, respecting escaping. -func splitPathOnSeparator(path string, separator rune) (ret []string) { - idx := 0 - if separator == '\\' { - // if the separator is '\\', then we can just split... - ret = strings.Split(path, string(separator)) - idx = len(ret) - } else { - // otherwise, we need to be careful of situations where the separator was escaped - cnt := strings.Count(path, string(separator)) - if cnt == 0 { - return []string{path} - } - - ret = make([]string, cnt+1) - pathlen := len(path) - separatorLen := utf8.RuneLen(separator) - emptyEnd := false - for start := 0; start < pathlen; { - end := indexRuneWithEscaping(path[start:], separator) - if end == -1 { - emptyEnd = false - end = pathlen - } else { - emptyEnd = true - end += start - } - ret[idx] = path[start:end] - start = end + separatorLen - idx++ - } - - // If the last rune is a path separator, we need to append an empty string to - // represent the last, empty path component. By default, the strings from - // make([]string, ...) will be empty, so we just need to icrement the count - if emptyEnd { - idx++ - } - } - - return ret[:idx] -} - -// Find the first index of a rune in a string, -// ignoring any times the rune is escaped using "\". -func indexRuneWithEscaping(s string, r rune) int { - end := strings.IndexRune(s, r) - if end == -1 { - return -1 - } - if end > 0 && s[end-1] == '\\' { - start := end + utf8.RuneLen(r) - end = indexRuneWithEscaping(s[start:], r) - if end != -1 { - end += start - } - } - return end -} - -// Find the last index of a rune in a string, -// ignoring any times the rune is escaped using "\". -func lastIndexRuneWithEscaping(s string, r rune) int { - end := strings.LastIndex(s, string(r)) - if end == -1 { - return -1 - } - if end > 0 && s[end-1] == '\\' { - end = lastIndexRuneWithEscaping(s[:end-1], r) - } - return end -} - -// Find the index of the first instance of one of the unicode characters in -// chars, ignoring any times those characters are escaped using "\". -func indexAnyWithEscaping(s, chars string) int { - end := strings.IndexAny(s, chars) - if end == -1 { - return -1 - } - if end > 0 && s[end-1] == '\\' { - _, adj := utf8.DecodeRuneInString(s[end:]) - start := end + adj - end = indexAnyWithEscaping(s[start:], chars) - if end != -1 { - end += start - } - } - return end -} - -// Split a set of alternatives such as {alt1,alt2,...} and returns the index of -// the rune after the closing curly brace. Respects nested alternatives and -// escaped runes. -func splitAlternatives(s string) (ret []string, idx int) { - ret = make([]string, 0, 2) - idx = 0 - slen := len(s) - braceCnt := 1 - esc := false - start := 0 - for braceCnt > 0 { - if idx >= slen { - return nil, -1 - } - - sRune, adj := utf8.DecodeRuneInString(s[idx:]) - if esc { - esc = false - } else if sRune == '\\' { - esc = true - } else if sRune == '{' { - braceCnt++ - } else if sRune == '}' { - braceCnt-- - } else if sRune == ',' && braceCnt == 1 { - ret = append(ret, s[start:idx]) - start = idx + adj - } - - idx += adj - } - ret = append(ret, s[start:idx-1]) - return -} - -// Returns true if the pattern is "zero length", meaning -// it could match zero or more characters. -func isZeroLengthPattern(pattern string) (ret bool, err error) { - // * can match zero - if pattern == "" || pattern == "*" || pattern == "**" { - return true, nil - } - - // an alternative with zero length can match zero, for example {,x} - the - // first alternative has zero length - r, adj := utf8.DecodeRuneInString(pattern) - if r == '{' { - options, endOptions := splitAlternatives(pattern[adj:]) - if endOptions == -1 { - return false, ErrBadPattern - } - if ret, err = isZeroLengthPattern(pattern[adj+endOptions:]); !ret || err != nil { - return - } - for _, o := range options { - if ret, err = isZeroLengthPattern(o); ret || err != nil { - return - } - } - } - - return false, nil -} - -// Match returns true if name matches the shell file name pattern. -// The pattern syntax is: -// -// pattern: -// { term } -// term: -// '*' matches any sequence of non-path-separators -// '**' matches any sequence of characters, including -// path separators. -// '?' matches any single non-path-separator character -// '[' [ '^' ] { character-range } ']' -// character class (must be non-empty) -// '{' { term } [ ',' { term } ... ] '}' -// c matches character c (c != '*', '?', '\\', '[') -// '\\' c matches character c -// -// character-range: -// c matches character c (c != '\\', '-', ']') -// '\\' c matches character c -// lo '-' hi matches character c for lo <= c <= hi -// -// Match requires pattern to match all of name, not just a substring. -// The path-separator defaults to the '/' character. The only possible -// returned error is ErrBadPattern, when pattern is malformed. -// -// Note: this is meant as a drop-in replacement for path.Match() which -// always uses '/' as the path separator. If you want to support systems -// which use a different path separator (such as Windows), what you want -// is the PathMatch() function below. -// -func Match(pattern, name string) (bool, error) { - return matchWithSeparator(pattern, name, '/') -} - -// PathMatch is like Match except that it uses your system's path separator. -// For most systems, this will be '/'. However, for Windows, it would be '\\'. -// Note that for systems where the path separator is '\\', escaping is -// disabled. -// -// Note: this is meant as a drop-in replacement for filepath.Match(). -// -func PathMatch(pattern, name string) (bool, error) { - return PathMatchOS(StandardOS, pattern, name) -} - -// PathMatchOS is like PathMatch except that it uses vos's path separator. -func PathMatchOS(vos OS, pattern, name string) (bool, error) { - pattern = filepath.ToSlash(pattern) - return matchWithSeparator(pattern, name, vos.PathSeparator()) -} - -// Match returns true if name matches the shell file name pattern. -// The pattern syntax is: -// -// pattern: -// { term } -// term: -// '*' matches any sequence of non-path-separators -// '**' matches any sequence of characters, including -// path separators. -// '?' matches any single non-path-separator character -// '[' [ '^' ] { character-range } ']' -// character class (must be non-empty) -// '{' { term } [ ',' { term } ... ] '}' -// c matches character c (c != '*', '?', '\\', '[') -// '\\' c matches character c -// -// character-range: -// c matches character c (c != '\\', '-', ']') -// '\\' c matches character c, unless separator is '\\' -// lo '-' hi matches character c for lo <= c <= hi -// -// Match requires pattern to match all of name, not just a substring. -// The only possible returned error is ErrBadPattern, when pattern -// is malformed. -// -func matchWithSeparator(pattern, name string, separator rune) (bool, error) { - nameComponents := splitPathOnSeparator(name, separator) - return doMatching(pattern, nameComponents) -} - -func doMatching(pattern string, nameComponents []string) (matched bool, err error) { - // check for some base-cases - patternLen, nameLen := len(pattern), len(nameComponents) - if patternLen == 0 && nameLen == 0 { - return true, nil - } - if patternLen == 0 { - if nameLen == 1 && nameComponents[0] == "" { - return true, nil - } else if nameLen == 0 { - return false, nil - } - } - - slashIdx := indexRuneWithEscaping(pattern, '/') - lastComponent := slashIdx == -1 - if lastComponent { - slashIdx = len(pattern) - } - if pattern[:slashIdx] == "**" { - // if our last pattern component is a doublestar, we're done - - // doublestar will match any remaining name components, if any. - if lastComponent { - return true, nil - } - - // otherwise, try matching remaining components - for nameIdx := 0; nameIdx < nameLen; nameIdx++ { - if m, _ := doMatching(pattern[slashIdx+1:], nameComponents[nameIdx:]); m { - return true, nil - } - } - return false, nil - } - - var matches []string - matches, err = matchComponent(pattern, nameComponents[0]) - if matches == nil || err != nil { - return - } - if len(matches) == 0 && nameLen == 1 { - return true, nil - } - - if nameLen > 1 { - for _, alt := range matches { - matched, err = doMatching(alt, nameComponents[1:]) - if matched || err != nil { - return - } - } - } - - return false, nil -} - -// Glob returns the names of all files matching pattern or nil -// if there is no matching file. The syntax of pattern is the same -// as in Match. The pattern may describe hierarchical names such as -// /usr/*/bin/ed (assuming the Separator is '/'). -// -// Glob ignores file system errors such as I/O errors reading directories. -// The only possible returned error is ErrBadPattern, when pattern -// is malformed. -// -// Your system path separator is automatically used. This means on -// systems where the separator is '\\' (Windows), escaping will be -// disabled. -// -// Note: this is meant as a drop-in replacement for filepath.Glob(). -// -func Glob(pattern string) (matches []string, err error) { - return GlobOS(StandardOS, pattern) -} - -// GlobOS is like Glob except that it operates on vos. -func GlobOS(vos OS, pattern string) (matches []string, err error) { - if len(pattern) == 0 { - return nil, nil - } - - // if the pattern starts with alternatives, we need to handle that here - the - // alternatives may be a mix of relative and absolute - if pattern[0] == '{' { - options, endOptions := splitAlternatives(pattern[1:]) - if endOptions == -1 { - return nil, ErrBadPattern - } - for _, o := range options { - m, e := Glob(o + pattern[endOptions+1:]) - if e != nil { - return nil, e - } - matches = append(matches, m...) - } - return matches, nil - } - - // If the pattern is relative or absolute and we're on a non-Windows machine, - // volumeName will be an empty string. If it is absolute and we're on a - // Windows machine, volumeName will be a drive letter ("C:") for filesystem - // paths or \\\ for UNC paths. - isAbs := filepath.IsAbs(pattern) || pattern[0] == '\\' || pattern[0] == '/' - volumeName := filepath.VolumeName(pattern) - isWindowsUNC := strings.HasPrefix(volumeName, `\\`) - if isWindowsUNC || isAbs { - startIdx := len(volumeName) + 1 - return doGlob(vos, fmt.Sprintf("%s%s", volumeName, string(vos.PathSeparator())), filepath.ToSlash(pattern[startIdx:]), matches) - } - - // otherwise, it's a relative pattern - return doGlob(vos, ".", filepath.ToSlash(pattern), matches) -} - -// Perform a glob -func doGlob(vos OS, basedir, pattern string, matches []string) (m []string, e error) { - m = matches - e = nil - - // if the pattern starts with any path components that aren't globbed (ie, - // `path/to/glob*`), we can skip over the un-globbed components (`path/to` in - // our example). - globIdx := indexAnyWithEscaping(pattern, "*?[{\\") - if globIdx > 0 { - globIdx = lastIndexRuneWithEscaping(pattern[:globIdx], '/') - } else if globIdx == -1 { - globIdx = lastIndexRuneWithEscaping(pattern, '/') - } - if globIdx > 0 { - basedir = filepath.Join(basedir, pattern[:globIdx]) - pattern = pattern[globIdx+1:] - } - - // Lstat will return an error if the file/directory doesn't exist - fi, err := vos.Lstat(basedir) - if err != nil { - return - } - - // if the pattern is empty, we've found a match - if len(pattern) == 0 { - m = append(m, basedir) - return - } - - // otherwise, we need to check each item in the directory... - // first, if basedir is a symlink, follow it... - if (fi.Mode() & os.ModeSymlink) != 0 { - fi, err = vos.Stat(basedir) - if err != nil { - return - } - } - - // confirm it's a directory... - if !fi.IsDir() { - return - } - - // read directory - dir, err := vos.Open(basedir) - if err != nil { - return - } - defer func() { - if err := dir.Close(); e == nil { - e = err - } - }() - - files, err := dir.Readdir(-1) - if err != nil { - return - } - sort.Slice(files, func(i, j int) bool { return files[i].Name() < files[j].Name() }) - - slashIdx := indexRuneWithEscaping(pattern, '/') - lastComponent := slashIdx == -1 - if lastComponent { - slashIdx = len(pattern) - } - if pattern[:slashIdx] == "**" { - // if the current component is a doublestar, we'll try depth-first - for _, file := range files { - // if symlink, we may want to follow - if (file.Mode() & os.ModeSymlink) != 0 { - file, err = vos.Stat(filepath.Join(basedir, file.Name())) - if err != nil { - continue - } - } - - if file.IsDir() { - // recurse into directories - if lastComponent { - m = append(m, filepath.Join(basedir, file.Name())) - } - m, e = doGlob(vos, filepath.Join(basedir, file.Name()), pattern, m) - } else if lastComponent { - // if the pattern's last component is a doublestar, we match filenames, too - m = append(m, filepath.Join(basedir, file.Name())) - } - } - if lastComponent { - return // we're done - } - - pattern = pattern[slashIdx+1:] - } - - // check items in current directory and recurse - var match []string - for _, file := range files { - match, e = matchComponent(pattern, file.Name()) - if e != nil { - return - } - if match != nil { - if len(match) == 0 { - m = append(m, filepath.Join(basedir, file.Name())) - } else { - for _, alt := range match { - m, e = doGlob(vos, filepath.Join(basedir, file.Name()), alt, m) - } - } - } - } - return -} - -// Attempt to match a single path component with a pattern. Note that the -// pattern may include multiple components but that the "name" is just a single -// path component. The return value is a slice of patterns that should be -// checked against subsequent path components or nil, indicating that the -// pattern does not match this path. It is assumed that pattern components are -// separated by '/' -func matchComponent(pattern, name string) ([]string, error) { - // check for matches one rune at a time - patternLen, nameLen := len(pattern), len(name) - patIdx, nameIdx := 0, 0 - for patIdx < patternLen && nameIdx < nameLen { - patRune, patAdj := utf8.DecodeRuneInString(pattern[patIdx:]) - nameRune, nameAdj := utf8.DecodeRuneInString(name[nameIdx:]) - if patRune == '/' { - patIdx++ - break - } else if patRune == '\\' { - // handle escaped runes, only if separator isn't '\\' - patIdx += patAdj - patRune, patAdj = utf8.DecodeRuneInString(pattern[patIdx:]) - if patRune == utf8.RuneError { - return nil, ErrBadPattern - } else if patRune == nameRune { - patIdx += patAdj - nameIdx += nameAdj - } else { - return nil, nil - } - } else if patRune == '*' { - // handle stars - a star at the end of the pattern or before a separator - // will always match the rest of the path component - if patIdx += patAdj; patIdx >= patternLen { - return []string{}, nil - } - if patRune, patAdj = utf8.DecodeRuneInString(pattern[patIdx:]); patRune == '/' { - return []string{pattern[patIdx+patAdj:]}, nil - } - - // check if we can make any matches - for ; nameIdx < nameLen; nameIdx += nameAdj { - if m, e := matchComponent(pattern[patIdx:], name[nameIdx:]); m != nil || e != nil { - return m, e - } - _, nameAdj = utf8.DecodeRuneInString(name[nameIdx:]) - } - return nil, nil - } else if patRune == '[' { - // handle character sets - patIdx += patAdj - endClass := indexRuneWithEscaping(pattern[patIdx:], ']') - if endClass == -1 { - return nil, ErrBadPattern - } - endClass += patIdx - classRunes := []rune(pattern[patIdx:endClass]) - classRunesLen := len(classRunes) - if classRunesLen > 0 { - classIdx := 0 - matchClass := false - if classRunes[0] == '^' { - classIdx++ - } - for classIdx < classRunesLen { - low := classRunes[classIdx] - if low == '-' { - return nil, ErrBadPattern - } - classIdx++ - if low == '\\' { - if classIdx < classRunesLen { - low = classRunes[classIdx] - classIdx++ - } else { - return nil, ErrBadPattern - } - } - high := low - if classIdx < classRunesLen && classRunes[classIdx] == '-' { - // we have a range of runes - if classIdx++; classIdx >= classRunesLen { - return nil, ErrBadPattern - } - high = classRunes[classIdx] - if high == '-' { - return nil, ErrBadPattern - } - classIdx++ - if high == '\\' { - if classIdx < classRunesLen { - high = classRunes[classIdx] - classIdx++ - } else { - return nil, ErrBadPattern - } - } - } - if low <= nameRune && nameRune <= high { - matchClass = true - } - } - if matchClass == (classRunes[0] == '^') { - return nil, nil - } - } else { - return nil, ErrBadPattern - } - patIdx = endClass + 1 - nameIdx += nameAdj - } else if patRune == '{' { - // handle alternatives such as {alt1,alt2,...} - patIdx += patAdj - options, endOptions := splitAlternatives(pattern[patIdx:]) - if endOptions == -1 { - return nil, ErrBadPattern - } - patIdx += endOptions - - results := make([][]string, 0, len(options)) - totalResults := 0 - for _, o := range options { - m, e := matchComponent(o+pattern[patIdx:], name[nameIdx:]) - if e != nil { - return nil, e - } - if m != nil { - results = append(results, m) - totalResults += len(m) - } - } - if len(results) > 0 { - lst := make([]string, 0, totalResults) - for _, m := range results { - lst = append(lst, m...) - } - return lst, nil - } - - return nil, nil - } else if patRune == '?' || patRune == nameRune { - // handle single-rune wildcard - patIdx += patAdj - nameIdx += nameAdj - } else { - return nil, nil - } - } - if nameIdx >= nameLen { - if patIdx >= patternLen { - return []string{}, nil - } - - pattern = pattern[patIdx:] - slashIdx := indexRuneWithEscaping(pattern, '/') - testPattern := pattern - if slashIdx >= 0 { - testPattern = pattern[:slashIdx] - } - - zeroLength, err := isZeroLengthPattern(testPattern) - if err != nil { - return nil, err - } - if zeroLength { - if slashIdx == -1 { - return []string{}, nil - } else { - return []string{pattern[slashIdx+1:]}, nil - } - } - } - return nil, nil -} diff --git a/vendor/github.com/bmatcuk/doublestar/v2/go.mod b/vendor/github.com/bmatcuk/doublestar/v2/go.mod deleted file mode 100644 index f0fa6bc59..000000000 --- a/vendor/github.com/bmatcuk/doublestar/v2/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/bmatcuk/doublestar/v2 - -go 1.12 diff --git a/vendor/modules.txt b/vendor/modules.txt index b73cfc031..447f6759a 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -40,8 +40,6 @@ github.com/agnivade/levenshtein github.com/antchfx/htmlquery # github.com/antchfx/xpath v1.1.6 github.com/antchfx/xpath -# github.com/bmatcuk/doublestar/v2 v2.0.1 -github.com/bmatcuk/doublestar/v2 # github.com/chromedp/cdproto v0.0.0-20200608134039-8a80cdaf865c github.com/chromedp/cdproto github.com/chromedp/cdproto/accessibility @@ -232,10 +230,10 @@ github.com/natefinch/pie github.com/pelletier/go-toml # github.com/pkg/errors v0.9.1 github.com/pkg/errors -# github.com/remeh/sizedwaitgroup v1.0.0 -github.com/remeh/sizedwaitgroup # github.com/pmezard/go-difflib v1.0.0 github.com/pmezard/go-difflib/difflib +# github.com/remeh/sizedwaitgroup v1.0.0 +github.com/remeh/sizedwaitgroup # github.com/rogpeppe/go-internal v1.3.0 github.com/rogpeppe/go-internal/modfile github.com/rogpeppe/go-internal/module