Browse code

Documentation improvements and code cleanups for graph package

Expand the godoc documentation for the graph package.

Centralize DefaultTag in the graphs/tag package instead of defining it
twice.

Remove some unnecessary "config" structs that are only used to pass
a few parameters to a function.

Simplify the GetParentsSize function - there's no reason for it to take
an accumulator argument.

Unexport some functions that aren't needed outside the package.

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>

Aaron Lehmann authored on 2015/07/30 08:45:47
Showing 19 changed files
... ...
@@ -526,7 +526,7 @@ func rewriteDockerfileFrom(dockerfileName string, translator func(string, regist
526 526
 			// Replace the line with a resolved "FROM repo@digest"
527 527
 			repo, tag := parsers.ParseRepositoryTag(matches[1])
528 528
 			if tag == "" {
529
-				tag = tags.DEFAULTTAG
529
+				tag = tags.DefaultTag
530 530
 			}
531 531
 			ref := registry.ParseReference(tag)
532 532
 
... ...
@@ -26,7 +26,7 @@ func (cli *DockerCli) pullImageCustomOut(image string, out io.Writer) error {
26 26
 	repos, tag := parsers.ParseRepositoryTag(image)
27 27
 	// pull only the image tagged 'latest' if no tag was specified
28 28
 	if tag == "" {
29
-		tag = tags.DEFAULTTAG
29
+		tag = tags.DefaultTag
30 30
 	}
31 31
 	v.Set("fromImage", repos)
32 32
 	v.Set("tag", tag)
... ...
@@ -96,7 +96,7 @@ func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runc
96 96
 
97 97
 	repo, tag := parsers.ParseRepositoryTag(config.Image)
98 98
 	if tag == "" {
99
-		tag = tags.DEFAULTTAG
99
+		tag = tags.DefaultTag
100 100
 	}
101 101
 
102 102
 	ref := registry.ParseReference(tag)
... ...
@@ -25,7 +25,7 @@ func (cli *DockerCli) CmdPull(args ...string) error {
25 25
 
26 26
 	taglessRemote, tag := parsers.ParseRepositoryTag(remote)
27 27
 	if tag == "" && !*allTags {
28
-		tag = tags.DEFAULTTAG
28
+		tag = tags.DefaultTag
29 29
 		fmt.Fprintf(cli.out, "Using default tag: %s\n", tag)
30 30
 	} else if tag != "" && *allTags {
31 31
 		return fmt.Errorf("tag can't be used with --all-tags/-a")
... ...
@@ -364,14 +364,8 @@ func (s *Server) getImagesJSON(version version.Version, w http.ResponseWriter, r
364 364
 		return err
365 365
 	}
366 366
 
367
-	imagesConfig := graph.ImagesConfig{
368
-		Filters: r.Form.Get("filters"),
369
-		// FIXME this parameter could just be a match filter
370
-		Filter: r.Form.Get("filter"),
371
-		All:    boolValue(r, "all"),
372
-	}
373
-
374
-	images, err := s.daemon.Repositories().Images(&imagesConfig)
367
+	// FIXME: The filter parameter could just be a match filter
368
+	images, err := s.daemon.Repositories().Images(r.Form.Get("filters"), r.Form.Get("filter"), boolValue(r, "all"))
375 369
 	if err != nil {
376 370
 		return err
377 371
 	}
... ...
@@ -785,23 +779,17 @@ func (s *Server) postImagesCreate(version version.Version, w http.ResponseWriter
785 785
 		}
786 786
 
787 787
 		src := r.Form.Get("fromSrc")
788
-		imageImportConfig := &graph.ImageImportConfig{
789
-			Changes:   r.Form["changes"],
790
-			InConfig:  r.Body,
791
-			OutStream: output,
792
-		}
793 788
 
794 789
 		// 'err' MUST NOT be defined within this block, we need any error
795 790
 		// generated from the download to be available to the output
796 791
 		// stream processing below
797 792
 		var newConfig *runconfig.Config
798
-		newConfig, err = builder.BuildFromConfig(s.daemon, &runconfig.Config{}, imageImportConfig.Changes)
793
+		newConfig, err = builder.BuildFromConfig(s.daemon, &runconfig.Config{}, r.Form["changes"])
799 794
 		if err != nil {
800 795
 			return err
801 796
 		}
802
-		imageImportConfig.ContainerConfig = newConfig
803 797
 
804
-		err = s.daemon.Repositories().Import(src, repo, tag, imageImportConfig)
798
+		err = s.daemon.Repositories().Import(src, repo, tag, r.Body, output, newConfig)
805 799
 	}
806 800
 	if err != nil {
807 801
 		if !output.Flushed() {
... ...
@@ -909,14 +897,14 @@ func (s *Server) getImagesGet(version version.Version, w http.ResponseWriter, r
909 909
 	w.Header().Set("Content-Type", "application/x-tar")
910 910
 
911 911
 	output := ioutils.NewWriteFlusher(w)
912
-	imageExportConfig := &graph.ImageExportConfig{Outstream: output}
912
+	var names []string
913 913
 	if name, ok := vars["name"]; ok {
914
-		imageExportConfig.Names = []string{name}
914
+		names = []string{name}
915 915
 	} else {
916
-		imageExportConfig.Names = r.Form["names"]
916
+		names = r.Form["names"]
917 917
 	}
918 918
 
919
-	if err := s.daemon.Repositories().ImageExport(imageExportConfig); err != nil {
919
+	if err := s.daemon.Repositories().ImageExport(names, output); err != nil {
920 920
 		if !output.Flushed() {
921 921
 			return err
922 922
 		}
... ...
@@ -4,7 +4,7 @@ import (
4 4
 	"fmt"
5 5
 
6 6
 	"github.com/Sirupsen/logrus"
7
-	"github.com/docker/docker/graph"
7
+	"github.com/docker/docker/graph/tags"
8 8
 	"github.com/docker/docker/image"
9 9
 	"github.com/docker/docker/pkg/parsers"
10 10
 	"github.com/docker/docker/runconfig"
... ...
@@ -27,7 +27,7 @@ func (daemon *Daemon) ContainerCreate(name string, config *runconfig.Config, hos
27 27
 		if daemon.Graph().IsNotExist(err, config.Image) {
28 28
 			_, tag := parsers.ParseRepositoryTag(config.Image)
29 29
 			if tag == "" {
30
-				tag = graph.DefaultTag
30
+				tag = tags.DefaultTag
31 31
 			}
32 32
 			return "", warnings, fmt.Errorf("No such image: %s (tag: %s)", config.Image, tag)
33 33
 		}
... ...
@@ -6,7 +6,7 @@ import (
6 6
 
7 7
 	"github.com/Sirupsen/logrus"
8 8
 	"github.com/docker/docker/api/types"
9
-	"github.com/docker/docker/graph"
9
+	"github.com/docker/docker/graph/tags"
10 10
 	"github.com/docker/docker/image"
11 11
 	"github.com/docker/docker/pkg/parsers"
12 12
 	"github.com/docker/docker/pkg/stringid"
... ...
@@ -27,16 +27,13 @@ func (daemon *Daemon) ImageDelete(name string, force, noprune bool) ([]types.Ima
27 27
 }
28 28
 
29 29
 func (daemon *Daemon) imgDeleteHelper(name string, list *[]types.ImageDelete, first, force, noprune bool) error {
30
-	var (
31
-		repoName, tag string
32
-		tags          = []string{}
33
-	)
30
+	var repoName, tag string
34 31
 	repoAndTags := make(map[string][]string)
35 32
 
36 33
 	// FIXME: please respect DRY and centralize repo+tag parsing in a single central place! -- shykes
37 34
 	repoName, tag = parsers.ParseRepositoryTag(name)
38 35
 	if tag == "" {
39
-		tag = graph.DefaultTag
36
+		tag = tags.DefaultTag
40 37
 	}
41 38
 
42 39
 	if name == "" {
... ...
@@ -111,7 +108,7 @@ func (daemon *Daemon) imgDeleteHelper(name string, list *[]types.ImageDelete, fi
111 111
 			}
112 112
 		}
113 113
 	}
114
-	tags = daemon.Repositories().ByID()[img.ID]
114
+	tags := daemon.Repositories().ByID()[img.ID]
115 115
 	if (len(tags) <= 1 && repoName == "") || len(tags) == 0 {
116 116
 		if len(byParents[img.ID]) == 0 {
117 117
 			if err := daemon.Repositories().DeleteAll(img.ID); err != nil {
... ...
@@ -13,21 +13,12 @@ import (
13 13
 	"github.com/docker/docker/registry"
14 14
 )
15 15
 
16
-// ImageExportConfig holds list of names to be exported to a output stream.
17
-// All images with the given tag and all versions
18
-// containing the same tag are exported. The resulting output is an
19
-// uncompressed tar ball.
20
-type ImageExportConfig struct {
21
-	// Names is the set of tags to export.
22
-	Names []string
23
-	// OutStream is the writer where the images are written to.
24
-	Outstream io.Writer
25
-}
26
-
27
-// ImageExport exports list of images to a output stream specified in the config.
28
-// The exported images are archived into a tar when written to the output stream.
29
-func (s *TagStore) ImageExport(imageExportConfig *ImageExportConfig) error {
30
-
16
+// ImageExport exports list of images to a output stream specified in the
17
+// config. The exported images are archived into a tar when written to the
18
+// output stream. All images with the given tag and all versions containing the
19
+// same tag are exported. names is the set of tags to export, and outStream
20
+// is the writer which the images are written to.
21
+func (s *TagStore) ImageExport(names []string, outStream io.Writer) error {
31 22
 	// get image json
32 23
 	tempdir, err := ioutil.TempDir("", "docker-export-")
33 24
 	if err != nil {
... ...
@@ -44,7 +35,7 @@ func (s *TagStore) ImageExport(imageExportConfig *ImageExportConfig) error {
44 44
 			repo[tag] = id
45 45
 		}
46 46
 	}
47
-	for _, name := range imageExportConfig.Names {
47
+	for _, name := range names {
48 48
 		name = registry.NormalizeLocalName(name)
49 49
 		logrus.Debugf("Serializing %s", name)
50 50
 		rootRepo := s.Repositories[name]
... ...
@@ -107,7 +98,7 @@ func (s *TagStore) ImageExport(imageExportConfig *ImageExportConfig) error {
107 107
 	}
108 108
 	defer fs.Close()
109 109
 
110
-	if _, err := io.Copy(imageExportConfig.Outstream, fs); err != nil {
110
+	if _, err := io.Copy(outStream, fs); err != nil {
111 111
 		return err
112 112
 	}
113 113
 	logrus.Debugf("End export image")
... ...
@@ -152,10 +152,11 @@ func (graph *Graph) restore() error {
152 152
 	return nil
153 153
 }
154 154
 
155
-// IsNotExist detects whether an image exists by parsing the incoming error message.
156
-// FIXME: Implement error subclass instead of looking at the error text
157
-// Note: This is the way golang implements os.IsNotExists on Plan9
155
+// IsNotExist detects whether an image exists by parsing the incoming error
156
+// message.
158 157
 func (graph *Graph) IsNotExist(err error, id string) bool {
158
+	// FIXME: Implement error subclass instead of looking at the error text
159
+	// Note: This is the way golang implements os.IsNotExists on Plan9
159 160
 	return err != nil && (strings.Contains(strings.ToLower(err.Error()), "does not exist") || strings.Contains(strings.ToLower(err.Error()), "no such")) && strings.Contains(err.Error(), id)
160 161
 }
161 162
 
... ...
@@ -415,13 +416,13 @@ func (graph *Graph) ByParent() map[string][]*image.Image {
415 415
 	return byParent
416 416
 }
417 417
 
418
-// Retain keeps the images and layers that are in pulling chain so that they are not deleted.
419
-// If not, they may be deleted by rmi with dangling condition.
418
+// Retain keeps the images and layers that are in the pulling chain so that
419
+// they are not deleted. If not retained, they may be deleted by rmi.
420 420
 func (graph *Graph) Retain(sessionID string, layerIDs ...string) {
421 421
 	graph.retained.Add(sessionID, layerIDs)
422 422
 }
423 423
 
424
-// Release removes the referenced image id from the provided set of layers.
424
+// Release removes the referenced image ID from the provided set of layers.
425 425
 func (graph *Graph) Release(sessionID string, layerIDs ...string) {
426 426
 	graph.retained.Delete(sessionID, layerIDs)
427 427
 }
... ...
@@ -67,7 +67,8 @@ func (graph *Graph) CheckDepth(img *image.Image) error {
67 67
 	return nil
68 68
 }
69 69
 
70
-// History returns a list of ImageHistory for the specified image name by walking the image lineage.
70
+// History returns a slice of ImageHistory structures for the specified image
71
+// name by walking the image lineage.
71 72
 func (s *TagStore) History(name string) ([]*types.ImageHistory, error) {
72 73
 	foundImage, err := s.LookupImage(name)
73 74
 	if err != nil {
... ...
@@ -102,7 +103,7 @@ func (s *TagStore) History(name string) ([]*types.ImageHistory, error) {
102 102
 	return history, err
103 103
 }
104 104
 
105
-// GetParent returns the parent image.
105
+// GetParent returns the parent image for the specified image.
106 106
 func (graph *Graph) GetParent(img *image.Image) (*image.Image, error) {
107 107
 	if img.Parent == "" {
108 108
 		return nil, nil
... ...
@@ -110,12 +111,12 @@ func (graph *Graph) GetParent(img *image.Image) (*image.Image, error) {
110 110
 	return graph.Get(img.Parent)
111 111
 }
112 112
 
113
-// GetParentsSize returns the size of the parent.
114
-func (graph *Graph) GetParentsSize(img *image.Image, size int64) int64 {
113
+// GetParentsSize returns the combined size of all parent images. If there is
114
+// no parent image or it's unavailable, it returns 0.
115
+func (graph *Graph) GetParentsSize(img *image.Image) int64 {
115 116
 	parentImage, err := graph.GetParent(img)
116 117
 	if err != nil || parentImage == nil {
117
-		return size
118
+		return 0
118 119
 	}
119
-	size += parentImage.Size
120
-	return graph.GetParentsSize(parentImage, size)
120
+	return parentImage.Size + graph.GetParentsSize(parentImage)
121 121
 }
... ...
@@ -13,22 +13,11 @@ import (
13 13
 	"github.com/docker/docker/utils"
14 14
 )
15 15
 
16
-// ImageImportConfig holds configuration to import a image.
17
-type ImageImportConfig struct {
18
-	// Changes are the container changes written to top layer.
19
-	Changes []string
20
-	// InConfig is the input stream containers layered data.
21
-	InConfig io.ReadCloser
22
-	// OutStream is the output stream where the image is written.
23
-	OutStream io.Writer
24
-	// ContainerConfig is the configuration of commit container.
25
-	ContainerConfig *runconfig.Config
26
-}
27
-
28
-// Import allows to download image from  a archive.
29
-// If the src is a URL, the content is downloaded from the archive. If the source is '-' then the imageImportConfig.InConfig
30
-// reader will be used to load the image. Once all the layers required are loaded locally, image is then tagged using the tag specified.
31
-func (s *TagStore) Import(src string, repo string, tag string, imageImportConfig *ImageImportConfig) error {
16
+// Import imports an image, getting the archived layer data either from
17
+// inConfig (if src is "-"), or from a URI specified in src. Progress output is
18
+// written to outStream. Repository and tag names can optionally be given in
19
+// the repo and tag arguments, respectively.
20
+func (s *TagStore) Import(src string, repo string, tag string, inConfig io.ReadCloser, outStream io.Writer, containerConfig *runconfig.Config) error {
32 21
 	var (
33 22
 		sf      = streamformatter.NewJSONStreamFormatter()
34 23
 		archive archive.ArchiveReader
... ...
@@ -36,7 +25,7 @@ func (s *TagStore) Import(src string, repo string, tag string, imageImportConfig
36 36
 	)
37 37
 
38 38
 	if src == "-" {
39
-		archive = imageImportConfig.InConfig
39
+		archive = inConfig
40 40
 	} else {
41 41
 		u, err := url.Parse(src)
42 42
 		if err != nil {
... ...
@@ -47,14 +36,14 @@ func (s *TagStore) Import(src string, repo string, tag string, imageImportConfig
47 47
 			u.Host = src
48 48
 			u.Path = ""
49 49
 		}
50
-		imageImportConfig.OutStream.Write(sf.FormatStatus("", "Downloading from %s", u))
50
+		outStream.Write(sf.FormatStatus("", "Downloading from %s", u))
51 51
 		resp, err = httputils.Download(u.String())
52 52
 		if err != nil {
53 53
 			return err
54 54
 		}
55 55
 		progressReader := progressreader.New(progressreader.Config{
56 56
 			In:        resp.Body,
57
-			Out:       imageImportConfig.OutStream,
57
+			Out:       outStream,
58 58
 			Formatter: sf,
59 59
 			Size:      int(resp.ContentLength),
60 60
 			NewLines:  true,
... ...
@@ -65,7 +54,7 @@ func (s *TagStore) Import(src string, repo string, tag string, imageImportConfig
65 65
 		archive = progressReader
66 66
 	}
67 67
 
68
-	img, err := s.graph.Create(archive, "", "", "Imported from "+src, "", nil, imageImportConfig.ContainerConfig)
68
+	img, err := s.graph.Create(archive, "", "", "Imported from "+src, "", nil, containerConfig)
69 69
 	if err != nil {
70 70
 		return err
71 71
 	}
... ...
@@ -75,7 +64,7 @@ func (s *TagStore) Import(src string, repo string, tag string, imageImportConfig
75 75
 			return err
76 76
 		}
77 77
 	}
78
-	imageImportConfig.OutStream.Write(sf.FormatStatus("", img.ID))
78
+	outStream.Write(sf.FormatStatus("", img.ID))
79 79
 	logID := img.ID
80 80
 	if tag != "" {
81 81
 		logID = utils.ImageReference(logID, tag)
... ...
@@ -18,25 +18,20 @@ var acceptedImageFilterTags = map[string]struct{}{
18 18
 	"label":    {},
19 19
 }
20 20
 
21
-// ImagesConfig defines the criteria to obtain a list of images.
22
-type ImagesConfig struct {
23
-	// Filters is supported list of filters used to get list of images.
24
-	Filters string
25
-	// Filter the list of images by name.
26
-	Filter string
27
-	// All inditest that all the images will be returned in the list, if set to true.
28
-	All bool
29
-}
30
-
31
-// byCreated is a temporary type used to sort list of images on their field 'Created'.
21
+// byCreated is a temporary type used to sort a list of images by creation
22
+// time.
32 23
 type byCreated []*types.Image
33 24
 
34 25
 func (r byCreated) Len() int           { return len(r) }
35 26
 func (r byCreated) Swap(i, j int)      { r[i], r[j] = r[j], r[i] }
36 27
 func (r byCreated) Less(i, j int) bool { return r[i].Created < r[j].Created }
37 28
 
38
-// Images provide list of images based on selection criteria.
39
-func (s *TagStore) Images(config *ImagesConfig) ([]*types.Image, error) {
29
+// Images returns a filtered list of images. filterArgs is a JSON-encoded set
30
+// of filter arguments which will be interpreted by pkg/parsers/filters.
31
+// filter is a shell glob string applied to repository names. The argument
32
+// named all controls whether all images in the graph are filtered, or just
33
+// the heads.
34
+func (s *TagStore) Images(filterArgs, filter string, all bool) ([]*types.Image, error) {
40 35
 	var (
41 36
 		allImages  map[string]*image.Image
42 37
 		err        error
... ...
@@ -44,7 +39,7 @@ func (s *TagStore) Images(config *ImagesConfig) ([]*types.Image, error) {
44 44
 		filtLabel  = false
45 45
 	)
46 46
 
47
-	imageFilters, err := filters.FromParam(config.Filters)
47
+	imageFilters, err := filters.FromParam(filterArgs)
48 48
 	if err != nil {
49 49
 		return nil, err
50 50
 	}
... ...
@@ -64,7 +59,7 @@ func (s *TagStore) Images(config *ImagesConfig) ([]*types.Image, error) {
64 64
 
65 65
 	_, filtLabel = imageFilters["label"]
66 66
 
67
-	if config.All && filtTagged {
67
+	if all && filtTagged {
68 68
 		allImages = s.graph.Map()
69 69
 	} else {
70 70
 		allImages = s.graph.Heads()
... ...
@@ -73,8 +68,8 @@ func (s *TagStore) Images(config *ImagesConfig) ([]*types.Image, error) {
73 73
 	lookup := make(map[string]*types.Image)
74 74
 	s.Lock()
75 75
 	for repoName, repository := range s.Repositories {
76
-		if config.Filter != "" {
77
-			if match, _ := path.Match(config.Filter, repoName); !match {
76
+		if filter != "" {
77
+			if match, _ := path.Match(filter, repoName); !match {
78 78
 				continue
79 79
 			}
80 80
 		}
... ...
@@ -106,7 +101,7 @@ func (s *TagStore) Images(config *ImagesConfig) ([]*types.Image, error) {
106 106
 					newImage.ID = image.ID
107 107
 					newImage.Created = int(image.Created.Unix())
108 108
 					newImage.Size = int(image.Size)
109
-					newImage.VirtualSize = int(s.graph.GetParentsSize(image, 0) + image.Size)
109
+					newImage.VirtualSize = int(s.graph.GetParentsSize(image) + image.Size)
110 110
 					newImage.Labels = image.ContainerConfig.Labels
111 111
 
112 112
 					if utils.DigestReference(ref) {
... ...
@@ -131,7 +126,7 @@ func (s *TagStore) Images(config *ImagesConfig) ([]*types.Image, error) {
131 131
 	}
132 132
 
133 133
 	// Display images which aren't part of a repository/tag
134
-	if config.Filter == "" || filtLabel {
134
+	if filter == "" || filtLabel {
135 135
 		for _, image := range allImages {
136 136
 			if !imageFilters.MatchKVList("label", image.ContainerConfig.Labels) {
137 137
 				continue
... ...
@@ -143,7 +138,7 @@ func (s *TagStore) Images(config *ImagesConfig) ([]*types.Image, error) {
143 143
 			newImage.ID = image.ID
144 144
 			newImage.Created = int(image.Created.Unix())
145 145
 			newImage.Size = int(image.Size)
146
-			newImage.VirtualSize = int(s.graph.GetParentsSize(image, 0) + image.Size)
146
+			newImage.VirtualSize = int(s.graph.GetParentsSize(image) + image.Size)
147 147
 			newImage.Labels = image.ContainerConfig.Labels
148 148
 
149 149
 			images = append(images, newImage)
... ...
@@ -71,7 +71,7 @@ func (s *TagStore) Load(inTar io.ReadCloser, outStream io.Writer) error {
71 71
 
72 72
 	for imageName, tagMap := range repositories {
73 73
 		for tag, address := range tagMap {
74
-			if err := s.SetLoad(imageName, tag, address, true, outStream); err != nil {
74
+			if err := s.setLoad(imageName, tag, address, true, outStream); err != nil {
75 75
 				return err
76 76
 			}
77 77
 		}
... ...
@@ -13,15 +13,18 @@ import (
13 13
 
14 14
 // ImagePullConfig stores pull configuration.
15 15
 type ImagePullConfig struct {
16
-	// MetaHeaders store meta data about the image (DockerHeaders with prefix X-Meta- in the request).
16
+	// MetaHeaders stores HTTP headers with metadata about the image
17
+	// (DockerHeaders with prefix X-Meta- in the request).
17 18
 	MetaHeaders map[string][]string
18
-	// AuthConfig holds authentication information for authorizing with the registry.
19
+	// AuthConfig holds authentication credentials for authenticating with
20
+	// the registry.
19 21
 	AuthConfig *cliconfig.AuthConfig
20
-	// OutStream is the output writer for showing the status of the pull operation.
22
+	// OutStream is the output writer for showing the status of the pull
23
+	// operation.
21 24
 	OutStream io.Writer
22 25
 }
23 26
 
24
-// Puller is an interface to define Pull behavior.
27
+// Puller is an interface that abstracts pulling for different API versions.
25 28
 type Puller interface {
26 29
 	// Pull tries to pull the image referenced by `tag`
27 30
 	// Pull returns an error if any, as well as a boolean that determines whether to retry Pull on the next configured endpoint.
... ...
@@ -30,7 +33,11 @@ type Puller interface {
30 30
 	Pull(tag string) (fallback bool, err error)
31 31
 }
32 32
 
33
-// NewPuller returns a new instance of an implementation conforming to Puller interface.
33
+// NewPuller returns a Puller interface that will pull from either a v1 or v2
34
+// registry. The endpoint argument contains a Version field that determines
35
+// whether a v1 or v2 puller will be created. The other parameters are passed
36
+// through to the underlying puller implementation for use during the actual
37
+// pull operation.
34 38
 func NewPuller(s *TagStore, endpoint registry.APIEndpoint, repoInfo *registry.RepositoryInfo, imagePullConfig *ImagePullConfig, sf *streamformatter.StreamFormatter) (Puller, error) {
35 39
 	switch endpoint.Version {
36 40
 	case registry.APIVersion2:
... ...
@@ -53,7 +60,8 @@ func NewPuller(s *TagStore, endpoint registry.APIEndpoint, repoInfo *registry.Re
53 53
 	return nil, fmt.Errorf("unknown version %d for registry %s", endpoint.Version, endpoint.URL)
54 54
 }
55 55
 
56
-// Pull downloads a image with specified name and tag from the repo.
56
+// Pull initiates a pull operation. image is the repository name to pull, and
57
+// tag may be either empty, or indicate a specific tag to pull.
57 58
 func (s *TagStore) Pull(image string, tag string, imagePullConfig *ImagePullConfig) error {
58 59
 	var sf = streamformatter.NewJSONStreamFormatter()
59 60
 
... ...
@@ -133,7 +141,10 @@ func (s *TagStore) Pull(image string, tag string, imagePullConfig *ImagePullConf
133 133
 	return lastErr
134 134
 }
135 135
 
136
-// writeStatus shows status of the pull command.
136
+// writeStatus writes a status message to out. If layersDownloaded is true, the
137
+// status message indicates that a newer image was downloaded. Otherwise, it
138
+// indicates that the image is up to date. requestedTag is the tag the message
139
+// will refer to.
137 140
 func writeStatus(requestedTag string, out io.Writer, sf *streamformatter.StreamFormatter, layersDownloaded bool) {
138 141
 	if layersDownloaded {
139 142
 		out.Write(sf.FormatStatus("", "Status: Downloaded newer image for %s", requestedTag))
... ...
@@ -12,17 +12,21 @@ import (
12 12
 
13 13
 // ImagePushConfig stores push configuration.
14 14
 type ImagePushConfig struct {
15
-	// MetaHeaders store meta data about the image (DockerHeaders with prefix X-Meta- in the request).
15
+	// MetaHeaders store HTTP headers with metadata about the image
16
+	// (DockerHeaders with prefix X-Meta- in the request).
16 17
 	MetaHeaders map[string][]string
17
-	// AuthConfig holds authentication information for authorizing with the registry.
18
+	// AuthConfig holds authentication credentials for authenticating with
19
+	// the registry.
18 20
 	AuthConfig *cliconfig.AuthConfig
19
-	// Tag is the specific variant of the image to be pushed, this tag used when image is pushed. If no tag is provided, all tags will be pushed.
21
+	// Tag is the specific variant of the image to be pushed.
22
+	// If no tag is provided, all tags will be pushed.
20 23
 	Tag string
21
-	// OutStream is the output writer for showing the status of the push operation.
24
+	// OutStream is the output writer for showing the status of the push
25
+	// operation.
22 26
 	OutStream io.Writer
23 27
 }
24 28
 
25
-// Pusher is an interface to define Push behavior.
29
+// Pusher is an interface that abstracts pushing for different API versions.
26 30
 type Pusher interface {
27 31
 	// Push tries to push the image configured at the creation of Pusher.
28 32
 	// Push returns an error if any, as well as a boolean that determines whether to retry Push on the next configured endpoint.
... ...
@@ -31,7 +35,11 @@ type Pusher interface {
31 31
 	Push() (fallback bool, err error)
32 32
 }
33 33
 
34
-// NewPusher returns a new instance of an implementation conforming to Pusher interface.
34
+// NewPusher creates a new Pusher interface that will push to either a v1 or v2
35
+// registry. The endpoint argument contains a Version field that determines
36
+// whether a v1 or v2 pusher will be created. The other parameters are passed
37
+// through to the underlying pusher implementation for use during the actual
38
+// push operation.
35 39
 func (s *TagStore) NewPusher(endpoint registry.APIEndpoint, localRepo Repository, repoInfo *registry.RepositoryInfo, imagePushConfig *ImagePushConfig, sf *streamformatter.StreamFormatter) (Pusher, error) {
36 40
 	switch endpoint.Version {
37 41
 	case registry.APIVersion2:
... ...
@@ -57,10 +65,10 @@ func (s *TagStore) NewPusher(endpoint registry.APIEndpoint, localRepo Repository
57 57
 	return nil, fmt.Errorf("unknown version %d for registry %s", endpoint.Version, endpoint.URL)
58 58
 }
59 59
 
60
-// FIXME: Allow to interrupt current push when new push of same image is done.
61
-
62
-// Push a image to the repo.
60
+// Push initiates a push operation on the repository named localName.
63 61
 func (s *TagStore) Push(localName string, imagePushConfig *ImagePushConfig) error {
62
+	// FIXME: Allow to interrupt current push when new push of same image is done.
63
+
64 64
 	var sf = streamformatter.NewJSONStreamFormatter()
65 65
 
66 66
 	// Resolve the Repository name from fqn to RepositoryInfo
... ...
@@ -27,7 +27,9 @@ func (dcs dumbCredentialStore) Basic(*url.URL) (string, string) {
27 27
 	return dcs.auth.Username, dcs.auth.Password
28 28
 }
29 29
 
30
-// NewV2Repository creates a v2 only repository.
30
+// NewV2Repository returns a repository (v2 only). It creates a HTTP transport
31
+// providing timeout settings and authentication support, and also verifies the
32
+// remote API version.
31 33
 func NewV2Repository(repoInfo *registry.RepositoryInfo, endpoint registry.APIEndpoint, metaHeaders http.Header, authConfig *cliconfig.AuthConfig) (distribution.Repository, error) {
32 34
 	ctx := context.Background()
33 35
 
... ...
@@ -10,6 +10,8 @@ import (
10 10
 	"github.com/docker/docker/api/types"
11 11
 )
12 12
 
13
+// lookupRaw looks up an image by name in a TagStore and returns the raw JSON
14
+// describing the image.
13 15
 func (s *TagStore) lookupRaw(name string) ([]byte, error) {
14 16
 	image, err := s.LookupImage(name)
15 17
 	if err != nil || image == nil {
... ...
@@ -24,7 +26,8 @@ func (s *TagStore) lookupRaw(name string) ([]byte, error) {
24 24
 	return imageInspectRaw, nil
25 25
 }
26 26
 
27
-// Lookup return an image encoded in JSON
27
+// Lookup looks up an image by name in a TagStore and returns it as an
28
+// ImageInspect structure.
28 29
 func (s *TagStore) Lookup(name string) (*types.ImageInspect, error) {
29 30
 	image, err := s.LookupImage(name)
30 31
 	if err != nil || image == nil {
... ...
@@ -44,7 +47,7 @@ func (s *TagStore) Lookup(name string) (*types.ImageInspect, error) {
44 44
 		Architecture:    image.Architecture,
45 45
 		Os:              image.OS,
46 46
 		Size:            image.Size,
47
-		VirtualSize:     s.graph.GetParentsSize(image, 0) + image.Size,
47
+		VirtualSize:     s.graph.GetParentsSize(image) + image.Size,
48 48
 	}
49 49
 
50 50
 	imageInspect.GraphDriver.Name = s.graph.driver.String()
... ...
@@ -24,13 +24,13 @@ import (
24 24
 	"github.com/docker/libtrust"
25 25
 )
26 26
 
27
-// DefaultTag defines the default tag used when performing images related actions and no tag string is specified
28
-const DefaultTag = "latest"
29
-
30
-// TagStore contains information to push and pull to the repo.
27
+// TagStore manages repositories. It encompasses the Graph used for versioned
28
+// storage, as well as various services involved in pushing and pulling
29
+// repositories.
31 30
 type TagStore struct {
32
-	path         string
33
-	graph        *Graph
31
+	path  string
32
+	graph *Graph
33
+	// Repositories is a map of repositories, indexed by name.
34 34
 	Repositories map[string]Repository
35 35
 	trustKey     libtrust.PrivateKey
36 36
 	sync.Mutex
... ...
@@ -43,7 +43,7 @@ type TagStore struct {
43 43
 	trustService    *trust.TrustStore
44 44
 }
45 45
 
46
-// Repository maps image id to image tag.
46
+// Repository maps tags to image IDs.
47 47
 type Repository map[string]string
48 48
 
49 49
 // Update updates repository mapping with content of repository 'u'.
... ...
@@ -53,7 +53,8 @@ func (r Repository) Update(u Repository) {
53 53
 	}
54 54
 }
55 55
 
56
-// Contains returns true if the contents of u Repository, are wholly contained in r Repository.
56
+// Contains returns true if the contents of Repository u are wholly contained
57
+// in Repository r.
57 58
 func (r Repository) Contains(u Repository) bool {
58 59
 	for k, v := range u {
59 60
 		// if u's key is not present in r OR u's key is present, but not the same value
... ...
@@ -64,16 +65,23 @@ func (r Repository) Contains(u Repository) bool {
64 64
 	return true
65 65
 }
66 66
 
67
-// TagStoreConfig holds tag store configuration.
67
+// TagStoreConfig provides parameters for a new TagStore.
68 68
 type TagStoreConfig struct {
69
-	Graph    *Graph
70
-	Key      libtrust.PrivateKey
69
+	// Graph is the versioned image store
70
+	Graph *Graph
71
+	// Key is the private key to use for signing manifests.
72
+	Key libtrust.PrivateKey
73
+	// Registry is the registry service to use for TLS configuration and
74
+	// endpoint lookup.
71 75
 	Registry *registry.Service
72
-	Events   *events.Events
73
-	Trust    *trust.TrustStore
76
+	// Events is the events service to use for logging.
77
+	Events *events.Events
78
+	// Trust is the trust service to use for push and pull operations.
79
+	Trust *trust.TrustStore
74 80
 }
75 81
 
76
-// NewTagStore creates a tag store to specified path.
82
+// NewTagStore creates a new TagStore at specified path, using the parameters
83
+// and services provided in cfg.
77 84
 func NewTagStore(path string, cfg *TagStoreConfig) (*TagStore, error) {
78 85
 	abspath, err := filepath.Abs(path)
79 86
 	if err != nil {
... ...
@@ -126,13 +134,15 @@ func (store *TagStore) reload() error {
126 126
 	return nil
127 127
 }
128 128
 
129
-// LookupImage returns the image from the store.
129
+// LookupImage returns pointer to an Image struct corresponding to the given
130
+// name. The name can include an optional tag; otherwise the default tag will
131
+// be used.
130 132
 func (store *TagStore) LookupImage(name string) (*image.Image, error) {
131 133
 	// FIXME: standardize on returning nil when the image doesn't exist, and err for everything else
132 134
 	// (so we can pass all errors here)
133 135
 	repoName, ref := parsers.ParseRepositoryTag(name)
134 136
 	if ref == "" {
135
-		ref = DefaultTag
137
+		ref = tags.DefaultTag
136 138
 	}
137 139
 	var (
138 140
 		err error
... ...
@@ -158,8 +168,8 @@ func (store *TagStore) LookupImage(name string) (*image.Image, error) {
158 158
 	return img, nil
159 159
 }
160 160
 
161
-// ByID returns a reverse-lookup table of all the names which refer to each image.
162
-// Eg. {"43b5f19b10584": {"base:latest", "base:v1"}}
161
+// ByID returns a reverse-lookup table of all the names which refer to each
162
+// image - e.g. {"43b5f19b10584": {"base:latest", "base:v1"}}
163 163
 func (store *TagStore) ByID() map[string][]string {
164 164
 	store.Lock()
165 165
 	defer store.Unlock()
... ...
@@ -178,7 +188,7 @@ func (store *TagStore) ByID() map[string][]string {
178 178
 	return byID
179 179
 }
180 180
 
181
-// ImageName returns name of the image.
181
+// ImageName returns name of an image, given the image's ID.
182 182
 func (store *TagStore) ImageName(id string) string {
183 183
 	if names, exists := store.ByID()[id]; exists && len(names) > 0 {
184 184
 		return names[0]
... ...
@@ -186,7 +196,7 @@ func (store *TagStore) ImageName(id string) string {
186 186
 	return stringid.TruncateID(id)
187 187
 }
188 188
 
189
-// DeleteAll removes images identified by a specific id from the store.
189
+// DeleteAll removes images identified by a specific ID from the store.
190 190
 func (store *TagStore) DeleteAll(id string) error {
191 191
 	names, exists := store.ByID()[id]
192 192
 	if !exists || len(names) == 0 {
... ...
@@ -207,7 +217,9 @@ func (store *TagStore) DeleteAll(id string) error {
207 207
 	return nil
208 208
 }
209 209
 
210
-// Delete removes a repo identified by a given name from the store
210
+// Delete deletes a repository or a specific tag. If ref is empty, the entire
211
+// repository named repoName will be deleted; otherwise only the tag named by
212
+// ref will be deleted.
211 213
 func (store *TagStore) Delete(repoName, ref string) (bool, error) {
212 214
 	store.Lock()
213 215
 	defer store.Unlock()
... ...
@@ -240,14 +252,16 @@ func (store *TagStore) Delete(repoName, ref string) (bool, error) {
240 240
 	return deleted, store.save()
241 241
 }
242 242
 
243
-// Tag adds a new tag to an existing image.
243
+// Tag creates a tag in the repository reponame, pointing to the image named
244
+// imageName. If force is true, an existing tag with the same name may be
245
+// overwritten.
244 246
 func (store *TagStore) Tag(repoName, tag, imageName string, force bool) error {
245
-	return store.SetLoad(repoName, tag, imageName, force, nil)
247
+	return store.setLoad(repoName, tag, imageName, force, nil)
246 248
 }
247 249
 
248
-// SetLoad stores the image to the store.
250
+// setLoad stores the image to the store.
249 251
 // If the imageName is already in the repo then a '-f' flag should be used to replace existing image.
250
-func (store *TagStore) SetLoad(repoName, tag, imageName string, force bool, out io.Writer) error {
252
+func (store *TagStore) setLoad(repoName, tag, imageName string, force bool, out io.Writer) error {
251 253
 	img, err := store.LookupImage(imageName)
252 254
 	store.Lock()
253 255
 	defer store.Unlock()
... ...
@@ -255,7 +269,7 @@ func (store *TagStore) SetLoad(repoName, tag, imageName string, force bool, out
255 255
 		return err
256 256
 	}
257 257
 	if tag == "" {
258
-		tag = tags.DEFAULTTAG
258
+		tag = tags.DefaultTag
259 259
 	}
260 260
 	if err := validateRepoName(repoName); err != nil {
261 261
 		return err
... ...
@@ -331,7 +345,7 @@ func (store *TagStore) SetDigest(repoName, digest, imageName string) error {
331 331
 	return store.save()
332 332
 }
333 333
 
334
-// Get returns a repo from the store.
334
+// Get returns the Repository tag/image map for a given repository.
335 335
 func (store *TagStore) Get(repoName string) (Repository, error) {
336 336
 	store.Lock()
337 337
 	defer store.Unlock()
... ...
@@ -345,7 +359,8 @@ func (store *TagStore) Get(repoName string) (Repository, error) {
345 345
 	return nil, nil
346 346
 }
347 347
 
348
-// GetImage returns an image from a given repo from the store.
348
+// GetImage returns a pointer to an Image structure describing the image
349
+// referred to by refOrID inside repository repoName.
349 350
 func (store *TagStore) GetImage(repoName, refOrID string) (*image.Image, error) {
350 351
 	repo, err := store.Get(repoName)
351 352
 
... ...
@@ -375,7 +390,8 @@ func (store *TagStore) GetImage(repoName, refOrID string) (*image.Image, error)
375 375
 	return nil, nil
376 376
 }
377 377
 
378
-// GetRepoRefs returns list of repos.
378
+// GetRepoRefs returns a map with image IDs as keys, and slices listing
379
+// repo/tag references as the values. It covers all repositories.
379 380
 func (store *TagStore) GetRepoRefs() map[string][]string {
380 381
 	store.Lock()
381 382
 	reporefs := make(map[string][]string)
... ...
@@ -6,8 +6,12 @@ import (
6 6
 	"github.com/docker/distribution/registry/api/v2"
7 7
 )
8 8
 
9
-const DEFAULTTAG = "latest"
9
+// DefaultTag is the default tag for the case where no explicit tag is
10
+// specified.
11
+const DefaultTag = "latest"
10 12
 
13
+// ErrTagInvalidFormat is an error type used when the tag name has invalid
14
+// characters or is longer than allowed.
11 15
 type ErrTagInvalidFormat struct {
12 16
 	name string
13 17
 }
... ...
@@ -11,6 +11,7 @@ import (
11 11
 	"github.com/docker/docker/daemon/events"
12 12
 	"github.com/docker/docker/daemon/graphdriver"
13 13
 	_ "github.com/docker/docker/daemon/graphdriver/vfs" // import the vfs driver so it is used in the tests
14
+	"github.com/docker/docker/graph/tags"
14 15
 	"github.com/docker/docker/image"
15 16
 	"github.com/docker/docker/trust"
16 17
 	"github.com/docker/docker/utils"
... ...
@@ -119,17 +120,17 @@ func TestLookupImage(t *testing.T) {
119 119
 		testOfficialImageName + ":" + testOfficialImageID,
120 120
 		testOfficialImageName + ":" + testOfficialImageIDShort,
121 121
 		testOfficialImageName,
122
-		testOfficialImageName + ":" + DefaultTag,
122
+		testOfficialImageName + ":" + tags.DefaultTag,
123 123
 		"docker.io/" + testOfficialImageName,
124
-		"docker.io/" + testOfficialImageName + ":" + DefaultTag,
124
+		"docker.io/" + testOfficialImageName + ":" + tags.DefaultTag,
125 125
 		"index.docker.io/" + testOfficialImageName,
126
-		"index.docker.io/" + testOfficialImageName + ":" + DefaultTag,
126
+		"index.docker.io/" + testOfficialImageName + ":" + tags.DefaultTag,
127 127
 		"library/" + testOfficialImageName,
128
-		"library/" + testOfficialImageName + ":" + DefaultTag,
128
+		"library/" + testOfficialImageName + ":" + tags.DefaultTag,
129 129
 		"docker.io/library/" + testOfficialImageName,
130
-		"docker.io/library/" + testOfficialImageName + ":" + DefaultTag,
130
+		"docker.io/library/" + testOfficialImageName + ":" + tags.DefaultTag,
131 131
 		"index.docker.io/library/" + testOfficialImageName,
132
-		"index.docker.io/library/" + testOfficialImageName + ":" + DefaultTag,
132
+		"index.docker.io/library/" + testOfficialImageName + ":" + tags.DefaultTag,
133 133
 	}
134 134
 
135 135
 	privateLookups := []string{
... ...
@@ -138,7 +139,7 @@ func TestLookupImage(t *testing.T) {
138 138
 		testPrivateImageName + ":" + testPrivateImageID,
139 139
 		testPrivateImageName + ":" + testPrivateImageIDShort,
140 140
 		testPrivateImageName,
141
-		testPrivateImageName + ":" + DefaultTag,
141
+		testPrivateImageName + ":" + tags.DefaultTag,
142 142
 	}
143 143
 
144 144
 	invalidLookups := []string{