Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate github.com/docker/docker/pkg/fileutils and remove docker dependency from main go.mod #105

Closed
wants to merge 47 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
cf85e14
Move Matches() file path matching function into pkg/fileutils
rafecolton Sep 30, 2014
6997122
Use logrus everywhere for logging
LK4D4 Oct 24, 2014
3f34172
Merge pull request #9345 from jfrazelle/bump_v1.4.0
Dec 12, 2014
c40acfb
Merge pull request #9623 from jfrazelle/merge_release_v1.4.0
tiborvass Dec 12, 2014
adf480f
Replace aliased imports of logrus, fixes #11762
Mar 26, 2015
729de31
Refactor ultis/utils_daemon, fixes #11908
Mar 29, 2015
0a27ce5
Refactor utils/utils, fixes #11923
Mar 29, 2015
efa3920
add support for exclusion rules in dockerignore
buddhamagnet Apr 9, 2015
12de81b
Add coverage on pkg/fileutils
vdemeester Apr 29, 2015
45ebe6e
Allow .dockerignore to ignore everything
May 30, 2015
c1c4092
linting changes
unclejack Jun 16, 2015
bcd8472
Merge pull request #13961 from unclejack/linting_changes
calavera Jun 16, 2015
b1e4b70
Fix copy from a "created" container. Fixes #14420
coolljt0725 Jul 8, 2015
0ef7a97
Add missing tests and docs for pkg/fileutils
vdemeester Jul 12, 2015
7a793b5
Windows: Fix warning on info
Sep 18, 2015
5874684
Merge pull request #16407 from Microsoft/10662-fixinfoprocerror
Sep 18, 2015
0fc3ada
Support multi-dir wildcards in .dockerignore
Oct 14, 2015
a2acf9a
Fix typos found across repository
jutaz Dec 13, 2015
35f2440
Merge pull request #18623 from jutaz/bugfix/typos
runcom Dec 13, 2015
84a541e
Windows CI: Fixes panic in test-unit for FileUtils
Feb 12, 2016
78e8dc8
Windows CI: Turn off failing unit test pkg\fileutils
Mar 3, 2016
357fbde
fix typos
allencloud May 3, 2016
ab6836d
fix typos
allencloud Jul 21, 2016
92cb27b
all: use strings.Contains instead Index
lelenanam Oct 13, 2016
94abe55
Fix use of **/ in .dockerignore
Dec 1, 2016
05da6ee
Fix inefficient file paths filter
tonistiigi Mar 8, 2017
3590d84
pkg/file{utils,notify}: don't compare to bool
unclejack Mar 30, 2017
e1cdf57
Enable a unit test on windows.
dnephin Apr 21, 2017
32ab3cb
Update logrus to v1.0.1
dmcgowan Jul 26, 2017
ddcb242
Add goimports to linters.
dnephin Aug 21, 2017
cd692c7
Add canonical import comment
dnephin Feb 5, 2018
aeae3e8
Automated migration using
dnephin Mar 13, 2018
6b3b3d2
Fix typos
skyc024 May 16, 2018
bf06bf6
Update tests to use gotest.tools 👼
vdemeester Jun 11, 2018
31861b4
Merge pull request #37243 from vdemeester/gotestyourself-with-tools
Jun 13, 2018
84a1066
Remove duplicated words in pkg files
mooncak Oct 5, 2018
e2f6f7e
gosec: add ignore comments for reported issues that can be ignored
thaJeztah Aug 28, 2019
a3c9386
Merge pull request #39668 from thaJeztah/replace_gometalinter
yongtang Sep 18, 2019
e67d934
bump gotest.tools v3.0.1 for compatibility with Go 1.14
thaJeztah Feb 7, 2020
0303540
pkg/fileutils: TestMatches: remove cases no longer valid for go1.16
thaJeztah May 17, 2021
b340094
pkg/fileutils: PatternMatcher.Matches(): remove debug logging
thaJeztah Jun 9, 2021
35f6224
Migrate github.com/docker/docker/pkg/fileutils
thaJeztah Jun 9, 2021
a8a9249
filematch: update package name
thaJeztah Jun 9, 2021
85eadbf
filematch: remove utilities we don't use
thaJeztah Jun 9, 2021
cab31cd
replace github.com/docker/docker/pkg/fileutils with filematch
thaJeztah Jun 9, 2021
eaffca0
bench: make separate module
thaJeztah Jun 9, 2021
82bb6d3
filematch: remove use of gotest.tools
thaJeztah Jun 9, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions bench/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module github.com/tonistiigi/fsutil/bench

go 1.13

require (
github.com/Microsoft/hcsshim v0.8.17 // indirect
github.com/containerd/containerd v1.5.2 // indirect
github.com/containerd/continuity v0.1.0
github.com/docker/docker v20.10.7+incompatible
github.com/moby/sys/mount v0.2.0 // indirect
github.com/pkg/errors v0.9.1
github.com/tonistiigi/fsutil v0.0.0-00010101000000-000000000000
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
)

replace github.com/tonistiigi/fsutil => ../
932 changes: 932 additions & 0 deletions bench/go.sum

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions copy/copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import (
"time"

"github.com/containerd/continuity/fs"
"github.com/docker/docker/pkg/fileutils"
"github.com/pkg/errors"
"github.com/tonistiigi/fsutil/filematch"
)

var bufferPool = &sync.Pool{
Expand Down Expand Up @@ -224,8 +224,8 @@ type copier struct {
mode *int
inodes map[uint64]string
xattrErrorHandler XAttrErrorHandler
includePatternMatcher *fileutils.PatternMatcher
excludePatternMatcher *fileutils.PatternMatcher
includePatternMatcher *filematch.PatternMatcher
excludePatternMatcher *filematch.PatternMatcher
parentDirs []parentDir
}

Expand All @@ -242,19 +242,19 @@ func newCopier(chown Chowner, tm *time.Time, mode *int, xeh XAttrErrorHandler, i
}
}

var includePatternMatcher *fileutils.PatternMatcher
var includePatternMatcher *filematch.PatternMatcher
if len(includePatterns) != 0 {
var err error
includePatternMatcher, err = fileutils.NewPatternMatcher(includePatterns)
includePatternMatcher, err = filematch.NewPatternMatcher(includePatterns)
if err != nil {
return nil, errors.Wrapf(err, "invalid includepatterns: %s", includePatterns)
}
}

var excludePatternMatcher *fileutils.PatternMatcher
var excludePatternMatcher *filematch.PatternMatcher
if len(excludePatterns) != 0 {
var err error
excludePatternMatcher, err = fileutils.NewPatternMatcher(excludePatterns)
excludePatternMatcher, err = filematch.NewPatternMatcher(excludePatterns)
if err != nil {
return nil, errors.Wrapf(err, "invalid excludepatterns: %s", excludePatterns)
}
Expand Down
224 changes: 224 additions & 0 deletions filematch/patternmatcher.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
package filematch

import (
"errors"
"os"
"path/filepath"
"regexp"
"strings"
"text/scanner"
)

// PatternMatcher allows checking paths against a list of patterns
type PatternMatcher struct {
patterns []*Pattern
exclusions bool
}

// NewPatternMatcher creates a new matcher object for specific patterns that can
// be used later to match against patterns against paths
func NewPatternMatcher(patterns []string) (*PatternMatcher, error) {
pm := &PatternMatcher{
patterns: make([]*Pattern, 0, len(patterns)),
}
for _, p := range patterns {
// Eliminate leading and trailing whitespace.
p = strings.TrimSpace(p)
if p == "" {
continue
}
p = filepath.Clean(p)
newp := &Pattern{}
if p[0] == '!' {
if len(p) == 1 {
return nil, errors.New("illegal exclusion pattern: \"!\"")
}
newp.exclusion = true
p = p[1:]
pm.exclusions = true
}
// Do some syntax checking on the pattern.
// filepath's Match() has some really weird rules that are inconsistent
// so instead of trying to dup their logic, just call Match() for its
// error state and if there is an error in the pattern return it.
// If this becomes an issue we can remove this since its really only
// needed in the error (syntax) case - which isn't really critical.
if _, err := filepath.Match(p, "."); err != nil {
return nil, err
}
newp.cleanedPattern = p
newp.dirs = strings.Split(p, string(os.PathSeparator))
pm.patterns = append(pm.patterns, newp)
}
return pm, nil
}

// Matches matches path against all the patterns. Matches is not safe to be
// called concurrently
func (pm *PatternMatcher) Matches(file string) (bool, error) {
matched := false
file = filepath.FromSlash(file)
parentPath := filepath.Dir(file)
parentPathDirs := strings.Split(parentPath, string(os.PathSeparator))

for _, pattern := range pm.patterns {
negative := false

if pattern.exclusion {
negative = true
}

match, err := pattern.match(file)
if err != nil {
return false, err
}

if !match && parentPath != "." {
// Check to see if the pattern matches one of our parent dirs.
if len(pattern.dirs) <= len(parentPathDirs) {
match, _ = pattern.match(strings.Join(parentPathDirs[:len(pattern.dirs)], string(os.PathSeparator)))
}
}

if match {
matched = !negative
}
}

return matched, nil
}

// Exclusions returns true if any of the patterns define exclusions
func (pm *PatternMatcher) Exclusions() bool {
return pm.exclusions
}

// Patterns returns array of active patterns
func (pm *PatternMatcher) Patterns() []*Pattern {
return pm.patterns
}

// Pattern defines a single regexp used to filter file paths.
type Pattern struct {
cleanedPattern string
dirs []string
regexp *regexp.Regexp
exclusion bool
}

func (p *Pattern) String() string {
return p.cleanedPattern
}

// Exclusion returns true if this pattern defines exclusion
func (p *Pattern) Exclusion() bool {
return p.exclusion
}

func (p *Pattern) match(path string) (bool, error) {

if p.regexp == nil {
if err := p.compile(); err != nil {
return false, filepath.ErrBadPattern
}
}

b := p.regexp.MatchString(path)

return b, nil
}

func (p *Pattern) compile() error {
regStr := "^"
pattern := p.cleanedPattern
// Go through the pattern and convert it to a regexp.
// We use a scanner so we can support utf-8 chars.
var scan scanner.Scanner
scan.Init(strings.NewReader(pattern))

sl := string(os.PathSeparator)
escSL := sl
if sl == `\` {
escSL += `\`
}

for scan.Peek() != scanner.EOF {
ch := scan.Next()

if ch == '*' {
if scan.Peek() == '*' {
// is some flavor of "**"
scan.Next()

// Treat **/ as ** so eat the "/"
if string(scan.Peek()) == sl {
scan.Next()
}

if scan.Peek() == scanner.EOF {
// is "**EOF" - to align with .gitignore just accept all
regStr += ".*"
} else {
// is "**"
// Note that this allows for any # of /'s (even 0) because
// the .* will eat everything, even /'s
regStr += "(.*" + escSL + ")?"
}
} else {
// is "*" so map it to anything but "/"
regStr += "[^" + escSL + "]*"
}
} else if ch == '?' {
// "?" is any char except "/"
regStr += "[^" + escSL + "]"
} else if ch == '.' || ch == '$' {
// Escape some regexp special chars that have no meaning
// in golang's filepath.Match
regStr += `\` + string(ch)
} else if ch == '\\' {
// escape next char. Note that a trailing \ in the pattern
// will be left alone (but need to escape it)
if sl == `\` {
// On windows map "\" to "\\", meaning an escaped backslash,
// and then just continue because filepath.Match on
// Windows doesn't allow escaping at all
regStr += escSL
continue
}
if scan.Peek() != scanner.EOF {
regStr += `\` + string(scan.Next())
} else {
regStr += `\`
}
} else {
regStr += string(ch)
}
}

regStr += "$"

re, err := regexp.Compile(regStr)
if err != nil {
return err
}

p.regexp = re
return nil
}

// Matches returns true if file matches any of the patterns
// and isn't excluded by any of the subsequent patterns.
func Matches(file string, patterns []string) (bool, error) {
pm, err := NewPatternMatcher(patterns)
if err != nil {
return false, err
}
file = filepath.Clean(file)

if file == "." {
// Don't let them exclude everything, kind of silly.
return false, nil
}

return pm.Matches(file)
}
Loading