vendor: vendor 'github.com/git-lfs/wildmatch'
This commit is contained in:
parent
529dc7acfa
commit
44f6f7c2ad
6
glide.lock
generated
6
glide.lock
generated
@ -1,10 +1,12 @@
|
||||
hash: e19b925b9eaca9a10a7742b4a4b1dc8047bff437584538dda59f4f10e69fa6ca
|
||||
updated: 2018-01-29T17:36:52.158516-08:00
|
||||
hash: c9bdd0387a338276a0e612967c6bff94d04bd7e9126c1cfcd485bfba891e9fc5
|
||||
updated: 2018-02-15T15:49:22.305256-08:00
|
||||
imports:
|
||||
- name: github.com/bgentry/go-netrc
|
||||
version: 9fd32a8b3d3d3f9d43c341bfe098430e07609480
|
||||
subpackages:
|
||||
- netrc
|
||||
- name: github.com/git-lfs/wildmatch
|
||||
version: 62fc450048a8e2e2ffe3f0b5b488b41d05c9bf3e
|
||||
- name: github.com/inconshreveable/mousetrap
|
||||
version: 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
|
||||
- name: github.com/kr/pty
|
||||
|
@ -26,3 +26,5 @@ import:
|
||||
version: 6b67b3fab74d992bd07f72550006ab2c6907c416
|
||||
- package: github.com/pkg/errors
|
||||
version: c605e284fe17294bda444b34710735b29d1a9d90
|
||||
- package: github.com/git-lfs/wildmatch
|
||||
version: 62fc450048a8e2e2ffe3f0b5b488b41d05c9bf3e
|
||||
|
3
vendor/github.com/git-lfs/wildmatch/.travis.yml
generated
vendored
Normal file
3
vendor/github.com/git-lfs/wildmatch/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
language: go
|
||||
notifications:
|
||||
email: false
|
21
vendor/github.com/git-lfs/wildmatch/LICENSE.md
generated
vendored
Normal file
21
vendor/github.com/git-lfs/wildmatch/LICENSE.md
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018- GitHub, Inc. and Git LFS contributors
|
||||
|
||||
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.
|
7
vendor/github.com/git-lfs/wildmatch/README.md
generated
vendored
Normal file
7
vendor/github.com/git-lfs/wildmatch/README.md
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
# wildmatch
|
||||
|
||||
package `wildmatch` is a reimplementation of Git's `wildmatch.c`-style filepath pattern matching.
|
||||
|
||||
For more information, see the [godoc][1].
|
||||
|
||||
[1]: https://godoc.org/github.com/git-lfs/wildmatch
|
40
vendor/github.com/git-lfs/wildmatch/package.go
generated
vendored
Normal file
40
vendor/github.com/git-lfs/wildmatch/package.go
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
// package Wildmatch is an implementation of Git's wildmatch.c-style pattern
|
||||
// matching.
|
||||
//
|
||||
// Wildmatch patterns are comprised of any combination of the following three
|
||||
// components:
|
||||
//
|
||||
// - String literals. A string literal is "foo", or "foo\*" (matching "foo",
|
||||
// and "foo\", respectively). In general, string literals match their exact
|
||||
// contents in a filepath, and cannot match over directories unless they
|
||||
// include the operating system-specific path separator.
|
||||
//
|
||||
// - Wildcards. There are three types of wildcards:
|
||||
//
|
||||
// - Single-asterisk ('*'): matches any combination of characters, any
|
||||
// number of times. Does not match path separators.
|
||||
//
|
||||
// - Single-question mark ('?'): matches any single character, but not a
|
||||
// path separator.
|
||||
//
|
||||
// - Double-asterisk ('**'): greedily matches any number of directories.
|
||||
// For example, '**/foo' matches '/foo', 'bar/baz/woot/foot', but not
|
||||
// 'foo/bar'. Double-asterisks must be separated by filepath separators
|
||||
// on either side.
|
||||
//
|
||||
// - Character groups. A character group is composed of a set of included and
|
||||
// excluded character types. The set of included character types begins the
|
||||
// character group, and a '^' or '!' separates it from the set of excluded
|
||||
// character types.
|
||||
//
|
||||
// A character type can be one of the following:
|
||||
//
|
||||
// - Character literal: a single character, i.e., 'c'.
|
||||
//
|
||||
// - Character group: a group of characters, i.e., '[:alnum:]', etc.
|
||||
//
|
||||
// - Character range: a range of characters, i.e., 'a-z'.
|
||||
//
|
||||
// A Wildmatch pattern can be any combination of the above components, in any
|
||||
// ordering, and repeated any number of times.
|
||||
package wildmatch
|
651
vendor/github.com/git-lfs/wildmatch/wildmatch.go
generated
vendored
Normal file
651
vendor/github.com/git-lfs/wildmatch/wildmatch.go
generated
vendored
Normal file
@ -0,0 +1,651 @@
|
||||
package wildmatch
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// opt is an option type for configuring a new Wildmatch instance.
|
||||
type opt func(w *Wildmatch)
|
||||
|
||||
var (
|
||||
// CaseFold allows the receiving Wildmatch to match paths with
|
||||
// different case structuring as in the pattern.
|
||||
CaseFold opt = func(w *Wildmatch) {
|
||||
w.caseFold = true
|
||||
}
|
||||
|
||||
// SystemCase either folds or does not fold filepaths and patterns,
|
||||
// according to whether or not the operating system on which Wildmatch
|
||||
// runs supports case sensitive files or not.
|
||||
SystemCase opt
|
||||
)
|
||||
|
||||
const (
|
||||
sep byte = '/'
|
||||
)
|
||||
|
||||
// Wildmatch implements pattern matching against filepaths using the format
|
||||
// described in the package documentation.
|
||||
//
|
||||
// For more, see documentation for package 'wildmatch'.
|
||||
type Wildmatch struct {
|
||||
// ts are the token set used to match the given pattern.
|
||||
ts []token
|
||||
// p is the raw pattern used to derive the token set.
|
||||
p string
|
||||
|
||||
// caseFold allows the instance Wildmatch to match patterns with the
|
||||
// same character but different case structures.
|
||||
caseFold bool
|
||||
}
|
||||
|
||||
// NewWildmatch constructs a new Wildmatch instance which matches filepaths
|
||||
// according to the given pattern and the rules for matching above.
|
||||
//
|
||||
// If the pattern is malformed, for instance, it has an unclosed character
|
||||
// group, escape sequence, or character class, NewWildmatch will panic().
|
||||
func NewWildmatch(p string, opts ...opt) *Wildmatch {
|
||||
w := &Wildmatch{p: p}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(w)
|
||||
}
|
||||
|
||||
if w.caseFold {
|
||||
// Before parsing the pattern, convert it to lower-case.
|
||||
w.p = strings.ToLower(w.p)
|
||||
}
|
||||
|
||||
w.ts = parseTokens(strings.Split(w.p, string(sep)))
|
||||
|
||||
return w
|
||||
}
|
||||
|
||||
const (
|
||||
// escapes is a constant string containing all escapable characters
|
||||
escapes = "\\[]*?"
|
||||
)
|
||||
|
||||
// escapable returns whether the given "c" is escapable.
|
||||
func escapable(c byte) bool {
|
||||
return strings.IndexByte(escapes, c) > -1
|
||||
}
|
||||
|
||||
// parseTokens parses a separated list of patterns into a sequence of
|
||||
// representative Tokens that will compose the pattern when applied in sequence.
|
||||
func parseTokens(dirs []string) []token {
|
||||
if len(dirs) == 0 {
|
||||
return make([]token, 0)
|
||||
}
|
||||
|
||||
switch dirs[0] {
|
||||
case "":
|
||||
return parseTokens(dirs[1:])
|
||||
case "**":
|
||||
rest := parseTokens(dirs[1:])
|
||||
if len(rest) == 0 {
|
||||
// If there are no remaining tokens, return a lone
|
||||
// doubleStar token.
|
||||
return []token{&doubleStar{
|
||||
Until: nil,
|
||||
}}
|
||||
}
|
||||
|
||||
// Otherwise, return a doubleStar token that will match greedily
|
||||
// until the first component in the remainder of the pattern,
|
||||
// and then the remainder of the pattern.
|
||||
return append([]token{&doubleStar{
|
||||
Until: rest[0],
|
||||
}}, rest[1:]...)
|
||||
default:
|
||||
// Ordinarily, simply return the appropriate component, and
|
||||
// continue on.
|
||||
return append([]token{&component{
|
||||
fns: parseComponent(dirs[0]),
|
||||
}}, parseTokens(dirs[1:])...)
|
||||
}
|
||||
}
|
||||
|
||||
// nonEmpty returns the non-empty strings in "all".
|
||||
func nonEmpty(all []string) (ne []string) {
|
||||
for _, x := range all {
|
||||
if len(x) > 0 {
|
||||
ne = append(ne, x)
|
||||
}
|
||||
}
|
||||
return ne
|
||||
}
|
||||
|
||||
// Match returns true if and only if the pattern matched by the receiving
|
||||
// Wildmatch matches the entire filepath "t".
|
||||
func (w *Wildmatch) Match(t string) bool {
|
||||
dirs, ok := w.consume(t)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return len(dirs) == 0
|
||||
}
|
||||
|
||||
// consume performs the inner match of "t" against the receiver's pattern, and
|
||||
// returns a slice of remaining directory paths, and whether or not there was a
|
||||
// disagreement while matching.
|
||||
func (w *Wildmatch) consume(t string) ([]string, bool) {
|
||||
if w.caseFold {
|
||||
// If the receiving Wildmatch is case insensitive, the pattern
|
||||
// "w.p" will be lower-case.
|
||||
//
|
||||
// To preserve insensitivity, lower the given path "t", as well.
|
||||
t = strings.ToLower(t)
|
||||
}
|
||||
|
||||
dirs := strings.Split(t, string(sep))
|
||||
isDir := strings.HasSuffix(t, string(sep))
|
||||
|
||||
// Match each directory token-wise, allowing each token to consume more
|
||||
// than one directory in the case of the '**' pattern.
|
||||
for _, tok := range w.ts {
|
||||
var ok bool
|
||||
|
||||
dirs, ok = tok.Consume(dirs, isDir)
|
||||
if !ok {
|
||||
// If a pattern could not match the remainder of the
|
||||
// filepath, return so immediately, along with the paths
|
||||
// that we did successfully manage to match.
|
||||
return dirs, false
|
||||
}
|
||||
}
|
||||
return dirs, true
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer and returns the receiver's pattern in the format
|
||||
// specified above.
|
||||
func (w *Wildmatch) String() string {
|
||||
return w.p
|
||||
}
|
||||
|
||||
// token matches zero, one, or more directory components.
|
||||
type token interface {
|
||||
// Consume matches zero, one, or more directory components.
|
||||
//
|
||||
// Consider the following examples:
|
||||
//
|
||||
// (["foo", "bar", "baz"]) -> (["oo", "bar", baz"], true)
|
||||
// (["foo", "bar", "baz"]) -> (["bar", baz"], true)
|
||||
// (["foo", "bar", "baz"]) -> (["baz"], true)
|
||||
// (["foo", "bar", "baz"]) -> ([], true)
|
||||
// (["foo", "bar", "baz"]) -> (["foo", "bar", "baz"], false)
|
||||
// (["foo", "bar", "baz"]) -> (["oo", "bar", "baz"], false)
|
||||
// (["foo", "bar", "baz"]) -> (["bar", "baz"], false)
|
||||
//
|
||||
// The Consume operation can reduce the size of a single entry in the
|
||||
// slice (see: example (1) above), or remove it entirely, (see: examples
|
||||
// (2), (3), and (4) above). It can also refuse to match forward after
|
||||
// making any amount of progress (see: examples (5), (6), and (7)
|
||||
// above).
|
||||
//
|
||||
// Consume accepts a slice representing a path-delimited filepath on
|
||||
// disk, and a bool indicating whether the given path is a directory
|
||||
// (i.e., "foo/bar/" is, but "foo/bar" isn't).
|
||||
Consume(path []string, isDir bool) ([]string, bool)
|
||||
|
||||
// String returns the string representation this component of the
|
||||
// pattern; i.e., a string that, when parsed, would form the same token.
|
||||
String() string
|
||||
}
|
||||
|
||||
// doubleStar is an implementation of the Token interface which greedily matches
|
||||
// one-or-more path components until a successor token.
|
||||
type doubleStar struct {
|
||||
Until token
|
||||
}
|
||||
|
||||
// Consume implements token.Consume as above.
|
||||
func (d *doubleStar) Consume(path []string, isDir bool) ([]string, bool) {
|
||||
// If there are no remaining tokens to match, allow matching the entire
|
||||
// path.
|
||||
if d.Until == nil {
|
||||
return nil, true
|
||||
}
|
||||
|
||||
for i := len(path); i > 0; i-- {
|
||||
rest, ok := d.Until.Consume(path[i:], false)
|
||||
if ok {
|
||||
return rest, ok
|
||||
}
|
||||
}
|
||||
|
||||
// If no match has been found, we assume that the '**' token matches the
|
||||
// empty string, and defer pattern matching to the rest of the path.
|
||||
return d.Until.Consume(path, isDir)
|
||||
}
|
||||
|
||||
// String implements Component.String.
|
||||
func (d *doubleStar) String() string {
|
||||
if d.Until == nil {
|
||||
return "**"
|
||||
}
|
||||
return fmt.Sprintf("**/%s", d.Until.String())
|
||||
}
|
||||
|
||||
// componentFn is a functional type designed to match a single component of a
|
||||
// directory structure by reducing the unmatched part, and returning whether or
|
||||
// not a match was successful.
|
||||
type componentFn interface {
|
||||
Apply(s string) (rest string, ok bool)
|
||||
String() string
|
||||
}
|
||||
|
||||
// cfn is a wrapper type for the Component interface that includes an applicable
|
||||
// function, and a string that represents it.
|
||||
type cfn struct {
|
||||
fn func(s string) (rest string, ok bool)
|
||||
str string
|
||||
}
|
||||
|
||||
// Apply executes the component function as described above.
|
||||
func (c *cfn) Apply(s string) (rest string, ok bool) {
|
||||
return c.fn(s)
|
||||
}
|
||||
|
||||
// String returns the string representation of this component.
|
||||
func (c *cfn) String() string {
|
||||
return c.str
|
||||
}
|
||||
|
||||
// component is an implementation of the Token interface, which matches a single
|
||||
// component at the front of a tree structure by successively applying
|
||||
// implementations of the componentFn type.
|
||||
type component struct {
|
||||
// fns is the list of componentFn implementations to be successively
|
||||
// applied.
|
||||
fns []componentFn
|
||||
}
|
||||
|
||||
// parseComponent parses a single component from its string representation,
|
||||
// including wildcards, character classes, string literals, and escape
|
||||
// sequences.
|
||||
func parseComponent(s string) []componentFn {
|
||||
if len(s) == 0 {
|
||||
// The empty string represents the absence of componentFn's.
|
||||
return make([]componentFn, 0)
|
||||
}
|
||||
|
||||
switch s[0] {
|
||||
case '\\':
|
||||
// If the first character is a '\', the following character is a
|
||||
// part of an escape sequence, or it is unclosed.
|
||||
if len(s) < 2 {
|
||||
panic("wildmatch: unclosed escape sequence")
|
||||
}
|
||||
|
||||
literal := substring(string(s[1]))
|
||||
|
||||
var rest []componentFn
|
||||
if len(s) > 2 {
|
||||
// If there is more to follow, i.e., "\*foo", then parse
|
||||
// the remainder.
|
||||
rest = parseComponent(s[2:])
|
||||
}
|
||||
return cons(literal, rest)
|
||||
case '[':
|
||||
var (
|
||||
// i will denote the currently-inspected index of the character
|
||||
// group.
|
||||
i int = 1
|
||||
// include will denote the list of included runeFn's
|
||||
// composing the character group.
|
||||
include []runeFn
|
||||
// exclude will denote the list of excluded runeFn's
|
||||
// composing the character group.
|
||||
exclude []runeFn
|
||||
// run is the current run of strings (to either compose
|
||||
// a range, or select "any")
|
||||
run string
|
||||
// neg is whether we have seen a negation marker.
|
||||
neg bool
|
||||
)
|
||||
|
||||
for i < len(s) {
|
||||
if s[i] == '^' || s[i] == '!' {
|
||||
// Once a '^' or '!' character has been seen,
|
||||
// anything following it will be negated.
|
||||
neg = !neg
|
||||
i = i + 1
|
||||
} else if strings.HasPrefix(s[i:], "[:") {
|
||||
close := strings.Index(s[i:], ":]")
|
||||
if close < 0 {
|
||||
panic("unclosed character class")
|
||||
}
|
||||
|
||||
if close == 1 {
|
||||
// The case "[:]" has a prefix "[:", and
|
||||
// a suffix ":]", but the atom refers to
|
||||
// a character group including the
|
||||
// literal ":", not an ill-formed
|
||||
// character class.
|
||||
//
|
||||
// Parse it as such; increment one
|
||||
// _less_ than expected, to terminate
|
||||
// the group.
|
||||
run += "[:]"
|
||||
i = i + 2
|
||||
continue
|
||||
}
|
||||
|
||||
// Find the associated character class.
|
||||
name := strings.TrimPrefix(
|
||||
strings.ToLower(s[i:i+close]), "[:")
|
||||
fn, ok := classes[name]
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("wildmatch: unknown class: %q", name))
|
||||
}
|
||||
|
||||
include, exclude = appendMaybe(!neg, include, exclude, fn)
|
||||
// Advance to the first index beyond the closing
|
||||
// ":]".
|
||||
i = i + close + 2
|
||||
} else if s[i] == '-' {
|
||||
if i < len(s) {
|
||||
// If there is a range marker at the
|
||||
// non-final position, construct a range
|
||||
// and an optional "any" match:
|
||||
var start, end byte
|
||||
if len(run) > 0 {
|
||||
// If there is at least one
|
||||
// character in the run, use it
|
||||
// as the starting point of the
|
||||
// range, and remove it from the
|
||||
// run.
|
||||
start = run[len(run)-1]
|
||||
run = run[:len(run)-1]
|
||||
}
|
||||
end = s[i+1]
|
||||
|
||||
if len(run) > 0 {
|
||||
// If there is still information
|
||||
// in the run, construct a rune
|
||||
// function matching any
|
||||
// characters in the run.
|
||||
cfn := anyRune(run)
|
||||
|
||||
include, exclude = appendMaybe(!neg, include, exclude, cfn)
|
||||
run = ""
|
||||
}
|
||||
|
||||
// Finally, construct the rune range and
|
||||
// add it appropriately.
|
||||
bfn := between(rune(start), rune(end))
|
||||
include, exclude = appendMaybe(!neg,
|
||||
include, exclude, bfn)
|
||||
|
||||
i = i + 2
|
||||
} else {
|
||||
// If this is in the final position, add
|
||||
// it to the run and exit the loop.
|
||||
run = run + "-"
|
||||
i = i + 2
|
||||
}
|
||||
} else if s[i] == '\\' {
|
||||
// If we encounter an escape sequence in the
|
||||
// group, check its bounds and add it to the
|
||||
// run.
|
||||
if i+1 >= len(s) {
|
||||
panic("wildmatch: unclosed escape")
|
||||
}
|
||||
run = run + string(s[i+1])
|
||||
i = i + 2
|
||||
} else if s[i] == ']' {
|
||||
// If we encounter a closing ']', then stop
|
||||
// parsing the group.
|
||||
break
|
||||
} else {
|
||||
// Otherwise, add the character to the run and
|
||||
// advance forward.
|
||||
run = run + string(s[i])
|
||||
i = i + 1
|
||||
}
|
||||
}
|
||||
|
||||
if len(run) > 0 {
|
||||
fn := anyRune(run)
|
||||
include, exclude = appendMaybe(!neg, include, exclude, fn)
|
||||
}
|
||||
|
||||
var rest string
|
||||
if i+1 < len(s) {
|
||||
rest = s[i+1:]
|
||||
}
|
||||
// Assemble a character class, and cons it in front of the
|
||||
// remainder of the component pattern.
|
||||
return cons(charClass(include, exclude), parseComponent(rest))
|
||||
case '?':
|
||||
return []componentFn{wildcard(1, parseComponent(s[1:]))}
|
||||
case '*':
|
||||
return []componentFn{wildcard(-1, parseComponent(s[1:]))}
|
||||
default:
|
||||
// Advance forward until we encounter a special character
|
||||
// (either '*', '[', '*', or '?') and parse across the divider.
|
||||
var i int
|
||||
for ; i < len(s); i++ {
|
||||
if s[i] == '[' ||
|
||||
s[i] == '*' ||
|
||||
s[i] == '?' ||
|
||||
s[i] == '\\' {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return cons(substring(s[:i]), parseComponent(s[i:]))
|
||||
}
|
||||
}
|
||||
|
||||
// appendMaybe appends the value "x" to either "a" or "b" depending on "yes".
|
||||
func appendMaybe(yes bool, a, b []runeFn, x runeFn) (ax, bx []runeFn) {
|
||||
if yes {
|
||||
return append(a, x), b
|
||||
}
|
||||
return a, append(b, x)
|
||||
}
|
||||
|
||||
// cons prepends the "head" componentFn to the "tail" of componentFn's.
|
||||
func cons(head componentFn, tail []componentFn) []componentFn {
|
||||
return append([]componentFn{head}, tail...)
|
||||
}
|
||||
|
||||
// Consume implements token.Consume as above by applying the above set of
|
||||
// componentFn's in succession to the first element of the path tree.
|
||||
func (c *component) Consume(path []string, isDir bool) ([]string, bool) {
|
||||
if len(path) == 0 {
|
||||
return path, false
|
||||
}
|
||||
|
||||
head := path[0]
|
||||
for _, fn := range c.fns {
|
||||
var ok bool
|
||||
|
||||
// Apply successively the component functions to make progress
|
||||
// matching the head.
|
||||
if head, ok = fn.Apply(head); !ok {
|
||||
// If any of the functions failed to match, there are
|
||||
// no other paths to match success, so return a failure
|
||||
// immediately.
|
||||
return path, false
|
||||
}
|
||||
}
|
||||
|
||||
if len(head) > 0 {
|
||||
return append([]string{head}, path[1:]...), false
|
||||
}
|
||||
|
||||
if len(path) == 1 {
|
||||
// Components can not match directories. If we were matching the
|
||||
// last path in a tree structure, we can only match if it
|
||||
// _wasn't_ a directory.
|
||||
return path[1:], !isDir
|
||||
}
|
||||
|
||||
return path[1:], true
|
||||
}
|
||||
|
||||
// String implements token.String.
|
||||
func (c *component) String() string {
|
||||
var str string
|
||||
|
||||
for _, fn := range c.fns {
|
||||
str += fn.String()
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
// substring returns a componentFn that matches a prefix of "sub".
|
||||
func substring(sub string) componentFn {
|
||||
return &cfn{
|
||||
fn: func(s string) (rest string, ok bool) {
|
||||
if !strings.HasPrefix(s, sub) {
|
||||
return s, false
|
||||
}
|
||||
return s[len(sub):], true
|
||||
},
|
||||
str: sub,
|
||||
}
|
||||
}
|
||||
|
||||
// wildcard returns a componentFn that greedily matches until a set of other
|
||||
// component functions no longer matches.
|
||||
func wildcard(n int, fns []componentFn) componentFn {
|
||||
until := func(s string) (string, bool) {
|
||||
head := s
|
||||
for _, fn := range fns {
|
||||
var ok bool
|
||||
|
||||
if head, ok = fn.Apply(head); !ok {
|
||||
return s, false
|
||||
}
|
||||
}
|
||||
|
||||
if len(head) > 0 {
|
||||
return s, false
|
||||
}
|
||||
return "", true
|
||||
}
|
||||
|
||||
var str string = "*"
|
||||
for _, fn := range fns {
|
||||
str += fn.String()
|
||||
}
|
||||
|
||||
return &cfn{
|
||||
fn: func(s string) (rest string, ok bool) {
|
||||
if n > -1 {
|
||||
if n > len(s) {
|
||||
return "", false
|
||||
}
|
||||
return until(s[n:])
|
||||
}
|
||||
|
||||
for i := len(s); i > 0; i-- {
|
||||
rest, ok = until(s[i:])
|
||||
if ok {
|
||||
return rest, ok
|
||||
}
|
||||
}
|
||||
return until(s)
|
||||
},
|
||||
str: str,
|
||||
}
|
||||
}
|
||||
|
||||
// charClass returns a component function emulating a character class, i.e.,
|
||||
// that a single character can match if and only if it is included in one of the
|
||||
// includes (or true if there were no includes) and none of the excludes.
|
||||
func charClass(include, exclude []runeFn) componentFn {
|
||||
return &cfn{
|
||||
fn: func(s string) (rest string, ok bool) {
|
||||
if len(s) == 0 {
|
||||
return s, false
|
||||
}
|
||||
|
||||
// Find "r", the first rune in the string "s".
|
||||
r, l := utf8.DecodeRuneInString(s)
|
||||
|
||||
var match bool
|
||||
for _, ifn := range include {
|
||||
// Attempt to find a match on "r" with "ifn".
|
||||
if ifn(r) {
|
||||
match = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// If there wasn't a match and there were some including
|
||||
// patterns, return a failure to match. Otherwise, continue on
|
||||
// to make sure that no patterns exclude the rune "r".
|
||||
if !match && len(include) != 0 {
|
||||
return s, false
|
||||
}
|
||||
|
||||
for _, efn := range exclude {
|
||||
// Attempt to find a negative match on "r" with "efn".
|
||||
if efn(r) {
|
||||
return s, false
|
||||
}
|
||||
}
|
||||
|
||||
// If we progressed this far, return the remainder of the
|
||||
// string.
|
||||
return s[l:], true
|
||||
},
|
||||
str: "<charclass>",
|
||||
}
|
||||
}
|
||||
|
||||
// runeFn matches a single rune.
|
||||
type runeFn func(rune) bool
|
||||
|
||||
var (
|
||||
// classes is a mapping from character class name to a rune function
|
||||
// that implements its behavior.
|
||||
classes = map[string]runeFn{
|
||||
"alnum": func(r rune) bool {
|
||||
return unicode.In(r, unicode.Number, unicode.Letter)
|
||||
},
|
||||
"alpha": unicode.IsLetter,
|
||||
"blank": func(r rune) bool {
|
||||
return r == ' ' || r == '\t'
|
||||
},
|
||||
"cntrl": unicode.IsControl,
|
||||
"digit": unicode.IsDigit,
|
||||
"graph": unicode.IsGraphic,
|
||||
"lower": unicode.IsLower,
|
||||
"print": unicode.IsPrint,
|
||||
"punct": unicode.IsPunct,
|
||||
"space": unicode.IsSpace,
|
||||
"upper": unicode.IsUpper,
|
||||
"xdigit": func(r rune) bool {
|
||||
return unicode.IsDigit(r) ||
|
||||
('a' <= r && r <= 'f') ||
|
||||
('A' <= r && r <= 'F')
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// anyRune returns true so long as the rune "r" appears in the string "s".
|
||||
func anyRune(s string) runeFn {
|
||||
return func(r rune) bool {
|
||||
return strings.IndexRune(s, r) > -1
|
||||
}
|
||||
}
|
||||
|
||||
// between returns true so long as the rune "r" appears between "a" and "b".
|
||||
func between(a, b rune) runeFn {
|
||||
if b < a {
|
||||
a, b = b, a
|
||||
}
|
||||
|
||||
return func(r rune) bool {
|
||||
return a <= r && r <= b
|
||||
}
|
||||
}
|
7
vendor/github.com/git-lfs/wildmatch/wildmatch_linux.go
generated
vendored
Normal file
7
vendor/github.com/git-lfs/wildmatch/wildmatch_linux.go
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
// +build linux
|
||||
|
||||
package wildmatch
|
||||
|
||||
func init() {
|
||||
SystemCase = CaseFold
|
||||
}
|
7
vendor/github.com/git-lfs/wildmatch/wildmatch_notlinux.go
generated
vendored
Normal file
7
vendor/github.com/git-lfs/wildmatch/wildmatch_notlinux.go
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
// +build !linux
|
||||
|
||||
package wildmatch
|
||||
|
||||
func init() {
|
||||
SystemCase = func(w *Wildmatch) {}
|
||||
}
|
621
vendor/github.com/git-lfs/wildmatch/wildmatch_test.go
generated
vendored
Normal file
621
vendor/github.com/git-lfs/wildmatch/wildmatch_test.go
generated
vendored
Normal file
@ -0,0 +1,621 @@
|
||||
package wildmatch
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
type Case struct {
|
||||
Pattern string
|
||||
Subject string
|
||||
Match bool
|
||||
Opts []opt
|
||||
}
|
||||
|
||||
func (c *Case) Assert(t *testing.T) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
if c.Match {
|
||||
t.Errorf("could not parse: %s (%s)", c.Pattern, err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
p := NewWildmatch(c.Pattern, c.Opts...)
|
||||
if p.Match(c.Subject) != c.Match {
|
||||
if c.Match {
|
||||
t.Errorf("expected match: %s, %s", c.Pattern, c.Subject)
|
||||
} else {
|
||||
t.Errorf("unexpected match: %s, %s", c.Pattern, c.Subject)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var Cases = []*Case{
|
||||
{
|
||||
Pattern: `foo`,
|
||||
Subject: `foo`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `bar`,
|
||||
Subject: `foo`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `???`,
|
||||
Subject: `foo`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `??`,
|
||||
Subject: `foo`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `*`,
|
||||
Subject: `foo`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `f*`,
|
||||
Subject: `foo`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `*f`,
|
||||
Subject: `foo`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `*foo*`,
|
||||
Subject: `foo`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `*ob*a*r*`,
|
||||
Subject: `foobar`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `*ab`,
|
||||
Subject: `aaaaaaabababab`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `foo\*`,
|
||||
Subject: `foo*`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `foo\*bar`,
|
||||
Subject: `foobar`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `f\\oo`,
|
||||
Subject: `f\oo`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `*[al]?`,
|
||||
Subject: `ball`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[ten]`,
|
||||
Subject: `ten`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `**[!te]`,
|
||||
Subject: `ten`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `**[!ten]`,
|
||||
Subject: `ten`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `t[a-g]n`,
|
||||
Subject: `ten`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `t[!a-g]n`,
|
||||
Subject: `ten`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `t[!a-g]n`,
|
||||
Subject: `ton`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `t[^a-g]n`,
|
||||
Subject: `ton`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `]`,
|
||||
Subject: `]`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `foo*bar`,
|
||||
Subject: `foo/baz/bar`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `foo?bar`,
|
||||
Subject: `foo/bar`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `foo[/]bar`,
|
||||
Subject: `foo/bar`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `f[^eiu][^eiu][^eiu][^eiu][^eiu]r`,
|
||||
Subject: `foo/bar`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `f[^eiu][^eiu][^eiu][^eiu][^eiu]r`,
|
||||
Subject: `foo-bar`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `**/foo`,
|
||||
Subject: `foo`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `**/foo`,
|
||||
Subject: `/foo`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `**/foo`,
|
||||
Subject: `bar/baz/foo`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `*/foo`,
|
||||
Subject: `bar/baz/foo`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `**/bar*`,
|
||||
Subject: `foo/bar/baz`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `**/bar/*`,
|
||||
Subject: `deep/foo/bar/baz`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `**/bar/*`,
|
||||
Subject: `deep/foo/bar/baz/`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `**/bar/**`,
|
||||
Subject: `deep/foo/bar/baz/`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `**/bar/*`,
|
||||
Subject: `deep/foo/bar`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `**/bar/**`,
|
||||
Subject: `deep/foo/bar/`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `*/bar/**`,
|
||||
Subject: `foo/bar/baz/x`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `*/bar/**`,
|
||||
Subject: `deep/foo/bar/baz/x`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `**/bar/*/*`,
|
||||
Subject: `deep/foo/bar/baz/x`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `*.txt`,
|
||||
Subject: `foo/bar/baz.txt`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `foo*`,
|
||||
Subject: `foobar`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `*foo*`,
|
||||
Subject: `somethingfoobar`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `*foo`,
|
||||
Subject: `barfoo`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `a[c-c]st`,
|
||||
Subject: `acrt`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `a[c-c]rt`,
|
||||
Subject: `acrt`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `\`,
|
||||
Subject: `''`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `\`,
|
||||
Subject: `\`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `*/\`,
|
||||
Subject: `/\`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `foo`,
|
||||
Subject: `foo`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `@foo`,
|
||||
Subject: `@foo`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `@foo`,
|
||||
Subject: `foo`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `\[ab]`,
|
||||
Subject: `[ab]`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[[]ab]`,
|
||||
Subject: `[ab]`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[[:]ab]`,
|
||||
Subject: `[ab]`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[[::]ab]`,
|
||||
Subject: `[ab]`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `[[:digit]ab]`,
|
||||
Subject: `[ab]`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `[\[:]ab]`,
|
||||
Subject: `[ab]`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `\??\?b`,
|
||||
Subject: `?a?b`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `\a\b\c`,
|
||||
Subject: `abc`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `''`,
|
||||
Subject: `foo`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `**/t[o]`,
|
||||
Subject: `foo/bar/baz/to`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[[:alpha:]][[:digit:]][[:upper:]]`,
|
||||
Subject: `a1B`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[[:digit:][:upper:][:space:]]`,
|
||||
Subject: `a`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `[[:digit:][:upper:][:space:]]`,
|
||||
Subject: `A`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[[:digit:][:upper:][:space:]]`,
|
||||
Subject: `1`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[[:digit:][:upper:][:spaci:]]`,
|
||||
Subject: `1`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `'`,
|
||||
Subject: `'`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[[:digit:][:upper:][:space:]]`,
|
||||
Subject: `.`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `[[:digit:][:punct:][:space:]]`,
|
||||
Subject: `.`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[[:xdigit:]]`,
|
||||
Subject: `5`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[[:xdigit:]]`,
|
||||
Subject: `f`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[[:xdigit:]]`,
|
||||
Subject: `D`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]`,
|
||||
Subject: `_`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[^[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]]`,
|
||||
Subject: `.`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[a-c[:digit:]x-z]`,
|
||||
Subject: `5`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[a-c[:digit:]x-z]`,
|
||||
Subject: `b`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[a-c[:digit:]x-z]`,
|
||||
Subject: `y`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[a-c[:digit:]x-z]`,
|
||||
Subject: `q`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `[\\-^]`,
|
||||
Subject: `]`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[\\-^]`,
|
||||
Subject: `[`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `a[]b`,
|
||||
Subject: `ab`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `a[]b`,
|
||||
Subject: `a[]b`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `[!`,
|
||||
Subject: `ab`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `[-`,
|
||||
Subject: `ab`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `[-]`,
|
||||
Subject: `-`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[a-`,
|
||||
Subject: `-`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `[!a-`,
|
||||
Subject: `-`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `'`,
|
||||
Subject: `'`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `'[`,
|
||||
Subject: `0`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `[---]`,
|
||||
Subject: `-`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[------]`,
|
||||
Subject: `-`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[!------]`,
|
||||
Subject: `a`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[a^bc]`,
|
||||
Subject: `^`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[\]`,
|
||||
Subject: `\`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `[\\]`,
|
||||
Subject: `\`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[!\\]`,
|
||||
Subject: `\`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `[A-\\]`,
|
||||
Subject: `G`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `b*a`,
|
||||
Subject: `aaabbb`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `*ba*`,
|
||||
Subject: `aabcaa`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `[,]`,
|
||||
Subject: `,`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[\\,]`,
|
||||
Subject: `,`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[\\,]`,
|
||||
Subject: `\`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[,-.]`,
|
||||
Subject: `-`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[,-.]`,
|
||||
Subject: `+`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `[,-.]`,
|
||||
Subject: `-.]`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `[\1-\3]`,
|
||||
Subject: `2`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `[\1-\3]`,
|
||||
Subject: `3`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `-*-*-*-*-*-*-12-*-*-*-m-*-*-*`,
|
||||
Subject: `-adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `-*-*-*-*-*-*-12-*-*-*-m-*-*-*`,
|
||||
Subject: `-adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `-*-*-*-*-*-*-12-*-*-*-m-*-*-*`,
|
||||
Subject: `-adobe-courier-bold-o-normal--12-120-75-75-/-70-iso8859-1`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `**/*a*b*g*n*t`,
|
||||
Subject: `abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txt`,
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `**/*a*b*g*n*t`,
|
||||
Subject: `abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txtz`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `foo`,
|
||||
Subject: `FOO`,
|
||||
Match: false,
|
||||
},
|
||||
{
|
||||
Pattern: `foo`,
|
||||
Subject: `FOO`,
|
||||
Opts: []opt{CaseFold},
|
||||
Match: true,
|
||||
},
|
||||
{
|
||||
Pattern: `**/a*.txt`,
|
||||
Subject: `foo-a.txt`,
|
||||
Match: false,
|
||||
},
|
||||
}
|
||||
|
||||
func TestWildmatch(t *testing.T) {
|
||||
for _, c := range Cases {
|
||||
c.Assert(t)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user