diff options
Diffstat (limited to 'cli/internal/doublestar/utils.go')
| -rw-r--r-- | cli/internal/doublestar/utils.go | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/cli/internal/doublestar/utils.go b/cli/internal/doublestar/utils.go new file mode 100644 index 0000000..7236cd0 --- /dev/null +++ b/cli/internal/doublestar/utils.go @@ -0,0 +1,71 @@ +// Package doublestar is adapted from https://github.com/bmatcuk/doublestar +// Copyright Bob Matcuk. All Rights Reserved. +// SPDX-License-Identifier: MIT +package doublestar + +// SplitPattern is a utility function. Given a pattern, SplitPattern will +// return two strings: the first string is everything up to the last slash +// (`/`) that appears _before_ any unescaped "meta" characters (ie, `*?[{`). +// The second string is everything after that slash. For example, given the +// pattern: +// +// ../../path/to/meta*/** +// ^----------- split here +// +// SplitPattern returns "../../path/to" and "meta*/**". This is useful for +// initializing os.DirFS() to call Glob() because Glob() will silently fail if +// your pattern includes `/./` or `/../`. For example: +// +// base, pattern := SplitPattern("../../path/to/meta*/**") +// fsys := os.DirFS(base) +// matches, err := Glob(fsys, pattern) +// +// If SplitPattern cannot find somewhere to split the pattern (for example, +// `meta*/**`), it will return "." and the unaltered pattern (`meta*/**` in +// this example). +// +// Of course, it is your responsibility to decide if the returned base path is +// "safe" in the context of your application. Perhaps you could use Match() to +// validate against a list of approved base directories? +func SplitPattern(p string) (string, string) { + base := "." + pattern := p + + splitIdx := -1 + for i := 0; i < len(p); i++ { + c := p[i] + if c == '\\' { + i++ + } else if c == '/' { + splitIdx = i + } else if c == '*' || c == '?' || c == '[' || c == '{' { + break + } + } + + if splitIdx >= 0 { + return p[:splitIdx], p[splitIdx+1:] + } + + return base, pattern +} + +// Finds the next comma, but ignores any commas that appear inside nested `{}`. +// Assumes that each opening bracket has a corresponding closing bracket. +func indexNextAlt(s string, allowEscaping bool) int { + alts := 1 + l := len(s) + for i := 0; i < l; i++ { + if allowEscaping && s[i] == '\\' { + // skip next byte + i++ + } else if s[i] == '{' { + alts++ + } else if s[i] == '}' { + alts-- + } else if s[i] == ',' && alts == 1 { + return i + } + } + return -1 +} |
