summaryrefslogtreecommitdiff
path: root/reference
diff options
context:
space:
mode:
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)
}