Skip to content

Commit

Permalink
Merge pull request #107 from aaronlehmann/use-updated-matches-methods
Browse files Browse the repository at this point in the history
Use updated PatternMatcher Matches methods for pattern matching
  • Loading branch information
aaronlehmann authored Aug 18, 2021
2 parents d72af97 + 8f9ded1 commit 4442383
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 38 deletions.
2 changes: 1 addition & 1 deletion bench/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyG
github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v20.10.3-0.20210609071616-4c2ec79bf2a8+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v20.10.3-0.20210817025855-ba2adeebdb8d+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v20.10.7+incompatible h1:Z6O9Nhsjv+ayUEeI1IojKbYcsGdgYSNqxe1s2MYzUhQ=
github.com/docker/docker v20.10.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
Expand Down
79 changes: 50 additions & 29 deletions copy/copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,7 @@ func Copy(ctx context.Context, srcRoot, src, dstRoot, dst string, opts ...Opt) e
if err != nil {
return err
}
skipIncludePatterns := c.includePatternMatcher == nil
if err := c.copy(ctx, srcFollowed, "", dst, false, skipIncludePatterns); err != nil {
if err := c.copy(ctx, srcFollowed, "", dst, false, false, false); err != nil {
return err
}
}
Expand Down Expand Up @@ -272,7 +271,7 @@ func newCopier(chown Chowner, tm *time.Time, mode *int, xeh XAttrErrorHandler, i
}

// dest is always clean
func (c *copier) copy(ctx context.Context, src, srcComponents, target string, overwriteTargetMetadata, skipIncludePatterns bool) error {
func (c *copier) copy(ctx context.Context, src, srcComponents, target string, overwriteTargetMetadata, parentMatchedInclude, parentMatchedExclude bool) error {
select {
case <-ctx.Done():
return ctx.Err()
Expand All @@ -285,18 +284,20 @@ func (c *copier) copy(ctx context.Context, src, srcComponents, target string, ov
}

include := true
matchesIncludePattern := false
matchesExcludePattern := false
if srcComponents != "" {
if !skipIncludePatterns {
include, err = c.include(srcComponents, fi)
if err != nil {
return err
}
matchesIncludePattern, err = c.include(srcComponents, fi, parentMatchedInclude)
if err != nil {
return err
}
exclude, err := c.exclude(srcComponents, fi)
include = matchesIncludePattern

matchesExcludePattern, err = c.exclude(srcComponents, fi, parentMatchedExclude)
if err != nil {
return err
}
if exclude {
if matchesExcludePattern {
include = false
}
}
Expand All @@ -321,9 +322,12 @@ func (c *copier) copy(ctx context.Context, src, srcComponents, target string, ov

switch {
case fi.IsDir():
if created, err := c.copyDirectory(ctx, src, srcComponents, target, fi, overwriteTargetMetadata, skipIncludePatterns, include); err != nil {
if created, err := c.copyDirectory(
ctx, src, srcComponents, target, fi, overwriteTargetMetadata,
include, matchesIncludePattern, matchesExcludePattern,
); err != nil {
return err
} else if !overwriteTargetMetadata || !skipIncludePatterns {
} else if !overwriteTargetMetadata || c.includePatternMatcher != nil {
copyFileInfo = created
}
case (fi.Mode() & os.ModeType) == 0:
Expand Down Expand Up @@ -367,24 +371,24 @@ func (c *copier) copy(ctx context.Context, src, srcComponents, target string, ov
return nil
}

func (c *copier) include(path string, fi os.FileInfo) (bool, error) {
func (c *copier) include(path string, fi os.FileInfo, parentMatchedInclude bool) (bool, error) {
if c.includePatternMatcher == nil {
return false, nil
return true, nil
}

m, err := c.includePatternMatcher.Matches(path)
m, err := c.includePatternMatcher.MatchesUsingParentResult(path, parentMatchedInclude)
if err != nil {
return false, errors.Wrap(err, "failed to match includepatterns")
}
return m, nil
}

func (c *copier) exclude(path string, fi os.FileInfo) (bool, error) {
func (c *copier) exclude(path string, fi os.FileInfo, parentMatchedExclude bool) (bool, error) {
if c.excludePatternMatcher == nil {
return false, nil
}

m, err := c.excludePatternMatcher.Matches(path)
m, err := c.excludePatternMatcher.MatchesUsingParentResult(path, parentMatchedExclude)
if err != nil {
return false, errors.Wrap(err, "failed to match excludepatterns")
}
Expand Down Expand Up @@ -426,30 +430,42 @@ func (c *copier) createParentDirs(src, srcComponents, target string, overwriteTa
return nil
}

func (c *copier) copyDirectory(ctx context.Context, src, srcComponents, dst string, stat os.FileInfo, overwriteTargetMetadata, skipIncludePatterns, matchedExactly bool) (bool, error) {
func (c *copier) copyDirectory(
ctx context.Context,
src string,
srcComponents string,
dst string,
stat os.FileInfo,
overwriteTargetMetadata bool,
include bool,
matchesIncludePattern bool,
matchesExcludePattern bool,
) (bool, error) {
if !stat.IsDir() {
return false, errors.Errorf("source is not directory")
}

created := false

// If there are no include patterns or this directory matched an include
// pattern exactly, go ahead and create the directory. Otherwise, delay to
// handle include patterns like a/*/c where we do not want to create a/b
// until we encounter a/b/c.
if matchedExactly || skipIncludePatterns {
parentDir := parentDir{
srcPath: src,
dstPath: dst,
}

// If this directory passed include/exclude matching directly, go ahead
// and create the directory. Otherwise, delay to handle include
// patterns like a/*/c where we do not want to create a/b until we
// encounter a/b/c.
if include {
var err error
created, err = copyDirectoryOnly(src, dst, stat, overwriteTargetMetadata)
if err != nil {
return created, err
}
parentDir.copied = true
}

c.parentDirs = append(c.parentDirs, parentDir{
srcPath: src,
dstPath: dst,
copied: skipIncludePatterns,
})
c.parentDirs = append(c.parentDirs, parentDir)

defer func() {
c.parentDirs = c.parentDirs[:len(c.parentDirs)-1]
Expand All @@ -461,7 +477,12 @@ func (c *copier) copyDirectory(ctx context.Context, src, srcComponents, dst stri
}

for _, fi := range fis {
if err := c.copy(ctx, filepath.Join(src, fi.Name()), filepath.Join(srcComponents, fi.Name()), filepath.Join(dst, fi.Name()), true, skipIncludePatterns); err != nil {
if err := c.copy(
ctx,
filepath.Join(src, fi.Name()), filepath.Join(srcComponents, fi.Name()),
filepath.Join(dst, fi.Name()),
true, matchesIncludePattern, matchesExcludePattern,
); err != nil {
return false, err
}
}
Expand Down
14 changes: 12 additions & 2 deletions copy/copy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,16 @@ func TestCopyIncludeExclude(t *testing.T) {
opts: []Opt{WithIncludePattern("**/foo3")},
expectedResults: []string{"bar", "bar/baz", "bar/baz/foo3"},
},
{
name: "doublestar matching second item in path",
opts: []Opt{WithIncludePattern("**/baz")},
expectedResults: []string{"bar", "bar/baz", "bar/baz/foo3"},
},
{
name: "doublestar matching first item in path",
opts: []Opt{WithIncludePattern("**/bar")},
expectedResults: []string{"bar", "bar/foo", "bar/baz", "bar/baz/foo3"},
},
{
name: "doublestar exclude",
opts: []Opt{WithIncludePattern("bar"), WithExcludePattern("**/foo3")},
Expand All @@ -461,10 +471,10 @@ func TestCopyIncludeExclude(t *testing.T) {
defer os.RemoveAll(t2)

err = Copy(context.Background(), t1, "/", t2, "/", tc.opts...)
require.NoError(t, err)
require.NoError(t, err, tc.name)

var results []string
for _, path := range []string{"bar", "bar/foo", "bar/baz", "bar/baz/foo3", "foo2"} {
for _, path := range []string{"bar", "bar/foo", "bar/baz", "bar/baz/asdf", "bar/baz/asdf/x", "bar/baz/foo3", "foo2"} {
_, err := os.Stat(filepath.Join(t2, path))
if err == nil {
results = append(results, path)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.13

require (
github.com/containerd/continuity v0.1.0
github.com/docker/docker v20.10.3-0.20210609071616-4c2ec79bf2a8+incompatible // master (v21.xx-dev)
github.com/docker/docker v20.10.3-0.20210817025855-ba2adeebdb8d+incompatible // master (v21.xx-dev)
github.com/gogo/protobuf v1.3.2
github.com/golang/protobuf v1.4.3 // indirect
github.com/google/go-cmp v0.5.2 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ 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/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/docker/docker v20.10.3-0.20210609071616-4c2ec79bf2a8+incompatible h1:vDUpBEVNJURujPYAl6dHaG0UDLJ7vl7m8/ZZOjAP3gg=
github.com/docker/docker v20.10.3-0.20210609071616-4c2ec79bf2a8+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v20.10.3-0.20210817025855-ba2adeebdb8d+incompatible h1:tSd7TeZCH0j9m4P14bfe/eO1KYawrt3DztHI8gZAmLM=
github.com/docker/docker v20.10.3-0.20210817025855-ba2adeebdb8d+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
Expand Down
31 changes: 28 additions & 3 deletions walker.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,12 @@ func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) err
}
}

var lastIncludedDir string
var (
lastIncludedDir string

parentDirs []string // used only for exclude handling
parentMatchedExclude []bool
)

seenFiles := make(map[uint64]string)
return filepath.Walk(root, func(path string, fi os.FileInfo, err error) (retErr error) {
Expand Down Expand Up @@ -118,17 +123,37 @@ func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) err
}
}
if pm != nil {
m, err := pm.Matches(path)
for len(parentMatchedExclude) != 0 {
lastParentDir := parentDirs[len(parentDirs)-1]
if strings.HasPrefix(path, lastParentDir) {
break
}
parentDirs = parentDirs[:len(parentDirs)-1]
parentMatchedExclude = parentMatchedExclude[:len(parentMatchedExclude)-1]
}

var m bool
if len(parentMatchedExclude) != 0 {
m, err = pm.MatchesUsingParentResult(path, parentMatchedExclude[len(parentMatchedExclude)-1])
} else {
m, err = pm.MatchesOrParentMatches(path)
}
if err != nil {
return errors.Wrap(err, "failed to match excludepatterns")
}

var dirSlash string
if fi.IsDir() {
dirSlash = path + string(filepath.Separator)
parentDirs = append(parentDirs, dirSlash)
parentMatchedExclude = append(parentMatchedExclude, m)
}

if m {
if fi.IsDir() {
if !pm.Exclusions() {
return filepath.SkipDir
}
dirSlash := path + string(filepath.Separator)
for _, pat := range pm.Patterns() {
if !pat.Exclusion() {
continue
Expand Down

0 comments on commit 4442383

Please sign in to comment.