summaryrefslogtreecommitdiff
path: root/reference
diff options
context:
space:
mode:
authorDerek McGowan <derek@mcgstyle.net>2017-01-25 16:54:18 -0800
committerDerek McGowan <derek@mcgstyle.net>2017-02-07 11:08:37 -0800
commit3a1279393faf78632bf169619d407e584da84b66 (patch)
tree25d89487c1dcfc045a0dc8bfa72dd2cf31d28489 /reference
parent2bea87393b7673fc88531851803f073198527021 (diff)
downloaddocker-3a1279393faf78632bf169619d407e584da84b66.tar.gz
Use distribution reference
Remove forked reference package. Use normalized named values everywhere and familiar functions to convert back to familiar strings for UX and storage compatibility. Enforce that the source repository in the distribution metadata is always a normalized string, ignore invalid values which are not. Update distribution tests to use normalized values. Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
Diffstat (limited to 'reference')
-rw-r--r--reference/reference.go194
-rw-r--r--reference/reference_test.go275
-rw-r--r--reference/store.go117
-rw-r--r--reference/store_test.go31
4 files changed, 87 insertions, 530 deletions
diff --git a/reference/reference.go b/reference/reference.go
deleted file mode 100644
index e6e070cb8c..0000000000
--- a/reference/reference.go
+++ /dev/null
@@ -1,194 +0,0 @@
-package reference
-
-import (
- "fmt"
-
- distreference "github.com/docker/distribution/reference"
- "github.com/docker/docker/pkg/stringid"
- "github.com/opencontainers/go-digest"
- "github.com/pkg/errors"
-)
-
-const (
- // DefaultTag defines the default tag used when performing images related actions and no tag or digest is specified
- DefaultTag = "latest"
- // DefaultHostname is the default built-in hostname
- DefaultHostname = "docker.io"
- // LegacyDefaultHostname is automatically converted to DefaultHostname
- LegacyDefaultHostname = "index.docker.io"
- // DefaultRepoPrefix is the prefix used for default repositories in default host
- DefaultRepoPrefix = "library/"
-)
-
-// Named is an object with a full name
-type Named interface {
- // Name returns normalized repository name, like "ubuntu".
- Name() string
- // String returns full reference, like "ubuntu@sha256:abcdef..."
- String() string
- // FullName returns full repository name with hostname, like "docker.io/library/ubuntu"
- FullName() string
- // Hostname returns hostname for the reference, like "docker.io"
- Hostname() string
- // RemoteName returns the repository component of the full name, like "library/ubuntu"
- RemoteName() string
-}
-
-// NamedTagged is an object including a name and tag.
-type NamedTagged interface {
- Named
- Tag() string
-}
-
-// Canonical reference is an object with a fully unique
-// name including a name with hostname and digest
-type Canonical interface {
- Named
- Digest() digest.Digest
-}
-
-// ParseNamed parses s and returns a syntactically valid reference implementing
-// the Named interface. The reference must have a name, otherwise an error is
-// returned.
-// If an error was encountered it is returned, along with a nil Reference.
-func ParseNamed(s string) (Named, error) {
- named, err := distreference.ParseNormalizedNamed(s)
- if err != nil {
- return nil, errors.Wrapf(err, "failed to parse reference %q", s)
- }
- if err := validateName(distreference.FamiliarName(named)); err != nil {
- return nil, err
- }
-
- // Ensure returned reference cannot have tag and digest
- if canonical, isCanonical := named.(distreference.Canonical); isCanonical {
- r, err := distreference.WithDigest(distreference.TrimNamed(named), canonical.Digest())
- if err != nil {
- return nil, err
- }
- return &canonicalRef{namedRef{r}}, nil
- }
- if tagged, isTagged := named.(distreference.NamedTagged); isTagged {
- r, err := distreference.WithTag(distreference.TrimNamed(named), tagged.Tag())
- if err != nil {
- return nil, err
- }
- return &taggedRef{namedRef{r}}, nil
- }
-
- return &namedRef{named}, nil
-}
-
-// TrimNamed removes any tag or digest from the named reference
-func TrimNamed(ref Named) Named {
- return &namedRef{distreference.TrimNamed(ref)}
-}
-
-// WithName returns a named object representing the given string. If the input
-// is invalid ErrReferenceInvalidFormat will be returned.
-func WithName(name string) (Named, error) {
- r, err := distreference.ParseNormalizedNamed(name)
- if err != nil {
- return nil, err
- }
- if err := validateName(distreference.FamiliarName(r)); err != nil {
- return nil, err
- }
- if !distreference.IsNameOnly(r) {
- return nil, distreference.ErrReferenceInvalidFormat
- }
- return &namedRef{r}, 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) (NamedTagged, error) {
- r, err := distreference.WithTag(name, tag)
- if err != nil {
- return nil, err
- }
- return &taggedRef{namedRef{r}}, 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) (Canonical, error) {
- r, err := distreference.WithDigest(name, digest)
- if err != nil {
- return nil, err
- }
- return &canonicalRef{namedRef{r}}, nil
-}
-
-type namedRef struct {
- distreference.Named
-}
-type taggedRef struct {
- namedRef
-}
-type canonicalRef struct {
- namedRef
-}
-
-func (r *namedRef) Name() string {
- return distreference.FamiliarName(r.Named)
-}
-
-func (r *namedRef) String() string {
- return distreference.FamiliarString(r.Named)
-}
-
-func (r *namedRef) FullName() string {
- return r.Named.Name()
-}
-func (r *namedRef) Hostname() string {
- return distreference.Domain(r.Named)
-}
-func (r *namedRef) RemoteName() string {
- return distreference.Path(r.Named)
-}
-func (r *taggedRef) Tag() string {
- return r.namedRef.Named.(distreference.NamedTagged).Tag()
-}
-func (r *canonicalRef) Digest() digest.Digest {
- return r.namedRef.Named.(distreference.Canonical).Digest()
-}
-
-// WithDefaultTag adds a default tag to a reference if it only has a repo name.
-func WithDefaultTag(ref Named) Named {
- if IsNameOnly(ref) {
- ref, _ = WithTag(ref, DefaultTag)
- }
- return ref
-}
-
-// IsNameOnly returns true if reference only contains a repo name.
-func IsNameOnly(ref Named) bool {
- if _, ok := ref.(NamedTagged); ok {
- return false
- }
- if _, ok := ref.(Canonical); ok {
- return false
- }
- return true
-}
-
-// ParseIDOrReference parses string for an image ID or a reference. ID can be
-// without a default prefix.
-func ParseIDOrReference(idOrRef string) (digest.Digest, Named, error) {
- if err := stringid.ValidateID(idOrRef); err == nil {
- idOrRef = "sha256:" + idOrRef
- }
- if dgst, err := digest.Parse(idOrRef); err == nil {
- return dgst, nil, nil
- }
- ref, err := ParseNamed(idOrRef)
- return "", ref, err
-}
-
-func validateName(name string) error {
- if err := stringid.ValidateID(name); err == nil {
- return fmt.Errorf("Invalid repository name (%s), cannot specify 64-byte hexadecimal strings", name)
- }
- return nil
-}
diff --git a/reference/reference_test.go b/reference/reference_test.go
deleted file mode 100644
index 481a2dd97b..0000000000
--- a/reference/reference_test.go
+++ /dev/null
@@ -1,275 +0,0 @@
-package reference
-
-import (
- "testing"
-
- "github.com/opencontainers/go-digest"
-)
-
-func TestValidateReferenceName(t *testing.T) {
- validRepoNames := []string{
- "docker/docker",
- "library/debian",
- "debian",
- "docker.io/docker/docker",
- "docker.io/library/debian",
- "docker.io/debian",
- "index.docker.io/docker/docker",
- "index.docker.io/library/debian",
- "index.docker.io/debian",
- "127.0.0.1:5000/docker/docker",
- "127.0.0.1:5000/library/debian",
- "127.0.0.1:5000/debian",
- "thisisthesongthatneverendsitgoesonandonandonthisisthesongthatnev",
- }
- invalidRepoNames := []string{
- "https://github.com/docker/docker",
- "docker/Docker",
- "-docker",
- "-docker/docker",
- "-docker.io/docker/docker",
- "docker///docker",
- "docker.io/docker/Docker",
- "docker.io/docker///docker",
- "1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a",
- "docker.io/1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a",
- }
-
- for _, name := range invalidRepoNames {
- _, err := ParseNamed(name)
- if err == nil {
- t.Fatalf("Expected invalid repo name for %q", name)
- }
- }
-
- for _, name := range validRepoNames {
- _, err := ParseNamed(name)
- if err != nil {
- t.Fatalf("Error parsing repo name %s, got: %q", name, err)
- }
- }
-}
-
-func TestValidateRemoteName(t *testing.T) {
- validRepositoryNames := []string{
- // Sanity check.
- "docker/docker",
-
- // Allow 64-character non-hexadecimal names (hexadecimal names are forbidden).
- "thisisthesongthatneverendsitgoesonandonandonthisisthesongthatnev",
-
- // Allow embedded hyphens.
- "docker-rules/docker",
-
- // Allow multiple hyphens as well.
- "docker---rules/docker",
-
- //Username doc and image name docker being tested.
- "doc/docker",
-
- // single character names are now allowed.
- "d/docker",
- "jess/t",
-
- // Consecutive underscores.
- "dock__er/docker",
- }
- for _, repositoryName := range validRepositoryNames {
- _, err := ParseNamed(repositoryName)
- if err != nil {
- t.Errorf("Repository name should be valid: %v. Error: %v", repositoryName, err)
- }
- }
-
- invalidRepositoryNames := []string{
- // Disallow capital letters.
- "docker/Docker",
-
- // Only allow one slash.
- "docker///docker",
-
- // Disallow 64-character hexadecimal.
- "1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a",
-
- // Disallow leading and trailing hyphens in namespace.
- "-docker/docker",
- "docker-/docker",
- "-docker-/docker",
-
- // Don't allow underscores everywhere (as opposed to hyphens).
- "____/____",
-
- "_docker/_docker",
-
- // Disallow consecutive periods.
- "dock..er/docker",
- "dock_.er/docker",
- "dock-.er/docker",
-
- // No repository.
- "docker/",
-
- //namespace too long
- "this_is_not_a_valid_namespace_because_its_lenth_is_greater_than_255_this_is_not_a_valid_namespace_because_its_lenth_is_greater_than_255_this_is_not_a_valid_namespace_because_its_lenth_is_greater_than_255_this_is_not_a_valid_namespace_because_its_lenth_is_greater_than_255/docker",
- }
- for _, repositoryName := range invalidRepositoryNames {
- if _, err := ParseNamed(repositoryName); err == nil {
- t.Errorf("Repository name should be invalid: %v", repositoryName)
- }
- }
-}
-
-func TestParseRepositoryInfo(t *testing.T) {
- type tcase struct {
- RemoteName, NormalizedName, FullName, AmbiguousName, Hostname string
- }
-
- tcases := []tcase{
- {
- RemoteName: "fooo/bar",
- NormalizedName: "fooo/bar",
- FullName: "docker.io/fooo/bar",
- AmbiguousName: "index.docker.io/fooo/bar",
- Hostname: "docker.io",
- },
- {
- RemoteName: "library/ubuntu",
- NormalizedName: "ubuntu",
- FullName: "docker.io/library/ubuntu",
- AmbiguousName: "library/ubuntu",
- Hostname: "docker.io",
- },
- {
- RemoteName: "nonlibrary/ubuntu",
- NormalizedName: "nonlibrary/ubuntu",
- FullName: "docker.io/nonlibrary/ubuntu",
- AmbiguousName: "",
- Hostname: "docker.io",
- },
- {
- RemoteName: "other/library",
- NormalizedName: "other/library",
- FullName: "docker.io/other/library",
- AmbiguousName: "",
- Hostname: "docker.io",
- },
- {
- RemoteName: "private/moonbase",
- NormalizedName: "127.0.0.1:8000/private/moonbase",
- FullName: "127.0.0.1:8000/private/moonbase",
- AmbiguousName: "",
- Hostname: "127.0.0.1:8000",
- },
- {
- RemoteName: "privatebase",
- NormalizedName: "127.0.0.1:8000/privatebase",
- FullName: "127.0.0.1:8000/privatebase",
- AmbiguousName: "",
- Hostname: "127.0.0.1:8000",
- },
- {
- RemoteName: "private/moonbase",
- NormalizedName: "example.com/private/moonbase",
- FullName: "example.com/private/moonbase",
- AmbiguousName: "",
- Hostname: "example.com",
- },
- {
- RemoteName: "privatebase",
- NormalizedName: "example.com/privatebase",
- FullName: "example.com/privatebase",
- AmbiguousName: "",
- Hostname: "example.com",
- },
- {
- RemoteName: "private/moonbase",
- NormalizedName: "example.com:8000/private/moonbase",
- FullName: "example.com:8000/private/moonbase",
- AmbiguousName: "",
- Hostname: "example.com:8000",
- },
- {
- RemoteName: "privatebasee",
- NormalizedName: "example.com:8000/privatebasee",
- FullName: "example.com:8000/privatebasee",
- AmbiguousName: "",
- Hostname: "example.com:8000",
- },
- {
- RemoteName: "library/ubuntu-12.04-base",
- NormalizedName: "ubuntu-12.04-base",
- FullName: "docker.io/library/ubuntu-12.04-base",
- AmbiguousName: "index.docker.io/library/ubuntu-12.04-base",
- Hostname: "docker.io",
- },
- }
-
- for _, tcase := range tcases {
- refStrings := []string{tcase.NormalizedName, tcase.FullName}
- if tcase.AmbiguousName != "" {
- refStrings = append(refStrings, tcase.AmbiguousName)
- }
-
- var refs []Named
- for _, r := range refStrings {
- named, err := ParseNamed(r)
- if err != nil {
- t.Fatal(err)
- }
- refs = append(refs, named)
- named, err = WithName(r)
- if err != nil {
- t.Fatal(err)
- }
- refs = append(refs, named)
- }
-
- for _, r := range refs {
- if expected, actual := tcase.NormalizedName, r.Name(); expected != actual {
- t.Fatalf("Invalid normalized reference for %q. Expected %q, got %q", r, expected, actual)
- }
- if expected, actual := tcase.FullName, r.FullName(); expected != actual {
- t.Fatalf("Invalid fullName for %q. Expected %q, got %q", r, expected, actual)
- }
- if expected, actual := tcase.Hostname, r.Hostname(); expected != actual {
- t.Fatalf("Invalid hostname for %q. Expected %q, got %q", r, expected, actual)
- }
- if expected, actual := tcase.RemoteName, r.RemoteName(); expected != actual {
- t.Fatalf("Invalid remoteName for %q. Expected %q, got %q", r, expected, actual)
- }
-
- }
- }
-}
-
-func TestParseReferenceWithTagAndDigest(t *testing.T) {
- ref, err := ParseNamed("busybox:latest@sha256:86e0e091d0da6bde2456dbb48306f3956bbeb2eae1b5b9a43045843f69fe4aaa")
- if err != nil {
- t.Fatal(err)
- }
- if _, isTagged := ref.(NamedTagged); isTagged {
- t.Fatalf("Reference from %q should not support tag", ref)
- }
- if _, isCanonical := ref.(Canonical); !isCanonical {
- t.Fatalf("Reference from %q should not support digest", ref)
- }
- if expected, actual := "busybox@sha256:86e0e091d0da6bde2456dbb48306f3956bbeb2eae1b5b9a43045843f69fe4aaa", ref.String(); actual != expected {
- t.Fatalf("Invalid parsed reference for %q: expected %q, got %q", ref, expected, actual)
- }
-}
-
-func TestInvalidReferenceComponents(t *testing.T) {
- if _, err := WithName("-foo"); err == nil {
- t.Fatal("Expected WithName to detect invalid name")
- }
- ref, err := WithName("busybox")
- if err != nil {
- t.Fatal(err)
- }
- if _, err := WithTag(ref, "-foo"); err == nil {
- t.Fatal("Expected WithName to detect invalid tag")
- }
- if _, err := WithDigest(ref, digest.Digest("foo")); err == nil {
- t.Fatal("Expected WithName to detect invalid digest")
- }
-}
diff --git a/reference/store.go b/reference/store.go
index 35ae33660a..844ebf5319 100644
--- a/reference/store.go
+++ b/reference/store.go
@@ -9,6 +9,7 @@ import (
"sort"
"sync"
+ "github.com/docker/distribution/reference"
"github.com/docker/docker/pkg/ioutils"
"github.com/opencontainers/go-digest"
)
@@ -21,18 +22,18 @@ var (
// An Association is a tuple associating a reference with an image ID.
type Association struct {
- Ref Named
+ Ref reference.Named
ID digest.Digest
}
// Store provides the set of methods which can operate on a tag store.
type Store interface {
- References(id digest.Digest) []Named
- ReferencesByName(ref Named) []Association
- AddTag(ref Named, id digest.Digest, force bool) error
- AddDigest(ref Canonical, id digest.Digest, force bool) error
- Delete(ref Named) (bool, error)
- Get(ref Named) (digest.Digest, error)
+ References(id digest.Digest) []reference.Named
+ ReferencesByName(ref reference.Named) []Association
+ AddTag(ref reference.Named, id digest.Digest, force bool) error
+ AddDigest(ref reference.Canonical, id digest.Digest, force bool) error
+ Delete(ref reference.Named) (bool, error)
+ Get(ref reference.Named) (digest.Digest, error)
}
type store struct {
@@ -44,24 +45,28 @@ type store struct {
Repositories map[string]repository
// referencesByIDCache is a cache of references indexed by ID, to speed
// up References.
- referencesByIDCache map[digest.Digest]map[string]Named
+ referencesByIDCache map[digest.Digest]map[string]reference.Named
}
// Repository maps tags to digests. The key is a stringified Reference,
// including the repository name.
type repository map[string]digest.Digest
-type lexicalRefs []Named
+type lexicalRefs []reference.Named
-func (a lexicalRefs) Len() int { return len(a) }
-func (a lexicalRefs) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
-func (a lexicalRefs) Less(i, j int) bool { return a[i].String() < a[j].String() }
+func (a lexicalRefs) Len() int { return len(a) }
+func (a lexicalRefs) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+func (a lexicalRefs) Less(i, j int) bool {
+ return a[i].String() < a[j].String()
+}
type lexicalAssociations []Association
-func (a lexicalAssociations) Len() int { return len(a) }
-func (a lexicalAssociations) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
-func (a lexicalAssociations) Less(i, j int) bool { return a[i].Ref.String() < a[j].Ref.String() }
+func (a lexicalAssociations) Len() int { return len(a) }
+func (a lexicalAssociations) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+func (a lexicalAssociations) Less(i, j int) bool {
+ return a[i].Ref.String() < a[j].Ref.String()
+}
// NewReferenceStore creates a new reference store, tied to a file path where
// the set of references are serialized in JSON format.
@@ -74,7 +79,7 @@ func NewReferenceStore(jsonPath string) (Store, error) {
store := &store{
jsonPath: abspath,
Repositories: make(map[string]repository),
- referencesByIDCache: make(map[digest.Digest]map[string]Named),
+ referencesByIDCache: make(map[digest.Digest]map[string]reference.Named),
}
// Load the json file if it exists, otherwise create it.
if err := store.reload(); os.IsNotExist(err) {
@@ -89,43 +94,45 @@ func NewReferenceStore(jsonPath string) (Store, error) {
// AddTag adds a tag reference to the store. If force is set to true, existing
// references can be overwritten. This only works for tags, not digests.
-func (store *store) AddTag(ref Named, id digest.Digest, force bool) error {
- if _, isCanonical := ref.(Canonical); isCanonical {
+func (store *store) AddTag(ref reference.Named, id digest.Digest, force bool) error {
+ if _, isCanonical := ref.(reference.Canonical); isCanonical {
return errors.New("refusing to create a tag with a digest reference")
}
- return store.addReference(WithDefaultTag(ref), id, force)
+ return store.addReference(reference.TagNameOnly(ref), id, force)
}
// AddDigest adds a digest reference to the store.
-func (store *store) AddDigest(ref Canonical, id digest.Digest, force bool) error {
+func (store *store) AddDigest(ref reference.Canonical, id digest.Digest, force bool) error {
return store.addReference(ref, id, force)
}
-func (store *store) addReference(ref Named, id digest.Digest, force bool) error {
- if ref.Name() == string(digest.Canonical) {
+func (store *store) addReference(ref reference.Named, id digest.Digest, force bool) error {
+ refName := reference.FamiliarName(ref)
+ refStr := reference.FamiliarString(ref)
+
+ if refName == string(digest.Canonical) {
return errors.New("refusing to create an ambiguous tag using digest algorithm as name")
}
store.mu.Lock()
defer store.mu.Unlock()
- repository, exists := store.Repositories[ref.Name()]
+ repository, exists := store.Repositories[refName]
if !exists || repository == nil {
repository = make(map[string]digest.Digest)
- store.Repositories[ref.Name()] = repository
+ store.Repositories[refName] = repository
}
- refStr := ref.String()
oldID, exists := repository[refStr]
if exists {
// force only works for tags
- if digested, isDigest := ref.(Canonical); isDigest {
+ if digested, isDigest := ref.(reference.Canonical); isDigest {
return fmt.Errorf("Cannot overwrite digest %s", digested.Digest().String())
}
if !force {
- return fmt.Errorf("Conflict: Tag %s is already set to image %s, if you want to replace it, please use -f option", ref.String(), oldID.String())
+ return fmt.Errorf("Conflict: Tag %s is already set to image %s, if you want to replace it, please use -f option", refStr, oldID.String())
}
if store.referencesByIDCache[oldID] != nil {
@@ -138,7 +145,7 @@ func (store *store) addReference(ref Named, id digest.Digest, force bool) error
repository[refStr] = id
if store.referencesByIDCache[id] == nil {
- store.referencesByIDCache[id] = make(map[string]Named)
+ store.referencesByIDCache[id] = make(map[string]reference.Named)
}
store.referencesByIDCache[id][refStr] = ref
@@ -147,24 +154,24 @@ func (store *store) addReference(ref Named, id digest.Digest, force bool) error
// Delete deletes a reference from the store. It returns true if a deletion
// happened, or false otherwise.
-func (store *store) Delete(ref Named) (bool, error) {
- ref = WithDefaultTag(ref)
+func (store *store) Delete(ref reference.Named) (bool, error) {
+ ref = reference.TagNameOnly(ref)
+
+ refName := reference.FamiliarName(ref)
+ refStr := reference.FamiliarString(ref)
store.mu.Lock()
defer store.mu.Unlock()
- repoName := ref.Name()
-
- repository, exists := store.Repositories[repoName]
+ repository, exists := store.Repositories[refName]
if !exists {
return false, ErrDoesNotExist
}
- refStr := ref.String()
if id, exists := repository[refStr]; exists {
delete(repository, refStr)
if len(repository) == 0 {
- delete(store.Repositories, repoName)
+ delete(store.Repositories, refName)
}
if store.referencesByIDCache[id] != nil {
delete(store.referencesByIDCache[id], refStr)
@@ -179,18 +186,34 @@ func (store *store) Delete(ref Named) (bool, error) {
}
// Get retrieves an item from the store by reference
-func (store *store) Get(ref Named) (digest.Digest, error) {
- ref = WithDefaultTag(ref)
+func (store *store) Get(ref reference.Named) (digest.Digest, error) {
+ if canonical, ok := ref.(reference.Canonical); ok {
+ // If reference contains both tag and digest, only
+ // lookup by digest as it takes precendent over
+ // tag, until tag/digest combos are stored.
+ if _, ok := ref.(reference.Tagged); ok {
+ var err error
+ ref, err = reference.WithDigest(reference.TrimNamed(canonical), canonical.Digest())
+ if err != nil {
+ return "", err
+ }
+ }
+ } else {
+ ref = reference.TagNameOnly(ref)
+ }
+
+ refName := reference.FamiliarName(ref)
+ refStr := reference.FamiliarString(ref)
store.mu.RLock()
defer store.mu.RUnlock()
- repository, exists := store.Repositories[ref.Name()]
+ repository, exists := store.Repositories[refName]
if !exists || repository == nil {
return "", ErrDoesNotExist
}
- id, exists := repository[ref.String()]
+ id, exists := repository[refStr]
if !exists {
return "", ErrDoesNotExist
}
@@ -200,7 +223,7 @@ func (store *store) Get(ref Named) (digest.Digest, error) {
// References returns a slice of references to the given ID. The slice
// will be nil if there are no references to this ID.
-func (store *store) References(id digest.Digest) []Named {
+func (store *store) References(id digest.Digest) []reference.Named {
store.mu.RLock()
defer store.mu.RUnlock()
@@ -208,7 +231,7 @@ func (store *store) References(id digest.Digest) []Named {
// 1) We must not return a mutable
// 2) It would be ugly to expose the extraneous map keys to callers.
- var references []Named
+ var references []reference.Named
for _, ref := range store.referencesByIDCache[id] {
references = append(references, ref)
}
@@ -221,18 +244,20 @@ func (store *store) References(id digest.Digest) []Named {
// ReferencesByName returns the references for a given repository name.
// If there are no references known for this repository name,
// ReferencesByName returns nil.
-func (store *store) ReferencesByName(ref Named) []Association {
+func (store *store) ReferencesByName(ref reference.Named) []Association {
+ refName := reference.FamiliarName(ref)
+
store.mu.RLock()
defer store.mu.RUnlock()
- repository, exists := store.Repositories[ref.Name()]
+ repository, exists := store.Repositories[refName]
if !exists {
return nil
}
var associations []Association
for refStr, refID := range repository {
- ref, err := ParseNamed(refStr)
+ ref, err := reference.ParseNormalizedNamed(refStr)
if err != nil {
// Should never happen
return nil
@@ -270,13 +295,13 @@ func (store *store) reload() error {
for _, repository := range store.Repositories {
for refStr, refID := range repository {
- ref, err := ParseNamed(refStr)
+ ref, err := reference.ParseNormalizedNamed(refStr)
if err != nil {
// Should never happen
continue
}
if store.referencesByIDCache[refID] == nil {
- store.referencesByIDCache[refID] = make(map[string]Named)
+ store.referencesByIDCache[refID] = make(map[string]reference.Named)
}
store.referencesByIDCache[refID][refStr] = ref
}
diff --git a/reference/store_test.go b/reference/store_test.go
index 0d96e6b694..8f0ff6304e 100644
--- a/reference/store_test.go
+++ b/reference/store_test.go
@@ -8,6 +8,7 @@ import (
"strings"
"testing"
+ "github.com/docker/distribution/reference"
"github.com/opencontainers/go-digest"
)
@@ -45,7 +46,7 @@ func TestLoad(t *testing.T) {
}
for refStr, expectedID := range saveLoadTestCases {
- ref, err := ParseNamed(refStr)
+ ref, err := reference.ParseNormalizedNamed(refStr)
if err != nil {
t.Fatalf("failed to parse reference: %v", err)
}
@@ -74,11 +75,11 @@ func TestSave(t *testing.T) {
}
for refStr, id := range saveLoadTestCases {
- ref, err := ParseNamed(refStr)
+ ref, err := reference.ParseNormalizedNamed(refStr)
if err != nil {
t.Fatalf("failed to parse reference: %v", err)
}
- if canonical, ok := ref.(Canonical); ok {
+ if canonical, ok := ref.(reference.Canonical); ok {
err = store.AddDigest(canonical, id, false)
if err != nil {
t.Fatalf("could not add digest reference %s: %v", refStr, err)
@@ -120,7 +121,7 @@ func TestAddDeleteGet(t *testing.T) {
testImageID3 := digest.Digest("sha256:9655aef5fd742a1b4e1b7b163aa9f1c76c186304bf39102283d80927c916ca9e")
// Try adding a reference with no tag or digest
- nameOnly, err := WithName("username/repo")
+ nameOnly, err := reference.ParseNormalizedNamed("username/repo")
if err != nil {
t.Fatalf("could not parse reference: %v", err)
}
@@ -129,7 +130,7 @@ func TestAddDeleteGet(t *testing.T) {
}
// Add a few references
- ref1, err := ParseNamed("username/repo1:latest")
+ ref1, err := reference.ParseNormalizedNamed("username/repo1:latest")
if err != nil {
t.Fatalf("could not parse reference: %v", err)
}
@@ -137,7 +138,7 @@ func TestAddDeleteGet(t *testing.T) {
t.Fatalf("error adding to store: %v", err)
}
- ref2, err := ParseNamed("username/repo1:old")
+ ref2, err := reference.ParseNormalizedNamed("username/repo1:old")
if err != nil {
t.Fatalf("could not parse reference: %v", err)
}
@@ -145,7 +146,7 @@ func TestAddDeleteGet(t *testing.T) {
t.Fatalf("error adding to store: %v", err)
}
- ref3, err := ParseNamed("username/repo1:alias")
+ ref3, err := reference.ParseNormalizedNamed("username/repo1:alias")
if err != nil {
t.Fatalf("could not parse reference: %v", err)
}
@@ -153,7 +154,7 @@ func TestAddDeleteGet(t *testing.T) {
t.Fatalf("error adding to store: %v", err)
}
- ref4, err := ParseNamed("username/repo2:latest")
+ ref4, err := reference.ParseNormalizedNamed("username/repo2:latest")
if err != nil {
t.Fatalf("could not parse reference: %v", err)
}
@@ -161,11 +162,11 @@ func TestAddDeleteGet(t *testing.T) {
t.Fatalf("error adding to store: %v", err)
}
- ref5, err := ParseNamed("username/repo3@sha256:58153dfb11794fad694460162bf0cb0a4fa710cfa3f60979c177d920813e267c")
+ ref5, err := reference.ParseNormalizedNamed("username/repo3@sha256:58153dfb11794fad694460162bf0cb0a4fa710cfa3f60979c177d920813e267c")
if err != nil {
t.Fatalf("could not parse reference: %v", err)
}
- if err = store.AddDigest(ref5.(Canonical), testImageID2, false); err != nil {
+ if err = store.AddDigest(ref5.(reference.Canonical), testImageID2, false); err != nil {
t.Fatalf("error adding to store: %v", err)
}
@@ -228,7 +229,7 @@ func TestAddDeleteGet(t *testing.T) {
}
// Get should return ErrDoesNotExist for a nonexistent repo
- nonExistRepo, err := ParseNamed("username/nonexistrepo:latest")
+ nonExistRepo, err := reference.ParseNormalizedNamed("username/nonexistrepo:latest")
if err != nil {
t.Fatalf("could not parse reference: %v", err)
}
@@ -237,7 +238,7 @@ func TestAddDeleteGet(t *testing.T) {
}
// Get should return ErrDoesNotExist for a nonexistent tag
- nonExistTag, err := ParseNamed("username/repo1:nonexist")
+ nonExistTag, err := reference.ParseNormalizedNamed("username/repo1:nonexist")
if err != nil {
t.Fatalf("could not parse reference: %v", err)
}
@@ -263,7 +264,7 @@ func TestAddDeleteGet(t *testing.T) {
}
// Check ReferencesByName
- repoName, err := WithName("username/repo1")
+ repoName, err := reference.ParseNormalizedNamed("username/repo1")
if err != nil {
t.Fatalf("could not parse reference: %v", err)
}
@@ -334,7 +335,7 @@ func TestInvalidTags(t *testing.T) {
id := digest.Digest("sha256:470022b8af682154f57a2163d030eb369549549cba00edc69e1b99b46bb924d6")
// sha256 as repo name
- ref, err := ParseNamed("sha256:abc")
+ ref, err := reference.ParseNormalizedNamed("sha256:abc")
if err != nil {
t.Fatal(err)
}
@@ -344,7 +345,7 @@ func TestInvalidTags(t *testing.T) {
}
// setting digest as a tag
- ref, err = ParseNamed("registry@sha256:367eb40fd0330a7e464777121e39d2f5b3e8e23a1e159342e53ab05c9e4d94e6")
+ ref, err = reference.ParseNormalizedNamed("registry@sha256:367eb40fd0330a7e464777121e39d2f5b3e8e23a1e159342e53ab05c9e4d94e6")
if err != nil {
t.Fatal(err)
}