Browse code

Add own reference package wrapper

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>

Tonis Tiigi authored on 2015/12/05 06:55:15
Showing 46 changed files
... ...
@@ -13,7 +13,6 @@ import (
13 13
 	"runtime"
14 14
 	"strings"
15 15
 
16
-	"github.com/docker/distribution/reference"
17 16
 	"github.com/docker/docker/api"
18 17
 	"github.com/docker/docker/api/types"
19 18
 	"github.com/docker/docker/builder/dockerignore"
... ...
@@ -29,8 +28,8 @@ import (
29 29
 	"github.com/docker/docker/pkg/streamformatter"
30 30
 	"github.com/docker/docker/pkg/ulimit"
31 31
 	"github.com/docker/docker/pkg/urlutil"
32
+	"github.com/docker/docker/reference"
32 33
 	"github.com/docker/docker/registry"
33
-	tagpkg "github.com/docker/docker/tag"
34 34
 	"github.com/docker/docker/utils"
35 35
 	"github.com/docker/go-units"
36 36
 )
... ...
@@ -532,11 +531,11 @@ func rewriteDockerfileFrom(dockerfileName string, translator func(reference.Name
532 532
 
533 533
 			digested := false
534 534
 			switch ref.(type) {
535
-			case reference.Tagged:
536
-			case reference.Digested:
535
+			case reference.NamedTagged:
536
+			case reference.Canonical:
537 537
 				digested = true
538 538
 			default:
539
-				ref, err = reference.WithTag(ref, tagpkg.DefaultTag)
539
+				ref, err = reference.WithTag(ref, reference.DefaultTag)
540 540
 				if err != nil {
541 541
 					return nil, nil, err
542 542
 				}
... ...
@@ -5,11 +5,11 @@ import (
5 5
 	"errors"
6 6
 	"fmt"
7 7
 
8
-	"github.com/docker/distribution/reference"
9 8
 	"github.com/docker/docker/api/types"
10 9
 	Cli "github.com/docker/docker/cli"
11 10
 	"github.com/docker/docker/opts"
12 11
 	flag "github.com/docker/docker/pkg/mflag"
12
+	"github.com/docker/docker/reference"
13 13
 	"github.com/docker/docker/registry"
14 14
 	"github.com/docker/docker/runconfig"
15 15
 )
... ...
@@ -51,9 +51,9 @@ func (cli *DockerCli) CmdCommit(args ...string) error {
51 51
 		repositoryName = ref.Name()
52 52
 
53 53
 		switch x := ref.(type) {
54
-		case reference.Digested:
54
+		case reference.Canonical:
55 55
 			return errors.New("cannot commit to digest reference")
56
-		case reference.Tagged:
56
+		case reference.NamedTagged:
57 57
 			tag = x.Tag()
58 58
 		}
59 59
 	}
... ...
@@ -5,14 +5,13 @@ import (
5 5
 	"io"
6 6
 	"os"
7 7
 
8
-	"github.com/docker/distribution/reference"
9 8
 	"github.com/docker/docker/api/client/lib"
10 9
 	"github.com/docker/docker/api/types"
11 10
 	Cli "github.com/docker/docker/cli"
12 11
 	"github.com/docker/docker/pkg/jsonmessage"
12
+	"github.com/docker/docker/reference"
13 13
 	"github.com/docker/docker/registry"
14 14
 	"github.com/docker/docker/runconfig"
15
-	tagpkg "github.com/docker/docker/tag"
16 15
 )
17 16
 
18 17
 func (cli *DockerCli) pullImage(image string) error {
... ...
@@ -27,13 +26,13 @@ func (cli *DockerCli) pullImageCustomOut(image string, out io.Writer) error {
27 27
 
28 28
 	var tag string
29 29
 	switch x := ref.(type) {
30
-	case reference.Digested:
30
+	case reference.Canonical:
31 31
 		tag = x.Digest().String()
32
-	case reference.Tagged:
32
+	case reference.NamedTagged:
33 33
 		tag = x.Tag()
34 34
 	default:
35 35
 		// pull only the image tagged 'latest' if no tag was specified
36
-		tag = tagpkg.DefaultTag
36
+		tag = reference.DefaultTag
37 37
 	}
38 38
 
39 39
 	// Resolve the Repository name from fqn to RepositoryInfo
... ...
@@ -99,13 +98,13 @@ func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runc
99 99
 		return nil, err
100 100
 	}
101 101
 
102
-	isDigested := false
102
+	isCanonical := false
103 103
 	switch ref.(type) {
104
-	case reference.Tagged:
105
-	case reference.Digested:
106
-		isDigested = true
104
+	case reference.NamedTagged:
105
+	case reference.Canonical:
106
+		isCanonical = true
107 107
 	default:
108
-		ref, err = reference.WithTag(ref, tagpkg.DefaultTag)
108
+		ref, err = reference.WithTag(ref, reference.DefaultTag)
109 109
 		if err != nil {
110 110
 			return nil, err
111 111
 		}
... ...
@@ -113,7 +112,7 @@ func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runc
113 113
 
114 114
 	var trustedRef reference.Canonical
115 115
 
116
-	if isTrusted() && !isDigested {
116
+	if isTrusted() && !isCanonical {
117 117
 		var err error
118 118
 		trustedRef, err = cli.trustedReference(ref.(reference.NamedTagged))
119 119
 		if err != nil {
... ...
@@ -133,7 +132,7 @@ func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runc
133 133
 			if err = cli.pullImageCustomOut(config.Image, cli.err); err != nil {
134 134
 				return nil, err
135 135
 			}
136
-			if trustedRef != nil && !isDigested {
136
+			if trustedRef != nil && !isCanonical {
137 137
 				if err := cli.tagTrusted(trustedRef, ref.(reference.NamedTagged)); err != nil {
138 138
 					return nil, err
139 139
 				}
... ...
@@ -6,13 +6,13 @@ import (
6 6
 	"text/tabwriter"
7 7
 	"time"
8 8
 
9
-	"github.com/docker/distribution/reference"
10 9
 	"github.com/docker/docker/api/types"
11 10
 	"github.com/docker/docker/api/types/filters"
12 11
 	Cli "github.com/docker/docker/cli"
13 12
 	"github.com/docker/docker/opts"
14 13
 	flag "github.com/docker/docker/pkg/mflag"
15 14
 	"github.com/docker/docker/pkg/stringid"
15
+	"github.com/docker/docker/reference"
16 16
 	"github.com/docker/go-units"
17 17
 )
18 18
 
... ...
@@ -98,9 +98,9 @@ func (cli *DockerCli) CmdImages(args ...string) error {
98 98
 				repo = ref.Name()
99 99
 
100 100
 				switch x := ref.(type) {
101
-				case reference.Digested:
101
+				case reference.Canonical:
102 102
 					digest = x.Digest().String()
103
-				case reference.Tagged:
103
+				case reference.NamedTagged:
104 104
 					tag = x.Tag()
105 105
 				}
106 106
 			}
... ...
@@ -5,13 +5,13 @@ import (
5 5
 	"io"
6 6
 	"os"
7 7
 
8
-	"github.com/docker/distribution/reference"
9 8
 	"github.com/docker/docker/api/types"
10 9
 	Cli "github.com/docker/docker/cli"
11 10
 	"github.com/docker/docker/opts"
12 11
 	"github.com/docker/docker/pkg/jsonmessage"
13 12
 	flag "github.com/docker/docker/pkg/mflag"
14 13
 	"github.com/docker/docker/pkg/urlutil"
14
+	"github.com/docker/docker/reference"
15 15
 	"github.com/docker/docker/registry"
16 16
 )
17 17
 
... ...
@@ -4,14 +4,13 @@ import (
4 4
 	"errors"
5 5
 	"fmt"
6 6
 
7
-	"github.com/docker/distribution/reference"
8 7
 	"github.com/docker/docker/api/client/lib"
9 8
 	"github.com/docker/docker/api/types"
10 9
 	Cli "github.com/docker/docker/cli"
11 10
 	"github.com/docker/docker/pkg/jsonmessage"
12 11
 	flag "github.com/docker/docker/pkg/mflag"
12
+	"github.com/docker/docker/reference"
13 13
 	"github.com/docker/docker/registry"
14
-	tagpkg "github.com/docker/docker/tag"
15 14
 )
16 15
 
17 16
 var errTagCantBeUsed = errors.New("tag can't be used with --all-tags/-a")
... ...
@@ -35,19 +34,19 @@ func (cli *DockerCli) CmdPull(args ...string) error {
35 35
 
36 36
 	var tag string
37 37
 	switch x := distributionRef.(type) {
38
-	case reference.Digested:
38
+	case reference.Canonical:
39 39
 		if *allTags {
40 40
 			return errTagCantBeUsed
41 41
 		}
42 42
 		tag = x.Digest().String()
43
-	case reference.Tagged:
43
+	case reference.NamedTagged:
44 44
 		if *allTags {
45 45
 			return errTagCantBeUsed
46 46
 		}
47 47
 		tag = x.Tag()
48 48
 	default:
49 49
 		if !*allTags {
50
-			tag = tagpkg.DefaultTag
50
+			tag = reference.DefaultTag
51 51
 			distributionRef, err = reference.WithTag(distributionRef, tag)
52 52
 			if err != nil {
53 53
 				return err
... ...
@@ -4,12 +4,12 @@ import (
4 4
 	"errors"
5 5
 	"io"
6 6
 
7
-	"github.com/docker/distribution/reference"
8 7
 	"github.com/docker/docker/api/client/lib"
9 8
 	"github.com/docker/docker/api/types"
10 9
 	Cli "github.com/docker/docker/cli"
11 10
 	"github.com/docker/docker/pkg/jsonmessage"
12 11
 	flag "github.com/docker/docker/pkg/mflag"
12
+	"github.com/docker/docker/reference"
13 13
 	"github.com/docker/docker/registry"
14 14
 )
15 15
 
... ...
@@ -30,9 +30,9 @@ func (cli *DockerCli) CmdPush(args ...string) error {
30 30
 
31 31
 	var tag string
32 32
 	switch x := ref.(type) {
33
-	case reference.Digested:
33
+	case reference.Canonical:
34 34
 		return errors.New("cannot push a digest reference")
35
-	case reference.Tagged:
35
+	case reference.NamedTagged:
36 36
 		tag = x.Tag()
37 37
 	}
38 38
 
... ...
@@ -3,10 +3,10 @@ package client
3 3
 import (
4 4
 	"errors"
5 5
 
6
-	"github.com/docker/distribution/reference"
7 6
 	"github.com/docker/docker/api/types"
8 7
 	Cli "github.com/docker/docker/cli"
9 8
 	flag "github.com/docker/docker/pkg/mflag"
9
+	"github.com/docker/docker/reference"
10 10
 	"github.com/docker/docker/registry"
11 11
 )
12 12
 
... ...
@@ -25,13 +25,12 @@ func (cli *DockerCli) CmdTag(args ...string) error {
25 25
 		return err
26 26
 	}
27 27
 
28
-	_, isDigested := ref.(reference.Digested)
29
-	if isDigested {
28
+	if _, isCanonical := ref.(reference.Canonical); isCanonical {
30 29
 		return errors.New("refusing to create a tag with a digest reference")
31 30
 	}
32 31
 
33 32
 	tag := ""
34
-	tagged, isTagged := ref.(reference.Tagged)
33
+	tagged, isTagged := ref.(reference.NamedTagged)
35 34
 	if isTagged {
36 35
 		tag = tagged.Tag()
37 36
 	}
... ...
@@ -19,7 +19,6 @@ import (
19 19
 
20 20
 	"github.com/Sirupsen/logrus"
21 21
 	"github.com/docker/distribution/digest"
22
-	"github.com/docker/distribution/reference"
23 22
 	"github.com/docker/distribution/registry/client/auth"
24 23
 	"github.com/docker/distribution/registry/client/transport"
25 24
 	"github.com/docker/docker/api/client/lib"
... ...
@@ -30,6 +29,7 @@ import (
30 30
 	"github.com/docker/docker/pkg/ioutils"
31 31
 	flag "github.com/docker/docker/pkg/mflag"
32 32
 	"github.com/docker/docker/pkg/tlsconfig"
33
+	"github.com/docker/docker/reference"
33 34
 	"github.com/docker/docker/registry"
34 35
 	"github.com/docker/notary/client"
35 36
 	"github.com/docker/notary/passphrase"
... ...
@@ -12,7 +12,6 @@ import (
12 12
 
13 13
 	"github.com/Sirupsen/logrus"
14 14
 	"github.com/docker/distribution/digest"
15
-	"github.com/docker/distribution/reference"
16 15
 	"github.com/docker/docker/api/server/httputils"
17 16
 	"github.com/docker/docker/api/types"
18 17
 	"github.com/docker/docker/builder"
... ...
@@ -25,8 +24,8 @@ import (
25 25
 	"github.com/docker/docker/pkg/progress"
26 26
 	"github.com/docker/docker/pkg/streamformatter"
27 27
 	"github.com/docker/docker/pkg/ulimit"
28
+	"github.com/docker/docker/reference"
28 29
 	"github.com/docker/docker/runconfig"
29
-	tagpkg "github.com/docker/docker/tag"
30 30
 	"github.com/docker/docker/utils"
31 31
 	"golang.org/x/net/context"
32 32
 )
... ...
@@ -156,7 +155,7 @@ func (s *router) postImagesCreate(ctx context.Context, w http.ResponseWriter, r
156 156
 			}
157 157
 
158 158
 			switch newRef.(type) {
159
-			case reference.Digested:
159
+			case reference.Canonical:
160 160
 				return errors.New("cannot import digest reference")
161 161
 			}
162 162
 
... ...
@@ -498,12 +497,12 @@ func sanitizeRepoAndTags(names []string) ([]reference.Named, error) {
498 498
 			return nil, err
499 499
 		}
500 500
 
501
-		if _, isDigested := ref.(reference.Digested); isDigested {
502
-			return nil, errors.New("build tag cannot be a digest")
501
+		if _, isCanonical := ref.(reference.Canonical); isCanonical {
502
+			return nil, errors.New("build tag cannot contain a digest")
503 503
 		}
504 504
 
505
-		if _, isTagged := ref.(reference.Tagged); !isTagged {
506
-			ref, err = reference.WithTag(ref, tagpkg.DefaultTag)
505
+		if _, isTagged := ref.(reference.NamedTagged); !isTagged {
506
+			ref, err = reference.WithTag(ref, reference.DefaultTag)
507 507
 		}
508 508
 
509 509
 		nameWithTag := ref.String()
... ...
@@ -7,7 +7,6 @@ import (
7 7
 	"strings"
8 8
 	"time"
9 9
 
10
-	"github.com/docker/distribution/reference"
11 10
 	"github.com/docker/docker/api/types"
12 11
 	"github.com/docker/docker/container"
13 12
 	"github.com/docker/docker/dockerversion"
... ...
@@ -15,6 +14,7 @@ import (
15 15
 	"github.com/docker/docker/layer"
16 16
 	"github.com/docker/docker/pkg/archive"
17 17
 	"github.com/docker/docker/pkg/ioutils"
18
+	"github.com/docker/docker/reference"
18 19
 	"github.com/docker/docker/runconfig"
19 20
 )
20 21
 
... ...
@@ -19,7 +19,6 @@ import (
19 19
 
20 20
 	"github.com/Sirupsen/logrus"
21 21
 	"github.com/docker/distribution/digest"
22
-	"github.com/docker/distribution/reference"
23 22
 	"github.com/docker/docker/api"
24 23
 	"github.com/docker/docker/api/types"
25 24
 	"github.com/docker/docker/api/types/filters"
... ...
@@ -58,9 +57,9 @@ import (
58 58
 	"github.com/docker/docker/pkg/sysinfo"
59 59
 	"github.com/docker/docker/pkg/system"
60 60
 	"github.com/docker/docker/pkg/truncindex"
61
+	"github.com/docker/docker/reference"
61 62
 	"github.com/docker/docker/registry"
62 63
 	"github.com/docker/docker/runconfig"
63
-	"github.com/docker/docker/tag"
64 64
 	"github.com/docker/docker/utils"
65 65
 	volumedrivers "github.com/docker/docker/volume/drivers"
66 66
 	"github.com/docker/docker/volume/local"
... ...
@@ -138,7 +137,7 @@ type Daemon struct {
138 138
 	repository                string
139 139
 	containers                *contStore
140 140
 	execCommands              *exec.Store
141
-	tagStore                  tag.Store
141
+	referenceStore            reference.Store
142 142
 	downloadManager           *xfer.LayerDownloadManager
143 143
 	uploadManager             *xfer.LayerUploadManager
144 144
 	distributionMetadataStore dmetadata.Store
... ...
@@ -789,16 +788,16 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
789 789
 
790 790
 	eventsService := events.New()
791 791
 
792
-	tagStore, err := tag.NewTagStore(filepath.Join(imageRoot, "repositories.json"))
792
+	referenceStore, err := reference.NewReferenceStore(filepath.Join(imageRoot, "repositories.json"))
793 793
 	if err != nil {
794 794
 		return nil, fmt.Errorf("Couldn't create Tag store repositories: %s", err)
795 795
 	}
796 796
 
797
-	if err := restoreCustomImage(d.driver, d.imageStore, d.layerStore, tagStore); err != nil {
797
+	if err := restoreCustomImage(d.driver, d.imageStore, d.layerStore, referenceStore); err != nil {
798 798
 		return nil, fmt.Errorf("Couldn't restore custom images: %s", err)
799 799
 	}
800 800
 
801
-	if err := v1.Migrate(config.Root, d.driver.String(), d.layerStore, d.imageStore, tagStore, distributionMetadataStore); err != nil {
801
+	if err := v1.Migrate(config.Root, d.driver.String(), d.layerStore, d.imageStore, referenceStore, distributionMetadataStore); err != nil {
802 802
 		return nil, err
803 803
 	}
804 804
 
... ...
@@ -848,7 +847,7 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
848 848
 	d.repository = daemonRepo
849 849
 	d.containers = &contStore{s: make(map[string]*container.Container)}
850 850
 	d.execCommands = exec.NewStore()
851
-	d.tagStore = tagStore
851
+	d.referenceStore = referenceStore
852 852
 	d.distributionMetadataStore = distributionMetadataStore
853 853
 	d.trustKey = trustKey
854 854
 	d.idIndex = truncindex.NewTruncIndex([]string{})
... ...
@@ -1045,7 +1044,7 @@ func (daemon *Daemon) TagImage(newTag reference.Named, imageName string) error {
1045 1045
 		return err
1046 1046
 	}
1047 1047
 	newTag = registry.NormalizeLocalReference(newTag)
1048
-	if err := daemon.tagStore.AddTag(newTag, imageID, true); err != nil {
1048
+	if err := daemon.referenceStore.AddTag(newTag, imageID, true); err != nil {
1049 1049
 		return err
1050 1050
 	}
1051 1051
 	daemon.EventsService.Log("tag", newTag.String(), "")
... ...
@@ -1091,7 +1090,7 @@ func (daemon *Daemon) PullImage(ref reference.Named, metaHeaders map[string][]st
1091 1091
 		EventsService:   daemon.EventsService,
1092 1092
 		MetadataStore:   daemon.distributionMetadataStore,
1093 1093
 		ImageStore:      daemon.imageStore,
1094
-		TagStore:        daemon.tagStore,
1094
+		ReferenceStore:  daemon.referenceStore,
1095 1095
 		DownloadManager: daemon.downloadManager,
1096 1096
 	}
1097 1097
 
... ...
@@ -1107,7 +1106,7 @@ func (daemon *Daemon) PullImage(ref reference.Named, metaHeaders map[string][]st
1107 1107
 // the same tag are exported. names is the set of tags to export, and
1108 1108
 // outStream is the writer which the images are written to.
1109 1109
 func (daemon *Daemon) ExportImage(names []string, outStream io.Writer) error {
1110
-	imageExporter := tarexport.NewTarExporter(daemon.imageStore, daemon.layerStore, daemon.tagStore)
1110
+	imageExporter := tarexport.NewTarExporter(daemon.imageStore, daemon.layerStore, daemon.referenceStore)
1111 1111
 	return imageExporter.Save(names, outStream)
1112 1112
 }
1113 1113
 
... ...
@@ -1135,7 +1134,7 @@ func (daemon *Daemon) PushImage(ref reference.Named, metaHeaders map[string][]st
1135 1135
 		MetadataStore:   daemon.distributionMetadataStore,
1136 1136
 		LayerStore:      daemon.layerStore,
1137 1137
 		ImageStore:      daemon.imageStore,
1138
-		TagStore:        daemon.tagStore,
1138
+		ReferenceStore:  daemon.referenceStore,
1139 1139
 		TrustKey:        daemon.trustKey,
1140 1140
 		UploadManager:   daemon.uploadManager,
1141 1141
 	}
... ...
@@ -1154,14 +1153,14 @@ func (daemon *Daemon) LookupImage(name string) (*types.ImageInspect, error) {
1154 1154
 		return nil, fmt.Errorf("No such image: %s", name)
1155 1155
 	}
1156 1156
 
1157
-	refs := daemon.tagStore.References(img.ID())
1157
+	refs := daemon.referenceStore.References(img.ID())
1158 1158
 	repoTags := []string{}
1159 1159
 	repoDigests := []string{}
1160 1160
 	for _, ref := range refs {
1161 1161
 		switch ref.(type) {
1162
-		case reference.Tagged:
1162
+		case reference.NamedTagged:
1163 1163
 			repoTags = append(repoTags, ref.String())
1164
-		case reference.Digested:
1164
+		case reference.Canonical:
1165 1165
 			repoDigests = append(repoDigests, ref.String())
1166 1166
 		}
1167 1167
 	}
... ...
@@ -1215,7 +1214,7 @@ func (daemon *Daemon) LookupImage(name string) (*types.ImageInspect, error) {
1215 1215
 // complement of ImageExport.  The input stream is an uncompressed tar
1216 1216
 // ball containing images and metadata.
1217 1217
 func (daemon *Daemon) LoadImage(inTar io.ReadCloser, outStream io.Writer) error {
1218
-	imageExporter := tarexport.NewTarExporter(daemon.imageStore, daemon.layerStore, daemon.tagStore)
1218
+	imageExporter := tarexport.NewTarExporter(daemon.imageStore, daemon.layerStore, daemon.referenceStore)
1219 1219
 	return imageExporter.Load(inTar, outStream)
1220 1220
 }
1221 1221
 
... ...
@@ -1271,7 +1270,7 @@ func (daemon *Daemon) ImageHistory(name string) ([]*types.ImageHistory, error) {
1271 1271
 		h.ID = id.String()
1272 1272
 
1273 1273
 		var tags []string
1274
-		for _, r := range daemon.tagStore.References(id) {
1274
+		for _, r := range daemon.referenceStore.References(id) {
1275 1275
 			if _, ok := r.(reference.NamedTagged); ok {
1276 1276
 				tags = append(tags, r.String())
1277 1277
 			}
... ...
@@ -1303,12 +1302,12 @@ func (daemon *Daemon) GetImageID(refOrID string) (image.ID, error) {
1303 1303
 	// Treat it as a possible tag or digest reference
1304 1304
 	if ref, err := reference.ParseNamed(refOrID); err == nil {
1305 1305
 		ref = registry.NormalizeLocalReference(ref)
1306
-		if id, err := daemon.tagStore.Get(ref); err == nil {
1306
+		if id, err := daemon.referenceStore.Get(ref); err == nil {
1307 1307
 			return id, nil
1308 1308
 		}
1309
-		if tagged, ok := ref.(reference.Tagged); ok {
1309
+		if tagged, ok := ref.(reference.NamedTagged); ok {
1310 1310
 			if id, err := daemon.imageStore.Search(tagged.Tag()); err == nil {
1311
-				for _, namedRef := range daemon.tagStore.References(id) {
1311
+				for _, namedRef := range daemon.referenceStore.References(id) {
1312 1312
 					if namedRef.Name() == ref.Name() {
1313 1313
 						return id, nil
1314 1314
 					}
... ...
@@ -22,8 +22,8 @@ import (
22 22
 	"github.com/docker/docker/pkg/parsers"
23 23
 	"github.com/docker/docker/pkg/parsers/kernel"
24 24
 	"github.com/docker/docker/pkg/sysinfo"
25
+	"github.com/docker/docker/reference"
25 26
 	"github.com/docker/docker/runconfig"
26
-	"github.com/docker/docker/tag"
27 27
 	"github.com/docker/libnetwork"
28 28
 	nwconfig "github.com/docker/libnetwork/config"
29 29
 	"github.com/docker/libnetwork/drivers/bridge"
... ...
@@ -694,7 +694,7 @@ func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container
694 694
 	daemon.Unmount(container)
695 695
 }
696 696
 
697
-func restoreCustomImage(driver graphdriver.Driver, is image.Store, ls layer.Store, ts tag.Store) error {
697
+func restoreCustomImage(driver graphdriver.Driver, is image.Store, ls layer.Store, rs reference.Store) error {
698 698
 	// Unix has no custom images to register
699 699
 	return nil
700 700
 }
... ...
@@ -9,13 +9,12 @@ import (
9 9
 	"strings"
10 10
 
11 11
 	"github.com/Sirupsen/logrus"
12
-	"github.com/docker/distribution/reference"
13 12
 	"github.com/docker/docker/container"
14 13
 	"github.com/docker/docker/daemon/graphdriver"
15 14
 	"github.com/docker/docker/dockerversion"
16 15
 	"github.com/docker/docker/image"
17 16
 	"github.com/docker/docker/layer"
18
-	"github.com/docker/docker/tag"
17
+	"github.com/docker/docker/reference"
19 18
 	// register the windows graph driver
20 19
 	"github.com/docker/docker/daemon/graphdriver/windows"
21 20
 	"github.com/docker/docker/pkg/system"
... ...
@@ -153,7 +152,7 @@ func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container
153 153
 	}
154 154
 }
155 155
 
156
-func restoreCustomImage(driver graphdriver.Driver, is image.Store, ls layer.Store, ts tag.Store) error {
156
+func restoreCustomImage(driver graphdriver.Driver, is image.Store, ls layer.Store, rs reference.Store) error {
157 157
 	if wd, ok := driver.(*windows.Driver); ok {
158 158
 		imageInfos, err := wd.GetCustomImageInfos()
159 159
 		if err != nil {
... ...
@@ -206,7 +205,7 @@ func restoreCustomImage(driver graphdriver.Driver, is image.Store, ls layer.Stor
206 206
 				return err
207 207
 			}
208 208
 
209
-			if err := ts.AddTag(ref, id, true); err != nil {
209
+			if err := rs.AddTag(ref, id, true); err != nil {
210 210
 				return err
211 211
 			}
212 212
 
... ...
@@ -9,7 +9,6 @@ import (
9 9
 	"strings"
10 10
 
11 11
 	"github.com/Sirupsen/logrus"
12
-	"github.com/docker/distribution/reference"
13 12
 	"github.com/docker/docker/api"
14 13
 	"github.com/docker/docker/api/types"
15 14
 	"github.com/docker/docker/builder"
... ...
@@ -20,6 +19,7 @@ import (
20 20
 	"github.com/docker/docker/pkg/idtools"
21 21
 	"github.com/docker/docker/pkg/ioutils"
22 22
 	"github.com/docker/docker/pkg/urlutil"
23
+	"github.com/docker/docker/reference"
23 24
 	"github.com/docker/docker/registry"
24 25
 	"github.com/docker/docker/runconfig"
25 26
 )
... ...
@@ -42,8 +42,8 @@ func (d Docker) Pull(name string) (*image.Image, error) {
42 42
 		return nil, err
43 43
 	}
44 44
 	switch ref.(type) {
45
-	case reference.Tagged:
46
-	case reference.Digested:
45
+	case reference.NamedTagged:
46
+	case reference.Canonical:
47 47
 	default:
48 48
 		ref, err = reference.WithTag(ref, "latest")
49 49
 		if err != nil {
... ...
@@ -3,9 +3,8 @@ package daemon
3 3
 import (
4 4
 	"strings"
5 5
 
6
-	"github.com/docker/distribution/reference"
7 6
 	derr "github.com/docker/docker/errors"
8
-	tagpkg "github.com/docker/docker/tag"
7
+	"github.com/docker/docker/reference"
9 8
 )
10 9
 
11 10
 func (d *Daemon) imageNotExistToErrcode(err error) error {
... ...
@@ -13,12 +12,12 @@ func (d *Daemon) imageNotExistToErrcode(err error) error {
13 13
 		if strings.Contains(dne.RefOrID, "@") {
14 14
 			return derr.ErrorCodeNoSuchImageHash.WithArgs(dne.RefOrID)
15 15
 		}
16
-		tag := tagpkg.DefaultTag
16
+		tag := reference.DefaultTag
17 17
 		ref, err := reference.ParseNamed(dne.RefOrID)
18 18
 		if err != nil {
19 19
 			return derr.ErrorCodeNoSuchImageTag.WithArgs(dne.RefOrID, tag)
20 20
 		}
21
-		if tagged, isTagged := ref.(reference.Tagged); isTagged {
21
+		if tagged, isTagged := ref.(reference.NamedTagged); isTagged {
22 22
 			tag = tagged.Tag()
23 23
 		}
24 24
 		return derr.ErrorCodeNoSuchImageTag.WithArgs(ref.Name(), tag)
... ...
@@ -1,9 +1,9 @@
1 1
 package events
2 2
 
3 3
 import (
4
-	"github.com/docker/distribution/reference"
5 4
 	"github.com/docker/docker/api/types/filters"
6 5
 	"github.com/docker/docker/pkg/jsonmessage"
6
+	"github.com/docker/docker/reference"
7 7
 )
8 8
 
9 9
 // Filter can filter out docker events from a stream
... ...
@@ -4,13 +4,12 @@ import (
4 4
 	"fmt"
5 5
 	"strings"
6 6
 
7
-	"github.com/docker/distribution/reference"
8 7
 	"github.com/docker/docker/api/types"
9 8
 	"github.com/docker/docker/container"
10 9
 	derr "github.com/docker/docker/errors"
11 10
 	"github.com/docker/docker/image"
12 11
 	"github.com/docker/docker/pkg/stringid"
13
-	tagpkg "github.com/docker/docker/tag"
12
+	"github.com/docker/docker/reference"
14 13
 )
15 14
 
16 15
 // ImageDelete deletes the image referenced by the given imageRef from this
... ...
@@ -58,7 +57,7 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
58 58
 		return nil, daemon.imageNotExistToErrcode(err)
59 59
 	}
60 60
 
61
-	repoRefs := daemon.tagStore.References(imgID)
61
+	repoRefs := daemon.referenceStore.References(imgID)
62 62
 
63 63
 	var removedRepositoryRef bool
64 64
 	if !isImageIDPrefix(imgID.String(), imageRef) {
... ...
@@ -151,11 +150,11 @@ func (daemon *Daemon) getContainerUsingImage(imageID image.ID) *container.Contai
151 151
 // tag is used. Returns the resolved image reference and an error.
152 152
 func (daemon *Daemon) removeImageRef(ref reference.Named) (reference.Named, error) {
153 153
 	switch ref.(type) {
154
-	case reference.Tagged:
155
-	case reference.Digested:
154
+	case reference.NamedTagged:
155
+	case reference.Canonical:
156 156
 	default:
157 157
 		var err error
158
-		ref, err = reference.WithTag(ref, tagpkg.DefaultTag)
158
+		ref, err = reference.WithTag(ref, reference.DefaultTag)
159 159
 		if err != nil {
160 160
 			return nil, err
161 161
 		}
... ...
@@ -164,7 +163,7 @@ func (daemon *Daemon) removeImageRef(ref reference.Named) (reference.Named, erro
164 164
 	// Ignore the boolean value returned, as far as we're concerned, this
165 165
 	// is an idempotent operation and it's okay if the reference didn't
166 166
 	// exist in the first place.
167
-	_, err := daemon.tagStore.Delete(ref)
167
+	_, err := daemon.referenceStore.Delete(ref)
168 168
 
169 169
 	return ref, err
170 170
 }
... ...
@@ -175,7 +174,7 @@ func (daemon *Daemon) removeImageRef(ref reference.Named) (reference.Named, erro
175 175
 // daemon's event service. An "Untagged" types.ImageDelete is added to the
176 176
 // given list of records.
177 177
 func (daemon *Daemon) removeAllReferencesToImageID(imgID image.ID, records *[]types.ImageDelete) error {
178
-	imageRefs := daemon.tagStore.References(imgID)
178
+	imageRefs := daemon.referenceStore.References(imgID)
179 179
 
180 180
 	for _, imageRef := range imageRefs {
181 181
 		parsedRef, err := daemon.removeImageRef(imageRef)
... ...
@@ -325,7 +324,7 @@ func (daemon *Daemon) checkImageDeleteHardConflict(imgID image.ID) *imageDeleteC
325 325
 
326 326
 func (daemon *Daemon) checkImageDeleteSoftConflict(imgID image.ID) *imageDeleteConflict {
327 327
 	// Check if any repository tags/digest reference this image.
328
-	if len(daemon.tagStore.References(imgID)) > 0 {
328
+	if len(daemon.referenceStore.References(imgID)) > 0 {
329 329
 		return &imageDeleteConflict{
330 330
 			imgID:   imgID,
331 331
 			message: "image is referenced in one or more repositories",
... ...
@@ -355,5 +354,5 @@ func (daemon *Daemon) checkImageDeleteSoftConflict(imgID image.ID) *imageDeleteC
355 355
 // that there are no repository references to the given image and it has no
356 356
 // child images.
357 357
 func (daemon *Daemon) imageIsDangling(imgID image.ID) bool {
358
-	return !(len(daemon.tagStore.References(imgID)) > 0 || len(daemon.imageStore.Children(imgID)) > 0)
358
+	return !(len(daemon.referenceStore.References(imgID)) > 0 || len(daemon.imageStore.Children(imgID)) > 0)
359 359
 }
... ...
@@ -5,11 +5,11 @@ import (
5 5
 	"path"
6 6
 	"sort"
7 7
 
8
-	"github.com/docker/distribution/reference"
9 8
 	"github.com/docker/docker/api/types"
10 9
 	"github.com/docker/docker/api/types/filters"
11 10
 	"github.com/docker/docker/image"
12 11
 	"github.com/docker/docker/layer"
12
+	"github.com/docker/docker/reference"
13 13
 )
14 14
 
15 15
 var acceptedImageFilterTags = map[string]bool{
... ...
@@ -68,9 +68,9 @@ func (daemon *Daemon) Images(filterArgs, filter string, all bool) ([]*types.Imag
68 68
 
69 69
 	var filterTagged bool
70 70
 	if filter != "" {
71
-		filterRef, err := reference.Parse(filter)
71
+		filterRef, err := reference.ParseNamed(filter)
72 72
 		if err == nil { // parse error means wildcard repo
73
-			if _, ok := filterRef.(reference.Tagged); ok {
73
+			if _, ok := filterRef.(reference.NamedTagged); ok {
74 74
 				filterTagged = true
75 75
 			}
76 76
 		}
... ...
@@ -105,7 +105,7 @@ func (daemon *Daemon) Images(filterArgs, filter string, all bool) ([]*types.Imag
105 105
 
106 106
 		newImage := newImage(img, size)
107 107
 
108
-		for _, ref := range daemon.tagStore.References(id) {
108
+		for _, ref := range daemon.referenceStore.References(id) {
109 109
 			if filter != "" { // filter by tag/repo name
110 110
 				if filterTagged { // filter by tag, require full ref match
111 111
 					if ref.String() != filter {
... ...
@@ -115,10 +115,10 @@ func (daemon *Daemon) Images(filterArgs, filter string, all bool) ([]*types.Imag
115 115
 					continue
116 116
 				}
117 117
 			}
118
-			if _, ok := ref.(reference.Digested); ok {
118
+			if _, ok := ref.(reference.Canonical); ok {
119 119
 				newImage.RepoDigests = append(newImage.RepoDigests, ref.String())
120 120
 			}
121
-			if _, ok := ref.(reference.Tagged); ok {
121
+			if _, ok := ref.(reference.NamedTagged); ok {
122 122
 				newImage.RepoTags = append(newImage.RepoTags, ref.String())
123 123
 			}
124 124
 		}
... ...
@@ -8,13 +8,13 @@ import (
8 8
 	"runtime"
9 9
 	"time"
10 10
 
11
-	"github.com/docker/distribution/reference"
12 11
 	"github.com/docker/docker/dockerversion"
13 12
 	"github.com/docker/docker/image"
14 13
 	"github.com/docker/docker/layer"
15 14
 	"github.com/docker/docker/pkg/httputils"
16 15
 	"github.com/docker/docker/pkg/progress"
17 16
 	"github.com/docker/docker/pkg/streamformatter"
17
+	"github.com/docker/docker/reference"
18 18
 	"github.com/docker/docker/runconfig"
19 19
 )
20 20
 
... ...
@@ -90,7 +90,7 @@ func (daemon *Daemon) ImportImage(src string, newRef reference.Named, msg string
90 90
 		return err
91 91
 	}
92 92
 
93
-	// FIXME: connect with commit code and call tagstore directly
93
+	// FIXME: connect with commit code and call refstore directly
94 94
 	if newRef != nil {
95 95
 		if err := daemon.TagImage(newRef, id.String()); err != nil {
96 96
 			return err
... ...
@@ -6,15 +6,14 @@ import (
6 6
 	"strings"
7 7
 
8 8
 	"github.com/Sirupsen/logrus"
9
-	"github.com/docker/distribution/reference"
10 9
 	"github.com/docker/docker/api/types"
11 10
 	"github.com/docker/docker/daemon/events"
12 11
 	"github.com/docker/docker/distribution/metadata"
13 12
 	"github.com/docker/docker/distribution/xfer"
14 13
 	"github.com/docker/docker/image"
15 14
 	"github.com/docker/docker/pkg/progress"
15
+	"github.com/docker/docker/reference"
16 16
 	"github.com/docker/docker/registry"
17
-	"github.com/docker/docker/tag"
18 17
 	"golang.org/x/net/context"
19 18
 )
20 19
 
... ...
@@ -39,8 +38,8 @@ type ImagePullConfig struct {
39 39
 	MetadataStore metadata.Store
40 40
 	// ImageStore manages images.
41 41
 	ImageStore image.Store
42
-	// TagStore manages tags.
43
-	TagStore tag.Store
42
+	// ReferenceStore manages tags.
43
+	ReferenceStore reference.Store
44 44
 	// DownloadManager manages concurrent pulls.
45 45
 	DownloadManager *xfer.LayerDownloadManager
46 46
 }
... ...
@@ -11,7 +11,6 @@ import (
11 11
 	"time"
12 12
 
13 13
 	"github.com/Sirupsen/logrus"
14
-	"github.com/docker/distribution/reference"
15 14
 	"github.com/docker/distribution/registry/client/transport"
16 15
 	"github.com/docker/docker/distribution/metadata"
17 16
 	"github.com/docker/docker/distribution/xfer"
... ...
@@ -21,6 +20,7 @@ import (
21 21
 	"github.com/docker/docker/pkg/ioutils"
22 22
 	"github.com/docker/docker/pkg/progress"
23 23
 	"github.com/docker/docker/pkg/stringid"
24
+	"github.com/docker/docker/reference"
24 25
 	"github.com/docker/docker/registry"
25 26
 	"golang.org/x/net/context"
26 27
 )
... ...
@@ -34,7 +34,7 @@ type v1Puller struct {
34 34
 }
35 35
 
36 36
 func (p *v1Puller) Pull(ctx context.Context, ref reference.Named) (fallback bool, err error) {
37
-	if _, isDigested := ref.(reference.Digested); isDigested {
37
+	if _, isCanonical := ref.(reference.Canonical); isCanonical {
38 38
 		// Allowing fallback, because HTTPS v1 is before HTTP v2
39 39
 		return true, registry.ErrNoSupport{Err: errors.New("Cannot pull by digest with v1 registry")}
40 40
 	}
... ...
@@ -84,7 +84,7 @@ func (p *v1Puller) pullRepository(ctx context.Context, ref reference.Named) erro
84 84
 
85 85
 	logrus.Debugf("Retrieving the tag list")
86 86
 	var tagsList map[string]string
87
-	tagged, isTagged := ref.(reference.Tagged)
87
+	tagged, isTagged := ref.(reference.NamedTagged)
88 88
 	if !isTagged {
89 89
 		tagsList, err = p.session.GetRemoteTags(repoData.Endpoints, p.repoInfo.RemoteName)
90 90
 	} else {
... ...
@@ -250,7 +250,7 @@ func (p *v1Puller) pullImage(ctx context.Context, v1ID, endpoint string, localNa
250 250
 		return err
251 251
 	}
252 252
 
253
-	if err := p.config.TagStore.AddTag(localNameRef, imageID, true); err != nil {
253
+	if err := p.config.ReferenceStore.AddTag(localNameRef, imageID, true); err != nil {
254 254
 		return err
255 255
 	}
256 256
 
... ...
@@ -13,7 +13,6 @@ import (
13 13
 	"github.com/docker/distribution"
14 14
 	"github.com/docker/distribution/digest"
15 15
 	"github.com/docker/distribution/manifest/schema1"
16
-	"github.com/docker/distribution/reference"
17 16
 	"github.com/docker/docker/distribution/metadata"
18 17
 	"github.com/docker/docker/distribution/xfer"
19 18
 	"github.com/docker/docker/image"
... ...
@@ -22,6 +21,7 @@ import (
22 22
 	"github.com/docker/docker/pkg/ioutils"
23 23
 	"github.com/docker/docker/pkg/progress"
24 24
 	"github.com/docker/docker/pkg/stringid"
25
+	"github.com/docker/docker/reference"
25 26
 	"github.com/docker/docker/registry"
26 27
 	"golang.org/x/net/context"
27 28
 )
... ...
@@ -55,13 +55,13 @@ func (p *v2Puller) Pull(ctx context.Context, ref reference.Named) (fallback bool
55 55
 func (p *v2Puller) pullV2Repository(ctx context.Context, ref reference.Named) (err error) {
56 56
 	var refs []reference.Named
57 57
 	taggedName := p.repoInfo.LocalName
58
-	if tagged, isTagged := ref.(reference.Tagged); isTagged {
58
+	if tagged, isTagged := ref.(reference.NamedTagged); isTagged {
59 59
 		taggedName, err = reference.WithTag(p.repoInfo.LocalName, tagged.Tag())
60 60
 		if err != nil {
61 61
 			return err
62 62
 		}
63 63
 		refs = []reference.Named{taggedName}
64
-	} else if digested, isDigested := ref.(reference.Digested); isDigested {
64
+	} else if digested, isCanonical := ref.(reference.Canonical); isCanonical {
65 65
 		taggedName, err = reference.WithDigest(p.repoInfo.LocalName, digested.Digest())
66 66
 		if err != nil {
67 67
 			return err
... ...
@@ -197,9 +197,9 @@ func (ld *v2LayerDescriptor) Registered(diffID layer.DiffID) {
197 197
 
198 198
 func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named) (tagUpdated bool, err error) {
199 199
 	tagOrDigest := ""
200
-	if tagged, isTagged := ref.(reference.Tagged); isTagged {
200
+	if tagged, isTagged := ref.(reference.NamedTagged); isTagged {
201 201
 		tagOrDigest = tagged.Tag()
202
-	} else if digested, isDigested := ref.(reference.Digested); isDigested {
202
+	} else if digested, isCanonical := ref.(reference.Canonical); isCanonical {
203 203
 		tagOrDigest = digested.Digest().String()
204 204
 	} else {
205 205
 		return false, fmt.Errorf("internal error: reference has neither a tag nor a digest: %s", ref.String())
... ...
@@ -300,27 +300,27 @@ func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named) (tagUpdat
300 300
 		progress.Message(p.config.ProgressOutput, "", "Digest: "+manifestDigest.String())
301 301
 	}
302 302
 
303
-	oldTagImageID, err := p.config.TagStore.Get(ref)
303
+	oldTagImageID, err := p.config.ReferenceStore.Get(ref)
304 304
 	if err == nil && oldTagImageID == imageID {
305 305
 		return false, nil
306 306
 	}
307 307
 
308 308
 	if canonical, ok := ref.(reference.Canonical); ok {
309
-		if err = p.config.TagStore.AddDigest(canonical, imageID, true); err != nil {
309
+		if err = p.config.ReferenceStore.AddDigest(canonical, imageID, true); err != nil {
310 310
 			return false, err
311 311
 		}
312
-	} else if err = p.config.TagStore.AddTag(ref, imageID, true); err != nil {
312
+	} else if err = p.config.ReferenceStore.AddTag(ref, imageID, true); err != nil {
313 313
 		return false, err
314 314
 	}
315 315
 
316 316
 	return true, nil
317 317
 }
318 318
 
319
-func verifyManifest(signedManifest *schema1.SignedManifest, ref reference.Reference) (m *schema1.Manifest, err error) {
319
+func verifyManifest(signedManifest *schema1.SignedManifest, ref reference.Named) (m *schema1.Manifest, err error) {
320 320
 	// If pull by digest, then verify the manifest digest. NOTE: It is
321 321
 	// important to do this first, before any other content validation. If the
322 322
 	// digest cannot be verified, don't even bother with those other things.
323
-	if digested, isDigested := ref.(reference.Digested); isDigested {
323
+	if digested, isCanonical := ref.(reference.Canonical); isCanonical {
324 324
 		verifier, err := digest.NewDigestVerifier(digested.Digest())
325 325
 		if err != nil {
326 326
 			return nil, err
... ...
@@ -9,7 +9,7 @@ import (
9 9
 
10 10
 	"github.com/docker/distribution/digest"
11 11
 	"github.com/docker/distribution/manifest/schema1"
12
-	"github.com/docker/distribution/reference"
12
+	"github.com/docker/docker/reference"
13 13
 )
14 14
 
15 15
 // TestFixManifestLayers checks that fixManifestLayers removes a duplicate
... ...
@@ -104,7 +104,7 @@ func TestFixManifestLayersBadParent(t *testing.T) {
104 104
 
105 105
 // TestValidateManifest verifies the validateManifest function
106 106
 func TestValidateManifest(t *testing.T) {
107
-	expectedDigest, err := reference.Parse("repo@sha256:02fee8c3220ba806531f606525eceb83f4feb654f62b207191b1c9209188dedd")
107
+	expectedDigest, err := reference.ParseNamed("repo@sha256:02fee8c3220ba806531f606525eceb83f4feb654f62b207191b1c9209188dedd")
108 108
 	if err != nil {
109 109
 		t.Fatal("could not parse reference")
110 110
 	}
... ...
@@ -8,7 +8,6 @@ import (
8 8
 
9 9
 	"github.com/Sirupsen/logrus"
10 10
 	"github.com/docker/distribution/digest"
11
-	"github.com/docker/distribution/reference"
12 11
 	"github.com/docker/docker/api/types"
13 12
 	"github.com/docker/docker/daemon/events"
14 13
 	"github.com/docker/docker/distribution/metadata"
... ...
@@ -16,8 +15,8 @@ import (
16 16
 	"github.com/docker/docker/image"
17 17
 	"github.com/docker/docker/layer"
18 18
 	"github.com/docker/docker/pkg/progress"
19
+	"github.com/docker/docker/reference"
19 20
 	"github.com/docker/docker/registry"
20
-	"github.com/docker/docker/tag"
21 21
 	"github.com/docker/libtrust"
22 22
 	"golang.org/x/net/context"
23 23
 )
... ...
@@ -45,8 +44,8 @@ type ImagePushConfig struct {
45 45
 	LayerStore layer.Store
46 46
 	// ImageStore manages images.
47 47
 	ImageStore image.Store
48
-	// TagStore manages tags.
49
-	TagStore tag.Store
48
+	// ReferenceStore manages tags.
49
+	ReferenceStore reference.Store
50 50
 	// TrustKey is the private key for legacy signatures. This is typically
51 51
 	// an ephemeral key, since these signatures are no longer verified.
52 52
 	TrustKey libtrust.PrivateKey
... ...
@@ -112,7 +111,7 @@ func Push(ctx context.Context, ref reference.Named, imagePushConfig *ImagePushCo
112 112
 
113 113
 	progress.Messagef(imagePushConfig.ProgressOutput, "", "The push refers to a repository [%s]", repoInfo.CanonicalName.String())
114 114
 
115
-	associations := imagePushConfig.TagStore.ReferencesByName(repoInfo.LocalName)
115
+	associations := imagePushConfig.ReferenceStore.ReferencesByName(repoInfo.LocalName)
116 116
 	if len(associations) == 0 {
117 117
 		return fmt.Errorf("Repository does not exist: %s", repoInfo.LocalName)
118 118
 	}
... ...
@@ -6,7 +6,6 @@ import (
6 6
 
7 7
 	"github.com/Sirupsen/logrus"
8 8
 	"github.com/docker/distribution/digest"
9
-	"github.com/docker/distribution/reference"
10 9
 	"github.com/docker/distribution/registry/client/transport"
11 10
 	"github.com/docker/docker/distribution/metadata"
12 11
 	"github.com/docker/docker/image"
... ...
@@ -15,6 +14,7 @@ import (
15 15
 	"github.com/docker/docker/pkg/ioutils"
16 16
 	"github.com/docker/docker/pkg/progress"
17 17
 	"github.com/docker/docker/pkg/stringid"
18
+	"github.com/docker/docker/reference"
18 19
 	"github.com/docker/docker/registry"
19 20
 	"golang.org/x/net/context"
20 21
 )
... ...
@@ -141,16 +141,15 @@ func (p *v1Pusher) getImageList() (imageList []v1Image, tagsByImage map[image.ID
141 141
 	tagsByImage = make(map[image.ID][]string)
142 142
 
143 143
 	// Ignore digest references
144
-	_, isDigested := p.ref.(reference.Digested)
145
-	if isDigested {
144
+	if _, isCanonical := p.ref.(reference.Canonical); isCanonical {
146 145
 		return
147 146
 	}
148 147
 
149
-	tagged, isTagged := p.ref.(reference.Tagged)
148
+	tagged, isTagged := p.ref.(reference.NamedTagged)
150 149
 	if isTagged {
151 150
 		// Push a specific tag
152 151
 		var imgID image.ID
153
-		imgID, err = p.config.TagStore.Get(p.ref)
152
+		imgID, err = p.config.ReferenceStore.Get(p.ref)
154 153
 		if err != nil {
155 154
 			return
156 155
 		}
... ...
@@ -168,9 +167,9 @@ func (p *v1Pusher) getImageList() (imageList []v1Image, tagsByImage map[image.ID
168 168
 	imagesSeen := make(map[image.ID]struct{})
169 169
 	dependenciesSeen := make(map[layer.ChainID]*v1DependencyImage)
170 170
 
171
-	associations := p.config.TagStore.ReferencesByName(p.ref)
171
+	associations := p.config.ReferenceStore.ReferencesByName(p.ref)
172 172
 	for _, association := range associations {
173
-		if tagged, isTagged = association.Ref.(reference.Tagged); !isTagged {
173
+		if tagged, isTagged = association.Ref.(reference.NamedTagged); !isTagged {
174 174
 			// Ignore digest references.
175 175
 			continue
176 176
 		}
... ...
@@ -13,7 +13,6 @@ import (
13 13
 	"github.com/docker/distribution/digest"
14 14
 	"github.com/docker/distribution/manifest"
15 15
 	"github.com/docker/distribution/manifest/schema1"
16
-	"github.com/docker/distribution/reference"
17 16
 	"github.com/docker/docker/distribution/metadata"
18 17
 	"github.com/docker/docker/distribution/xfer"
19 18
 	"github.com/docker/docker/image"
... ...
@@ -22,8 +21,8 @@ import (
22 22
 	"github.com/docker/docker/pkg/ioutils"
23 23
 	"github.com/docker/docker/pkg/progress"
24 24
 	"github.com/docker/docker/pkg/stringid"
25
+	"github.com/docker/docker/reference"
25 26
 	"github.com/docker/docker/registry"
26
-	"github.com/docker/docker/tag"
27 27
 	"golang.org/x/net/context"
28 28
 )
29 29
 
... ...
@@ -55,14 +54,14 @@ func (p *v2Pusher) Push(ctx context.Context) (fallback bool, err error) {
55 55
 
56 56
 	localName := p.repoInfo.LocalName.Name()
57 57
 
58
-	var associations []tag.Association
59
-	if _, isTagged := p.ref.(reference.Tagged); isTagged {
60
-		imageID, err := p.config.TagStore.Get(p.ref)
58
+	var associations []reference.Association
59
+	if _, isTagged := p.ref.(reference.NamedTagged); isTagged {
60
+		imageID, err := p.config.ReferenceStore.Get(p.ref)
61 61
 		if err != nil {
62 62
 			return false, fmt.Errorf("tag does not exist: %s", p.ref.String())
63 63
 		}
64 64
 
65
-		associations = []tag.Association{
65
+		associations = []reference.Association{
66 66
 			{
67 67
 				Ref:     p.ref,
68 68
 				ImageID: imageID,
... ...
@@ -70,7 +69,7 @@ func (p *v2Pusher) Push(ctx context.Context) (fallback bool, err error) {
70 70
 		}
71 71
 	} else {
72 72
 		// Pull all tags
73
-		associations = p.config.TagStore.ReferencesByName(p.ref)
73
+		associations = p.config.ReferenceStore.ReferencesByName(p.ref)
74 74
 	}
75 75
 	if err != nil {
76 76
 		return false, fmt.Errorf("error getting tags for %s: %s", localName, err)
... ...
@@ -88,7 +87,7 @@ func (p *v2Pusher) Push(ctx context.Context) (fallback bool, err error) {
88 88
 	return false, nil
89 89
 }
90 90
 
91
-func (p *v2Pusher) pushV2Tag(ctx context.Context, association tag.Association) error {
91
+func (p *v2Pusher) pushV2Tag(ctx context.Context, association reference.Association) error {
92 92
 	ref := association.Ref
93 93
 	logrus.Debugf("Pushing repository: %s", ref.String())
94 94
 
... ...
@@ -146,7 +145,7 @@ func (p *v2Pusher) pushV2Tag(ctx context.Context, association tag.Association) e
146 146
 	}
147 147
 
148 148
 	var tag string
149
-	if tagged, isTagged := ref.(reference.Tagged); isTagged {
149
+	if tagged, isTagged := ref.(reference.NamedTagged); isTagged {
150 150
 		tag = tagged.Tag()
151 151
 	}
152 152
 	m, err := CreateV2Manifest(p.repo.Name(), tag, img, fsLayers)
... ...
@@ -165,7 +164,7 @@ func (p *v2Pusher) pushV2Tag(ctx context.Context, association tag.Association) e
165 165
 		return err
166 166
 	}
167 167
 	if manifestDigest != "" {
168
-		if tagged, isTagged := ref.(reference.Tagged); isTagged {
168
+		if tagged, isTagged := ref.(reference.NamedTagged); isTagged {
169 169
 			// NOTE: do not change this format without first changing the trust client
170 170
 			// code. This information is used to determine what was pushed and should be signed.
171 171
 			progress.Messagef(p.config.ProgressOutput, "", "%s: digest: %s size: %d", tagged.Tag(), manifestDigest, manifestSize)
... ...
@@ -8,10 +8,10 @@ import (
8 8
 	"testing"
9 9
 
10 10
 	"github.com/Sirupsen/logrus"
11
-	"github.com/docker/distribution/reference"
12 11
 	"github.com/docker/distribution/registry/client/auth"
13 12
 	"github.com/docker/docker/api/types"
14 13
 	registrytypes "github.com/docker/docker/api/types/registry"
14
+	"github.com/docker/docker/reference"
15 15
 	"github.com/docker/docker/registry"
16 16
 	"github.com/docker/docker/utils"
17 17
 	"golang.org/x/net/context"
... ...
@@ -9,13 +9,13 @@ import (
9 9
 	"path/filepath"
10 10
 
11 11
 	"github.com/Sirupsen/logrus"
12
-	"github.com/docker/distribution/reference"
13 12
 	"github.com/docker/docker/image"
14 13
 	"github.com/docker/docker/image/v1"
15 14
 	"github.com/docker/docker/layer"
16 15
 	"github.com/docker/docker/pkg/archive"
17 16
 	"github.com/docker/docker/pkg/chrootarchive"
18 17
 	"github.com/docker/docker/pkg/symlink"
18
+	"github.com/docker/docker/reference"
19 19
 )
20 20
 
21 21
 func (l *tarexporter) Load(inTar io.ReadCloser, outStream io.Writer) error {
... ...
@@ -124,11 +124,11 @@ func (l *tarexporter) loadLayer(filename string, rootFS image.RootFS) (layer.Lay
124 124
 }
125 125
 
126 126
 func (l *tarexporter) setLoadedTag(ref reference.NamedTagged, imgID image.ID, outStream io.Writer) error {
127
-	if prevID, err := l.ts.Get(ref); err == nil && prevID != imgID {
127
+	if prevID, err := l.rs.Get(ref); err == nil && prevID != imgID {
128 128
 		fmt.Fprintf(outStream, "The image %s already exists, renaming the old one with ID %s to empty string\n", ref.String(), string(prevID)) // todo: this message is wrong in case of multiple tags
129 129
 	}
130 130
 
131
-	if err := l.ts.AddTag(ref, imgID, true); err != nil {
131
+	if err := l.rs.AddTag(ref, imgID, true); err != nil {
132 132
 		return err
133 133
 	}
134 134
 	return nil
... ...
@@ -10,13 +10,12 @@ import (
10 10
 	"time"
11 11
 
12 12
 	"github.com/docker/distribution/digest"
13
-	"github.com/docker/distribution/reference"
14 13
 	"github.com/docker/docker/image"
15 14
 	"github.com/docker/docker/image/v1"
16 15
 	"github.com/docker/docker/layer"
17 16
 	"github.com/docker/docker/pkg/archive"
17
+	"github.com/docker/docker/reference"
18 18
 	"github.com/docker/docker/registry"
19
-	"github.com/docker/docker/tag"
20 19
 )
21 20
 
22 21
 type imageDescriptor struct {
... ...
@@ -50,13 +49,13 @@ func (l *tarexporter) parseNames(names []string) (map[image.ID]*imageDescriptor,
50 50
 
51 51
 		if ref != nil {
52 52
 			var tagged reference.NamedTagged
53
-			if _, ok := ref.(reference.Digested); ok {
53
+			if _, ok := ref.(reference.Canonical); ok {
54 54
 				return
55 55
 			}
56 56
 			var ok bool
57 57
 			if tagged, ok = ref.(reference.NamedTagged); !ok {
58 58
 				var err error
59
-				if tagged, err = reference.WithTag(ref, tag.DefaultTag); err != nil {
59
+				if tagged, err = reference.WithTag(ref, reference.DefaultTag); err != nil {
60 60
 					return
61 61
 				}
62 62
 			}
... ...
@@ -84,9 +83,9 @@ func (l *tarexporter) parseNames(names []string) (map[image.ID]*imageDescriptor,
84 84
 			addAssoc(imgID, nil)
85 85
 			continue
86 86
 		}
87
-		if _, ok := ref.(reference.Digested); !ok {
87
+		if _, ok := ref.(reference.Canonical); !ok {
88 88
 			if _, ok := ref.(reference.NamedTagged); !ok {
89
-				assocs := l.ts.ReferencesByName(ref)
89
+				assocs := l.rs.ReferencesByName(ref)
90 90
 				for _, assoc := range assocs {
91 91
 					addAssoc(assoc.ImageID, assoc.Ref)
92 92
 				}
... ...
@@ -101,7 +100,7 @@ func (l *tarexporter) parseNames(names []string) (map[image.ID]*imageDescriptor,
101 101
 			}
102 102
 		}
103 103
 		var imgID image.ID
104
-		if imgID, err = l.ts.Get(ref); err != nil {
104
+		if imgID, err = l.rs.Get(ref); err != nil {
105 105
 			return nil, err
106 106
 		}
107 107
 		addAssoc(imgID, ref)
... ...
@@ -3,7 +3,7 @@ package tarexport
3 3
 import (
4 4
 	"github.com/docker/docker/image"
5 5
 	"github.com/docker/docker/layer"
6
-	"github.com/docker/docker/tag"
6
+	"github.com/docker/docker/reference"
7 7
 )
8 8
 
9 9
 const (
... ...
@@ -23,14 +23,14 @@ type manifestItem struct {
23 23
 type tarexporter struct {
24 24
 	is image.Store
25 25
 	ls layer.Store
26
-	ts tag.Store
26
+	rs reference.Store
27 27
 }
28 28
 
29 29
 // NewTarExporter returns new ImageExporter for tar packages
30
-func NewTarExporter(is image.Store, ls layer.Store, ts tag.Store) image.Exporter {
30
+func NewTarExporter(is image.Store, ls layer.Store, rs reference.Store) image.Exporter {
31 31
 	return &tarexporter{
32 32
 		is: is,
33 33
 		ls: ls,
34
-		ts: ts,
34
+		rs: rs,
35 35
 	}
36 36
 }
... ...
@@ -11,12 +11,11 @@ import (
11 11
 
12 12
 	"github.com/Sirupsen/logrus"
13 13
 	"github.com/docker/distribution/digest"
14
-	"github.com/docker/distribution/reference"
15 14
 	"github.com/docker/docker/distribution/metadata"
16 15
 	"github.com/docker/docker/image"
17 16
 	imagev1 "github.com/docker/docker/image/v1"
18 17
 	"github.com/docker/docker/layer"
19
-	"github.com/docker/docker/tag"
18
+	"github.com/docker/docker/reference"
20 19
 )
21 20
 
22 21
 type graphIDRegistrar interface {
... ...
@@ -46,7 +45,7 @@ var (
46 46
 
47 47
 // Migrate takes an old graph directory and transforms the metadata into the
48 48
 // new format.
49
-func Migrate(root, driverName string, ls layer.Store, is image.Store, ts tag.Store, ms metadata.Store) error {
49
+func Migrate(root, driverName string, ls layer.Store, is image.Store, rs reference.Store, ms metadata.Store) error {
50 50
 	mappings := make(map[string]image.ID)
51 51
 
52 52
 	if registrar, ok := ls.(graphIDRegistrar); !ok {
... ...
@@ -61,7 +60,7 @@ func Migrate(root, driverName string, ls layer.Store, is image.Store, ts tag.Sto
61 61
 		return err
62 62
 	}
63 63
 
64
-	if err := migrateTags(root, driverName, ts, mappings); err != nil {
64
+	if err := migrateRefs(root, driverName, rs, mappings); err != nil {
65 65
 		return err
66 66
 	}
67 67
 
... ...
@@ -189,12 +188,12 @@ func migrateContainers(root string, ls graphIDMounter, is image.Store, imageMapp
189 189
 	return nil
190 190
 }
191 191
 
192
-type tagAdder interface {
192
+type refAdder interface {
193 193
 	AddTag(ref reference.Named, id image.ID, force bool) error
194 194
 	AddDigest(ref reference.Canonical, id image.ID, force bool) error
195 195
 }
196 196
 
197
-func migrateTags(root, driverName string, ts tagAdder, mappings map[string]image.ID) error {
197
+func migrateRefs(root, driverName string, rs refAdder, mappings map[string]image.ID) error {
198 198
 	migrationFile := filepath.Join(root, migrationTagsFileName)
199 199
 	if _, err := os.Lstat(migrationFile); !os.IsNotExist(err) {
200 200
 		return err
... ...
@@ -232,7 +231,7 @@ func migrateTags(root, driverName string, ts tagAdder, mappings map[string]image
232 232
 						logrus.Errorf("migrate tags: invalid digest %q, %q", dgst, err)
233 233
 						continue
234 234
 					}
235
-					if err := ts.AddDigest(canonical, strongID, false); err != nil {
235
+					if err := rs.AddDigest(canonical, strongID, false); err != nil {
236 236
 						logrus.Errorf("can't migrate digest %q for %q, err: %q", ref.String(), strongID, err)
237 237
 					}
238 238
 				} else {
... ...
@@ -241,7 +240,7 @@ func migrateTags(root, driverName string, ts tagAdder, mappings map[string]image
241 241
 						logrus.Errorf("migrate tags: invalid tag %q, %q", tag, err)
242 242
 						continue
243 243
 					}
244
-					if err := ts.AddTag(tagRef, strongID, false); err != nil {
244
+					if err := rs.AddTag(tagRef, strongID, false); err != nil {
245 245
 						logrus.Errorf("can't migrate tag %q for %q, err: %q", ref.String(), strongID, err)
246 246
 					}
247 247
 				}
... ...
@@ -13,13 +13,13 @@ import (
13 13
 	"testing"
14 14
 
15 15
 	"github.com/docker/distribution/digest"
16
-	"github.com/docker/distribution/reference"
17 16
 	"github.com/docker/docker/distribution/metadata"
18 17
 	"github.com/docker/docker/image"
19 18
 	"github.com/docker/docker/layer"
19
+	"github.com/docker/docker/reference"
20 20
 )
21 21
 
22
-func TestMigrateTags(t *testing.T) {
22
+func TestMigrateRefs(t *testing.T) {
23 23
 	tmpdir, err := ioutil.TempDir("", "migrate-tags")
24 24
 	if err != nil {
25 25
 		t.Fatal(err)
... ...
@@ -29,7 +29,7 @@ func TestMigrateTags(t *testing.T) {
29 29
 	ioutil.WriteFile(filepath.Join(tmpdir, "repositories-generic"), []byte(`{"Repositories":{"busybox":{"latest":"b3ca410aa2c115c05969a7b2c8cf8a9fcf62c1340ed6a601c9ee50df337ec108","sha256:16a2a52884c2a9481ed267c2d46483eac7693b813a63132368ab098a71303f8a":"b3ca410aa2c115c05969a7b2c8cf8a9fcf62c1340ed6a601c9ee50df337ec108"},"registry":{"2":"5d165b8e4b203685301c815e95663231691d383fd5e3d3185d1ce3f8dddead3d","latest":"8d5547a9f329b1d3f93198cd661fb5117e5a96b721c5cf9a2c389e7dd4877128"}}}`), 0600)
30 30
 
31 31
 	ta := &mockTagAdder{}
32
-	err = migrateTags(tmpdir, "generic", ta, map[string]image.ID{
32
+	err = migrateRefs(tmpdir, "generic", ta, map[string]image.ID{
33 33
 		"5d165b8e4b203685301c815e95663231691d383fd5e3d3185d1ce3f8dddead3d": image.ID("sha256:2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"),
34 34
 		"b3ca410aa2c115c05969a7b2c8cf8a9fcf62c1340ed6a601c9ee50df337ec108": image.ID("sha256:fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9"),
35 35
 		"abcdef3434c115c05969a7b2c8cf8a9fcf62c1340ed6a601c9ee50df337ec108": image.ID("sha256:56434342345ae68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"),
... ...
@@ -50,7 +50,7 @@ func TestMigrateTags(t *testing.T) {
50 50
 
51 51
 	// second migration is no-op
52 52
 	ioutil.WriteFile(filepath.Join(tmpdir, "repositories-generic"), []byte(`{"Repositories":{"busybox":{"latest":"b3ca410aa2c115c05969a7b2c8cf8a9fcf62c1340ed6a601c9ee50df337ec108"`), 0600)
53
-	err = migrateTags(tmpdir, "generic", ta, map[string]image.ID{
53
+	err = migrateRefs(tmpdir, "generic", ta, map[string]image.ID{
54 54
 		"b3ca410aa2c115c05969a7b2c8cf8a9fcf62c1340ed6a601c9ee50df337ec108": image.ID("sha256:fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9"),
55 55
 	})
56 56
 	if err != nil {
57 57
new file mode 100644
... ...
@@ -0,0 +1,60 @@
0
+package reference
1
+
2
+import (
3
+	"github.com/docker/distribution/digest"
4
+	distreference "github.com/docker/distribution/reference"
5
+)
6
+
7
+// Reference is an opaque object reference identifier that may include
8
+// modifiers such as a hostname, name, tag, and digest.
9
+type Reference interface {
10
+	// String returns the full reference
11
+	String() string
12
+}
13
+
14
+// Named is an object with a full name
15
+type Named interface {
16
+	Reference
17
+	Name() string
18
+}
19
+
20
+// NamedTagged is an object including a name and tag.
21
+type NamedTagged interface {
22
+	Named
23
+	Tag() string
24
+}
25
+
26
+// Canonical reference is an object with a fully unique
27
+// name including a name with hostname and digest
28
+type Canonical interface {
29
+	Named
30
+	Digest() digest.Digest
31
+}
32
+
33
+// ParseNamed parses s and returns a syntactically valid reference implementing
34
+// the Named interface. The reference must have a name, otherwise an error is
35
+// returned.
36
+// If an error was encountered it is returned, along with a nil Reference.
37
+// NOTE: ParseNamed will not handle short digests.
38
+func ParseNamed(s string) (Named, error) {
39
+	// todo: docker specific validation
40
+	return distreference.ParseNamed(s)
41
+}
42
+
43
+// WithName returns a named object representing the given string. If the input
44
+// is invalid ErrReferenceInvalidFormat will be returned.
45
+func WithName(name string) (Named, error) {
46
+	return distreference.WithName(name)
47
+}
48
+
49
+// WithTag combines the name from "name" and the tag from "tag" to form a
50
+// reference incorporating both the name and the tag.
51
+func WithTag(name Named, tag string) (NamedTagged, error) {
52
+	return distreference.WithTag(name, tag)
53
+}
54
+
55
+// WithDigest combines the name from "name" and the digest from "digest" to form
56
+// a reference incorporating both the name and the digest.
57
+func WithDigest(name Named, digest digest.Digest) (Canonical, error) {
58
+	return distreference.WithDigest(name, digest)
59
+}
0 60
new file mode 100644
... ...
@@ -0,0 +1,314 @@
0
+package reference
1
+
2
+import (
3
+	"encoding/json"
4
+	"errors"
5
+	"fmt"
6
+	"io/ioutil"
7
+	"os"
8
+	"path/filepath"
9
+	"sort"
10
+	"sync"
11
+
12
+	"github.com/docker/distribution/digest"
13
+	"github.com/docker/docker/image"
14
+)
15
+
16
+// DefaultTag defines the default tag used when performing images related actions and no tag string is specified
17
+const DefaultTag = "latest"
18
+
19
+var (
20
+	// ErrDoesNotExist is returned if a reference is not found in the
21
+	// store.
22
+	ErrDoesNotExist = errors.New("reference does not exist")
23
+)
24
+
25
+// An Association is a tuple associating a reference with an image ID.
26
+type Association struct {
27
+	Ref     Named
28
+	ImageID image.ID
29
+}
30
+
31
+// Store provides the set of methods which can operate on a tag store.
32
+type Store interface {
33
+	References(id image.ID) []Named
34
+	ReferencesByName(ref Named) []Association
35
+	AddTag(ref Named, id image.ID, force bool) error
36
+	AddDigest(ref Canonical, id image.ID, force bool) error
37
+	Delete(ref Named) (bool, error)
38
+	Get(ref Named) (image.ID, error)
39
+}
40
+
41
+type store struct {
42
+	mu sync.RWMutex
43
+	// jsonPath is the path to the file where the serialized tag data is
44
+	// stored.
45
+	jsonPath string
46
+	// Repositories is a map of repositories, indexed by name.
47
+	Repositories map[string]repository
48
+	// referencesByIDCache is a cache of references indexed by ID, to speed
49
+	// up References.
50
+	referencesByIDCache map[image.ID]map[string]Named
51
+}
52
+
53
+// Repository maps tags to image IDs. The key is a a stringified Reference,
54
+// including the repository name.
55
+type repository map[string]image.ID
56
+
57
+type lexicalRefs []Named
58
+
59
+func (a lexicalRefs) Len() int           { return len(a) }
60
+func (a lexicalRefs) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
61
+func (a lexicalRefs) Less(i, j int) bool { return a[i].String() < a[j].String() }
62
+
63
+type lexicalAssociations []Association
64
+
65
+func (a lexicalAssociations) Len() int           { return len(a) }
66
+func (a lexicalAssociations) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
67
+func (a lexicalAssociations) Less(i, j int) bool { return a[i].Ref.String() < a[j].Ref.String() }
68
+
69
+func defaultTagIfNameOnly(ref Named) Named {
70
+	switch ref.(type) {
71
+	case NamedTagged:
72
+		return ref
73
+	case Canonical:
74
+		return ref
75
+	default:
76
+		// Should never fail
77
+		ref, _ = WithTag(ref, DefaultTag)
78
+		return ref
79
+	}
80
+}
81
+
82
+// NewReferenceStore creates a new reference store, tied to a file path where
83
+// the set of references are serialized in JSON format.
84
+func NewReferenceStore(jsonPath string) (Store, error) {
85
+	abspath, err := filepath.Abs(jsonPath)
86
+	if err != nil {
87
+		return nil, err
88
+	}
89
+
90
+	store := &store{
91
+		jsonPath:            abspath,
92
+		Repositories:        make(map[string]repository),
93
+		referencesByIDCache: make(map[image.ID]map[string]Named),
94
+	}
95
+	// Load the json file if it exists, otherwise create it.
96
+	if err := store.reload(); os.IsNotExist(err) {
97
+		if err := store.save(); err != nil {
98
+			return nil, err
99
+		}
100
+	} else if err != nil {
101
+		return nil, err
102
+	}
103
+	return store, nil
104
+}
105
+
106
+// AddTag adds a tag reference to the store. If force is set to true, existing
107
+// references can be overwritten. This only works for tags, not digests.
108
+func (store *store) AddTag(ref Named, id image.ID, force bool) error {
109
+	if _, isCanonical := ref.(Canonical); isCanonical {
110
+		return errors.New("refusing to create a tag with a digest reference")
111
+	}
112
+	return store.addReference(defaultTagIfNameOnly(ref), id, force)
113
+}
114
+
115
+// AddDigest adds a digest reference to the store.
116
+func (store *store) AddDigest(ref Canonical, id image.ID, force bool) error {
117
+	return store.addReference(ref, id, force)
118
+}
119
+
120
+func (store *store) addReference(ref Named, id image.ID, force bool) error {
121
+	if ref.Name() == string(digest.Canonical) {
122
+		return errors.New("refusing to create an ambiguous tag using digest algorithm as name")
123
+	}
124
+
125
+	store.mu.Lock()
126
+	defer store.mu.Unlock()
127
+
128
+	repository, exists := store.Repositories[ref.Name()]
129
+	if !exists || repository == nil {
130
+		repository = make(map[string]image.ID)
131
+		store.Repositories[ref.Name()] = repository
132
+	}
133
+
134
+	refStr := ref.String()
135
+	oldID, exists := repository[refStr]
136
+
137
+	if exists {
138
+		// force only works for tags
139
+		if digested, isDigest := ref.(Canonical); isDigest {
140
+			return fmt.Errorf("Cannot overwrite digest %s", digested.Digest().String())
141
+		}
142
+
143
+		if !force {
144
+			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())
145
+		}
146
+
147
+		if store.referencesByIDCache[oldID] != nil {
148
+			delete(store.referencesByIDCache[oldID], refStr)
149
+			if len(store.referencesByIDCache[oldID]) == 0 {
150
+				delete(store.referencesByIDCache, oldID)
151
+			}
152
+		}
153
+	}
154
+
155
+	repository[refStr] = id
156
+	if store.referencesByIDCache[id] == nil {
157
+		store.referencesByIDCache[id] = make(map[string]Named)
158
+	}
159
+	store.referencesByIDCache[id][refStr] = ref
160
+
161
+	return store.save()
162
+}
163
+
164
+// Delete deletes a reference from the store. It returns true if a deletion
165
+// happened, or false otherwise.
166
+func (store *store) Delete(ref Named) (bool, error) {
167
+	ref = defaultTagIfNameOnly(ref)
168
+
169
+	store.mu.Lock()
170
+	defer store.mu.Unlock()
171
+
172
+	repoName := ref.Name()
173
+
174
+	repository, exists := store.Repositories[repoName]
175
+	if !exists {
176
+		return false, ErrDoesNotExist
177
+	}
178
+
179
+	refStr := ref.String()
180
+	if id, exists := repository[refStr]; exists {
181
+		delete(repository, refStr)
182
+		if len(repository) == 0 {
183
+			delete(store.Repositories, repoName)
184
+		}
185
+		if store.referencesByIDCache[id] != nil {
186
+			delete(store.referencesByIDCache[id], refStr)
187
+			if len(store.referencesByIDCache[id]) == 0 {
188
+				delete(store.referencesByIDCache, id)
189
+			}
190
+		}
191
+		return true, store.save()
192
+	}
193
+
194
+	return false, ErrDoesNotExist
195
+}
196
+
197
+// Get retrieves an item from the store by
198
+func (store *store) Get(ref Named) (image.ID, error) {
199
+	ref = defaultTagIfNameOnly(ref)
200
+
201
+	store.mu.RLock()
202
+	defer store.mu.RUnlock()
203
+
204
+	repository, exists := store.Repositories[ref.Name()]
205
+	if !exists || repository == nil {
206
+		return "", ErrDoesNotExist
207
+	}
208
+
209
+	id, exists := repository[ref.String()]
210
+	if !exists {
211
+		return "", ErrDoesNotExist
212
+	}
213
+
214
+	return id, nil
215
+}
216
+
217
+// References returns a slice of references to the given image ID. The slice
218
+// will be nil if there are no references to this image ID.
219
+func (store *store) References(id image.ID) []Named {
220
+	store.mu.RLock()
221
+	defer store.mu.RUnlock()
222
+
223
+	// Convert the internal map to an array for two reasons:
224
+	// 1) We must not return a mutable
225
+	// 2) It would be ugly to expose the extraneous map keys to callers.
226
+
227
+	var references []Named
228
+	for _, ref := range store.referencesByIDCache[id] {
229
+		references = append(references, ref)
230
+	}
231
+
232
+	sort.Sort(lexicalRefs(references))
233
+
234
+	return references
235
+}
236
+
237
+// ReferencesByName returns the references for a given repository name.
238
+// If there are no references known for this repository name,
239
+// ReferencesByName returns nil.
240
+func (store *store) ReferencesByName(ref Named) []Association {
241
+	store.mu.RLock()
242
+	defer store.mu.RUnlock()
243
+
244
+	repository, exists := store.Repositories[ref.Name()]
245
+	if !exists {
246
+		return nil
247
+	}
248
+
249
+	var associations []Association
250
+	for refStr, refID := range repository {
251
+		ref, err := ParseNamed(refStr)
252
+		if err != nil {
253
+			// Should never happen
254
+			return nil
255
+		}
256
+		associations = append(associations,
257
+			Association{
258
+				Ref:     ref,
259
+				ImageID: refID,
260
+			})
261
+	}
262
+
263
+	sort.Sort(lexicalAssociations(associations))
264
+
265
+	return associations
266
+}
267
+
268
+func (store *store) save() error {
269
+	// Store the json
270
+	jsonData, err := json.Marshal(store)
271
+	if err != nil {
272
+		return err
273
+	}
274
+
275
+	tempFilePath := store.jsonPath + ".tmp"
276
+
277
+	if err := ioutil.WriteFile(tempFilePath, jsonData, 0600); err != nil {
278
+		return err
279
+	}
280
+
281
+	if err := os.Rename(tempFilePath, store.jsonPath); err != nil {
282
+		return err
283
+	}
284
+
285
+	return nil
286
+}
287
+
288
+func (store *store) reload() error {
289
+	f, err := os.Open(store.jsonPath)
290
+	if err != nil {
291
+		return err
292
+	}
293
+	defer f.Close()
294
+	if err := json.NewDecoder(f).Decode(&store); err != nil {
295
+		return err
296
+	}
297
+
298
+	for _, repository := range store.Repositories {
299
+		for refStr, refID := range repository {
300
+			ref, err := ParseNamed(refStr)
301
+			if err != nil {
302
+				// Should never happen
303
+				continue
304
+			}
305
+			if store.referencesByIDCache[refID] == nil {
306
+				store.referencesByIDCache[refID] = make(map[string]Named)
307
+			}
308
+			store.referencesByIDCache[refID][refStr] = ref
309
+		}
310
+	}
311
+
312
+	return nil
313
+}
0 314
new file mode 100644
... ...
@@ -0,0 +1,356 @@
0
+package reference
1
+
2
+import (
3
+	"bytes"
4
+	"io/ioutil"
5
+	"os"
6
+	"path/filepath"
7
+	"strings"
8
+	"testing"
9
+
10
+	"github.com/docker/docker/image"
11
+)
12
+
13
+var (
14
+	saveLoadTestCases = map[string]image.ID{
15
+		"registry:5000/foobar:HEAD":                                                        "sha256:470022b8af682154f57a2163d030eb369549549cba00edc69e1b99b46bb924d6",
16
+		"registry:5000/foobar:alternate":                                                   "sha256:ae300ebc4a4f00693702cfb0a5e0b7bc527b353828dc86ad09fb95c8a681b793",
17
+		"registry:5000/foobar:latest":                                                      "sha256:6153498b9ac00968d71b66cca4eac37e990b5f9eb50c26877eb8799c8847451b",
18
+		"registry:5000/foobar:master":                                                      "sha256:6c9917af4c4e05001b346421959d7ea81b6dc9d25718466a37a6add865dfd7fc",
19
+		"jess/hollywood:latest":                                                            "sha256:ae7a5519a0a55a2d4ef20ddcbd5d0ca0888a1f7ab806acc8e2a27baf46f529fe",
20
+		"registry@sha256:367eb40fd0330a7e464777121e39d2f5b3e8e23a1e159342e53ab05c9e4d94e6": "sha256:24126a56805beb9711be5f4590cc2eb55ab8d4a85ebd618eed72bb19fc50631c",
21
+		"busybox:latest": "sha256:91e54dfb11794fad694460162bf0cb0a4fa710cfa3f60979c177d920813e267c",
22
+	}
23
+
24
+	marshalledSaveLoadTestCases = []byte(`{"Repositories":{"busybox":{"busybox:latest":"sha256:91e54dfb11794fad694460162bf0cb0a4fa710cfa3f60979c177d920813e267c"},"jess/hollywood":{"jess/hollywood:latest":"sha256:ae7a5519a0a55a2d4ef20ddcbd5d0ca0888a1f7ab806acc8e2a27baf46f529fe"},"registry":{"registry@sha256:367eb40fd0330a7e464777121e39d2f5b3e8e23a1e159342e53ab05c9e4d94e6":"sha256:24126a56805beb9711be5f4590cc2eb55ab8d4a85ebd618eed72bb19fc50631c"},"registry:5000/foobar":{"registry:5000/foobar:HEAD":"sha256:470022b8af682154f57a2163d030eb369549549cba00edc69e1b99b46bb924d6","registry:5000/foobar:alternate":"sha256:ae300ebc4a4f00693702cfb0a5e0b7bc527b353828dc86ad09fb95c8a681b793","registry:5000/foobar:latest":"sha256:6153498b9ac00968d71b66cca4eac37e990b5f9eb50c26877eb8799c8847451b","registry:5000/foobar:master":"sha256:6c9917af4c4e05001b346421959d7ea81b6dc9d25718466a37a6add865dfd7fc"}}}`)
25
+)
26
+
27
+func TestLoad(t *testing.T) {
28
+	jsonFile, err := ioutil.TempFile("", "tag-store-test")
29
+	if err != nil {
30
+		t.Fatalf("error creating temp file: %v", err)
31
+	}
32
+	defer os.RemoveAll(jsonFile.Name())
33
+
34
+	// Write canned json to the temp file
35
+	_, err = jsonFile.Write(marshalledSaveLoadTestCases)
36
+	if err != nil {
37
+		t.Fatalf("error writing to temp file: %v", err)
38
+	}
39
+	jsonFile.Close()
40
+
41
+	store, err := NewReferenceStore(jsonFile.Name())
42
+	if err != nil {
43
+		t.Fatalf("error creating tag store: %v", err)
44
+	}
45
+
46
+	for refStr, expectedID := range saveLoadTestCases {
47
+		ref, err := ParseNamed(refStr)
48
+		if err != nil {
49
+			t.Fatalf("failed to parse reference: %v", err)
50
+		}
51
+		id, err := store.Get(ref)
52
+		if err != nil {
53
+			t.Fatalf("could not find reference %s: %v", refStr, err)
54
+		}
55
+		if id != expectedID {
56
+			t.Fatalf("expected %s - got %s", expectedID, id)
57
+		}
58
+	}
59
+}
60
+
61
+func TestSave(t *testing.T) {
62
+	jsonFile, err := ioutil.TempFile("", "tag-store-test")
63
+	if err != nil {
64
+		t.Fatalf("error creating temp file: %v", err)
65
+	}
66
+	_, err = jsonFile.Write([]byte(`{}`))
67
+	jsonFile.Close()
68
+	defer os.RemoveAll(jsonFile.Name())
69
+
70
+	store, err := NewReferenceStore(jsonFile.Name())
71
+	if err != nil {
72
+		t.Fatalf("error creating tag store: %v", err)
73
+	}
74
+
75
+	for refStr, id := range saveLoadTestCases {
76
+		ref, err := ParseNamed(refStr)
77
+		if err != nil {
78
+			t.Fatalf("failed to parse reference: %v", err)
79
+		}
80
+		if canonical, ok := ref.(Canonical); ok {
81
+			err = store.AddDigest(canonical, id, false)
82
+			if err != nil {
83
+				t.Fatalf("could not add digest reference %s: %v", refStr, err)
84
+			}
85
+		} else {
86
+			err = store.AddTag(ref, id, false)
87
+			if err != nil {
88
+				t.Fatalf("could not add reference %s: %v", refStr, err)
89
+			}
90
+		}
91
+	}
92
+
93
+	jsonBytes, err := ioutil.ReadFile(jsonFile.Name())
94
+	if err != nil {
95
+		t.Fatalf("could not read json file: %v", err)
96
+	}
97
+
98
+	if !bytes.Equal(jsonBytes, marshalledSaveLoadTestCases) {
99
+		t.Fatalf("save output did not match expectations\nexpected:\n%s\ngot:\n%s", marshalledSaveLoadTestCases, jsonBytes)
100
+	}
101
+}
102
+
103
+func TestAddDeleteGet(t *testing.T) {
104
+	jsonFile, err := ioutil.TempFile("", "tag-store-test")
105
+	if err != nil {
106
+		t.Fatalf("error creating temp file: %v", err)
107
+	}
108
+	_, err = jsonFile.Write([]byte(`{}`))
109
+	jsonFile.Close()
110
+	defer os.RemoveAll(jsonFile.Name())
111
+
112
+	store, err := NewReferenceStore(jsonFile.Name())
113
+	if err != nil {
114
+		t.Fatalf("error creating tag store: %v", err)
115
+	}
116
+
117
+	testImageID1 := image.ID("sha256:9655aef5fd742a1b4e1b7b163aa9f1c76c186304bf39102283d80927c916ca9c")
118
+	testImageID2 := image.ID("sha256:9655aef5fd742a1b4e1b7b163aa9f1c76c186304bf39102283d80927c916ca9d")
119
+	testImageID3 := image.ID("sha256:9655aef5fd742a1b4e1b7b163aa9f1c76c186304bf39102283d80927c916ca9e")
120
+
121
+	// Try adding a reference with no tag or digest
122
+	nameOnly, err := WithName("username/repo")
123
+	if err != nil {
124
+		t.Fatalf("could not parse reference: %v", err)
125
+	}
126
+	if err = store.AddTag(nameOnly, testImageID1, false); err != nil {
127
+		t.Fatalf("error adding to store: %v", err)
128
+	}
129
+
130
+	// Add a few references
131
+	ref1, err := ParseNamed("username/repo1:latest")
132
+	if err != nil {
133
+		t.Fatalf("could not parse reference: %v", err)
134
+	}
135
+	if err = store.AddTag(ref1, testImageID1, false); err != nil {
136
+		t.Fatalf("error adding to store: %v", err)
137
+	}
138
+
139
+	ref2, err := ParseNamed("username/repo1:old")
140
+	if err != nil {
141
+		t.Fatalf("could not parse reference: %v", err)
142
+	}
143
+	if err = store.AddTag(ref2, testImageID2, false); err != nil {
144
+		t.Fatalf("error adding to store: %v", err)
145
+	}
146
+
147
+	ref3, err := ParseNamed("username/repo1:alias")
148
+	if err != nil {
149
+		t.Fatalf("could not parse reference: %v", err)
150
+	}
151
+	if err = store.AddTag(ref3, testImageID1, false); err != nil {
152
+		t.Fatalf("error adding to store: %v", err)
153
+	}
154
+
155
+	ref4, err := ParseNamed("username/repo2:latest")
156
+	if err != nil {
157
+		t.Fatalf("could not parse reference: %v", err)
158
+	}
159
+	if err = store.AddTag(ref4, testImageID2, false); err != nil {
160
+		t.Fatalf("error adding to store: %v", err)
161
+	}
162
+
163
+	ref5, err := ParseNamed("username/repo3@sha256:58153dfb11794fad694460162bf0cb0a4fa710cfa3f60979c177d920813e267c")
164
+	if err != nil {
165
+		t.Fatalf("could not parse reference: %v", err)
166
+	}
167
+	if err = store.AddDigest(ref5.(Canonical), testImageID2, false); err != nil {
168
+		t.Fatalf("error adding to store: %v", err)
169
+	}
170
+
171
+	// Attempt to overwrite with force == false
172
+	if err = store.AddTag(ref4, testImageID3, false); err == nil || !strings.HasPrefix(err.Error(), "Conflict:") {
173
+		t.Fatalf("did not get expected error on overwrite attempt - got %v", err)
174
+	}
175
+	// Repeat to overwrite with force == true
176
+	if err = store.AddTag(ref4, testImageID3, true); err != nil {
177
+		t.Fatalf("failed to force tag overwrite: %v", err)
178
+	}
179
+
180
+	// Check references so far
181
+	id, err := store.Get(nameOnly)
182
+	if err != nil {
183
+		t.Fatalf("Get returned error: %v", err)
184
+	}
185
+	if id != testImageID1 {
186
+		t.Fatalf("id mismatch: got %s instead of %s", id.String(), testImageID1.String())
187
+	}
188
+
189
+	id, err = store.Get(ref1)
190
+	if err != nil {
191
+		t.Fatalf("Get returned error: %v", err)
192
+	}
193
+	if id != testImageID1 {
194
+		t.Fatalf("id mismatch: got %s instead of %s", id.String(), testImageID1.String())
195
+	}
196
+
197
+	id, err = store.Get(ref2)
198
+	if err != nil {
199
+		t.Fatalf("Get returned error: %v", err)
200
+	}
201
+	if id != testImageID2 {
202
+		t.Fatalf("id mismatch: got %s instead of %s", id.String(), testImageID2.String())
203
+	}
204
+
205
+	id, err = store.Get(ref3)
206
+	if err != nil {
207
+		t.Fatalf("Get returned error: %v", err)
208
+	}
209
+	if id != testImageID1 {
210
+		t.Fatalf("id mismatch: got %s instead of %s", id.String(), testImageID1.String())
211
+	}
212
+
213
+	id, err = store.Get(ref4)
214
+	if err != nil {
215
+		t.Fatalf("Get returned error: %v", err)
216
+	}
217
+	if id != testImageID3 {
218
+		t.Fatalf("id mismatch: got %s instead of %s", id.String(), testImageID3.String())
219
+	}
220
+
221
+	id, err = store.Get(ref5)
222
+	if err != nil {
223
+		t.Fatalf("Get returned error: %v", err)
224
+	}
225
+	if id != testImageID2 {
226
+		t.Fatalf("id mismatch: got %s instead of %s", id.String(), testImageID3.String())
227
+	}
228
+
229
+	// Get should return ErrDoesNotExist for a nonexistent repo
230
+	nonExistRepo, err := ParseNamed("username/nonexistrepo:latest")
231
+	if err != nil {
232
+		t.Fatalf("could not parse reference: %v", err)
233
+	}
234
+	if _, err = store.Get(nonExistRepo); err != ErrDoesNotExist {
235
+		t.Fatal("Expected ErrDoesNotExist from Get")
236
+	}
237
+
238
+	// Get should return ErrDoesNotExist for a nonexistent tag
239
+	nonExistTag, err := ParseNamed("username/repo1:nonexist")
240
+	if err != nil {
241
+		t.Fatalf("could not parse reference: %v", err)
242
+	}
243
+	if _, err = store.Get(nonExistTag); err != ErrDoesNotExist {
244
+		t.Fatal("Expected ErrDoesNotExist from Get")
245
+	}
246
+
247
+	// Check References
248
+	refs := store.References(testImageID1)
249
+	if len(refs) != 3 {
250
+		t.Fatal("unexpected number of references")
251
+	}
252
+	// Looking for the references in this order verifies that they are
253
+	// returned lexically sorted.
254
+	if refs[0].String() != ref3.String() {
255
+		t.Fatalf("unexpected reference: %v", refs[0].String())
256
+	}
257
+	if refs[1].String() != ref1.String() {
258
+		t.Fatalf("unexpected reference: %v", refs[1].String())
259
+	}
260
+	if refs[2].String() != nameOnly.String()+":latest" {
261
+		t.Fatalf("unexpected reference: %v", refs[2].String())
262
+	}
263
+
264
+	// Check ReferencesByName
265
+	repoName, err := WithName("username/repo1")
266
+	if err != nil {
267
+		t.Fatalf("could not parse reference: %v", err)
268
+	}
269
+	associations := store.ReferencesByName(repoName)
270
+	if len(associations) != 3 {
271
+		t.Fatal("unexpected number of associations")
272
+	}
273
+	// Looking for the associations in this order verifies that they are
274
+	// returned lexically sorted.
275
+	if associations[0].Ref.String() != ref3.String() {
276
+		t.Fatalf("unexpected reference: %v", associations[0].Ref.String())
277
+	}
278
+	if associations[0].ImageID != testImageID1 {
279
+		t.Fatalf("unexpected reference: %v", associations[0].Ref.String())
280
+	}
281
+	if associations[1].Ref.String() != ref1.String() {
282
+		t.Fatalf("unexpected reference: %v", associations[1].Ref.String())
283
+	}
284
+	if associations[1].ImageID != testImageID1 {
285
+		t.Fatalf("unexpected reference: %v", associations[1].Ref.String())
286
+	}
287
+	if associations[2].Ref.String() != ref2.String() {
288
+		t.Fatalf("unexpected reference: %v", associations[2].Ref.String())
289
+	}
290
+	if associations[2].ImageID != testImageID2 {
291
+		t.Fatalf("unexpected reference: %v", associations[2].Ref.String())
292
+	}
293
+
294
+	// Delete should return ErrDoesNotExist for a nonexistent repo
295
+	if _, err = store.Delete(nonExistRepo); err != ErrDoesNotExist {
296
+		t.Fatal("Expected ErrDoesNotExist from Delete")
297
+	}
298
+
299
+	// Delete should return ErrDoesNotExist for a nonexistent tag
300
+	if _, err = store.Delete(nonExistTag); err != ErrDoesNotExist {
301
+		t.Fatal("Expected ErrDoesNotExist from Delete")
302
+	}
303
+
304
+	// Delete a few references
305
+	if deleted, err := store.Delete(ref1); err != nil || deleted != true {
306
+		t.Fatal("Delete failed")
307
+	}
308
+	if _, err := store.Get(ref1); err != ErrDoesNotExist {
309
+		t.Fatal("Expected ErrDoesNotExist from Get")
310
+	}
311
+	if deleted, err := store.Delete(ref5); err != nil || deleted != true {
312
+		t.Fatal("Delete failed")
313
+	}
314
+	if _, err := store.Get(ref5); err != ErrDoesNotExist {
315
+		t.Fatal("Expected ErrDoesNotExist from Get")
316
+	}
317
+	if deleted, err := store.Delete(nameOnly); err != nil || deleted != true {
318
+		t.Fatal("Delete failed")
319
+	}
320
+	if _, err := store.Get(nameOnly); err != ErrDoesNotExist {
321
+		t.Fatal("Expected ErrDoesNotExist from Get")
322
+	}
323
+}
324
+
325
+func TestInvalidTags(t *testing.T) {
326
+	tmpDir, err := ioutil.TempDir("", "tag-store-test")
327
+	defer os.RemoveAll(tmpDir)
328
+
329
+	store, err := NewReferenceStore(filepath.Join(tmpDir, "repositories.json"))
330
+	if err != nil {
331
+		t.Fatalf("error creating tag store: %v", err)
332
+	}
333
+	id := image.ID("sha256:470022b8af682154f57a2163d030eb369549549cba00edc69e1b99b46bb924d6")
334
+
335
+	// sha256 as repo name
336
+	ref, err := ParseNamed("sha256:abc")
337
+	if err != nil {
338
+		t.Fatal(err)
339
+	}
340
+	err = store.AddTag(ref, id, true)
341
+	if err == nil {
342
+		t.Fatalf("expected setting tag %q to fail", ref)
343
+	}
344
+
345
+	// setting digest as a tag
346
+	ref, err = ParseNamed("registry@sha256:367eb40fd0330a7e464777121e39d2f5b3e8e23a1e159342e53ab05c9e4d94e6")
347
+	if err != nil {
348
+		t.Fatal(err)
349
+	}
350
+	err = store.AddTag(ref, id, true)
351
+	if err == nil {
352
+		t.Fatalf("expected setting digest %q to fail", ref)
353
+	}
354
+
355
+}
... ...
@@ -7,11 +7,12 @@ import (
7 7
 	"net/url"
8 8
 	"strings"
9 9
 
10
-	"github.com/docker/distribution/reference"
10
+	distreference "github.com/docker/distribution/reference"
11 11
 	registrytypes "github.com/docker/docker/api/types/registry"
12 12
 	"github.com/docker/docker/image/v1"
13 13
 	"github.com/docker/docker/opts"
14 14
 	flag "github.com/docker/docker/pkg/mflag"
15
+	"github.com/docker/docker/reference"
15 16
 )
16 17
 
17 18
 // Options holds command line options.
... ...
@@ -269,7 +270,7 @@ func GetAuthConfigKey(index *registrytypes.IndexInfo) string {
269 269
 // splitReposName breaks a reposName into an index name and remote name
270 270
 func splitReposName(reposName reference.Named) (indexName string, remoteName reference.Named, err error) {
271 271
 	var remoteNameStr string
272
-	indexName, remoteNameStr = reference.SplitHostname(reposName)
272
+	indexName, remoteNameStr = distreference.SplitHostname(reposName)
273 273
 	if indexName == "" || (!strings.Contains(indexName, ".") &&
274 274
 		!strings.Contains(indexName, ":") && indexName != "localhost") {
275 275
 		// This is a Docker Index repos (ex: samalba/hipache or ubuntu)
... ...
@@ -405,13 +406,13 @@ func localNameFromRemote(indexName string, remoteName reference.Named) (referenc
405 405
 // error.
406 406
 func NormalizeLocalReference(ref reference.Named) reference.Named {
407 407
 	localName := NormalizeLocalName(ref)
408
-	if tagged, isTagged := ref.(reference.Tagged); isTagged {
408
+	if tagged, isTagged := ref.(reference.NamedTagged); isTagged {
409 409
 		newRef, err := reference.WithTag(localName, tagged.Tag())
410 410
 		if err != nil {
411 411
 			return ref
412 412
 		}
413 413
 		return newRef
414
-	} else if digested, isDigested := ref.(reference.Digested); isDigested {
414
+	} else if digested, isCanonical := ref.(reference.Canonical); isCanonical {
415 415
 		newRef, err := reference.WithDigest(localName, digested.Digest())
416 416
 		if err != nil {
417 417
 			return ref
... ...
@@ -15,9 +15,9 @@ import (
15 15
 	"testing"
16 16
 	"time"
17 17
 
18
-	"github.com/docker/distribution/reference"
19 18
 	registrytypes "github.com/docker/docker/api/types/registry"
20 19
 	"github.com/docker/docker/opts"
20
+	"github.com/docker/docker/reference"
21 21
 	"github.com/gorilla/mux"
22 22
 
23 23
 	"github.com/Sirupsen/logrus"
... ...
@@ -8,10 +8,10 @@ import (
8 8
 	"strings"
9 9
 	"testing"
10 10
 
11
-	"github.com/docker/distribution/reference"
12 11
 	"github.com/docker/distribution/registry/client/transport"
13 12
 	"github.com/docker/docker/api/types"
14 13
 	registrytypes "github.com/docker/docker/api/types/registry"
14
+	"github.com/docker/docker/reference"
15 15
 )
16 16
 
17 17
 var (
... ...
@@ -6,10 +6,10 @@ import (
6 6
 	"net/url"
7 7
 	"strings"
8 8
 
9
-	"github.com/docker/distribution/reference"
10 9
 	"github.com/docker/distribution/registry/client/auth"
11 10
 	"github.com/docker/docker/api/types"
12 11
 	registrytypes "github.com/docker/docker/api/types/registry"
12
+	"github.com/docker/docker/reference"
13 13
 )
14 14
 
15 15
 // Service is a registry service. It tracks configuration data such as a list
... ...
@@ -4,8 +4,8 @@ import (
4 4
 	"fmt"
5 5
 	"strings"
6 6
 
7
-	"github.com/docker/distribution/reference"
8 7
 	"github.com/docker/docker/pkg/tlsconfig"
8
+	"github.com/docker/docker/reference"
9 9
 )
10 10
 
11 11
 func (s *Service) lookupV1Endpoints(repoName reference.Named) (endpoints []APIEndpoint, err error) {
... ...
@@ -4,9 +4,9 @@ import (
4 4
 	"fmt"
5 5
 	"strings"
6 6
 
7
-	"github.com/docker/distribution/reference"
8 7
 	"github.com/docker/distribution/registry/client/auth"
9 8
 	"github.com/docker/docker/pkg/tlsconfig"
9
+	"github.com/docker/docker/reference"
10 10
 )
11 11
 
12 12
 func (s *Service) lookupV2Endpoints(repoName reference.Named) (endpoints []APIEndpoint, err error) {
... ...
@@ -19,13 +19,13 @@ import (
19 19
 	"strings"
20 20
 
21 21
 	"github.com/Sirupsen/logrus"
22
-	"github.com/docker/distribution/reference"
23 22
 	"github.com/docker/docker/api/types"
24 23
 	registrytypes "github.com/docker/docker/api/types/registry"
25 24
 	"github.com/docker/docker/pkg/httputils"
26 25
 	"github.com/docker/docker/pkg/ioutils"
27 26
 	"github.com/docker/docker/pkg/stringid"
28 27
 	"github.com/docker/docker/pkg/tarsum"
28
+	"github.com/docker/docker/reference"
29 29
 )
30 30
 
31 31
 var (
... ...
@@ -1,8 +1,8 @@
1 1
 package registry
2 2
 
3 3
 import (
4
-	"github.com/docker/distribution/reference"
5 4
 	registrytypes "github.com/docker/docker/api/types/registry"
5
+	"github.com/docker/docker/reference"
6 6
 )
7 7
 
8 8
 // RepositoryData tracks the image list, list of endpoints, and list of tokens
9 9
deleted file mode 100644
... ...
@@ -1,315 +0,0 @@
1
-package tag
2
-
3
-import (
4
-	"encoding/json"
5
-	"errors"
6
-	"fmt"
7
-	"io/ioutil"
8
-	"os"
9
-	"path/filepath"
10
-	"sort"
11
-	"sync"
12
-
13
-	"github.com/docker/distribution/digest"
14
-	"github.com/docker/distribution/reference"
15
-	"github.com/docker/docker/image"
16
-)
17
-
18
-// DefaultTag defines the default tag used when performing images related actions and no tag string is specified
19
-const DefaultTag = "latest"
20
-
21
-var (
22
-	// ErrDoesNotExist is returned if a reference is not found in the
23
-	// store.
24
-	ErrDoesNotExist = errors.New("reference does not exist")
25
-)
26
-
27
-// An Association is a tuple associating a reference with an image ID.
28
-type Association struct {
29
-	Ref     reference.Named
30
-	ImageID image.ID
31
-}
32
-
33
-// Store provides the set of methods which can operate on a tag store.
34
-type Store interface {
35
-	References(id image.ID) []reference.Named
36
-	ReferencesByName(ref reference.Named) []Association
37
-	AddTag(ref reference.Named, id image.ID, force bool) error
38
-	AddDigest(ref reference.Canonical, id image.ID, force bool) error
39
-	Delete(ref reference.Named) (bool, error)
40
-	Get(ref reference.Named) (image.ID, error)
41
-}
42
-
43
-type store struct {
44
-	mu sync.RWMutex
45
-	// jsonPath is the path to the file where the serialized tag data is
46
-	// stored.
47
-	jsonPath string
48
-	// Repositories is a map of repositories, indexed by name.
49
-	Repositories map[string]repository
50
-	// referencesByIDCache is a cache of references indexed by ID, to speed
51
-	// up References.
52
-	referencesByIDCache map[image.ID]map[string]reference.Named
53
-}
54
-
55
-// Repository maps tags to image IDs. The key is a a stringified Reference,
56
-// including the repository name.
57
-type repository map[string]image.ID
58
-
59
-type lexicalRefs []reference.Named
60
-
61
-func (a lexicalRefs) Len() int           { return len(a) }
62
-func (a lexicalRefs) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
63
-func (a lexicalRefs) Less(i, j int) bool { return a[i].String() < a[j].String() }
64
-
65
-type lexicalAssociations []Association
66
-
67
-func (a lexicalAssociations) Len() int           { return len(a) }
68
-func (a lexicalAssociations) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
69
-func (a lexicalAssociations) Less(i, j int) bool { return a[i].Ref.String() < a[j].Ref.String() }
70
-
71
-func defaultTagIfNameOnly(ref reference.Named) reference.Named {
72
-	switch ref.(type) {
73
-	case reference.Tagged:
74
-		return ref
75
-	case reference.Digested:
76
-		return ref
77
-	default:
78
-		// Should never fail
79
-		ref, _ = reference.WithTag(ref, DefaultTag)
80
-		return ref
81
-	}
82
-}
83
-
84
-// NewTagStore creates a new tag store, tied to a file path where the set of
85
-// tags is serialized in JSON format.
86
-func NewTagStore(jsonPath string) (Store, error) {
87
-	abspath, err := filepath.Abs(jsonPath)
88
-	if err != nil {
89
-		return nil, err
90
-	}
91
-
92
-	store := &store{
93
-		jsonPath:            abspath,
94
-		Repositories:        make(map[string]repository),
95
-		referencesByIDCache: make(map[image.ID]map[string]reference.Named),
96
-	}
97
-	// Load the json file if it exists, otherwise create it.
98
-	if err := store.reload(); os.IsNotExist(err) {
99
-		if err := store.save(); err != nil {
100
-			return nil, err
101
-		}
102
-	} else if err != nil {
103
-		return nil, err
104
-	}
105
-	return store, nil
106
-}
107
-
108
-// Add adds a tag to the store. If force is set to true, existing
109
-// references can be overwritten. This only works for tags, not digests.
110
-func (store *store) AddTag(ref reference.Named, id image.ID, force bool) error {
111
-	if _, isDigested := ref.(reference.Digested); isDigested {
112
-		return errors.New("refusing to create a tag with a digest reference")
113
-	}
114
-	return store.addReference(defaultTagIfNameOnly(ref), id, force)
115
-}
116
-
117
-// Add adds a digest reference to the store.
118
-func (store *store) AddDigest(ref reference.Canonical, id image.ID, force bool) error {
119
-	return store.addReference(ref, id, force)
120
-}
121
-
122
-func (store *store) addReference(ref reference.Named, id image.ID, force bool) error {
123
-	if ref.Name() == string(digest.Canonical) {
124
-		return errors.New("refusing to create an ambiguous tag using digest algorithm as name")
125
-	}
126
-
127
-	store.mu.Lock()
128
-	defer store.mu.Unlock()
129
-
130
-	repository, exists := store.Repositories[ref.Name()]
131
-	if !exists || repository == nil {
132
-		repository = make(map[string]image.ID)
133
-		store.Repositories[ref.Name()] = repository
134
-	}
135
-
136
-	refStr := ref.String()
137
-	oldID, exists := repository[refStr]
138
-
139
-	if exists {
140
-		// force only works for tags
141
-		if digested, isDigest := ref.(reference.Digested); isDigest {
142
-			return fmt.Errorf("Cannot overwrite digest %s", digested.Digest().String())
143
-		}
144
-
145
-		if !force {
146
-			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())
147
-		}
148
-
149
-		if store.referencesByIDCache[oldID] != nil {
150
-			delete(store.referencesByIDCache[oldID], refStr)
151
-			if len(store.referencesByIDCache[oldID]) == 0 {
152
-				delete(store.referencesByIDCache, oldID)
153
-			}
154
-		}
155
-	}
156
-
157
-	repository[refStr] = id
158
-	if store.referencesByIDCache[id] == nil {
159
-		store.referencesByIDCache[id] = make(map[string]reference.Named)
160
-	}
161
-	store.referencesByIDCache[id][refStr] = ref
162
-
163
-	return store.save()
164
-}
165
-
166
-// Delete deletes a reference from the store. It returns true if a deletion
167
-// happened, or false otherwise.
168
-func (store *store) Delete(ref reference.Named) (bool, error) {
169
-	ref = defaultTagIfNameOnly(ref)
170
-
171
-	store.mu.Lock()
172
-	defer store.mu.Unlock()
173
-
174
-	repoName := ref.Name()
175
-
176
-	repository, exists := store.Repositories[repoName]
177
-	if !exists {
178
-		return false, ErrDoesNotExist
179
-	}
180
-
181
-	refStr := ref.String()
182
-	if id, exists := repository[refStr]; exists {
183
-		delete(repository, refStr)
184
-		if len(repository) == 0 {
185
-			delete(store.Repositories, repoName)
186
-		}
187
-		if store.referencesByIDCache[id] != nil {
188
-			delete(store.referencesByIDCache[id], refStr)
189
-			if len(store.referencesByIDCache[id]) == 0 {
190
-				delete(store.referencesByIDCache, id)
191
-			}
192
-		}
193
-		return true, store.save()
194
-	}
195
-
196
-	return false, ErrDoesNotExist
197
-}
198
-
199
-// Get retrieves an item from the store by reference.
200
-func (store *store) Get(ref reference.Named) (image.ID, error) {
201
-	ref = defaultTagIfNameOnly(ref)
202
-
203
-	store.mu.RLock()
204
-	defer store.mu.RUnlock()
205
-
206
-	repository, exists := store.Repositories[ref.Name()]
207
-	if !exists || repository == nil {
208
-		return "", ErrDoesNotExist
209
-	}
210
-
211
-	id, exists := repository[ref.String()]
212
-	if !exists {
213
-		return "", ErrDoesNotExist
214
-	}
215
-
216
-	return id, nil
217
-}
218
-
219
-// References returns a slice of references to the given image ID. The slice
220
-// will be nil if there are no references to this image ID.
221
-func (store *store) References(id image.ID) []reference.Named {
222
-	store.mu.RLock()
223
-	defer store.mu.RUnlock()
224
-
225
-	// Convert the internal map to an array for two reasons:
226
-	// 1) We must not return a mutable reference.
227
-	// 2) It would be ugly to expose the extraneous map keys to callers.
228
-
229
-	var references []reference.Named
230
-	for _, ref := range store.referencesByIDCache[id] {
231
-		references = append(references, ref)
232
-	}
233
-
234
-	sort.Sort(lexicalRefs(references))
235
-
236
-	return references
237
-}
238
-
239
-// ReferencesByName returns the references for a given repository name.
240
-// If there are no references known for this repository name,
241
-// ReferencesByName returns nil.
242
-func (store *store) ReferencesByName(ref reference.Named) []Association {
243
-	store.mu.RLock()
244
-	defer store.mu.RUnlock()
245
-
246
-	repository, exists := store.Repositories[ref.Name()]
247
-	if !exists {
248
-		return nil
249
-	}
250
-
251
-	var associations []Association
252
-	for refStr, refID := range repository {
253
-		ref, err := reference.ParseNamed(refStr)
254
-		if err != nil {
255
-			// Should never happen
256
-			return nil
257
-		}
258
-		associations = append(associations,
259
-			Association{
260
-				Ref:     ref,
261
-				ImageID: refID,
262
-			})
263
-	}
264
-
265
-	sort.Sort(lexicalAssociations(associations))
266
-
267
-	return associations
268
-}
269
-
270
-func (store *store) save() error {
271
-	// Store the json
272
-	jsonData, err := json.Marshal(store)
273
-	if err != nil {
274
-		return err
275
-	}
276
-
277
-	tempFilePath := store.jsonPath + ".tmp"
278
-
279
-	if err := ioutil.WriteFile(tempFilePath, jsonData, 0600); err != nil {
280
-		return err
281
-	}
282
-
283
-	if err := os.Rename(tempFilePath, store.jsonPath); err != nil {
284
-		return err
285
-	}
286
-
287
-	return nil
288
-}
289
-
290
-func (store *store) reload() error {
291
-	f, err := os.Open(store.jsonPath)
292
-	if err != nil {
293
-		return err
294
-	}
295
-	defer f.Close()
296
-	if err := json.NewDecoder(f).Decode(&store); err != nil {
297
-		return err
298
-	}
299
-
300
-	for _, repository := range store.Repositories {
301
-		for refStr, refID := range repository {
302
-			ref, err := reference.ParseNamed(refStr)
303
-			if err != nil {
304
-				// Should never happen
305
-				continue
306
-			}
307
-			if store.referencesByIDCache[refID] == nil {
308
-				store.referencesByIDCache[refID] = make(map[string]reference.Named)
309
-			}
310
-			store.referencesByIDCache[refID][refStr] = ref
311
-		}
312
-	}
313
-
314
-	return nil
315
-}
316 1
deleted file mode 100644
... ...
@@ -1,357 +0,0 @@
1
-package tag
2
-
3
-import (
4
-	"bytes"
5
-	"io/ioutil"
6
-	"os"
7
-	"path/filepath"
8
-	"strings"
9
-	"testing"
10
-
11
-	"github.com/docker/distribution/reference"
12
-	"github.com/docker/docker/image"
13
-)
14
-
15
-var (
16
-	saveLoadTestCases = map[string]image.ID{
17
-		"registry:5000/foobar:HEAD":                                                        "sha256:470022b8af682154f57a2163d030eb369549549cba00edc69e1b99b46bb924d6",
18
-		"registry:5000/foobar:alternate":                                                   "sha256:ae300ebc4a4f00693702cfb0a5e0b7bc527b353828dc86ad09fb95c8a681b793",
19
-		"registry:5000/foobar:latest":                                                      "sha256:6153498b9ac00968d71b66cca4eac37e990b5f9eb50c26877eb8799c8847451b",
20
-		"registry:5000/foobar:master":                                                      "sha256:6c9917af4c4e05001b346421959d7ea81b6dc9d25718466a37a6add865dfd7fc",
21
-		"jess/hollywood:latest":                                                            "sha256:ae7a5519a0a55a2d4ef20ddcbd5d0ca0888a1f7ab806acc8e2a27baf46f529fe",
22
-		"registry@sha256:367eb40fd0330a7e464777121e39d2f5b3e8e23a1e159342e53ab05c9e4d94e6": "sha256:24126a56805beb9711be5f4590cc2eb55ab8d4a85ebd618eed72bb19fc50631c",
23
-		"busybox:latest": "sha256:91e54dfb11794fad694460162bf0cb0a4fa710cfa3f60979c177d920813e267c",
24
-	}
25
-
26
-	marshalledSaveLoadTestCases = []byte(`{"Repositories":{"busybox":{"busybox:latest":"sha256:91e54dfb11794fad694460162bf0cb0a4fa710cfa3f60979c177d920813e267c"},"jess/hollywood":{"jess/hollywood:latest":"sha256:ae7a5519a0a55a2d4ef20ddcbd5d0ca0888a1f7ab806acc8e2a27baf46f529fe"},"registry":{"registry@sha256:367eb40fd0330a7e464777121e39d2f5b3e8e23a1e159342e53ab05c9e4d94e6":"sha256:24126a56805beb9711be5f4590cc2eb55ab8d4a85ebd618eed72bb19fc50631c"},"registry:5000/foobar":{"registry:5000/foobar:HEAD":"sha256:470022b8af682154f57a2163d030eb369549549cba00edc69e1b99b46bb924d6","registry:5000/foobar:alternate":"sha256:ae300ebc4a4f00693702cfb0a5e0b7bc527b353828dc86ad09fb95c8a681b793","registry:5000/foobar:latest":"sha256:6153498b9ac00968d71b66cca4eac37e990b5f9eb50c26877eb8799c8847451b","registry:5000/foobar:master":"sha256:6c9917af4c4e05001b346421959d7ea81b6dc9d25718466a37a6add865dfd7fc"}}}`)
27
-)
28
-
29
-func TestLoad(t *testing.T) {
30
-	jsonFile, err := ioutil.TempFile("", "tag-store-test")
31
-	if err != nil {
32
-		t.Fatalf("error creating temp file: %v", err)
33
-	}
34
-	defer os.RemoveAll(jsonFile.Name())
35
-
36
-	// Write canned json to the temp file
37
-	_, err = jsonFile.Write(marshalledSaveLoadTestCases)
38
-	if err != nil {
39
-		t.Fatalf("error writing to temp file: %v", err)
40
-	}
41
-	jsonFile.Close()
42
-
43
-	store, err := NewTagStore(jsonFile.Name())
44
-	if err != nil {
45
-		t.Fatalf("error creating tag store: %v", err)
46
-	}
47
-
48
-	for refStr, expectedID := range saveLoadTestCases {
49
-		ref, err := reference.ParseNamed(refStr)
50
-		if err != nil {
51
-			t.Fatalf("failed to parse reference: %v", err)
52
-		}
53
-		id, err := store.Get(ref)
54
-		if err != nil {
55
-			t.Fatalf("could not find reference %s: %v", refStr, err)
56
-		}
57
-		if id != expectedID {
58
-			t.Fatalf("expected %s - got %s", expectedID, id)
59
-		}
60
-	}
61
-}
62
-
63
-func TestSave(t *testing.T) {
64
-	jsonFile, err := ioutil.TempFile("", "tag-store-test")
65
-	if err != nil {
66
-		t.Fatalf("error creating temp file: %v", err)
67
-	}
68
-	_, err = jsonFile.Write([]byte(`{}`))
69
-	jsonFile.Close()
70
-	defer os.RemoveAll(jsonFile.Name())
71
-
72
-	store, err := NewTagStore(jsonFile.Name())
73
-	if err != nil {
74
-		t.Fatalf("error creating tag store: %v", err)
75
-	}
76
-
77
-	for refStr, id := range saveLoadTestCases {
78
-		ref, err := reference.ParseNamed(refStr)
79
-		if err != nil {
80
-			t.Fatalf("failed to parse reference: %v", err)
81
-		}
82
-		if canonical, ok := ref.(reference.Canonical); ok {
83
-			err = store.AddDigest(canonical, id, false)
84
-			if err != nil {
85
-				t.Fatalf("could not add digest reference %s: %v", refStr, err)
86
-			}
87
-		} else {
88
-			err = store.AddTag(ref, id, false)
89
-			if err != nil {
90
-				t.Fatalf("could not add reference %s: %v", refStr, err)
91
-			}
92
-		}
93
-	}
94
-
95
-	jsonBytes, err := ioutil.ReadFile(jsonFile.Name())
96
-	if err != nil {
97
-		t.Fatalf("could not read json file: %v", err)
98
-	}
99
-
100
-	if !bytes.Equal(jsonBytes, marshalledSaveLoadTestCases) {
101
-		t.Fatalf("save output did not match expectations\nexpected:\n%s\ngot:\n%s", marshalledSaveLoadTestCases, jsonBytes)
102
-	}
103
-}
104
-
105
-func TestAddDeleteGet(t *testing.T) {
106
-	jsonFile, err := ioutil.TempFile("", "tag-store-test")
107
-	if err != nil {
108
-		t.Fatalf("error creating temp file: %v", err)
109
-	}
110
-	_, err = jsonFile.Write([]byte(`{}`))
111
-	jsonFile.Close()
112
-	defer os.RemoveAll(jsonFile.Name())
113
-
114
-	store, err := NewTagStore(jsonFile.Name())
115
-	if err != nil {
116
-		t.Fatalf("error creating tag store: %v", err)
117
-	}
118
-
119
-	testImageID1 := image.ID("sha256:9655aef5fd742a1b4e1b7b163aa9f1c76c186304bf39102283d80927c916ca9c")
120
-	testImageID2 := image.ID("sha256:9655aef5fd742a1b4e1b7b163aa9f1c76c186304bf39102283d80927c916ca9d")
121
-	testImageID3 := image.ID("sha256:9655aef5fd742a1b4e1b7b163aa9f1c76c186304bf39102283d80927c916ca9e")
122
-
123
-	// Try adding a reference with no tag or digest
124
-	nameOnly, err := reference.WithName("username/repo")
125
-	if err != nil {
126
-		t.Fatalf("could not parse reference: %v", err)
127
-	}
128
-	if err = store.AddTag(nameOnly, testImageID1, false); err != nil {
129
-		t.Fatalf("error adding to store: %v", err)
130
-	}
131
-
132
-	// Add a few references
133
-	ref1, err := reference.ParseNamed("username/repo1:latest")
134
-	if err != nil {
135
-		t.Fatalf("could not parse reference: %v", err)
136
-	}
137
-	if err = store.AddTag(ref1, testImageID1, false); err != nil {
138
-		t.Fatalf("error adding to store: %v", err)
139
-	}
140
-
141
-	ref2, err := reference.ParseNamed("username/repo1:old")
142
-	if err != nil {
143
-		t.Fatalf("could not parse reference: %v", err)
144
-	}
145
-	if err = store.AddTag(ref2, testImageID2, false); err != nil {
146
-		t.Fatalf("error adding to store: %v", err)
147
-	}
148
-
149
-	ref3, err := reference.ParseNamed("username/repo1:alias")
150
-	if err != nil {
151
-		t.Fatalf("could not parse reference: %v", err)
152
-	}
153
-	if err = store.AddTag(ref3, testImageID1, false); err != nil {
154
-		t.Fatalf("error adding to store: %v", err)
155
-	}
156
-
157
-	ref4, err := reference.ParseNamed("username/repo2:latest")
158
-	if err != nil {
159
-		t.Fatalf("could not parse reference: %v", err)
160
-	}
161
-	if err = store.AddTag(ref4, testImageID2, false); err != nil {
162
-		t.Fatalf("error adding to store: %v", err)
163
-	}
164
-
165
-	ref5, err := reference.ParseNamed("username/repo3@sha256:58153dfb11794fad694460162bf0cb0a4fa710cfa3f60979c177d920813e267c")
166
-	if err != nil {
167
-		t.Fatalf("could not parse reference: %v", err)
168
-	}
169
-	if err = store.AddDigest(ref5.(reference.Canonical), testImageID2, false); err != nil {
170
-		t.Fatalf("error adding to store: %v", err)
171
-	}
172
-
173
-	// Attempt to overwrite with force == false
174
-	if err = store.AddTag(ref4, testImageID3, false); err == nil || !strings.HasPrefix(err.Error(), "Conflict:") {
175
-		t.Fatalf("did not get expected error on overwrite attempt - got %v", err)
176
-	}
177
-	// Repeat to overwrite with force == true
178
-	if err = store.AddTag(ref4, testImageID3, true); err != nil {
179
-		t.Fatalf("failed to force tag overwrite: %v", err)
180
-	}
181
-
182
-	// Check references so far
183
-	id, err := store.Get(nameOnly)
184
-	if err != nil {
185
-		t.Fatalf("Get returned error: %v", err)
186
-	}
187
-	if id != testImageID1 {
188
-		t.Fatalf("id mismatch: got %s instead of %s", id.String(), testImageID1.String())
189
-	}
190
-
191
-	id, err = store.Get(ref1)
192
-	if err != nil {
193
-		t.Fatalf("Get returned error: %v", err)
194
-	}
195
-	if id != testImageID1 {
196
-		t.Fatalf("id mismatch: got %s instead of %s", id.String(), testImageID1.String())
197
-	}
198
-
199
-	id, err = store.Get(ref2)
200
-	if err != nil {
201
-		t.Fatalf("Get returned error: %v", err)
202
-	}
203
-	if id != testImageID2 {
204
-		t.Fatalf("id mismatch: got %s instead of %s", id.String(), testImageID2.String())
205
-	}
206
-
207
-	id, err = store.Get(ref3)
208
-	if err != nil {
209
-		t.Fatalf("Get returned error: %v", err)
210
-	}
211
-	if id != testImageID1 {
212
-		t.Fatalf("id mismatch: got %s instead of %s", id.String(), testImageID1.String())
213
-	}
214
-
215
-	id, err = store.Get(ref4)
216
-	if err != nil {
217
-		t.Fatalf("Get returned error: %v", err)
218
-	}
219
-	if id != testImageID3 {
220
-		t.Fatalf("id mismatch: got %s instead of %s", id.String(), testImageID3.String())
221
-	}
222
-
223
-	id, err = store.Get(ref5)
224
-	if err != nil {
225
-		t.Fatalf("Get returned error: %v", err)
226
-	}
227
-	if id != testImageID2 {
228
-		t.Fatalf("id mismatch: got %s instead of %s", id.String(), testImageID3.String())
229
-	}
230
-
231
-	// Get should return ErrDoesNotExist for a nonexistent repo
232
-	nonExistRepo, err := reference.ParseNamed("username/nonexistrepo:latest")
233
-	if err != nil {
234
-		t.Fatalf("could not parse reference: %v", err)
235
-	}
236
-	if _, err = store.Get(nonExistRepo); err != ErrDoesNotExist {
237
-		t.Fatal("Expected ErrDoesNotExist from Get")
238
-	}
239
-
240
-	// Get should return ErrDoesNotExist for a nonexistent tag
241
-	nonExistTag, err := reference.ParseNamed("username/repo1:nonexist")
242
-	if err != nil {
243
-		t.Fatalf("could not parse reference: %v", err)
244
-	}
245
-	if _, err = store.Get(nonExistTag); err != ErrDoesNotExist {
246
-		t.Fatal("Expected ErrDoesNotExist from Get")
247
-	}
248
-
249
-	// Check References
250
-	refs := store.References(testImageID1)
251
-	if len(refs) != 3 {
252
-		t.Fatal("unexpected number of references")
253
-	}
254
-	// Looking for the references in this order verifies that they are
255
-	// returned lexically sorted.
256
-	if refs[0].String() != ref3.String() {
257
-		t.Fatalf("unexpected reference: %v", refs[0].String())
258
-	}
259
-	if refs[1].String() != ref1.String() {
260
-		t.Fatalf("unexpected reference: %v", refs[1].String())
261
-	}
262
-	if refs[2].String() != nameOnly.String()+":latest" {
263
-		t.Fatalf("unexpected reference: %v", refs[2].String())
264
-	}
265
-
266
-	// Check ReferencesByName
267
-	repoName, err := reference.WithName("username/repo1")
268
-	if err != nil {
269
-		t.Fatalf("could not parse reference: %v", err)
270
-	}
271
-	associations := store.ReferencesByName(repoName)
272
-	if len(associations) != 3 {
273
-		t.Fatal("unexpected number of associations")
274
-	}
275
-	// Looking for the associations in this order verifies that they are
276
-	// returned lexically sorted.
277
-	if associations[0].Ref.String() != ref3.String() {
278
-		t.Fatalf("unexpected reference: %v", associations[0].Ref.String())
279
-	}
280
-	if associations[0].ImageID != testImageID1 {
281
-		t.Fatalf("unexpected reference: %v", associations[0].Ref.String())
282
-	}
283
-	if associations[1].Ref.String() != ref1.String() {
284
-		t.Fatalf("unexpected reference: %v", associations[1].Ref.String())
285
-	}
286
-	if associations[1].ImageID != testImageID1 {
287
-		t.Fatalf("unexpected reference: %v", associations[1].Ref.String())
288
-	}
289
-	if associations[2].Ref.String() != ref2.String() {
290
-		t.Fatalf("unexpected reference: %v", associations[2].Ref.String())
291
-	}
292
-	if associations[2].ImageID != testImageID2 {
293
-		t.Fatalf("unexpected reference: %v", associations[2].Ref.String())
294
-	}
295
-
296
-	// Delete should return ErrDoesNotExist for a nonexistent repo
297
-	if _, err = store.Delete(nonExistRepo); err != ErrDoesNotExist {
298
-		t.Fatal("Expected ErrDoesNotExist from Delete")
299
-	}
300
-
301
-	// Delete should return ErrDoesNotExist for a nonexistent tag
302
-	if _, err = store.Delete(nonExistTag); err != ErrDoesNotExist {
303
-		t.Fatal("Expected ErrDoesNotExist from Delete")
304
-	}
305
-
306
-	// Delete a few references
307
-	if deleted, err := store.Delete(ref1); err != nil || deleted != true {
308
-		t.Fatal("Delete failed")
309
-	}
310
-	if _, err := store.Get(ref1); err != ErrDoesNotExist {
311
-		t.Fatal("Expected ErrDoesNotExist from Get")
312
-	}
313
-	if deleted, err := store.Delete(ref5); err != nil || deleted != true {
314
-		t.Fatal("Delete failed")
315
-	}
316
-	if _, err := store.Get(ref5); err != ErrDoesNotExist {
317
-		t.Fatal("Expected ErrDoesNotExist from Get")
318
-	}
319
-	if deleted, err := store.Delete(nameOnly); err != nil || deleted != true {
320
-		t.Fatal("Delete failed")
321
-	}
322
-	if _, err := store.Get(nameOnly); err != ErrDoesNotExist {
323
-		t.Fatal("Expected ErrDoesNotExist from Get")
324
-	}
325
-}
326
-
327
-func TestInvalidTags(t *testing.T) {
328
-	tmpDir, err := ioutil.TempDir("", "tag-store-test")
329
-	defer os.RemoveAll(tmpDir)
330
-
331
-	store, err := NewTagStore(filepath.Join(tmpDir, "repositories.json"))
332
-	if err != nil {
333
-		t.Fatalf("error creating tag store: %v", err)
334
-	}
335
-	id := image.ID("sha256:470022b8af682154f57a2163d030eb369549549cba00edc69e1b99b46bb924d6")
336
-
337
-	// sha256 as repo name
338
-	ref, err := reference.ParseNamed("sha256:abc")
339
-	if err != nil {
340
-		t.Fatal(err)
341
-	}
342
-	err = store.AddTag(ref, id, true)
343
-	if err == nil {
344
-		t.Fatalf("expected setting tag %q to fail", ref)
345
-	}
346
-
347
-	// setting digest as a tag
348
-	ref, err = reference.ParseNamed("registry@sha256:367eb40fd0330a7e464777121e39d2f5b3e8e23a1e159342e53ab05c9e4d94e6")
349
-	if err != nil {
350
-		t.Fatal(err)
351
-	}
352
-	err = store.AddTag(ref, id, true)
353
-	if err == nil {
354
-		t.Fatalf("expected setting digest %q to fail", ref)
355
-	}
356
-
357
-}