Add WithTag and WithDigest combinator functions
These functions allow a Named type to be combined with a tag or a digest. WithTag will replace the ImageReference function in github.com/docker/docker/utils as the Docker Engine transitions to the reference package. Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>master
							parent
							
								
									3943c4165c
								
							
						
					
					
						commit
						b07d759241
					
				|  | @ -43,6 +43,12 @@ var ( | |||
| 	// ErrReferenceInvalidFormat represents an error while trying to parse a string as a reference.
 | ||||
| 	ErrReferenceInvalidFormat = errors.New("invalid reference format") | ||||
| 
 | ||||
| 	// ErrTagInvalidFormat represents an error while trying to parse a string as a tag.
 | ||||
| 	ErrTagInvalidFormat = errors.New("invalid tag format") | ||||
| 
 | ||||
| 	// ErrDigestInvalidFormat represents an error while trying to parse a string as a tag.
 | ||||
| 	ErrDigestInvalidFormat = errors.New("invalid digest format") | ||||
| 
 | ||||
| 	// ErrNameEmpty is returned for empty, invalid repository names.
 | ||||
| 	ErrNameEmpty = errors.New("repository name must have at least one component") | ||||
| 
 | ||||
|  | @ -182,6 +188,30 @@ func ParseNamed(name string) (Named, error) { | |||
| 	return repository(name), nil | ||||
| } | ||||
| 
 | ||||
| // WithTag combines the name from "name" and the tag from "tag" to form a
 | ||||
| // reference incorporating both the name and the tag.
 | ||||
| func WithTag(name Named, tag string) (Tagged, error) { | ||||
| 	if !anchoredNameRegexp.MatchString(tag) { | ||||
| 		return nil, ErrTagInvalidFormat | ||||
| 	} | ||||
| 	return taggedReference{ | ||||
| 		name: name.Name(), | ||||
| 		tag:  tag, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| // WithDigest combines the name from "name" and the digest from "digest" to form
 | ||||
| // a reference incorporating both the name and the digest.
 | ||||
| func WithDigest(name Named, digest digest.Digest) (Digested, error) { | ||||
| 	if !anchoredDigestRegexp.MatchString(digest.String()) { | ||||
| 		return nil, ErrDigestInvalidFormat | ||||
| 	} | ||||
| 	return canonicalReference{ | ||||
| 		name:   name.Name(), | ||||
| 		digest: digest, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func getBestReferenceType(ref reference) Reference { | ||||
| 	if ref.name == "" { | ||||
| 		// Allow digest only references
 | ||||
|  |  | |||
|  | @ -395,3 +395,87 @@ func TestSerialization(t *testing.T) { | |||
| 
 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestWithTag(t *testing.T) { | ||||
| 	testcases := []struct { | ||||
| 		name     string | ||||
| 		tag      string | ||||
| 		combined string | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name:     "test.com/foo", | ||||
| 			tag:      "tag", | ||||
| 			combined: "test.com/foo:tag", | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:     "foo", | ||||
| 			tag:      "tag2", | ||||
| 			combined: "foo:tag2", | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:     "test.com:8000/foo", | ||||
| 			tag:      "tag4", | ||||
| 			combined: "test.com:8000/foo:tag4", | ||||
| 		}, | ||||
| 	} | ||||
| 	for _, testcase := range testcases { | ||||
| 		failf := func(format string, v ...interface{}) { | ||||
| 			t.Logf(strconv.Quote(testcase.name)+": "+format, v...) | ||||
| 			t.Fail() | ||||
| 		} | ||||
| 
 | ||||
| 		named, err := ParseNamed(testcase.name) | ||||
| 		if err != nil { | ||||
| 			failf("error parsing name: %s", err) | ||||
| 		} | ||||
| 		tagged, err := WithTag(named, testcase.tag) | ||||
| 		if err != nil { | ||||
| 			failf("WithTag failed: %s", err) | ||||
| 		} | ||||
| 		if tagged.String() != testcase.combined { | ||||
| 			failf("unexpected: got %q, expected %q", tagged.String(), testcase.combined) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestWithDigest(t *testing.T) { | ||||
| 	testcases := []struct { | ||||
| 		name     string | ||||
| 		digest   digest.Digest | ||||
| 		combined string | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name:     "test.com/foo", | ||||
| 			digest:   "sha256:1234567890098765432112345667890098765", | ||||
| 			combined: "test.com/foo@sha256:1234567890098765432112345667890098765", | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:     "foo", | ||||
| 			digest:   "sha256:1234567890098765432112345667890098765", | ||||
| 			combined: "foo@sha256:1234567890098765432112345667890098765", | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:     "test.com:8000/foo", | ||||
| 			digest:   "sha256:1234567890098765432112345667890098765", | ||||
| 			combined: "test.com:8000/foo@sha256:1234567890098765432112345667890098765", | ||||
| 		}, | ||||
| 	} | ||||
| 	for _, testcase := range testcases { | ||||
| 		failf := func(format string, v ...interface{}) { | ||||
| 			t.Logf(strconv.Quote(testcase.name)+": "+format, v...) | ||||
| 			t.Fail() | ||||
| 		} | ||||
| 
 | ||||
| 		named, err := ParseNamed(testcase.name) | ||||
| 		if err != nil { | ||||
| 			failf("error parsing name: %s", err) | ||||
| 		} | ||||
| 		digested, err := WithDigest(named, testcase.digest) | ||||
| 		if err != nil { | ||||
| 			failf("WithDigest failed: %s", err) | ||||
| 		} | ||||
| 		if digested.String() != testcase.combined { | ||||
| 			failf("unexpected: got %q, expected %q", digested.String(), testcase.combined) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -28,6 +28,13 @@ var ( | |||
| 	// end of the matched string.
 | ||||
| 	anchoredTagRegexp = regexp.MustCompile(`^` + TagRegexp.String() + `$`) | ||||
| 
 | ||||
| 	// DigestRegexp matches valid digests.
 | ||||
| 	DigestRegexp = regexp.MustCompile(`[A-Za-z][A-Za-z0-9]*(?:[-_+.][A-Za-z][A-Za-z0-9]*)*[:][[:xdigit:]]{32,}`) | ||||
| 
 | ||||
| 	// anchoredDigestRegexp matches valid digests, anchored at the start and
 | ||||
| 	// end of the matched string.
 | ||||
| 	anchoredDigestRegexp = regexp.MustCompile(`^` + DigestRegexp.String() + `$`) | ||||
| 
 | ||||
| 	// NameRegexp is the format for the name component of references. The
 | ||||
| 	// regexp has capturing groups for the hostname and name part omitting
 | ||||
| 	// the seperating forward slash from either.
 | ||||
|  | @ -35,7 +42,7 @@ var ( | |||
| 
 | ||||
| 	// ReferenceRegexp is the full supported format of a reference. The
 | ||||
| 	// regexp has capturing groups for name, tag, and digest components.
 | ||||
| 	ReferenceRegexp = regexp.MustCompile(`^((?:` + hostnameRegexp.String() + `/)?` + nameRegexp.String() + `)(?:[:](` + TagRegexp.String() + `))?(?:[@]([A-Za-z][A-Za-z0-9]*(?:[-_+.][A-Za-z][A-Za-z0-9]*)*[:][[:xdigit:]]{32,}))?$`) | ||||
| 	ReferenceRegexp = regexp.MustCompile(`^((?:` + hostnameRegexp.String() + `/)?` + nameRegexp.String() + `)(?:[:](` + TagRegexp.String() + `))?(?:[@](` + DigestRegexp.String() + `))?$`) | ||||
| 
 | ||||
| 	// anchoredNameRegexp is used to parse a name value, capturing hostname
 | ||||
| 	anchoredNameRegexp = regexp.MustCompile(`^(?:(` + hostnameRegexp.String() + `)/)?(` + nameRegexp.String() + `)$`) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue