Usability improvements for reference package
Various improvements motivated by early real-world use in engine code under development: - Make `WithDigest` return `Canonical`, since the return value always has a name and a digest. - Introduce a `NamedTagged` type, which can be used for strongly typing cases where something must have a name and a tag. - Rename `ParseNamed` to `WithName`, and create a `ParseNamed` that accepts tags and digests (returning a `Named` type). The new `ParseNamed` makes code using the reference package much less verbose, since typical use cases require a name, and this is an additional type assertion and error case after every `Parse` call. Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>master
							parent
							
								
									4c4112bdcf
								
							
						
					
					
						commit
						16eea0cc47
					
				|  | @ -114,6 +114,12 @@ type Tagged interface { | ||||||
| 	Tag() string | 	Tag() string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // NamedTagged is an object including a name and tag.
 | ||||||
|  | type NamedTagged interface { | ||||||
|  | 	Named | ||||||
|  | 	Tag() string | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // Digested is an object which has a digest
 | // Digested is an object which has a digest
 | ||||||
| // in which it can be referenced by
 | // in which it can be referenced by
 | ||||||
| type Digested interface { | type Digested interface { | ||||||
|  | @ -178,10 +184,26 @@ func Parse(s string) (Reference, error) { | ||||||
| 	return r, nil | 	return r, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // ParseNamed parses the input string and returns a named
 | // ParseNamed parses s and returns a syntactically valid reference implementing
 | ||||||
| // object representing the given string. If the input is
 | // the Named interface. The reference must have a name, otherwise an error is
 | ||||||
| // invalid ErrReferenceInvalidFormat will be returned.
 | // returned.
 | ||||||
| func ParseNamed(name string) (Named, error) { | // If an error was encountered it is returned, along with a nil Reference.
 | ||||||
|  | // NOTE: ParseNamed will not handle short digests.
 | ||||||
|  | func ParseNamed(s string) (Named, error) { | ||||||
|  | 	ref, err := Parse(s) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	named, isNamed := ref.(Named) | ||||||
|  | 	if !isNamed { | ||||||
|  | 		return nil, fmt.Errorf("reference %s has no name", ref.String()) | ||||||
|  | 	} | ||||||
|  | 	return named, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // WithName returns a named object representing the given string. If the input
 | ||||||
|  | // is invalid ErrReferenceInvalidFormat will be returned.
 | ||||||
|  | func WithName(name string) (Named, error) { | ||||||
| 	if !anchoredNameRegexp.MatchString(name) { | 	if !anchoredNameRegexp.MatchString(name) { | ||||||
| 		return nil, ErrReferenceInvalidFormat | 		return nil, ErrReferenceInvalidFormat | ||||||
| 	} | 	} | ||||||
|  | @ -190,7 +212,7 @@ func ParseNamed(name string) (Named, error) { | ||||||
| 
 | 
 | ||||||
| // WithTag combines the name from "name" and the tag from "tag" to form a
 | // WithTag combines the name from "name" and the tag from "tag" to form a
 | ||||||
| // reference incorporating both the name and the tag.
 | // reference incorporating both the name and the tag.
 | ||||||
| func WithTag(name Named, tag string) (Tagged, error) { | func WithTag(name Named, tag string) (NamedTagged, error) { | ||||||
| 	if !anchoredNameRegexp.MatchString(tag) { | 	if !anchoredNameRegexp.MatchString(tag) { | ||||||
| 		return nil, ErrTagInvalidFormat | 		return nil, ErrTagInvalidFormat | ||||||
| 	} | 	} | ||||||
|  | @ -202,7 +224,7 @@ func WithTag(name Named, tag string) (Tagged, error) { | ||||||
| 
 | 
 | ||||||
| // WithDigest combines the name from "name" and the digest from "digest" to form
 | // WithDigest combines the name from "name" and the digest from "digest" to form
 | ||||||
| // a reference incorporating both the name and the digest.
 | // a reference incorporating both the name and the digest.
 | ||||||
| func WithDigest(name Named, digest digest.Digest) (Digested, error) { | func WithDigest(name Named, digest digest.Digest) (Canonical, error) { | ||||||
| 	if !anchoredDigestRegexp.MatchString(digest.String()) { | 	if !anchoredDigestRegexp.MatchString(digest.String()) { | ||||||
| 		return nil, ErrDigestInvalidFormat | 		return nil, ErrDigestInvalidFormat | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -253,7 +253,7 @@ func TestSplitHostname(t *testing.T) { | ||||||
| 			t.Fail() | 			t.Fail() | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		named, err := ParseNamed(testcase.input) | 		named, err := WithName(testcase.input) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			failf("error parsing name: %s", err) | 			failf("error parsing name: %s", err) | ||||||
| 		} | 		} | ||||||
|  | @ -424,7 +424,7 @@ func TestWithTag(t *testing.T) { | ||||||
| 			t.Fail() | 			t.Fail() | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		named, err := ParseNamed(testcase.name) | 		named, err := WithName(testcase.name) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			failf("error parsing name: %s", err) | 			failf("error parsing name: %s", err) | ||||||
| 		} | 		} | ||||||
|  | @ -466,7 +466,7 @@ func TestWithDigest(t *testing.T) { | ||||||
| 			t.Fail() | 			t.Fail() | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		named, err := ParseNamed(testcase.name) | 		named, err := WithName(testcase.name) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			failf("error parsing name: %s", err) | 			failf("error parsing name: %s", err) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue