diff --git a/reference/reference.go b/reference/reference.go index 8f30f6b01..66294cd37 100644 --- a/reference/reference.go +++ b/reference/reference.go @@ -24,6 +24,7 @@ package reference import ( "errors" "fmt" + "path" "strings" "github.com/docker/distribution/digest" @@ -250,6 +251,16 @@ func WithDigest(name Named, digest digest.Digest) (Canonical, error) { }, nil } +// Match reports whether ref matches the specified pattern. +// See https://godoc.org/path#Match for supported patterns. +func Match(pattern string, ref Reference) (bool, error) { + matched, err := path.Match(pattern, ref.String()) + if namedRef, isNamed := ref.(Named); isNamed && !matched { + matched, _ = path.Match(pattern, namedRef.Name()) + } + return matched, err +} + func getBestReferenceType(ref reference) Reference { if ref.name == "" { // Allow digest only references diff --git a/reference/reference_test.go b/reference/reference_test.go index be27a3628..405c47c05 100644 --- a/reference/reference_test.go +++ b/reference/reference_test.go @@ -581,3 +581,81 @@ func TestWithDigest(t *testing.T) { } } } + +func TestMatchError(t *testing.T) { + named, err := Parse("foo") + if err != nil { + t.Fatal(err) + } + _, err = Match("[-x]", named) + if err == nil { + t.Fatalf("expected an error, got nothing") + } +} + +func TestMatch(t *testing.T) { + matchCases := []struct { + reference string + pattern string + expected bool + }{ + { + reference: "foo", + pattern: "foo/**/ba[rz]", + expected: false, + }, + { + reference: "foo/any/bat", + pattern: "foo/**/ba[rz]", + expected: false, + }, + { + reference: "foo/a/bar", + pattern: "foo/**/ba[rz]", + expected: true, + }, + { + reference: "foo/b/baz", + pattern: "foo/**/ba[rz]", + expected: true, + }, + { + reference: "foo/c/baz:tag", + pattern: "foo/**/ba[rz]", + expected: true, + }, + { + reference: "foo/c/baz:tag", + pattern: "foo/*/baz:tag", + expected: true, + }, + { + reference: "foo/c/baz:tag", + pattern: "foo/c/baz:tag", + expected: true, + }, + { + reference: "example.com/foo/c/baz:tag", + pattern: "*/foo/c/baz", + expected: true, + }, + { + reference: "example.com/foo/c/baz:tag", + pattern: "example.com/foo/c/baz", + expected: true, + }, + } + for _, c := range matchCases { + named, err := Parse(c.reference) + if err != nil { + t.Fatal(err) + } + actual, err := Match(c.pattern, named) + if err != nil { + t.Fatal(err) + } + if actual != c.expected { + t.Fatalf("expected %s match %s to be %v, was %v", c.reference, c.pattern, c.expected, actual) + } + } +}