diff --git a/go.mod b/go.mod index a60ef99342bb..e81cd7e27884 100644 --- a/go.mod +++ b/go.mod @@ -101,6 +101,7 @@ require ( replace ( git.apache.org/thrift.git => github.com/apache/thrift v0.0.0-20180902110319-2566ecd5d999 github.com/briandowns/spinner => github.com/alonyb/spinner v1.12.7 + github.com/cheggaaa/pb/v3 => github.com/yayaha/pb/v3 v3.0.9-0.20210722161537-6336041c275e github.com/docker/machine => github.com/machine-drivers/machine v0.7.1-0.20210719174735-6eca26732baa github.com/samalba/dockerclient => github.com/sayboras/dockerclient v1.0.0 k8s.io/api => k8s.io/api v0.21.2 diff --git a/go.sum b/go.sum index bca11cfce877..bfd5cabc8148 100644 --- a/go.sum +++ b/go.sum @@ -189,8 +189,6 @@ github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d8 github.com/cheekybits/genny v0.0.0-20170328200008-9127e812e1e9/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= github.com/cheggaaa/pb v1.0.27 h1:wIkZHkNfC7R6GI5w7l/PdAdzXzlrbcI3p8OAlnkTsnc= github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= -github.com/cheggaaa/pb/v3 v3.0.8 h1:bC8oemdChbke2FHIIGy9mn4DPJ2caZYQnfbRqwmdCoA= -github.com/cheggaaa/pb/v3 v3.0.8/go.mod h1:UICbiLec/XO6Hw6k+BHEtHeQFzzBH4i2/qk/ow1EJTA= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -1117,6 +1115,8 @@ github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6Ut github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yayaha/pb/v3 v3.0.9-0.20210722161537-6336041c275e h1:PK0yVMa+nkHKXg7p7snXAELMGIZ+JIIT+HQUUUtjzDM= +github.com/yayaha/pb/v3 v3.0.9-0.20210722161537-6336041c275e/go.mod h1:UICbiLec/XO6Hw6k+BHEtHeQFzzBH4i2/qk/ow1EJTA= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= diff --git a/pkg/minikube/download/image.go b/pkg/minikube/download/image.go index ee17a020a6ab..db11af4a29d8 100644 --- a/pkg/minikube/download/image.go +++ b/pkg/minikube/download/image.go @@ -140,18 +140,25 @@ func ImageToCache(img string) error { } klog.V(3).Infof("Writing image %v", tag) errchan := make(chan error) - p := pb.Full.Start64(0) fn := strings.Split(ref.Name(), "@")[0] // abbreviate filename for progress maxwidth := 30 - len("...") if len(fn) > maxwidth { fn = fn[0:maxwidth] + "..." } + + size, err := tarball.CalculateSize(map[name.Reference]v1.Image{tag: i}) + if err != nil { + return errors.Wrap(err, "calculating image size") + } + p := pb.New64(size).SetTemplate(pb.Full) p.Set("prefix", " > "+fn+": ") p.Set(pb.Bytes, true) - // Just a hair less than 80 (standard terminal width) for aesthetics & pasting into docs p.SetWidth(79) + if err := DefaultProgressBar.AddProgressBar(p); err != nil { + klog.Errorf("error adding progress bar to pool: %v", err) + } go func() { err = tarball.WriteToFile(f, tag, i, tarball.WithProgress(c)) @@ -162,9 +169,11 @@ func ImageToCache(img string) error { select { case update = <-c: p.SetCurrent(update.Complete) - p.SetTotal(update.Total) case err = <-errchan: p.Finish() + if err := DefaultProgressBar.RemoveProgressBar(p); err != nil { + klog.Errorf("error removing progress bar from pool: %v", err) + } if err != nil { return errors.Wrap(err, "writing tarball image") } @@ -271,18 +280,25 @@ func ImageToDaemon(img string) error { klog.V(3).Infof("Writing image %v", tag) errchan := make(chan error) - p := pb.Full.Start64(0) fn := strings.Split(ref.Name(), "@")[0] // abbreviate filename for progress maxwidth := 30 - len("...") if len(fn) > maxwidth { fn = fn[0:maxwidth] + "..." } + + size, err := tarball.CalculateSize(map[name.Reference]v1.Image{tag: i}) + if err != nil { + return errors.Wrap(err, "calculating image size") + } + p := pb.New64(size).SetTemplate(pb.Full) p.Set("prefix", " > "+fn+": ") p.Set(pb.Bytes, true) - // Just a hair less than 80 (standard terminal width) for aesthetics & pasting into docs p.SetWidth(79) + if err := DefaultProgressBar.AddProgressBar(p); err != nil { + klog.Errorf("error adding progress bar to pool: %v", err) + } go func() { _, err = daemon.Write(tag, i) @@ -294,9 +310,11 @@ loop: select { case update = <-c: p.SetCurrent(update.Complete) - p.SetTotal(update.Total) case err = <-errchan: p.Finish() + if err := DefaultProgressBar.RemoveProgressBar(p); err != nil { + klog.Errorf("error removing progress bar from pool: %v", err) + } if err != nil { return errors.Wrap(err, "writing daemon image") } diff --git a/pkg/minikube/download/progressbar.go b/pkg/minikube/download/progressbar.go index a80a887e0f35..0886d1cf0d00 100644 --- a/pkg/minikube/download/progressbar.go +++ b/pkg/minikube/download/progressbar.go @@ -27,26 +27,60 @@ import ( "github.com/cheggaaa/pb/v3" "github.com/hashicorp/go-getter" + "k8s.io/klog/v2" ) -// DefaultProgressBar is the default cheggaaa progress bar -var DefaultProgressBar getter.ProgressTracker = &progressBar{} +// PoolProgressTracker defines a progress tracker interface used to track a +// pool of progress bars. +type PoolProgressTracker interface { + getter.ProgressTracker + AddProgressBar(*pb.ProgressBar) error + RemoveProgressBar(p *pb.ProgressBar) error +} + +// DefaultProgressBar is the default cheggaaa progress bar. +var DefaultProgressBar PoolProgressTracker = &progressBar{} type progressBar struct { - lock sync.Mutex - progress *pb.ProgressBar + lock sync.Mutex + pool *pb.Pool + pbs int +} + +// AddProgressBar add progress bar to the concurrent pool +func (cpb *progressBar) AddProgressBar(p *pb.ProgressBar) error { + cpb.lock.Lock() + defer cpb.lock.Unlock() + if cpb.pool == nil { + cpb.pool = pb.NewPool() + if err := cpb.pool.Start(); err != nil { + return err + } + } + cpb.pool.Add(p) + cpb.pbs++ + return nil +} + +// RemoveProgressBar removes progress bar from the concurrent pool +func (cpb *progressBar) RemoveProgressBar(p *pb.ProgressBar) error { + cpb.lock.Lock() + defer cpb.lock.Unlock() + cpb.pbs-- + if cpb.pbs <= 0 { + if err := cpb.pool.Stop(); err != nil { + return err + } + cpb.pool = nil + } + return nil } // TrackProgress instantiates a new progress bar that will // display the progress of stream until closed. // total can be 0. func (cpb *progressBar) TrackProgress(src string, currentSize, totalSize int64, stream io.ReadCloser) io.ReadCloser { - cpb.lock.Lock() - defer cpb.lock.Unlock() - if cpb.progress == nil { - cpb.progress = pb.New64(totalSize) - } - p := pb.Full.Start64(totalSize) + p := pb.New64(totalSize).SetTemplate(pb.Full) fn := filepath.Base(src) // abbreviate filename for progress maxwidth := 30 - len("...") @@ -59,14 +93,19 @@ func (cpb *progressBar) TrackProgress(src string, currentSize, totalSize int64, // Just a hair less than 80 (standard terminal width) for aesthetics & pasting into docs p.SetWidth(79) + + if err := cpb.AddProgressBar(p); err != nil { + klog.Errorf("pool start: %v", err) + } barReader := p.NewProxyReader(stream) return &readCloser{ Reader: barReader, close: func() error { - cpb.lock.Lock() - defer cpb.lock.Unlock() p.Finish() + if err := cpb.RemoveProgressBar(p); err != nil { + klog.Errorf("pool stop: %v", err) + } return nil }, }