瀏覽代碼

Add progress bar to docker load

Signed-off-by: Lei Jitang <leijitang@huawei.com>
Lei Jitang 9 年之前
父節點
當前提交
fae09e2569
共有 5 個文件被更改,包括 47 次插入15 次删除
  1. 5 2
      api/client/load.go
  2. 6 1
      api/server/router/local/image.go
  3. 2 2
      daemon/daemon.go
  4. 1 1
      image/image.go
  5. 33 9
      image/tarexport/load.go

+ 5 - 2
api/client/load.go

@@ -19,6 +19,7 @@ import (
 func (cli *DockerCli) CmdLoad(args ...string) error {
 	cmd := Cli.Subcmd("load", nil, Cli.DockerCommands["load"].Description, true)
 	infile := cmd.String([]string{"i", "-input"}, "", "Read from a tar archive file, instead of STDIN")
+	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Suppress the load output")
 	cmd.Require(flag.Exact, 0)
 	cmd.ParseFlags(args, true)
 
@@ -31,8 +32,10 @@ func (cli *DockerCli) CmdLoad(args ...string) error {
 		defer file.Close()
 		input = file
 	}
-
-	response, err := cli.client.ImageLoad(context.Background(), input, true)
+	if !cli.isTerminalOut {
+		*quiet = true
+	}
+	response, err := cli.client.ImageLoad(context.Background(), input, *quiet)
 	if err != nil {
 		return err
 	}

+ 6 - 1
api/server/router/local/image.go

@@ -270,7 +270,12 @@ func (s *router) getImagesGet(ctx context.Context, w http.ResponseWriter, r *htt
 }
 
 func (s *router) postImagesLoad(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	return s.daemon.LoadImage(r.Body, w)
+	if err := httputils.ParseForm(r); err != nil {
+		return err
+	}
+	quiet := httputils.BoolValueOrDefault(r, "quiet", true)
+	w.Header().Set("Content-Type", "application/json")
+	return s.daemon.LoadImage(r.Body, w, quiet)
 }
 
 func (s *router) deleteImages(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {

+ 2 - 2
daemon/daemon.go

@@ -1187,9 +1187,9 @@ func (daemon *Daemon) LookupImage(name string) (*types.ImageInspect, error) {
 // LoadImage uploads a set of images into the repository. This is the
 // complement of ImageExport.  The input stream is an uncompressed tar
 // ball containing images and metadata.
-func (daemon *Daemon) LoadImage(inTar io.ReadCloser, outStream io.Writer) error {
+func (daemon *Daemon) LoadImage(inTar io.ReadCloser, outStream io.Writer, quiet bool) error {
 	imageExporter := tarexport.NewTarExporter(daemon.imageStore, daemon.layerStore, daemon.referenceStore)
-	return imageExporter.Load(inTar, outStream)
+	return imageExporter.Load(inTar, outStream, quiet)
 }
 
 // ImageHistory returns a slice of ImageHistory structures for the specified image

+ 1 - 1
image/image.go

@@ -116,7 +116,7 @@ type History struct {
 
 // Exporter provides interface for exporting and importing images
 type Exporter interface {
-	Load(io.ReadCloser, io.Writer) error
+	Load(io.ReadCloser, io.Writer, bool) error
 	// TODO: Load(net.Context, io.ReadCloser, <- chan StatusMessage) error
 	Save([]string, io.Writer) error
 }

+ 33 - 9
image/tarexport/load.go

@@ -14,11 +14,24 @@ import (
 	"github.com/docker/docker/layer"
 	"github.com/docker/docker/pkg/archive"
 	"github.com/docker/docker/pkg/chrootarchive"
+	"github.com/docker/docker/pkg/progress"
+	"github.com/docker/docker/pkg/streamformatter"
+	"github.com/docker/docker/pkg/stringid"
 	"github.com/docker/docker/pkg/symlink"
 	"github.com/docker/docker/reference"
 )
 
-func (l *tarexporter) Load(inTar io.ReadCloser, outStream io.Writer) error {
+func (l *tarexporter) Load(inTar io.ReadCloser, outStream io.Writer, quiet bool) error {
+	var (
+		sf             = streamformatter.NewJSONStreamFormatter()
+		progressOutput progress.Output
+	)
+	if !quiet {
+		progressOutput = sf.NewProgressOutput(outStream, false)
+	} else {
+		progressOutput = nil
+	}
+
 	tmpDir, err := ioutil.TempDir("", "docker-import-")
 	if err != nil {
 		return err
@@ -36,7 +49,7 @@ func (l *tarexporter) Load(inTar io.ReadCloser, outStream io.Writer) error {
 	manifestFile, err := os.Open(manifestPath)
 	if err != nil {
 		if os.IsNotExist(err) {
-			return l.legacyLoad(tmpDir, outStream)
+			return l.legacyLoad(tmpDir, outStream, progressOutput)
 		}
 		return manifestFile.Close()
 	}
@@ -77,7 +90,7 @@ func (l *tarexporter) Load(inTar io.ReadCloser, outStream io.Writer) error {
 			r.Append(diffID)
 			newLayer, err := l.ls.Get(r.ChainID())
 			if err != nil {
-				newLayer, err = l.loadLayer(layerPath, rootFS)
+				newLayer, err = l.loadLayer(layerPath, rootFS, diffID.String(), progressOutput)
 				if err != nil {
 					return err
 				}
@@ -111,7 +124,7 @@ func (l *tarexporter) Load(inTar io.ReadCloser, outStream io.Writer) error {
 	return nil
 }
 
-func (l *tarexporter) loadLayer(filename string, rootFS image.RootFS) (layer.Layer, error) {
+func (l *tarexporter) loadLayer(filename string, rootFS image.RootFS, id string, progressOutput progress.Output) (layer.Layer, error) {
 	rawTar, err := os.Open(filename)
 	if err != nil {
 		logrus.Debugf("Error reading embedded tar: %v", err)
@@ -125,6 +138,17 @@ func (l *tarexporter) loadLayer(filename string, rootFS image.RootFS) (layer.Lay
 	}
 	defer inflatedLayerData.Close()
 
+	if progressOutput != nil {
+		fileInfo, err := os.Stat(filename)
+		if err != nil {
+			logrus.Debugf("Error statting file: %v", err)
+			return nil, err
+		}
+
+		progressReader := progress.NewProgressReader(inflatedLayerData, progressOutput, fileInfo.Size(), stringid.TruncateID(id), "Loading layer")
+
+		return l.ls.Register(progressReader, rootFS.ChainID())
+	}
 	return l.ls.Register(inflatedLayerData, rootFS.ChainID())
 }
 
@@ -139,7 +163,7 @@ func (l *tarexporter) setLoadedTag(ref reference.NamedTagged, imgID image.ID, ou
 	return nil
 }
 
-func (l *tarexporter) legacyLoad(tmpDir string, outStream io.Writer) error {
+func (l *tarexporter) legacyLoad(tmpDir string, outStream io.Writer, progressOutput progress.Output) error {
 	legacyLoadedMap := make(map[string]image.ID)
 
 	dirs, err := ioutil.ReadDir(tmpDir)
@@ -150,7 +174,7 @@ func (l *tarexporter) legacyLoad(tmpDir string, outStream io.Writer) error {
 	// every dir represents an image
 	for _, d := range dirs {
 		if d.IsDir() {
-			if err := l.legacyLoadImage(d.Name(), tmpDir, legacyLoadedMap); err != nil {
+			if err := l.legacyLoadImage(d.Name(), tmpDir, legacyLoadedMap, progressOutput); err != nil {
 				return err
 			}
 		}
@@ -196,7 +220,7 @@ func (l *tarexporter) legacyLoad(tmpDir string, outStream io.Writer) error {
 	return nil
 }
 
-func (l *tarexporter) legacyLoadImage(oldID, sourceDir string, loadedMap map[string]image.ID) error {
+func (l *tarexporter) legacyLoadImage(oldID, sourceDir string, loadedMap map[string]image.ID, progressOutput progress.Output) error {
 	if _, loaded := loadedMap[oldID]; loaded {
 		return nil
 	}
@@ -220,7 +244,7 @@ func (l *tarexporter) legacyLoadImage(oldID, sourceDir string, loadedMap map[str
 		for {
 			var loaded bool
 			if parentID, loaded = loadedMap[img.Parent]; !loaded {
-				if err := l.legacyLoadImage(img.Parent, sourceDir, loadedMap); err != nil {
+				if err := l.legacyLoadImage(img.Parent, sourceDir, loadedMap, progressOutput); err != nil {
 					return err
 				}
 			} else {
@@ -247,7 +271,7 @@ func (l *tarexporter) legacyLoadImage(oldID, sourceDir string, loadedMap map[str
 	if err != nil {
 		return err
 	}
-	newLayer, err := l.loadLayer(layerPath, *rootFS)
+	newLayer, err := l.loadLayer(layerPath, *rootFS, oldID, progressOutput)
 	if err != nil {
 		return err
 	}