summaryrefslogtreecommitdiff
path: root/reference/store.go
diff options
context:
space:
mode:
Diffstat (limited to 'reference/store.go')
-rw-r--r--reference/store.go117
1 files changed, 71 insertions, 46 deletions
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
}