Bump wildmatch to v2.0.1

Now that we have a fully Git-compatible wildmatch, let's use it in Git
LFS.  Vendor the module appropriately.
This commit is contained in:
brian m. carlson 2021-08-23 15:52:52 +00:00
parent 56abb7122a
commit 7cc4bce5e4
No known key found for this signature in database
GPG Key ID: 2D0C9BC12F82B3A1
14 changed files with 169 additions and 20 deletions

@ -4,7 +4,7 @@ import (
"path/filepath"
"strings"
"github.com/git-lfs/wildmatch"
"github.com/git-lfs/wildmatch/v2"
"github.com/rubyist/tracerx"
)

@ -8,7 +8,7 @@ import (
"strings"
"github.com/git-lfs/git-lfs/v2/errors"
"github.com/git-lfs/wildmatch"
"github.com/git-lfs/wildmatch/v2"
)
const attrPrefix = "[attr]"

@ -6,7 +6,7 @@ import (
"testing"
"github.com/git-lfs/gitobj/v2"
"github.com/git-lfs/wildmatch"
"github.com/git-lfs/wildmatch/v2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

2
go.mod

@ -8,7 +8,7 @@ require (
github.com/git-lfs/gitobj/v2 v2.0.2
github.com/git-lfs/go-netrc v0.0.0-20180525200031-e0e9ca483a18
github.com/git-lfs/pktline v0.0.0-20210330133718-06e9096e2825
github.com/git-lfs/wildmatch v1.0.4
github.com/git-lfs/wildmatch/v2 v2.0.1
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/mattn/go-isatty v0.0.4
github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0

6
go.sum

@ -7,16 +7,14 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dpotapov/go-spnego v0.0.0-20210315154721-298b63a54430 h1:oempk9HjNt6rVKyKmpdnoN7XABQv3SXLWu3pxUI7Vlk=
github.com/dpotapov/go-spnego v0.0.0-20210315154721-298b63a54430/go.mod h1:AVSs/gZKt1bOd2AhkhbS7Qh56Hv7klde22yXVbwYJhc=
github.com/git-lfs/gitobj/v2 v2.0.1 h1:mUGOWP+fU36rs7TY7a5Lol9FuockOBjPFUW/lwOM7Mo=
github.com/git-lfs/gitobj/v2 v2.0.1/go.mod h1:q6aqxl6Uu3gWsip5GEKpw+7459F97er8COmU45ncAxw=
github.com/git-lfs/gitobj/v2 v2.0.2 h1:p8rWlhEyiSsC+4Qc+EdufySatf8sDtvJIrHAHgf7Ar8=
github.com/git-lfs/gitobj/v2 v2.0.2/go.mod h1:q6aqxl6Uu3gWsip5GEKpw+7459F97er8COmU45ncAxw=
github.com/git-lfs/go-netrc v0.0.0-20180525200031-e0e9ca483a18 h1:7Th0eBA4rT8WJNiM1vppjaIv9W5WJinhpbCJvRJxloI=
github.com/git-lfs/go-netrc v0.0.0-20180525200031-e0e9ca483a18/go.mod h1:70O4NAtvWn1jW8V8V+OKrJJYcxDLTmIozfi2fmSz5SI=
github.com/git-lfs/pktline v0.0.0-20210330133718-06e9096e2825 h1:riQhgheTL7tMF4d5raz9t3+IzoR1i1wqxE1kZC6dY+U=
github.com/git-lfs/pktline v0.0.0-20210330133718-06e9096e2825/go.mod h1:fenKRzpXDjNpsIBhuhUzvjCKlDjKam0boRAenTE0Q6A=
github.com/git-lfs/wildmatch v1.0.4 h1:Mj6LPnNZ6QSHLAAPDCH596pu6A/Z1xVm2Vk0+s3CtkY=
github.com/git-lfs/wildmatch v1.0.4/go.mod h1:SdHAGnApDpnFYQ0vAxbniWR0sn7yLJ3QXo9RRfhn2ew=
github.com/git-lfs/wildmatch/v2 v2.0.1 h1:Ds+aobrV5bK0wStILUOn9irllPyf9qrFETbKzwzoER8=
github.com/git-lfs/wildmatch/v2 v2.0.1/go.mod h1:EVqonpk9mXbREP3N8UkwoWdrF249uHpCUo5CPXY81gw=
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=

4
vendor/github.com/git-lfs/wildmatch/v2/SECURITY.md generated vendored Normal file

@ -0,0 +1,4 @@
Please see
[SECURITY.md](https://github.com/git-lfs/git-lfs/blob/master/SECURITY.md)
in the main Git LFS repository for information on how to report security
vulnerabilities in this package.

3
vendor/github.com/git-lfs/wildmatch/v2/go.mod generated vendored Normal file

@ -0,0 +1,3 @@
module github.com/git-lfs/wildmatch/v2
go 1.15

@ -28,6 +28,19 @@ var (
w.caseFold = true
}
// GitAttributes augments the functionality of the matching algorithm
// to match behavior of git when working with .gitattributes files.
GitAttributes opt = func(w *Wildmatch) {
w.gitattributes = true
}
// Contents indicates that if a pattern matches a directory that is a
// parent of a path, then that path is included. This is the behavior
// of patterns for .gitignore.
Contents opt = func(w *Wildmatch) {
w.contents = 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.
@ -55,6 +68,20 @@ type Wildmatch struct {
// caseFold allows the instance Wildmatch to match patterns with the
// same character but different case structures.
caseFold bool
// gitattributes flag indicates that logic specific to the .gitattributes file
// should be used. The two main differences are that negative expressions are
// not allowed and directories are not matched.
gitattributes bool
// contents indicates that if a pattern matches a directory that is a
// parent of a path, then that path is included. This is the behavior
// of patterns for .gitignore.
contents bool
}
type MatchOpts struct {
IsDirectory bool
}
// NewWildmatch constructs a new Wildmatch instance which matches filepaths
@ -78,7 +105,7 @@ func NewWildmatch(p string, opts ...opt) *Wildmatch {
if len(parts) > 1 {
w.basename = false
}
w.ts = parseTokens(parts)
w.ts = w.parseTokens(parts)
return w
}
@ -126,16 +153,62 @@ func escapable(c byte) bool {
// 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 {
func (w *Wildmatch) parseTokens(dirs []string) []token {
if len(dirs) == 0 {
return make([]token, 0)
}
var finalComponents []token
if !w.gitattributes {
trailingIsEmpty := len(dirs) > 1 && dirs[len(dirs)-1] == ""
numNonEmptyDirs := len(dirs)
if trailingIsEmpty {
numNonEmptyDirs -= 1
}
if w.contents {
finalComponents = []token{&trailingComponents{}}
if trailingIsEmpty {
// Strip off the trailing empty string.
dirs = dirs[:numNonEmptyDirs]
}
}
// If we have one component, ignoring trailing empty
// components and we know that a directory is permissible…
if numNonEmptyDirs == 1 && (trailingIsEmpty || w.contents) {
// We don't have a slash in the middle, so this can go
// anywhere in the hierarchy. If there had been a slash
// here, it would have been anchored at the root.
rest := w.parseTokensSimple(dirs)
tokens := append([]token{&unanchoredDirectory{
Until: rest[0],
}})
// If we're not matching all contents, then do include
// the empty component so we don't match
// non-directories.
if finalComponents == nil && len(rest) > 1 {
finalComponents = rest[1:]
}
return append(tokens, finalComponents...)
}
}
components := w.parseTokensSimple(dirs)
return append(components, finalComponents...)
}
func (w *Wildmatch) parseTokensSimple(dirs []string) []token {
if len(dirs) == 0 {
return make([]token, 0)
}
switch dirs[0] {
case "":
return parseTokens(dirs[1:])
if len(dirs) == 1 {
return []token{&component{fns: []componentFn{substring("")}}}
}
return w.parseTokensSimple(dirs[1:])
case "**":
rest := parseTokens(dirs[1:])
rest := w.parseTokensSimple(dirs[1:])
if len(rest) == 0 {
// If there are no remaining tokens, return a lone
// doubleStar token.
@ -155,7 +228,7 @@ func parseTokens(dirs []string) []token {
// continue on.
return append([]token{&component{
fns: parseComponent(dirs[0]),
}}, parseTokens(dirs[1:])...)
}}, w.parseTokensSimple(dirs[1:])...)
}
}
@ -172,7 +245,15 @@ func nonEmpty(all []string) (ne []string) {
// 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)
dirs, ok := w.consume(t, MatchOpts{})
if !ok {
return false
}
return len(dirs) == 0
}
func (w *Wildmatch) MatchWithOpts(t string, opt MatchOpts) bool {
dirs, ok := w.consume(t, opt)
if !ok {
return false
}
@ -182,7 +263,7 @@ func (w *Wildmatch) Match(t string) bool {
// 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) {
func (w *Wildmatch) consume(t string, opt MatchOpts) ([]string, bool) {
if w.basename {
// If the receiving Wildmatch has basename set, the pattern
// matches only the basename of the given "t".
@ -197,8 +278,24 @@ func (w *Wildmatch) consume(t string) ([]string, bool) {
t = strings.ToLower(t)
}
var isDir bool
if opt.IsDirectory {
isDir = true
// Standardize the formation of subject string so directories always
// end with '/'
if !strings.HasSuffix(t, "/") {
t = t + "/"
}
} else {
isDir = strings.HasSuffix(t, string(sep))
}
dirs := strings.Split(t, string(sep))
isDir := strings.HasSuffix(t, string(sep))
// Git-attribute style matching can never match a directory
if w.gitattributes && isDir {
return dirs, false
}
// Match each directory token-wise, allowing each token to consume more
// than one directory in the case of the '**' pattern.
@ -213,6 +310,11 @@ func (w *Wildmatch) consume(t string) ([]string, bool) {
return dirs, false
}
}
// If this is a directory that we've otherwise matched and all we have
// left is an empty path component, then this is a match.
if isDir && len(dirs) == 1 && len(dirs[0]) == 0 {
return nil, true
}
return dirs, true
}
@ -255,11 +357,16 @@ type token interface {
// 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
Until token
EmptyPath bool
}
// Consume implements token.Consume as above.
func (d *doubleStar) Consume(path []string, isDir bool) ([]string, bool) {
if len(path) == 0 {
return path, d.EmptyPath
}
// If there are no remaining tokens to match, allow matching the entire
// path.
if d.Until == nil {
@ -286,6 +393,43 @@ func (d *doubleStar) String() string {
return fmt.Sprintf("**/%s", d.Until.String())
}
// unanchoredDirectory is an implementation of the Token interface which
// greedily matches one-or-more path components until a successor token.
type unanchoredDirectory struct {
Until token
}
// Consume implements token.Consume as above.
func (d *unanchoredDirectory) Consume(path []string, isDir bool) ([]string, bool) {
// This matches the same way as a doubleStar, so just use that
// implementation.
s := &doubleStar{Until: d.Until}
return s.Consume(path, isDir)
}
// String implements Component.String.
func (d *unanchoredDirectory) String() string {
return fmt.Sprintf("%s/", d.Until.String())
}
// trailingComponents is an implementation of the Token interface which
// greedily matches any trailing components, even if empty.
type trailingComponents struct {
}
// Consume implements token.Consume as above.
func (d *trailingComponents) Consume(path []string, isDir bool) ([]string, bool) {
// This matches the same way as a doubleStar, so just use that
// implementation.
s := &doubleStar{Until: nil, EmptyPath: true}
return s.Consume(path, isDir)
}
// String implements Component.String.
func (d *trailingComponents) String() string {
return ""
}
// 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.
@ -540,7 +684,7 @@ func (c *component) Consume(path []string, isDir bool) ([]string, bool) {
// 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
}
return path[1:], true

4
vendor/modules.txt vendored

@ -17,8 +17,8 @@ github.com/git-lfs/gitobj/v2/storage
github.com/git-lfs/go-netrc/netrc
# github.com/git-lfs/pktline v0.0.0-20210330133718-06e9096e2825
github.com/git-lfs/pktline
# github.com/git-lfs/wildmatch v1.0.4
github.com/git-lfs/wildmatch
# github.com/git-lfs/wildmatch/v2 v2.0.1
github.com/git-lfs/wildmatch/v2
# github.com/hashicorp/go-uuid v1.0.2
github.com/hashicorp/go-uuid
# github.com/inconshreveable/mousetrap v1.0.0