Merge pull request #4301 from bk2204/strict-filepathfilter

Fix pattern matching for .gitattributes
This commit is contained in:
brian m. carlson 2020-11-16 15:29:54 +00:00 committed by GitHub
commit f529c87d5e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 97 additions and 34 deletions

@ -128,46 +128,71 @@ const (
sep byte = '/'
)
func NewPattern(p string) Pattern {
pp := p
type patternOptions struct {
strict bool
}
// Special case: the below patterns match anything according to existing
// behavior.
switch pp {
case `*`, `.`, `./`, `.\`:
pp = join("**", "*")
type patternOption func(*patternOptions)
// Strict is an option representing whether to strictly match wildmatch patterns
// the way Git does. If disabled, additional modifications are made to patterns
// for backwards compatibility.
func Strict(val bool) patternOption {
return func(args *patternOptions) {
args.strict = val
}
}
func NewPattern(p string, setters ...patternOption) Pattern {
args := &patternOptions{strict: false}
for _, setter := range setters {
setter(args)
}
dirs := strings.Contains(pp, string(sep))
rooted := strings.HasPrefix(pp, string(sep))
wild := strings.Contains(pp, "*")
pp := p
if !dirs && !wild {
// Special case: if pp is a literal string (optionally including
// a character class), rewrite it is a substring match.
pp = join("**", pp, "**")
} else {
if dirs && !rooted {
// Special case: if there are any directory separators,
// rewrite "pp" as a substring match.
if !wild {
pp = join("**", pp, "**")
}
dirs := strings.Contains(pp, string(sep))
if !args.strict {
// Special case: the below patterns match anything according to existing
// behavior.
switch pp {
case `*`, `.`, `./`, `.\`:
pp = join("**", "*")
}
dirs = strings.Contains(pp, string(sep))
rooted := strings.HasPrefix(pp, string(sep))
wild := strings.Contains(pp, "*")
if !dirs && !wild {
// Special case: if pp is a literal string (optionally including
// a character class), rewrite it is a substring match.
pp = join("**", pp, "**")
} else {
if rooted {
// Special case: if there are not any directory
// separators, rewrite "pp" as a substring
// match.
pp = join(pp, "**")
if dirs && !rooted {
// Special case: if there are any directory separators,
// rewrite "pp" as a substring match.
if !wild {
pp = join("**", pp, "**")
}
} else {
// Special case: if there are not any directory
// separators, rewrite "pp" as a substring
// match.
pp = join("**", pp)
if rooted {
// Special case: if there are not any directory
// separators, rewrite "pp" as a substring
// match.
pp = join(pp, "**")
} else {
// Special case: if there are not any directory
// separators, rewrite "pp" as a substring
// match.
pp = join("**", pp)
}
}
}
}
tracerx.Printf("filepathfilter: rewrite %q as %q", p, pp)
tracerx.Printf("filepathfilter: rewrite %q as %q (strict: %v)", p, pp, args.strict)
return &wm{
p: p,
@ -195,10 +220,10 @@ func join(paths ...string) string {
return joined
}
func convertToWildmatch(rawpatterns []string) []Pattern {
func convertToWildmatch(rawpatterns []string, setters ...patternOption) []Pattern {
patterns := make([]Pattern, len(rawpatterns))
for i, raw := range rawpatterns {
patterns[i] = NewPattern(raw)
patterns[i] = NewPattern(raw, setters...)
}
return patterns
}

@ -159,7 +159,7 @@ func GetAttributeFilter(workingDir, gitDir string) *filepathfilter.Filter {
for _, path := range paths {
// Convert all separators to `/` before creating a pattern to
// avoid characters being escaped in situations like `subtree\*.md`
patterns = append(patterns, filepathfilter.NewPattern(filepath.ToSlash(path.Path)))
patterns = append(patterns, filepathfilter.NewPattern(filepath.ToSlash(path.Path), filepathfilter.Strict(true)))
}
return filepathfilter.NewFromPatterns(patterns, nil)

@ -225,3 +225,41 @@ begin_test "migrate import --no-rewrite (with empty commit message)"
fi
)
end_test
begin_test "migrate import --no-rewrite (strict .gitattributes)"
(
set -e
reponame="$(basename "$0" ".sh")-strict-match"
clone_repo "$reponame" repo-strict-match
mkdir -p major-oak/mainst/.yarn-offline-mirror/
mkdir -p major-oak/major-oak/frontend/.yarn-offline-mirror/
foo_contents="foo"
foo_oid=$(calc_oid "$foo_contents")
bar_contents="bar"
bar_oid=$(calc_oid "$bar_contents")
printf "$foo_contents" > major-oak/mainst/.yarn-offline-mirror/typescript-3.4.3.tgz
printf "$bar_contents" > major-oak/major-oak/frontend/.yarn-offline-mirror/typescript-2.9.2.tgz
git add .
git commit -m 'Initial import'
cat >.gitattributes <<EOF
major-oak/mainst/.yarn-offline-mirror/typescript-3.4.3.tgz filter=lfs diff=lfs merge=lfs -text
major-oak/major-oak/frontend/.yarn-offline-mirror/typescript-2.9.2.tgz filter=lfs diff=lfs merge=lfs -text
EOF
git add .
git commit -m '.gitattributes'
git lfs migrate import --yes --no-rewrite \
major-oak/mainst/.yarn-offline-mirror/typescript-3.4.3.tgz \
major-oak/major-oak/frontend/.yarn-offline-mirror/typescript-2.9.2.tgz
assert_pointer "refs/heads/main" "major-oak/mainst/.yarn-offline-mirror/typescript-3.4.3.tgz" "$foo_oid" "3"
assert_pointer "refs/heads/main" "major-oak/major-oak/frontend/.yarn-offline-mirror/typescript-2.9.2.tgz" "$bar_oid" "3"
assert_local_object "$foo_oid" "3"
assert_local_object "$bar_oid" "3"
)
end_test