1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

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 # EXAMPLES
# Pull a repository with multiple images # 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 $ sudo docker pull fedora
Pulling repository fedora Pulling repository fedora
@ -31,6 +33,8 @@ It is also possible to specify a non-default registry to pull from.
511136ea3c5a: Download complete 511136ea3c5a: Download complete
73bd853d2ea5: Download complete 73bd853d2ea5: Download complete
Status: Downloaded newer image for fedora
$ sudo docker images $ sudo docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
fedora rawhide ad57ef8d78d7 5 days ago 359.3 MB 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 fedora latest 105182bb5e8b 5 days ago 372.7 MB
# Pull an image, manually specifying path to the registry and tag # 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 $ sudo docker pull registry.hub.docker.com/fedora:20
Pulling repository fedora Pulling repository fedora
@ -46,6 +52,8 @@ It is also possible to specify a non-default registry to pull from.
511136ea3c5a: Download complete 511136ea3c5a: Download complete
fd241224e9cf: Download complete fd241224e9cf: Download complete
Status: Downloaded newer image for registry.hub.docker.com/fedora:20
$ sudo docker images $ sudo docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
fedora 20 3f2fed40e4b0 4 days ago 372.7 MB fedora 20 3f2fed40e4b0 4 days ago 372.7 MB

View file

@ -93,6 +93,8 @@ download the `centos` image.
ef52fb1fe610: Download complete 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 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 can run a container from this image and we won't have to wait to
download the image. 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 511136ea3c5a: Download complete
7064731afe90: Download complete 7064731afe90: Download complete
Status: Downloaded newer image for centos
You now have an image from which you can run containers. You now have an image from which you can run containers.
## Contributing to Docker Hub ## 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) errors := make(chan error)
layers_downloaded := false
for _, image := range repoData.ImgList { for _, image := range repoData.ImgList {
downloadImage := func(img *registry.ImgData) { downloadImage := func(img *registry.ImgData) {
if askedTag != "" && img.Tag != askedTag { 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)) out.Write(sf.FormatProgress(utils.TruncateID(img.ID), fmt.Sprintf("Pulling image (%s) from %s", img.Tag, localName), nil))
success := false success := false
var lastErr error var lastErr, err error
var is_downloaded bool
if mirrors != nil { if mirrors != nil {
for _, ep := range mirrors { 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)) 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. // Don't report errors when pulling from mirrors.
log.Debugf("Error pulling image (%s) from %s, mirror: %s, %s", img.Tag, localName, ep, err) log.Debugf("Error pulling image (%s) from %s, mirror: %s, %s", img.Tag, localName, ep, err)
continue continue
} }
layers_downloaded = layers_downloaded || is_downloaded
success = true success = true
break break
} }
@ -174,13 +178,14 @@ func (s *TagStore) pullRepository(r *registry.Session, out io.Writer, localName,
if !success { if !success {
for _, ep := range repoData.Endpoints { 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)) 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. // 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. // As the error is also given to the output stream the user will see the error.
lastErr = err 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)) 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 continue
} }
layers_downloaded = layers_downloaded || is_downloaded
success = true success = true
break 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 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) history, err := r.GetRemoteHistory(imgID, endpoint, token)
if err != nil { if err != nil {
return err return false, err
} }
out.Write(sf.FormatProgress(utils.TruncateID(imgID), "Pulling dependent layers", nil)) out.Write(sf.FormatProgress(utils.TruncateID(imgID), "Pulling dependent layers", nil))
// FIXME: Try to stream the images? // FIXME: Try to stream the images?
// FIXME: Launch the getRemoteImage() in goroutines // FIXME: Launch the getRemoteImage() in goroutines
layers_downloaded := false
for i := len(history) - 1; i >= 0; i-- { for i := len(history) - 1; i >= 0; i-- {
id := history[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) imgJSON, imgSize, err = r.GetRemoteImageJSON(id, endpoint, token)
if err != nil && j == retries { if err != nil && j == retries {
out.Write(sf.FormatProgress(utils.TruncateID(id), "Error pulling dependent layers", nil)) out.Write(sf.FormatProgress(utils.TruncateID(id), "Error pulling dependent layers", nil))
return err return layers_downloaded, err
} else if err != nil { } else if err != nil {
time.Sleep(time.Duration(j) * 500 * time.Millisecond) time.Sleep(time.Duration(j) * 500 * time.Millisecond)
continue continue
} }
img, err = image.NewImgJSON(imgJSON) img, err = image.NewImgJSON(imgJSON)
layers_downloaded = true
if err != nil && j == retries { if err != nil && j == retries {
out.Write(sf.FormatProgress(utils.TruncateID(id), "Error pulling dependent layers", nil)) 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 { } else if err != nil {
time.Sleep(time.Duration(j) * 500 * time.Millisecond) time.Sleep(time.Duration(j) * 500 * time.Millisecond)
continue continue
@ -295,8 +307,9 @@ func (s *TagStore) pullImage(r *registry.Session, out io.Writer, imgID, endpoint
continue continue
} else if err != nil { } else if err != nil {
out.Write(sf.FormatProgress(utils.TruncateID(id), "Error pulling dependent layers", 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() defer layer.Close()
err = s.graph.Register(img, imgJSON, err = s.graph.Register(img, imgJSON,
@ -306,14 +319,21 @@ func (s *TagStore) pullImage(r *registry.Session, out io.Writer, imgID, endpoint
continue continue
} else if err != nil { } else if err != nil {
out.Write(sf.FormatProgress(utils.TruncateID(id), "Error downloading dependent layers", nil)) out.Write(sf.FormatProgress(utils.TruncateID(id), "Error downloading dependent layers", nil))
return err return layers_downloaded, err
} else { } else {
break break
} }
} }
} }
out.Write(sf.FormatProgress(utils.TruncateID(id), "Download complete", nil)) 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))
}
} }