Merge pull request #8213 from brahmaroutu/pull_status_2404

Print a status message when pull command is executed
This commit is contained in:
Jessie Frazelle 2014-10-02 09:56:18 -07:00
commit f69a262464
4 changed files with 43 additions and 11 deletions

View file

@ -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

View file

@ -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.

View file

@ -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

View file

@ -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))
}
}