Print a status message when pull command is executed

Using repo tag in the status message for better usability, as per review comments
Added documentation and Changed code to print Status after downloads are complete

Addresses #2404

Signed-off-by: Srini Brahmaroutu <srbrahma@us.ibm.com>
This commit is contained in:
Srini Brahmaroutu 2014-09-23 22:53:43 +00:00
Родитель 4c8b8861ec
Коммит ecff6303a3
4 изменённых файлов: 43 добавлений и 11 удалений

Просмотреть файл

@ -23,6 +23,8 @@ It is also possible to specify a non-default registry to pull from.
# EXAMPLES
# Pull a repository with multiple images
# Note that if the image is previously downloaded then the status would be
# 'Status: Image is up to date for fedora'
$ sudo docker pull fedora
Pulling repository fedora
@ -31,6 +33,8 @@ It is also possible to specify a non-default registry to pull from.
511136ea3c5a: Download complete
73bd853d2ea5: Download complete
Status: Downloaded newer image for fedora
$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
fedora rawhide ad57ef8d78d7 5 days ago 359.3 MB
@ -39,6 +43,8 @@ It is also possible to specify a non-default registry to pull from.
fedora latest 105182bb5e8b 5 days ago 372.7 MB
# Pull an image, manually specifying path to the registry and tag
# Note that if the image is previously downloaded then the status would be
# 'Status: Image is up to date for registry.hub.docker.com/fedora:20'
$ sudo docker pull registry.hub.docker.com/fedora:20
Pulling repository fedora
@ -46,6 +52,8 @@ It is also possible to specify a non-default registry to pull from.
511136ea3c5a: Download complete
fd241224e9cf: Download complete
Status: Downloaded newer image for registry.hub.docker.com/fedora:20
$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
fedora 20 3f2fed40e4b0 4 days ago 372.7 MB

Просмотреть файл

@ -93,6 +93,8 @@ download the `centos` image.
ef52fb1fe610: Download complete
. . .
Status: Downloaded newer image for centos
We can see that each layer of the image has been pulled down and now we
can run a container from this image and we won't have to wait to
download the image.

Просмотреть файл

@ -67,6 +67,8 @@ Once you've found the image you want, you can download it with `docker pull <ima
511136ea3c5a: Download complete
7064731afe90: Download complete
Status: Downloaded newer image for centos
You now have an image from which you can run containers.
## Contributing to Docker Hub

Просмотреть файл

@ -122,6 +122,8 @@ func (s *TagStore) pullRepository(r *registry.Session, out io.Writer, localName,
}
errors := make(chan error)
layers_downloaded := false
for _, image := range repoData.ImgList {
downloadImage := func(img *registry.ImgData) {
if askedTag != "" && img.Tag != askedTag {
@ -158,15 +160,17 @@ func (s *TagStore) pullRepository(r *registry.Session, out io.Writer, localName,
out.Write(sf.FormatProgress(utils.TruncateID(img.ID), fmt.Sprintf("Pulling image (%s) from %s", img.Tag, localName), nil))
success := false
var lastErr error
var lastErr, err error
var is_downloaded bool
if mirrors != nil {
for _, ep := range mirrors {
out.Write(sf.FormatProgress(utils.TruncateID(img.ID), fmt.Sprintf("Pulling image (%s) from %s, mirror: %s", img.Tag, localName, ep), nil))
if err := s.pullImage(r, out, img.ID, ep, repoData.Tokens, sf); err != nil {
if is_downloaded, err = s.pullImage(r, out, img.ID, ep, repoData.Tokens, sf); err != nil {
// Don't report errors when pulling from mirrors.
log.Debugf("Error pulling image (%s) from %s, mirror: %s, %s", img.Tag, localName, ep, err)
continue
}
layers_downloaded = layers_downloaded || is_downloaded
success = true
break
}
@ -174,13 +178,14 @@ func (s *TagStore) pullRepository(r *registry.Session, out io.Writer, localName,
if !success {
for _, ep := range repoData.Endpoints {
out.Write(sf.FormatProgress(utils.TruncateID(img.ID), fmt.Sprintf("Pulling image (%s) from %s, endpoint: %s", img.Tag, localName, ep), nil))
if err := s.pullImage(r, out, img.ID, ep, repoData.Tokens, sf); err != nil {
if is_downloaded, err = s.pullImage(r, out, img.ID, ep, repoData.Tokens, sf); err != nil {
// It's not ideal that only the last error is returned, it would be better to concatenate the errors.
// As the error is also given to the output stream the user will see the error.
lastErr = err
out.Write(sf.FormatProgress(utils.TruncateID(img.ID), fmt.Sprintf("Error pulling image (%s) from %s, endpoint: %s, %s", img.Tag, localName, ep, err), nil))
continue
}
layers_downloaded = layers_downloaded || is_downloaded
success = true
break
}
@ -227,18 +232,24 @@ func (s *TagStore) pullRepository(r *registry.Session, out io.Writer, localName,
}
}
requestedTag := localName
if len(askedTag) > 0 {
requestedTag = localName + ":" + askedTag
}
WriteStatus(requestedTag, out, sf, layers_downloaded)
return nil
}
func (s *TagStore) pullImage(r *registry.Session, out io.Writer, imgID, endpoint string, token []string, sf *utils.StreamFormatter) error {
func (s *TagStore) pullImage(r *registry.Session, out io.Writer, imgID, endpoint string, token []string, sf *utils.StreamFormatter) (bool, error) {
history, err := r.GetRemoteHistory(imgID, endpoint, token)
if err != nil {
return err
return false, err
}
out.Write(sf.FormatProgress(utils.TruncateID(imgID), "Pulling dependent layers", nil))
// FIXME: Try to stream the images?
// FIXME: Launch the getRemoteImage() in goroutines
layers_downloaded := false
for i := len(history) - 1; i >= 0; i-- {
id := history[i]
@ -262,15 +273,16 @@ func (s *TagStore) pullImage(r *registry.Session, out io.Writer, imgID, endpoint
imgJSON, imgSize, err = r.GetRemoteImageJSON(id, endpoint, token)
if err != nil && j == retries {
out.Write(sf.FormatProgress(utils.TruncateID(id), "Error pulling dependent layers", nil))
return err
return layers_downloaded, err
} else if err != nil {
time.Sleep(time.Duration(j) * 500 * time.Millisecond)
continue
}
img, err = image.NewImgJSON(imgJSON)
layers_downloaded = true
if err != nil && j == retries {
out.Write(sf.FormatProgress(utils.TruncateID(id), "Error pulling dependent layers", nil))
return fmt.Errorf("Failed to parse json: %s", err)
return layers_downloaded, fmt.Errorf("Failed to parse json: %s", err)
} else if err != nil {
time.Sleep(time.Duration(j) * 500 * time.Millisecond)
continue
@ -295,8 +307,9 @@ func (s *TagStore) pullImage(r *registry.Session, out io.Writer, imgID, endpoint
continue
} else if err != nil {
out.Write(sf.FormatProgress(utils.TruncateID(id), "Error pulling dependent layers", nil))
return err
return layers_downloaded, err
}
layers_downloaded = true
defer layer.Close()
err = s.graph.Register(img, imgJSON,
@ -306,14 +319,21 @@ func (s *TagStore) pullImage(r *registry.Session, out io.Writer, imgID, endpoint
continue
} else if err != nil {
out.Write(sf.FormatProgress(utils.TruncateID(id), "Error downloading dependent layers", nil))
return err
return layers_downloaded, err
} else {
break
}
}
}
out.Write(sf.FormatProgress(utils.TruncateID(id), "Download complete", nil))
}
return nil
return layers_downloaded, nil
}
func WriteStatus(requestedTag string, out io.Writer, sf *utils.StreamFormatter, layers_downloaded bool) {
if layers_downloaded {
out.Write(sf.FormatStatus("", "Status: Downloaded newer image for %s", requestedTag))
} else {
out.Write(sf.FormatStatus("", "Status: Image is up to date for %s", requestedTag))
}
}