mirror of
https://github.com/containers/skopeo.git
synced 2025-09-20 01:20:09 +00:00
Update c/image after https://github.com/containers/image/pull/1816
... to work around some of the "unexpected EOF" failures. Signed-off-by: Miloslav Trmač <mitr@redhat.com>
This commit is contained in:
91
vendor/github.com/vbauerster/mpb/v7/cwriter/writer.go
generated
vendored
91
vendor/github.com/vbauerster/mpb/v7/cwriter/writer.go
generated
vendored
@@ -1,91 +0,0 @@
|
||||
package cwriter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// ErrNotTTY not a TeleTYpewriter error.
|
||||
var ErrNotTTY = errors.New("not a terminal")
|
||||
|
||||
// https://github.com/dylanaraps/pure-sh-bible#cursor-movement
|
||||
const (
|
||||
escOpen = "\x1b["
|
||||
cuuAndEd = "A\x1b[J"
|
||||
)
|
||||
|
||||
// Writer is a buffered the writer that updates the terminal. The
|
||||
// contents of writer will be flushed when Flush is called.
|
||||
type Writer struct {
|
||||
out io.Writer
|
||||
buf bytes.Buffer
|
||||
lines int // how much lines to clear before flushing new ones
|
||||
fd int
|
||||
terminal bool
|
||||
termSize func(int) (int, int, error)
|
||||
}
|
||||
|
||||
// New returns a new Writer with defaults.
|
||||
func New(out io.Writer) *Writer {
|
||||
w := &Writer{
|
||||
out: out,
|
||||
termSize: func(_ int) (int, int, error) {
|
||||
return -1, -1, ErrNotTTY
|
||||
},
|
||||
}
|
||||
if f, ok := out.(*os.File); ok {
|
||||
w.fd = int(f.Fd())
|
||||
if IsTerminal(w.fd) {
|
||||
w.terminal = true
|
||||
w.termSize = func(fd int) (int, int, error) {
|
||||
return GetSize(fd)
|
||||
}
|
||||
}
|
||||
}
|
||||
return w
|
||||
}
|
||||
|
||||
// Flush flushes the underlying buffer.
|
||||
func (w *Writer) Flush(lines int) (err error) {
|
||||
// some terminals interpret 'cursor up 0' as 'cursor up 1'
|
||||
if w.lines > 0 {
|
||||
err = w.clearLines()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
w.lines = lines
|
||||
_, err = w.buf.WriteTo(w.out)
|
||||
return
|
||||
}
|
||||
|
||||
// Write appends the contents of p to the underlying buffer.
|
||||
func (w *Writer) Write(p []byte) (n int, err error) {
|
||||
return w.buf.Write(p)
|
||||
}
|
||||
|
||||
// WriteString writes string to the underlying buffer.
|
||||
func (w *Writer) WriteString(s string) (n int, err error) {
|
||||
return w.buf.WriteString(s)
|
||||
}
|
||||
|
||||
// ReadFrom reads from the provided io.Reader and writes to the
|
||||
// underlying buffer.
|
||||
func (w *Writer) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
return w.buf.ReadFrom(r)
|
||||
}
|
||||
|
||||
// GetTermSize returns WxH of underlying terminal.
|
||||
func (w *Writer) GetTermSize() (width, height int, err error) {
|
||||
return w.termSize(w.fd)
|
||||
}
|
||||
|
||||
func (w *Writer) ansiCuuAndEd() error {
|
||||
buf := make([]byte, 8)
|
||||
buf = strconv.AppendInt(buf[:copy(buf, escOpen)], int64(w.lines), 10)
|
||||
_, err := w.out.Write(append(buf, cuuAndEd...))
|
||||
return err
|
||||
}
|
26
vendor/github.com/vbauerster/mpb/v7/cwriter/writer_posix.go
generated
vendored
26
vendor/github.com/vbauerster/mpb/v7/cwriter/writer_posix.go
generated
vendored
@@ -1,26 +0,0 @@
|
||||
// +build !windows
|
||||
|
||||
package cwriter
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func (w *Writer) clearLines() error {
|
||||
return w.ansiCuuAndEd()
|
||||
}
|
||||
|
||||
// GetSize returns the dimensions of the given terminal.
|
||||
func GetSize(fd int) (width, height int, err error) {
|
||||
ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ)
|
||||
if err != nil {
|
||||
return -1, -1, err
|
||||
}
|
||||
return int(ws.Col), int(ws.Row), nil
|
||||
}
|
||||
|
||||
// IsTerminal returns whether the given file descriptor is a terminal.
|
||||
func IsTerminal(fd int) bool {
|
||||
_, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
|
||||
return err == nil
|
||||
}
|
10
vendor/github.com/vbauerster/mpb/v7/decor/optimistic_string_writer.go
generated
vendored
10
vendor/github.com/vbauerster/mpb/v7/decor/optimistic_string_writer.go
generated
vendored
@@ -1,10 +0,0 @@
|
||||
package decor
|
||||
|
||||
import "io"
|
||||
|
||||
func mustWriteString(w io.Writer, s string) {
|
||||
_, err := io.WriteString(w, s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
79
vendor/github.com/vbauerster/mpb/v7/proxyreader.go
generated
vendored
79
vendor/github.com/vbauerster/mpb/v7/proxyreader.go
generated
vendored
@@ -1,79 +0,0 @@
|
||||
package mpb
|
||||
|
||||
import (
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
type proxyReader struct {
|
||||
io.ReadCloser
|
||||
bar *Bar
|
||||
}
|
||||
|
||||
func (x proxyReader) Read(p []byte) (int, error) {
|
||||
n, err := x.ReadCloser.Read(p)
|
||||
x.bar.IncrBy(n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
type proxyWriterTo struct {
|
||||
proxyReader
|
||||
wt io.WriterTo
|
||||
}
|
||||
|
||||
func (x proxyWriterTo) WriteTo(w io.Writer) (int64, error) {
|
||||
n, err := x.wt.WriteTo(w)
|
||||
x.bar.IncrInt64(n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
type ewmaProxyReader struct {
|
||||
proxyReader
|
||||
}
|
||||
|
||||
func (x ewmaProxyReader) Read(p []byte) (int, error) {
|
||||
start := time.Now()
|
||||
n, err := x.proxyReader.Read(p)
|
||||
if n > 0 {
|
||||
x.bar.DecoratorEwmaUpdate(time.Since(start))
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
type ewmaProxyWriterTo struct {
|
||||
ewmaProxyReader
|
||||
wt proxyWriterTo
|
||||
}
|
||||
|
||||
func (x ewmaProxyWriterTo) WriteTo(w io.Writer) (int64, error) {
|
||||
start := time.Now()
|
||||
n, err := x.wt.WriteTo(w)
|
||||
if n > 0 {
|
||||
x.bar.DecoratorEwmaUpdate(time.Since(start))
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (b *Bar) newProxyReader(r io.Reader) (rc io.ReadCloser) {
|
||||
pr := proxyReader{toReadCloser(r), b}
|
||||
if wt, ok := r.(io.WriterTo); ok {
|
||||
pw := proxyWriterTo{pr, wt}
|
||||
if b.hasEwma {
|
||||
rc = ewmaProxyWriterTo{ewmaProxyReader{pr}, pw}
|
||||
} else {
|
||||
rc = pw
|
||||
}
|
||||
} else if b.hasEwma {
|
||||
rc = ewmaProxyReader{pr}
|
||||
} else {
|
||||
rc = pr
|
||||
}
|
||||
return rc
|
||||
}
|
||||
|
||||
func toReadCloser(r io.Reader) io.ReadCloser {
|
||||
if rc, ok := r.(io.ReadCloser); ok {
|
||||
return rc
|
||||
}
|
||||
return io.NopCloser(r)
|
||||
}
|
@@ -1,8 +1,8 @@
|
||||
# Multi Progress Bar
|
||||
|
||||
[](https://pkg.go.dev/github.com/vbauerster/mpb/v7)
|
||||
[](https://pkg.go.dev/github.com/vbauerster/mpb/v8)
|
||||
[](https://github.com/vbauerster/mpb/actions/workflows/test.yml)
|
||||
[](https://www.paypal.me/vbauerster)
|
||||
[](https://github.com/vbauerster/mpb/actions/workflows/golangci-lint.yml)
|
||||
|
||||
**mpb** is a Go lib for rendering progress bars in terminal applications.
|
||||
|
||||
@@ -26,8 +26,8 @@ import (
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/vbauerster/mpb/v7"
|
||||
"github.com/vbauerster/mpb/v7/decor"
|
||||
"github.com/vbauerster/mpb/v8"
|
||||
"github.com/vbauerster/mpb/v8/decor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -97,9 +97,8 @@ func main() {
|
||||
// EWMA's unit of measure is an iteration's duration
|
||||
start := time.Now()
|
||||
time.Sleep(time.Duration(rng.Intn(10)+1) * max / 10)
|
||||
bar.Increment()
|
||||
// we need to call DecoratorEwmaUpdate to fulfill ewma decorator's contract
|
||||
bar.DecoratorEwmaUpdate(time.Since(start))
|
||||
// we need to call EwmaIncrement to fulfill ewma decorator's contract
|
||||
bar.EwmaIncrement(time.Since(start))
|
||||
}
|
||||
}()
|
||||
}
|
429
vendor/github.com/vbauerster/mpb/v7/bar.go → vendor/github.com/vbauerster/mpb/v8/bar.go
generated
vendored
429
vendor/github.com/vbauerster/mpb/v7/bar.go → vendor/github.com/vbauerster/mpb/v8/bar.go
generated
vendored
@@ -3,43 +3,40 @@ package mpb
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/acarl005/stripansi"
|
||||
"github.com/mattn/go-runewidth"
|
||||
"github.com/vbauerster/mpb/v7/decor"
|
||||
"github.com/vbauerster/mpb/v8/decor"
|
||||
)
|
||||
|
||||
// Bar represents a progress bar.
|
||||
type Bar struct {
|
||||
index int // used by heap
|
||||
priority int // used by heap
|
||||
hasEwma bool
|
||||
frameCh chan *renderFrame
|
||||
operateState chan func(*bState)
|
||||
done chan struct{}
|
||||
container *Progress
|
||||
bs *bState
|
||||
cancel func()
|
||||
recoveredPanic interface{}
|
||||
index int // used by heap
|
||||
priority int // used by heap
|
||||
frameCh chan *renderFrame
|
||||
operateState chan func(*bState)
|
||||
done chan struct{}
|
||||
container *Progress
|
||||
bs *bState
|
||||
cancel func()
|
||||
}
|
||||
|
||||
type extenderFunc func(rows []io.Reader, width int, stat decor.Statistics) []io.Reader
|
||||
type syncTable [2][]chan int
|
||||
type extenderFunc func([]io.Reader, decor.Statistics) ([]io.Reader, error)
|
||||
|
||||
// bState is actual bar's state.
|
||||
type bState struct {
|
||||
id int
|
||||
priority int
|
||||
reqWidth int
|
||||
shutdown int
|
||||
total int64
|
||||
current int64
|
||||
refill int64
|
||||
lastIncrement int64
|
||||
trimSpace bool
|
||||
completed bool
|
||||
aborted bool
|
||||
@@ -55,7 +52,7 @@ type bState struct {
|
||||
filler BarFiller
|
||||
middleware func(BarFiller) BarFiller
|
||||
extender extenderFunc
|
||||
debugOut io.Writer
|
||||
manualRefresh chan interface{}
|
||||
|
||||
wait struct {
|
||||
bar *Bar // key for (*pState).queueBars
|
||||
@@ -65,7 +62,8 @@ type bState struct {
|
||||
|
||||
type renderFrame struct {
|
||||
rows []io.Reader
|
||||
shutdown int
|
||||
shutdown bool
|
||||
err error
|
||||
}
|
||||
|
||||
func newBar(container *Progress, bs *bState) *Bar {
|
||||
@@ -73,7 +71,6 @@ func newBar(container *Progress, bs *bState) *Bar {
|
||||
|
||||
bar := &Bar{
|
||||
priority: bs.priority,
|
||||
hasEwma: len(bs.ewmaDecorators) != 0,
|
||||
frameCh: make(chan *renderFrame, 1),
|
||||
operateState: make(chan func(*bState)),
|
||||
done: make(chan struct{}),
|
||||
@@ -85,20 +82,37 @@ func newBar(container *Progress, bs *bState) *Bar {
|
||||
return bar
|
||||
}
|
||||
|
||||
// ProxyReader wraps r with metrics required for progress tracking.
|
||||
// If r is 'unknown total/size' reader it's mandatory to call
|
||||
// (*Bar).SetTotal(-1, true) method after (Reader).Read returns io.EOF.
|
||||
// Panics if r is nil. If bar is already completed or aborted, returns
|
||||
// nil.
|
||||
// ProxyReader wraps io.Reader with metrics required for progress tracking.
|
||||
// If `r` is 'unknown total/size' reader it's mandatory to call
|
||||
// (*Bar).SetTotal(-1, true) method after (io.Reader).Read returns io.EOF.
|
||||
// If bar is already completed or aborted, returns nil.
|
||||
// Panics if `r` is nil.
|
||||
func (b *Bar) ProxyReader(r io.Reader) io.ReadCloser {
|
||||
if r == nil {
|
||||
panic("expected non nil io.Reader")
|
||||
}
|
||||
result := make(chan bool)
|
||||
select {
|
||||
case b.operateState <- func(s *bState) { result <- len(s.ewmaDecorators) != 0 }:
|
||||
return newProxyReader(r, b, <-result)
|
||||
case <-b.done:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// ProxyWriter wraps io.Writer with metrics required for progress tracking.
|
||||
// If bar is already completed or aborted, returns nil.
|
||||
// Panics if `w` is nil.
|
||||
func (b *Bar) ProxyWriter(w io.Writer) io.WriteCloser {
|
||||
if w == nil {
|
||||
panic("expected non nil io.Writer")
|
||||
}
|
||||
result := make(chan bool)
|
||||
select {
|
||||
case b.operateState <- func(s *bState) { result <- len(s.ewmaDecorators) != 0 }:
|
||||
return newProxyWriter(w, b, <-result)
|
||||
case <-b.done:
|
||||
return nil
|
||||
default:
|
||||
return b.newProxyReader(r)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,7 +156,8 @@ func (b *Bar) TraverseDecorators(cb func(decor.Decorator)) {
|
||||
sync := make(chan struct{})
|
||||
select {
|
||||
case b.operateState <- func(s *bState) {
|
||||
for _, decorators := range [...][]decor.Decorator{
|
||||
defer close(sync)
|
||||
for _, decorators := range [][]decor.Decorator{
|
||||
s.pDecorators,
|
||||
s.aDecorators,
|
||||
} {
|
||||
@@ -150,7 +165,6 @@ func (b *Bar) TraverseDecorators(cb func(decor.Decorator)) {
|
||||
cb(extractBaseDecorator(d))
|
||||
}
|
||||
}
|
||||
close(sync)
|
||||
}:
|
||||
<-sync
|
||||
case <-b.done:
|
||||
@@ -158,7 +172,7 @@ func (b *Bar) TraverseDecorators(cb func(decor.Decorator)) {
|
||||
}
|
||||
|
||||
// EnableTriggerComplete enables triggering complete event. It's
|
||||
// effective only for bar which was constructed with `total <= 0` and
|
||||
// effective only for bars which were constructed with `total <= 0` and
|
||||
// after total has been set with (*Bar).SetTotal(int64, false). If bar
|
||||
// has been incremented to the total, complete event is triggered right
|
||||
// away.
|
||||
@@ -171,7 +185,7 @@ func (b *Bar) EnableTriggerComplete() {
|
||||
if s.current >= s.total {
|
||||
s.current = s.total
|
||||
s.completed = true
|
||||
go b.forceRefresh()
|
||||
b.forceRefresh(s.manualRefresh)
|
||||
} else {
|
||||
s.triggerComplete = true
|
||||
}
|
||||
@@ -182,7 +196,7 @@ func (b *Bar) EnableTriggerComplete() {
|
||||
|
||||
// SetTotal sets total to an arbitrary value. It's effective only for
|
||||
// bar which was constructed with `total <= 0`. Setting total to negative
|
||||
// value is equivalent to (*Bar).SetTotal((*Bar).Current(), bool).
|
||||
// value is equivalent to (*Bar).SetTotal((*Bar).Current(), bool) but faster.
|
||||
// If triggerCompleteNow is true, total value is set to current and
|
||||
// complete event is triggered right away.
|
||||
func (b *Bar) SetTotal(total int64, triggerCompleteNow bool) {
|
||||
@@ -199,7 +213,7 @@ func (b *Bar) SetTotal(total int64, triggerCompleteNow bool) {
|
||||
if triggerCompleteNow {
|
||||
s.current = s.total
|
||||
s.completed = true
|
||||
go b.forceRefresh()
|
||||
b.forceRefresh(s.manualRefresh)
|
||||
}
|
||||
}:
|
||||
case <-b.done:
|
||||
@@ -207,16 +221,39 @@ func (b *Bar) SetTotal(total int64, triggerCompleteNow bool) {
|
||||
}
|
||||
|
||||
// SetCurrent sets progress' current to an arbitrary value.
|
||||
// Setting a negative value will cause a panic.
|
||||
func (b *Bar) SetCurrent(current int64) {
|
||||
if current < 0 {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case b.operateState <- func(s *bState) {
|
||||
s.lastIncrement = current - s.current
|
||||
s.current = current
|
||||
if s.triggerComplete && s.current >= s.total {
|
||||
s.current = s.total
|
||||
s.completed = true
|
||||
go b.forceRefresh()
|
||||
b.forceRefresh(s.manualRefresh)
|
||||
}
|
||||
}:
|
||||
case <-b.done:
|
||||
}
|
||||
}
|
||||
|
||||
// EwmaSetCurrent sets progress' current to an arbitrary value and updates
|
||||
// EWMA based decorators by dur of a single iteration.
|
||||
func (b *Bar) EwmaSetCurrent(current int64, iterDur time.Duration) {
|
||||
if current < 0 {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case b.operateState <- func(s *bState) {
|
||||
if n := current - s.current; n > 0 {
|
||||
s.ewmaUpdate(n, iterDur)
|
||||
}
|
||||
s.current = current
|
||||
if s.triggerComplete && s.current >= s.total {
|
||||
s.current = s.total
|
||||
s.completed = true
|
||||
b.forceRefresh(s.manualRefresh)
|
||||
}
|
||||
}:
|
||||
case <-b.done:
|
||||
@@ -240,37 +277,44 @@ func (b *Bar) IncrInt64(n int64) {
|
||||
}
|
||||
select {
|
||||
case b.operateState <- func(s *bState) {
|
||||
s.lastIncrement = n
|
||||
s.current += n
|
||||
if s.triggerComplete && s.current >= s.total {
|
||||
s.current = s.total
|
||||
s.completed = true
|
||||
go b.forceRefresh()
|
||||
b.forceRefresh(s.manualRefresh)
|
||||
}
|
||||
}:
|
||||
case <-b.done:
|
||||
}
|
||||
}
|
||||
|
||||
// DecoratorEwmaUpdate updates all EWMA based decorators. Should be
|
||||
// called on each iteration, because EWMA's unit of measure is an
|
||||
// iteration's duration. Panics if called before *Bar.Incr... family
|
||||
// methods.
|
||||
func (b *Bar) DecoratorEwmaUpdate(dur time.Duration) {
|
||||
// EwmaIncrement is a shorthand for b.EwmaIncrInt64(1, iterDur).
|
||||
func (b *Bar) EwmaIncrement(iterDur time.Duration) {
|
||||
b.EwmaIncrInt64(1, iterDur)
|
||||
}
|
||||
|
||||
// EwmaIncrBy is a shorthand for b.EwmaIncrInt64(int64(n), iterDur).
|
||||
func (b *Bar) EwmaIncrBy(n int, iterDur time.Duration) {
|
||||
b.EwmaIncrInt64(int64(n), iterDur)
|
||||
}
|
||||
|
||||
// EwmaIncrInt64 increments progress by amount of n and updates EWMA based
|
||||
// decorators by dur of a single iteration.
|
||||
func (b *Bar) EwmaIncrInt64(n int64, iterDur time.Duration) {
|
||||
if n <= 0 {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case b.operateState <- func(s *bState) {
|
||||
if s.lastIncrement > 0 {
|
||||
s.decoratorEwmaUpdate(dur)
|
||||
s.lastIncrement = 0
|
||||
} else {
|
||||
panic("increment required before ewma iteration update")
|
||||
s.ewmaUpdate(n, iterDur)
|
||||
s.current += n
|
||||
if s.triggerComplete && s.current >= s.total {
|
||||
s.current = s.total
|
||||
s.completed = true
|
||||
b.forceRefresh(s.manualRefresh)
|
||||
}
|
||||
}:
|
||||
case <-b.done:
|
||||
if b.bs.lastIncrement > 0 {
|
||||
b.bs.decoratorEwmaUpdate(dur)
|
||||
b.bs.lastIncrement = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,7 +349,7 @@ func (b *Bar) Abort(drop bool) {
|
||||
}
|
||||
s.aborted = true
|
||||
s.dropOnComplete = drop
|
||||
go b.forceRefresh()
|
||||
b.forceRefresh(s.manualRefresh)
|
||||
}:
|
||||
case <-b.done:
|
||||
}
|
||||
@@ -333,6 +377,20 @@ func (b *Bar) Completed() bool {
|
||||
}
|
||||
}
|
||||
|
||||
// IsRunning reports whether the bar is running, i.e. not yet completed
|
||||
// and not yet aborted.
|
||||
func (b *Bar) IsRunning() bool {
|
||||
result := make(chan bool)
|
||||
select {
|
||||
case b.operateState <- func(s *bState) {
|
||||
result <- !s.completed && !s.aborted
|
||||
}:
|
||||
return <-result
|
||||
case <-b.done:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Wait blocks until bar is completed or aborted.
|
||||
func (b *Bar) Wait() {
|
||||
<-b.done
|
||||
@@ -358,74 +416,54 @@ func (b *Bar) serve(ctx context.Context, bs *bState) {
|
||||
}
|
||||
|
||||
func (b *Bar) render(tw int) {
|
||||
select {
|
||||
case b.operateState <- func(s *bState) {
|
||||
var done bool
|
||||
fn := func(s *bState) {
|
||||
var rows []io.Reader
|
||||
stat := newStatistics(tw, s)
|
||||
defer func() {
|
||||
// recovering if user defined decorator panics for example
|
||||
if p := recover(); p != nil {
|
||||
if s.debugOut != nil {
|
||||
for _, fn := range []func() (int, error){
|
||||
func() (int, error) {
|
||||
return fmt.Fprintln(s.debugOut, p)
|
||||
},
|
||||
func() (int, error) {
|
||||
return s.debugOut.Write(debug.Stack())
|
||||
},
|
||||
} {
|
||||
if _, err := fn(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
s.aborted = !s.completed
|
||||
s.extender = makePanicExtender(p)
|
||||
b.recoveredPanic = p
|
||||
}
|
||||
if fn := s.extender; fn != nil {
|
||||
rows = fn(rows, s.reqWidth, stat)
|
||||
}
|
||||
frame := &renderFrame{
|
||||
rows: rows,
|
||||
}
|
||||
if s.completed || s.aborted {
|
||||
b.cancel()
|
||||
frame.shutdown++
|
||||
}
|
||||
b.frameCh <- frame
|
||||
}()
|
||||
if b.recoveredPanic == nil {
|
||||
rows = append(rows, s.draw(stat))
|
||||
r, err := s.draw(stat)
|
||||
if err != nil {
|
||||
b.frameCh <- &renderFrame{err: err}
|
||||
return
|
||||
}
|
||||
}:
|
||||
case <-b.done:
|
||||
var rows []io.Reader
|
||||
s, stat := b.bs, newStatistics(tw, b.bs)
|
||||
if b.recoveredPanic == nil {
|
||||
rows = append(rows, s.draw(stat))
|
||||
rows = append(rows, r)
|
||||
if s.extender != nil {
|
||||
rows, err = s.extender(rows, stat)
|
||||
if err != nil {
|
||||
b.frameCh <- &renderFrame{err: err}
|
||||
return
|
||||
}
|
||||
}
|
||||
if fn := s.extender; fn != nil {
|
||||
rows = fn(rows, s.reqWidth, stat)
|
||||
}
|
||||
frame := &renderFrame{
|
||||
rows: rows,
|
||||
frame := &renderFrame{rows: rows}
|
||||
if s.completed || s.aborted {
|
||||
frame.shutdown = !done || s.shutdown == 1
|
||||
b.cancel()
|
||||
}
|
||||
b.frameCh <- frame
|
||||
}
|
||||
select {
|
||||
case b.operateState <- fn:
|
||||
case <-b.done:
|
||||
done = true
|
||||
fn(b.bs)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Bar) forceRefresh() {
|
||||
func (b *Bar) forceRefresh(refreshCh chan interface{}) {
|
||||
b.container.bwg.Add(1)
|
||||
go b.forceRefreshImpl(refreshCh)
|
||||
}
|
||||
|
||||
func (b *Bar) forceRefreshImpl(refreshCh chan interface{}) {
|
||||
defer b.container.bwg.Done()
|
||||
var anyOtherRunning bool
|
||||
b.container.traverseBars(func(bar *Bar) bool {
|
||||
anyOtherRunning = b != bar && bar.isRunning()
|
||||
anyOtherRunning = b != bar && bar.IsRunning()
|
||||
return !anyOtherRunning
|
||||
})
|
||||
if !anyOtherRunning {
|
||||
for {
|
||||
select {
|
||||
case b.container.refreshCh <- time.Now():
|
||||
time.Sleep(prr)
|
||||
case refreshCh <- time.Now():
|
||||
case <-b.done:
|
||||
return
|
||||
}
|
||||
@@ -433,20 +471,8 @@ func (b *Bar) forceRefresh() {
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Bar) isRunning() bool {
|
||||
result := make(chan bool)
|
||||
select {
|
||||
case b.operateState <- func(s *bState) {
|
||||
result <- !s.completed && !s.aborted
|
||||
}:
|
||||
return <-result
|
||||
case <-b.done:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Bar) wSyncTable() [][]chan int {
|
||||
result := make(chan [][]chan int)
|
||||
func (b *Bar) wSyncTable() syncTable {
|
||||
result := make(chan syncTable)
|
||||
select {
|
||||
case b.operateState <- func(s *bState) { result <- s.wSyncTable() }:
|
||||
return <-result
|
||||
@@ -455,68 +481,111 @@ func (b *Bar) wSyncTable() [][]chan int {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *bState) draw(stat decor.Statistics) io.Reader {
|
||||
bufP, bufB, bufA := s.buffers[0], s.buffers[1], s.buffers[2]
|
||||
nlr := bytes.NewReader([]byte("\n"))
|
||||
tw := stat.AvailableWidth
|
||||
for _, d := range s.pDecorators {
|
||||
str := d.Decor(stat)
|
||||
stat.AvailableWidth -= runewidth.StringWidth(stripansi.Strip(str))
|
||||
bufP.WriteString(str)
|
||||
func (s *bState) draw(stat decor.Statistics) (io.Reader, error) {
|
||||
r, err := s.drawImpl(stat)
|
||||
if err != nil {
|
||||
for _, b := range s.buffers {
|
||||
b.Reset()
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if stat.AvailableWidth < 1 {
|
||||
trunc := strings.NewReader(runewidth.Truncate(stripansi.Strip(bufP.String()), tw, "…"))
|
||||
bufP.Reset()
|
||||
return io.MultiReader(trunc, nlr)
|
||||
}
|
||||
|
||||
if !s.trimSpace && stat.AvailableWidth > 1 {
|
||||
stat.AvailableWidth -= 2
|
||||
bufB.WriteByte(' ')
|
||||
defer bufB.WriteByte(' ')
|
||||
}
|
||||
|
||||
tw = stat.AvailableWidth
|
||||
for _, d := range s.aDecorators {
|
||||
str := d.Decor(stat)
|
||||
stat.AvailableWidth -= runewidth.StringWidth(stripansi.Strip(str))
|
||||
bufA.WriteString(str)
|
||||
}
|
||||
if stat.AvailableWidth < 1 {
|
||||
trunc := strings.NewReader(runewidth.Truncate(stripansi.Strip(bufA.String()), tw, "…"))
|
||||
bufA.Reset()
|
||||
return io.MultiReader(bufP, bufB, trunc, nlr)
|
||||
}
|
||||
|
||||
s.filler.Fill(bufB, s.reqWidth, stat)
|
||||
|
||||
return io.MultiReader(bufP, bufB, bufA, nlr)
|
||||
return io.MultiReader(r, strings.NewReader("\n")), nil
|
||||
}
|
||||
|
||||
func (s *bState) wSyncTable() [][]chan int {
|
||||
columns := make([]chan int, 0, len(s.pDecorators)+len(s.aDecorators))
|
||||
var pCount int
|
||||
for _, d := range s.pDecorators {
|
||||
if ch, ok := d.Sync(); ok {
|
||||
columns = append(columns, ch)
|
||||
pCount++
|
||||
func (s *bState) drawImpl(stat decor.Statistics) (io.Reader, error) {
|
||||
decorFiller := func(buf *bytes.Buffer, decorators []decor.Decorator) (res struct {
|
||||
width int
|
||||
truncate bool
|
||||
err error
|
||||
}) {
|
||||
res.width = stat.AvailableWidth
|
||||
for _, d := range decorators {
|
||||
str := d.Decor(stat)
|
||||
if stat.AvailableWidth > 0 {
|
||||
stat.AvailableWidth -= runewidth.StringWidth(stripansi.Strip(str))
|
||||
if res.err == nil {
|
||||
_, res.err = buf.WriteString(str)
|
||||
}
|
||||
}
|
||||
}
|
||||
res.truncate = stat.AvailableWidth < 0
|
||||
return res
|
||||
}
|
||||
|
||||
bufP, bufB, bufA := s.buffers[0], s.buffers[1], s.buffers[2]
|
||||
|
||||
resP := decorFiller(bufP, s.pDecorators)
|
||||
resA := decorFiller(bufA, s.aDecorators)
|
||||
|
||||
for _, err := range []error{resP.err, resA.err} {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
var aCount int
|
||||
for _, d := range s.aDecorators {
|
||||
if ch, ok := d.Sync(); ok {
|
||||
columns = append(columns, ch)
|
||||
aCount++
|
||||
|
||||
if resP.truncate {
|
||||
trunc := strings.NewReader(runewidth.Truncate(stripansi.Strip(bufP.String()), resP.width, "…"))
|
||||
bufP.Reset()
|
||||
bufA.Reset()
|
||||
return trunc, nil
|
||||
}
|
||||
|
||||
if resA.truncate {
|
||||
trunc := strings.NewReader(runewidth.Truncate(stripansi.Strip(bufA.String()), resA.width, "…"))
|
||||
bufA.Reset()
|
||||
return io.MultiReader(bufP, trunc), nil
|
||||
}
|
||||
|
||||
if !s.trimSpace && stat.AvailableWidth >= 2 {
|
||||
stat.AvailableWidth -= 2
|
||||
writeFiller := func(buf *bytes.Buffer) error {
|
||||
return s.filler.Fill(buf, stat)
|
||||
}
|
||||
for _, fn := range []func(*bytes.Buffer) error{
|
||||
writeSpace,
|
||||
writeFiller,
|
||||
writeSpace,
|
||||
} {
|
||||
if err := fn(bufB); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err := s.filler.Fill(bufB, stat)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return io.MultiReader(bufP, bufB, bufA), nil
|
||||
}
|
||||
|
||||
func (s *bState) wSyncTable() (table syncTable) {
|
||||
var count int
|
||||
var row []chan int
|
||||
|
||||
for i, decorators := range [][]decor.Decorator{
|
||||
s.pDecorators,
|
||||
s.aDecorators,
|
||||
} {
|
||||
for _, d := range decorators {
|
||||
if ch, ok := d.Sync(); ok {
|
||||
row = append(row, ch)
|
||||
count++
|
||||
}
|
||||
}
|
||||
switch i {
|
||||
case 0:
|
||||
table[i] = row[0:count]
|
||||
default:
|
||||
table[i] = row[len(table[i-1]):count]
|
||||
}
|
||||
}
|
||||
table := make([][]chan int, 2)
|
||||
table[0] = columns[0:pCount]
|
||||
table[1] = columns[pCount : pCount+aCount : pCount+aCount]
|
||||
return table
|
||||
}
|
||||
|
||||
func (s *bState) subscribeDecorators() {
|
||||
for _, decorators := range [...][]decor.Decorator{
|
||||
for _, decorators := range [][]decor.Decorator{
|
||||
s.pDecorators,
|
||||
s.aDecorators,
|
||||
} {
|
||||
@@ -535,16 +604,16 @@ func (s *bState) subscribeDecorators() {
|
||||
}
|
||||
}
|
||||
|
||||
func (s bState) decoratorEwmaUpdate(dur time.Duration) {
|
||||
wg := new(sync.WaitGroup)
|
||||
func (s bState) ewmaUpdate(n int64, dur time.Duration) {
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < len(s.ewmaDecorators); i++ {
|
||||
switch d := s.ewmaDecorators[i]; i {
|
||||
case len(s.ewmaDecorators) - 1:
|
||||
d.EwmaUpdate(s.lastIncrement, dur)
|
||||
d.EwmaUpdate(n, dur)
|
||||
default:
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
d.EwmaUpdate(s.lastIncrement, dur)
|
||||
d.EwmaUpdate(n, dur)
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
@@ -553,7 +622,7 @@ func (s bState) decoratorEwmaUpdate(dur time.Duration) {
|
||||
}
|
||||
|
||||
func (s bState) decoratorAverageAdjust(start time.Time) {
|
||||
wg := new(sync.WaitGroup)
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < len(s.averageDecorators); i++ {
|
||||
switch d := s.averageDecorators[i]; i {
|
||||
case len(s.averageDecorators) - 1:
|
||||
@@ -570,7 +639,7 @@ func (s bState) decoratorAverageAdjust(start time.Time) {
|
||||
}
|
||||
|
||||
func (s bState) decoratorShutdownNotify() {
|
||||
wg := new(sync.WaitGroup)
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < len(s.shutdownListeners); i++ {
|
||||
switch d := s.shutdownListeners[i]; i {
|
||||
case len(s.shutdownListeners) - 1:
|
||||
@@ -589,6 +658,7 @@ func (s bState) decoratorShutdownNotify() {
|
||||
func newStatistics(tw int, s *bState) decor.Statistics {
|
||||
return decor.Statistics{
|
||||
AvailableWidth: tw,
|
||||
RequestedWidth: s.reqWidth,
|
||||
ID: s.id,
|
||||
Total: s.total,
|
||||
Current: s.current,
|
||||
@@ -605,13 +675,6 @@ func extractBaseDecorator(d decor.Decorator) decor.Decorator {
|
||||
return d
|
||||
}
|
||||
|
||||
func makePanicExtender(p interface{}) extenderFunc {
|
||||
pstr := fmt.Sprint(p)
|
||||
return func(rows []io.Reader, _ int, stat decor.Statistics) []io.Reader {
|
||||
r := io.MultiReader(
|
||||
strings.NewReader(runewidth.Truncate(pstr, stat.AvailableWidth, "…")),
|
||||
bytes.NewReader([]byte("\n")),
|
||||
)
|
||||
return append(rows, r)
|
||||
}
|
||||
func writeSpace(buf *bytes.Buffer) error {
|
||||
return buf.WriteByte(' ')
|
||||
}
|
@@ -3,17 +3,13 @@ package mpb
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/vbauerster/mpb/v7/decor"
|
||||
"github.com/vbauerster/mpb/v8/decor"
|
||||
)
|
||||
|
||||
// BarFiller interface.
|
||||
// Bar (without decorators) renders itself by calling BarFiller's Fill method.
|
||||
//
|
||||
// reqWidth is requested width set by `func WithWidth(int) ContainerOption`.
|
||||
// If not set, it defaults to terminal width.
|
||||
//
|
||||
type BarFiller interface {
|
||||
Fill(w io.Writer, reqWidth int, stat decor.Statistics)
|
||||
Fill(io.Writer, decor.Statistics) error
|
||||
}
|
||||
|
||||
// BarFillerBuilder interface.
|
||||
@@ -22,17 +18,16 @@ type BarFiller interface {
|
||||
// BarStyle()
|
||||
// SpinnerStyle()
|
||||
// NopStyle()
|
||||
//
|
||||
type BarFillerBuilder interface {
|
||||
Build() BarFiller
|
||||
}
|
||||
|
||||
// BarFillerFunc is function type adapter to convert compatible function
|
||||
// into BarFiller interface.
|
||||
type BarFillerFunc func(w io.Writer, reqWidth int, stat decor.Statistics)
|
||||
type BarFillerFunc func(io.Writer, decor.Statistics) error
|
||||
|
||||
func (f BarFillerFunc) Fill(w io.Writer, reqWidth int, stat decor.Statistics) {
|
||||
f(w, reqWidth, stat)
|
||||
func (f BarFillerFunc) Fill(w io.Writer, stat decor.Statistics) error {
|
||||
return f(w, stat)
|
||||
}
|
||||
|
||||
// BarFillerBuilderFunc is function type adapter to convert compatible
|
||||
@@ -42,9 +37,3 @@ type BarFillerBuilderFunc func() BarFiller
|
||||
func (f BarFillerBuilderFunc) Build() BarFiller {
|
||||
return f()
|
||||
}
|
||||
|
||||
// NewBarFiller constructs a BarFiller from provided BarFillerBuilder.
|
||||
// Deprecated. Prefer using `*Progress.New(...)` directly.
|
||||
func NewBarFiller(b BarFillerBuilder) BarFiller {
|
||||
return b.Build()
|
||||
}
|
@@ -5,8 +5,8 @@ import (
|
||||
|
||||
"github.com/acarl005/stripansi"
|
||||
"github.com/mattn/go-runewidth"
|
||||
"github.com/vbauerster/mpb/v7/decor"
|
||||
"github.com/vbauerster/mpb/v7/internal"
|
||||
"github.com/vbauerster/mpb/v8/decor"
|
||||
"github.com/vbauerster/mpb/v8/internal"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -36,8 +36,8 @@ type bFiller struct {
|
||||
components [components]*component
|
||||
tip struct {
|
||||
count uint
|
||||
onComplete *component
|
||||
frames []*component
|
||||
onComplete *component
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,20 +148,22 @@ func (s *barStyle) Build() BarFiller {
|
||||
return bf
|
||||
}
|
||||
|
||||
func (s *bFiller) Fill(w io.Writer, width int, stat decor.Statistics) {
|
||||
width = internal.CheckRequestedWidth(width, stat.AvailableWidth)
|
||||
brackets := s.components[iLbound].width + s.components[iRbound].width
|
||||
func (s *bFiller) Fill(w io.Writer, stat decor.Statistics) (err error) {
|
||||
width := internal.CheckRequestedWidth(stat.RequestedWidth, stat.AvailableWidth)
|
||||
// don't count brackets as progress
|
||||
width -= brackets
|
||||
width -= (s.components[iLbound].width + s.components[iRbound].width)
|
||||
if width < 0 {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
mustWrite(w, s.components[iLbound].bytes)
|
||||
defer mustWrite(w, s.components[iRbound].bytes)
|
||||
_, err = w.Write(s.components[iLbound].bytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if width == 0 {
|
||||
return
|
||||
_, err = w.Write(s.components[iRbound].bytes)
|
||||
return err
|
||||
}
|
||||
|
||||
var filling [][]byte
|
||||
@@ -171,7 +173,7 @@ func (s *bFiller) Fill(w io.Writer, width int, stat decor.Statistics) {
|
||||
var refWidth int
|
||||
curWidth := int(internal.PercentageRound(stat.Total, stat.Current, uint(width)))
|
||||
|
||||
if stat.Current >= stat.Total {
|
||||
if stat.Completed {
|
||||
tip = s.tip.onComplete
|
||||
} else {
|
||||
tip = s.tip.frames[s.tip.count%uint(len(s.tip.frames))]
|
||||
@@ -230,24 +232,28 @@ func (s *bFiller) Fill(w io.Writer, width int, stat decor.Statistics) {
|
||||
}
|
||||
|
||||
if s.rev {
|
||||
flush(w, padding, filling)
|
||||
} else {
|
||||
flush(w, filling, padding)
|
||||
filling, padding = padding, filling
|
||||
}
|
||||
err = flush(w, filling, padding)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = w.Write(s.components[iRbound].bytes)
|
||||
return err
|
||||
}
|
||||
|
||||
func flush(w io.Writer, filling, padding [][]byte) {
|
||||
func flush(w io.Writer, filling, padding [][]byte) error {
|
||||
for i := len(filling) - 1; i >= 0; i-- {
|
||||
mustWrite(w, filling[i])
|
||||
_, err := w.Write(filling[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(padding); i++ {
|
||||
mustWrite(w, padding[i])
|
||||
}
|
||||
}
|
||||
|
||||
func mustWrite(w io.Writer, p []byte) {
|
||||
_, err := w.Write(p)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
_, err := w.Write(padding[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
@@ -3,12 +3,14 @@ package mpb
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/vbauerster/mpb/v7/decor"
|
||||
"github.com/vbauerster/mpb/v8/decor"
|
||||
)
|
||||
|
||||
// NopStyle provides BarFillerBuilder which builds NOP BarFiller.
|
||||
func NopStyle() BarFillerBuilder {
|
||||
return BarFillerBuilderFunc(func() BarFiller {
|
||||
return BarFillerFunc(func(io.Writer, int, decor.Statistics) {})
|
||||
return BarFillerFunc(func(io.Writer, decor.Statistics) error {
|
||||
return nil
|
||||
})
|
||||
})
|
||||
}
|
@@ -6,8 +6,8 @@ import (
|
||||
|
||||
"github.com/acarl005/stripansi"
|
||||
"github.com/mattn/go-runewidth"
|
||||
"github.com/vbauerster/mpb/v7/decor"
|
||||
"github.com/vbauerster/mpb/v7/internal"
|
||||
"github.com/vbauerster/mpb/v8/decor"
|
||||
"github.com/vbauerster/mpb/v8/internal"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -63,17 +63,16 @@ func (s *spinnerStyle) Build() BarFiller {
|
||||
return sf
|
||||
}
|
||||
|
||||
func (s *sFiller) Fill(w io.Writer, width int, stat decor.Statistics) {
|
||||
width = internal.CheckRequestedWidth(width, stat.AvailableWidth)
|
||||
func (s *sFiller) Fill(w io.Writer, stat decor.Statistics) (err error) {
|
||||
width := internal.CheckRequestedWidth(stat.RequestedWidth, stat.AvailableWidth)
|
||||
|
||||
frame := s.frames[s.count%uint(len(s.frames))]
|
||||
frameWidth := runewidth.StringWidth(stripansi.Strip(frame))
|
||||
|
||||
if width < frameWidth {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
var err error
|
||||
rest := width - frameWidth
|
||||
switch s.position {
|
||||
case positionLeft:
|
||||
@@ -84,8 +83,6 @@ func (s *sFiller) Fill(w io.Writer, width int, stat decor.Statistics) {
|
||||
str := strings.Repeat(" ", rest/2) + frame + strings.Repeat(" ", rest/2+rest%2)
|
||||
_, err = io.WriteString(w, str)
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
s.count++
|
||||
return err
|
||||
}
|
@@ -4,44 +4,41 @@ import (
|
||||
"bytes"
|
||||
"io"
|
||||
|
||||
"github.com/vbauerster/mpb/v7/decor"
|
||||
"github.com/vbauerster/mpb/v8/decor"
|
||||
)
|
||||
|
||||
// BarOption is a func option to alter default behavior of a bar.
|
||||
type BarOption func(*bState)
|
||||
|
||||
func skipNil(decorators []decor.Decorator) (filtered []decor.Decorator) {
|
||||
for _, d := range decorators {
|
||||
if d != nil {
|
||||
filtered = append(filtered, d)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *bState) addDecorators(dest *[]decor.Decorator, decorators ...decor.Decorator) {
|
||||
func inspect(decorators []decor.Decorator) (dest []decor.Decorator) {
|
||||
type mergeWrapper interface {
|
||||
MergeUnwrap() []decor.Decorator
|
||||
}
|
||||
for _, decorator := range decorators {
|
||||
if mw, ok := decorator.(mergeWrapper); ok {
|
||||
*dest = append(*dest, mw.MergeUnwrap()...)
|
||||
if decorator == nil {
|
||||
continue
|
||||
}
|
||||
*dest = append(*dest, decorator)
|
||||
if mw, ok := decorator.(mergeWrapper); ok {
|
||||
dest = append(dest, mw.MergeUnwrap()...)
|
||||
}
|
||||
dest = append(dest, decorator)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// AppendDecorators let you inject decorators to the bar's right side.
|
||||
func AppendDecorators(decorators ...decor.Decorator) BarOption {
|
||||
decorators = inspect(decorators)
|
||||
return func(s *bState) {
|
||||
s.addDecorators(&s.aDecorators, skipNil(decorators)...)
|
||||
s.aDecorators = decorators
|
||||
}
|
||||
}
|
||||
|
||||
// PrependDecorators let you inject decorators to the bar's left side.
|
||||
func PrependDecorators(decorators ...decor.Decorator) BarOption {
|
||||
decorators = inspect(decorators)
|
||||
return func(s *bState) {
|
||||
s.addDecorators(&s.pDecorators, skipNil(decorators)...)
|
||||
s.pDecorators = decorators
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,15 +88,12 @@ func BarFillerClearOnComplete() BarOption {
|
||||
// BarFillerOnComplete replaces bar's filler with message, on complete event.
|
||||
func BarFillerOnComplete(message string) BarOption {
|
||||
return BarFillerMiddleware(func(base BarFiller) BarFiller {
|
||||
return BarFillerFunc(func(w io.Writer, reqWidth int, st decor.Statistics) {
|
||||
return BarFillerFunc(func(w io.Writer, st decor.Statistics) error {
|
||||
if st.Completed {
|
||||
_, err := io.WriteString(w, message)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
base.Fill(w, reqWidth, st)
|
||||
return err
|
||||
}
|
||||
return base.Fill(w, st)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -121,32 +115,26 @@ func BarPriority(priority int) BarOption {
|
||||
|
||||
// BarExtender extends bar with arbitrary lines. Provided BarFiller will be
|
||||
// called at each render/flush cycle. Any lines written to the underlying
|
||||
// io.Writer will be printed after the bar itself.
|
||||
func BarExtender(filler BarFiller) BarOption {
|
||||
return barExtender(filler, false)
|
||||
}
|
||||
|
||||
// BarExtenderRev extends bar with arbitrary lines in reverse order. Provided
|
||||
// BarFiller will be called at each render/flush cycle. Any lines written
|
||||
// to the underlying io.Writer will be printed before the bar itself.
|
||||
func BarExtenderRev(filler BarFiller) BarOption {
|
||||
return barExtender(filler, true)
|
||||
}
|
||||
|
||||
func barExtender(filler BarFiller, rev bool) BarOption {
|
||||
// io.Writer will extend the bar either in above (rev = true) or below
|
||||
// (rev = false) direction.
|
||||
func BarExtender(filler BarFiller, rev bool) BarOption {
|
||||
if filler == nil {
|
||||
return nil
|
||||
}
|
||||
fn := makeExtenderFunc(filler, rev)
|
||||
return func(s *bState) {
|
||||
s.extender = makeExtenderFunc(filler, rev)
|
||||
s.extender = fn
|
||||
}
|
||||
}
|
||||
|
||||
func makeExtenderFunc(filler BarFiller, rev bool) extenderFunc {
|
||||
buf := new(bytes.Buffer)
|
||||
base := func(rows []io.Reader, width int, stat decor.Statistics) []io.Reader {
|
||||
buf.Reset()
|
||||
filler.Fill(buf, width, stat)
|
||||
base := func(rows []io.Reader, stat decor.Statistics) ([]io.Reader, error) {
|
||||
err := filler.Fill(buf, stat)
|
||||
if err != nil {
|
||||
buf.Reset()
|
||||
return rows, err
|
||||
}
|
||||
for {
|
||||
b, err := buf.ReadBytes('\n')
|
||||
if err != nil {
|
||||
@@ -154,19 +142,22 @@ func makeExtenderFunc(filler BarFiller, rev bool) extenderFunc {
|
||||
}
|
||||
rows = append(rows, bytes.NewReader(b))
|
||||
}
|
||||
return rows
|
||||
buf.Reset()
|
||||
return rows, err
|
||||
}
|
||||
|
||||
if !rev {
|
||||
return base
|
||||
} else {
|
||||
return func(rows []io.Reader, width int, stat decor.Statistics) []io.Reader {
|
||||
rows = base(rows, width, stat)
|
||||
for left, right := 0, len(rows)-1; left < right; left, right = left+1, right-1 {
|
||||
rows[left], rows[right] = rows[right], rows[left]
|
||||
}
|
||||
return rows
|
||||
}
|
||||
return func(rows []io.Reader, stat decor.Statistics) ([]io.Reader, error) {
|
||||
rows, err := base(rows, stat)
|
||||
if err != nil {
|
||||
return rows, err
|
||||
}
|
||||
for left, right := 0, len(rows)-1; left < right; left, right = left+1, right-1 {
|
||||
rows[left], rows[right] = rows[right], rows[left]
|
||||
}
|
||||
return rows, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,7 +176,7 @@ func BarNoPop() BarOption {
|
||||
}
|
||||
}
|
||||
|
||||
// BarOptional will invoke provided option only when cond is true.
|
||||
// BarOptional will return provided option only when cond is true.
|
||||
func BarOptional(option BarOption, cond bool) BarOption {
|
||||
if cond {
|
||||
return option
|
||||
@@ -193,11 +184,26 @@ func BarOptional(option BarOption, cond bool) BarOption {
|
||||
return nil
|
||||
}
|
||||
|
||||
// BarOptOn will invoke provided option only when higher order predicate
|
||||
// evaluates to true.
|
||||
// BarOptOn will return provided option only when predicate evaluates to true.
|
||||
func BarOptOn(option BarOption, predicate func() bool) BarOption {
|
||||
if predicate() {
|
||||
return option
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BarFuncOptional will call option and return its value only when cond is true.
|
||||
func BarFuncOptional(option func() BarOption, cond bool) BarOption {
|
||||
if cond {
|
||||
return option()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BarFuncOptOn will call option and return its value only when predicate evaluates to true.
|
||||
func BarFuncOptOn(option func() BarOption, predicate func() bool) BarOption {
|
||||
if predicate() {
|
||||
return option()
|
||||
}
|
||||
return nil
|
||||
}
|
@@ -33,15 +33,16 @@ func WithWidth(width int) ContainerOption {
|
||||
// WithRefreshRate overrides default 150ms refresh rate.
|
||||
func WithRefreshRate(d time.Duration) ContainerOption {
|
||||
return func(s *pState) {
|
||||
s.rr = d
|
||||
s.refreshRate = d
|
||||
}
|
||||
}
|
||||
|
||||
// WithManualRefresh disables internal auto refresh time.Ticker.
|
||||
// Refresh will occur upon receive value from provided ch.
|
||||
func WithManualRefresh(ch <-chan interface{}) ContainerOption {
|
||||
func WithManualRefresh(ch chan interface{}) ContainerOption {
|
||||
return func(s *pState) {
|
||||
s.externalRefresh = ch
|
||||
s.manualRefresh = ch
|
||||
s.disableAutoRefresh = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,34 +72,37 @@ func WithShutdownNotifier(ch chan struct{}) ContainerOption {
|
||||
// will effectively disable auto refresh rate and discard any output,
|
||||
// useful if you want to disable progress bars with little overhead.
|
||||
func WithOutput(w io.Writer) ContainerOption {
|
||||
var discarded bool
|
||||
if w == nil {
|
||||
w = io.Discard
|
||||
discarded = true
|
||||
}
|
||||
return func(s *pState) {
|
||||
if w == nil {
|
||||
s.output = io.Discard
|
||||
s.outputDiscarded = true
|
||||
return
|
||||
}
|
||||
s.output = w
|
||||
s.outputDiscarded = discarded
|
||||
}
|
||||
}
|
||||
|
||||
// WithDebugOutput sets debug output.
|
||||
func WithDebugOutput(w io.Writer) ContainerOption {
|
||||
if w == nil {
|
||||
return nil
|
||||
w = io.Discard
|
||||
}
|
||||
return func(s *pState) {
|
||||
s.debugOut = w
|
||||
}
|
||||
}
|
||||
|
||||
// PopCompletedMode will pop and stop rendering completed bars.
|
||||
// PopCompletedMode will pop completed bars to the top.
|
||||
// To stop rendering bar after it has been popped, use
|
||||
// mpb.BarRemoveOnComplete() option on that bar.
|
||||
func PopCompletedMode() ContainerOption {
|
||||
return func(s *pState) {
|
||||
s.popCompleted = true
|
||||
}
|
||||
}
|
||||
|
||||
// ContainerOptional will invoke provided option only when cond is true.
|
||||
// ContainerOptional will return provided option only when cond is true.
|
||||
func ContainerOptional(option ContainerOption, cond bool) ContainerOption {
|
||||
if cond {
|
||||
return option
|
||||
@@ -106,11 +110,26 @@ func ContainerOptional(option ContainerOption, cond bool) ContainerOption {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContainerOptOn will invoke provided option only when higher order
|
||||
// predicate evaluates to true.
|
||||
// ContainerOptOn will return provided option only when predicate evaluates to true.
|
||||
func ContainerOptOn(option ContainerOption, predicate func() bool) ContainerOption {
|
||||
if predicate() {
|
||||
return option
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContainerFuncOptional will call option and return its value only when cond is true.
|
||||
func ContainerFuncOptional(option func() ContainerOption, cond bool) ContainerOption {
|
||||
if cond {
|
||||
return option()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContainerFuncOptOn will call option and return its value only when predicate evaluates to true.
|
||||
func ContainerFuncOptOn(option func() ContainerOption, predicate func() bool) ContainerOption {
|
||||
if predicate() {
|
||||
return option()
|
||||
}
|
||||
return nil
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
// +build darwin dragonfly freebsd netbsd openbsd
|
||||
//go:build darwin || dragonfly || freebsd || netbsd || openbsd
|
||||
|
||||
package cwriter
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// +build aix linux
|
||||
//go:build aix || linux
|
||||
|
||||
package cwriter
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// +build solaris
|
||||
//go:build solaris
|
||||
|
||||
package cwriter
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// +build zos
|
||||
//go:build zos
|
||||
|
||||
package cwriter
|
||||
|
54
vendor/github.com/vbauerster/mpb/v8/cwriter/writer.go
generated
vendored
Normal file
54
vendor/github.com/vbauerster/mpb/v8/cwriter/writer.go
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
package cwriter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// https://github.com/dylanaraps/pure-sh-bible#cursor-movement
|
||||
const (
|
||||
escOpen = "\x1b["
|
||||
cuuAndEd = "A\x1b[J"
|
||||
)
|
||||
|
||||
// ErrNotTTY not a TeleTYpewriter error.
|
||||
var ErrNotTTY = errors.New("not a terminal")
|
||||
|
||||
// New returns a new Writer with defaults.
|
||||
func New(out io.Writer) *Writer {
|
||||
w := &Writer{
|
||||
Buffer: new(bytes.Buffer),
|
||||
out: out,
|
||||
termSize: func(_ int) (int, int, error) {
|
||||
return -1, -1, ErrNotTTY
|
||||
},
|
||||
}
|
||||
if f, ok := out.(*os.File); ok {
|
||||
w.fd = int(f.Fd())
|
||||
if IsTerminal(w.fd) {
|
||||
w.terminal = true
|
||||
w.termSize = func(fd int) (int, int, error) {
|
||||
return GetSize(fd)
|
||||
}
|
||||
}
|
||||
}
|
||||
bb := make([]byte, 16)
|
||||
w.ew = escWriter(bb[:copy(bb, []byte(escOpen))])
|
||||
return w
|
||||
}
|
||||
|
||||
// GetTermSize returns WxH of underlying terminal.
|
||||
func (w *Writer) GetTermSize() (width, height int, err error) {
|
||||
return w.termSize(w.fd)
|
||||
}
|
||||
|
||||
type escWriter []byte
|
||||
|
||||
func (b escWriter) ansiCuuAndEd(out io.Writer, n int) error {
|
||||
b = strconv.AppendInt(b, int64(n), 10)
|
||||
_, err := out.Write(append(b, []byte(cuuAndEd)...))
|
||||
return err
|
||||
}
|
48
vendor/github.com/vbauerster/mpb/v8/cwriter/writer_posix.go
generated
vendored
Normal file
48
vendor/github.com/vbauerster/mpb/v8/cwriter/writer_posix.go
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
//go:build !windows
|
||||
|
||||
package cwriter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// Writer is a buffered terminal writer, which moves cursor N lines up
|
||||
// on each flush except the first one, where N is a number of lines of
|
||||
// a previous flush.
|
||||
type Writer struct {
|
||||
*bytes.Buffer
|
||||
out io.Writer
|
||||
ew escWriter
|
||||
fd int
|
||||
terminal bool
|
||||
termSize func(int) (int, int, error)
|
||||
}
|
||||
|
||||
// Flush flushes the underlying buffer.
|
||||
// It's caller's responsibility to pass correct number of lines.
|
||||
func (w *Writer) Flush(lines int) error {
|
||||
_, err := w.WriteTo(w.out)
|
||||
// some terminals interpret 'cursor up 0' as 'cursor up 1'
|
||||
if err == nil && lines > 0 {
|
||||
err = w.ew.ansiCuuAndEd(w, lines)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// GetSize returns the dimensions of the given terminal.
|
||||
func GetSize(fd int) (width, height int, err error) {
|
||||
ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ)
|
||||
if err != nil {
|
||||
return -1, -1, err
|
||||
}
|
||||
return int(ws.Col), int(ws.Row), nil
|
||||
}
|
||||
|
||||
// IsTerminal returns whether the given file descriptor is a terminal.
|
||||
func IsTerminal(fd int) bool {
|
||||
_, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
|
||||
return err == nil
|
||||
}
|
@@ -1,8 +1,10 @@
|
||||
// +build windows
|
||||
//go:build windows
|
||||
|
||||
package cwriter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
@@ -15,10 +17,37 @@ var (
|
||||
procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW")
|
||||
)
|
||||
|
||||
func (w *Writer) clearLines() error {
|
||||
// Writer is a buffered terminal writer, which moves cursor N lines up
|
||||
// on each flush except the first one, where N is a number of lines of
|
||||
// a previous flush.
|
||||
type Writer struct {
|
||||
*bytes.Buffer
|
||||
out io.Writer
|
||||
ew escWriter
|
||||
lines int
|
||||
fd int
|
||||
terminal bool
|
||||
termSize func(int) (int, int, error)
|
||||
}
|
||||
|
||||
// Flush flushes the underlying buffer.
|
||||
// It's caller's responsibility to pass correct number of lines.
|
||||
func (w *Writer) Flush(lines int) error {
|
||||
if w.lines > 0 {
|
||||
err := w.clearLines(w.lines)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
w.lines = lines
|
||||
_, err := w.WriteTo(w.out)
|
||||
return err
|
||||
}
|
||||
|
||||
func (w *Writer) clearLines(n int) error {
|
||||
if !w.terminal {
|
||||
// hope it's cygwin or similar
|
||||
return w.ansiCuuAndEd()
|
||||
return w.ew.ansiCuuAndEd(w.out, n)
|
||||
}
|
||||
|
||||
var info windows.ConsoleScreenBufferInfo
|
||||
@@ -26,7 +55,7 @@ func (w *Writer) clearLines() error {
|
||||
return err
|
||||
}
|
||||
|
||||
info.CursorPosition.Y -= int16(w.lines)
|
||||
info.CursorPosition.Y -= int16(n)
|
||||
if info.CursorPosition.Y < 0 {
|
||||
info.CursorPosition.Y = 0
|
||||
}
|
||||
@@ -40,7 +69,7 @@ func (w *Writer) clearLines() error {
|
||||
X: info.Window.Left,
|
||||
Y: info.CursorPosition.Y,
|
||||
}
|
||||
count := uint32(info.Size.X) * uint32(w.lines)
|
||||
count := uint32(info.Size.X) * uint32(n)
|
||||
_, _, _ = procFillConsoleOutputCharacter.Call(
|
||||
uintptr(w.fd),
|
||||
uintptr(' '),
|
||||
@@ -52,7 +81,6 @@ func (w *Writer) clearLines() error {
|
||||
}
|
||||
|
||||
// GetSize returns the visible dimensions of the given terminal.
|
||||
//
|
||||
// These dimensions don't include any scrollback buffer height.
|
||||
func GetSize(fd int) (width, height int, err error) {
|
||||
var info windows.ConsoleScreenBufferInfo
|
@@ -6,7 +6,6 @@ package decor
|
||||
// `fn` DecorFunc callback
|
||||
//
|
||||
// `wcc` optional WC config
|
||||
//
|
||||
func Any(fn DecorFunc, wcc ...WC) Decorator {
|
||||
return &any{initWC(wcc...), fn}
|
||||
}
|
@@ -42,7 +42,6 @@ func CountersKiloByte(pairFmt string, wcc ...WC) Decorator {
|
||||
// pairFmt="% .1f / % .1f" output: "1.0 MB / 12.0 MB"
|
||||
// pairFmt="%d / %d" output: "1MB / 12MB"
|
||||
// pairFmt="% d / % d" output: "1 MB / 12 MB"
|
||||
//
|
||||
func Counters(unit int, pairFmt string, wcc ...WC) Decorator {
|
||||
producer := func(unit int, pairFmt string) DecorFunc {
|
||||
if pairFmt == "" {
|
||||
@@ -99,7 +98,6 @@ func TotalKiloByte(format string, wcc ...WC) Decorator {
|
||||
// format="% .1f" output: "12.0 MiB"
|
||||
// format="%d" output: "12MiB"
|
||||
// format="% d" output: "12 MiB"
|
||||
//
|
||||
func Total(unit int, format string, wcc ...WC) Decorator {
|
||||
producer := func(unit int, format string) DecorFunc {
|
||||
if format == "" {
|
||||
@@ -157,7 +155,6 @@ func CurrentKiloByte(format string, wcc ...WC) Decorator {
|
||||
// format="% .1f" output: "12.0 MiB"
|
||||
// format="%d" output: "12MiB"
|
||||
// format="% d" output: "12 MiB"
|
||||
//
|
||||
func Current(unit int, format string, wcc ...WC) Decorator {
|
||||
producer := func(unit int, format string) DecorFunc {
|
||||
if format == "" {
|
||||
@@ -215,7 +212,6 @@ func InvertedCurrentKiloByte(format string, wcc ...WC) Decorator {
|
||||
// format="% .1f" output: "12.0 MiB"
|
||||
// format="%d" output: "12MiB"
|
||||
// format="% d" output: "12 MiB"
|
||||
//
|
||||
func InvertedCurrent(unit int, format string, wcc ...WC) Decorator {
|
||||
producer := func(unit int, format string) DecorFunc {
|
||||
if format == "" {
|
@@ -44,10 +44,11 @@ const (
|
||||
ET_STYLE_MMSS
|
||||
)
|
||||
|
||||
// Statistics consists of progress related statistics, that Decorator
|
||||
// may need.
|
||||
// Statistics contains fields which are necessary for implementing
|
||||
// `decor.Decorator` and `mpb.BarFiller` interfaces.
|
||||
type Statistics struct {
|
||||
AvailableWidth int
|
||||
AvailableWidth int // calculated width initially equal to terminal width
|
||||
RequestedWidth int // width set by `mpb.WithWidth`
|
||||
ID int
|
||||
Total int64
|
||||
Current int64
|
||||
@@ -138,17 +139,17 @@ type WC struct {
|
||||
// Should be called by any Decorator implementation.
|
||||
func (wc *WC) FormatMsg(msg string) string {
|
||||
pureWidth := runewidth.StringWidth(msg)
|
||||
stripWidth := runewidth.StringWidth(stripansi.Strip(msg))
|
||||
maxCell := wc.W
|
||||
viewWidth := runewidth.StringWidth(stripansi.Strip(msg))
|
||||
max := wc.W
|
||||
if (wc.C & DSyncWidth) != 0 {
|
||||
cellCount := stripWidth
|
||||
viewWidth := viewWidth
|
||||
if (wc.C & DextraSpace) != 0 {
|
||||
cellCount++
|
||||
viewWidth++
|
||||
}
|
||||
wc.wsync <- cellCount
|
||||
maxCell = <-wc.wsync
|
||||
wc.wsync <- viewWidth
|
||||
max = <-wc.wsync
|
||||
}
|
||||
return wc.fill(msg, maxCell+(pureWidth-stripWidth))
|
||||
return wc.fill(msg, max-viewWidth+pureWidth)
|
||||
}
|
||||
|
||||
// Init initializes width related config.
|
@@ -1,4 +1,4 @@
|
||||
// Package decor provides common decorators for "github.com/vbauerster/mpb/v7" module.
|
||||
// Package decor provides common decorators for "github.com/vbauerster/mpb/v8" module.
|
||||
//
|
||||
// Some decorators returned by this package might have a closure state. It is ok to use
|
||||
// decorators concurrently, unless you share the same decorator among multiple
|
||||
@@ -6,10 +6,10 @@
|
||||
//
|
||||
// Don't:
|
||||
//
|
||||
// p := mpb.New()
|
||||
// name := decor.Name("bar")
|
||||
// p.AddBar(100, mpb.AppendDecorators(name))
|
||||
// p.AddBar(100, mpb.AppendDecorators(name))
|
||||
// p := mpb.New()
|
||||
// name := decor.Name("bar")
|
||||
// p.AddBar(100, mpb.AppendDecorators(name))
|
||||
// p.AddBar(100, mpb.AppendDecorators(name))
|
||||
//
|
||||
// Do:
|
||||
//
|
@@ -9,7 +9,6 @@ import (
|
||||
// `style` one of [ET_STYLE_GO|ET_STYLE_HHMMSS|ET_STYLE_HHMM|ET_STYLE_MMSS]
|
||||
//
|
||||
// `wcc` optional WC config
|
||||
//
|
||||
func Elapsed(style TimeStyle, wcc ...WC) Decorator {
|
||||
return NewElapsed(style, time.Now(), wcc...)
|
||||
}
|
||||
@@ -21,7 +20,6 @@ func Elapsed(style TimeStyle, wcc ...WC) Decorator {
|
||||
// `startTime` start time
|
||||
//
|
||||
// `wcc` optional WC config
|
||||
//
|
||||
func NewElapsed(style TimeStyle, startTime time.Time, wcc ...WC) Decorator {
|
||||
var msg string
|
||||
producer := chooseTimeProducer(style)
|
@@ -22,10 +22,9 @@ func (f TimeNormalizerFunc) Normalize(src time.Duration) time.Duration {
|
||||
return f(src)
|
||||
}
|
||||
|
||||
// EwmaETA exponential-weighted-moving-average based ETA decorator.
|
||||
// For this decorator to work correctly you have to measure each
|
||||
// iteration's duration and pass it to the
|
||||
// *Bar.DecoratorEwmaUpdate(time.Duration) method after each increment.
|
||||
// EwmaETA exponential-weighted-moving-average based ETA decorator. For this
|
||||
// decorator to work correctly you have to measure each iteration's duration
|
||||
// and pass it to one of the (*Bar).EwmaIncr... family methods.
|
||||
func EwmaETA(style TimeStyle, age float64, wcc ...WC) Decorator {
|
||||
var average ewma.MovingAverage
|
||||
if age == 0 {
|
||||
@@ -45,7 +44,6 @@ func EwmaETA(style TimeStyle, age float64, wcc ...WC) Decorator {
|
||||
// `normalizer` available implementations are [FixedIntervalTimeNormalizer|MaxTolerateTimeNormalizer]
|
||||
//
|
||||
// `wcc` optional WC config
|
||||
//
|
||||
func MovingAverageETA(style TimeStyle, average ewma.MovingAverage, normalizer TimeNormalizer, wcc ...WC) Decorator {
|
||||
d := &movingAverageETA{
|
||||
WC: initWC(wcc...),
|
||||
@@ -85,7 +83,6 @@ func (d *movingAverageETA) EwmaUpdate(n int64, dur time.Duration) {
|
||||
// `style` one of [ET_STYLE_GO|ET_STYLE_HHMMSS|ET_STYLE_HHMM|ET_STYLE_MMSS]
|
||||
//
|
||||
// `wcc` optional WC config
|
||||
//
|
||||
func AverageETA(style TimeStyle, wcc ...WC) Decorator {
|
||||
return NewAverageETA(style, time.Now(), nil, wcc...)
|
||||
}
|
||||
@@ -99,7 +96,6 @@ func AverageETA(style TimeStyle, wcc ...WC) Decorator {
|
||||
// `normalizer` available implementations are [FixedIntervalTimeNormalizer|MaxTolerateTimeNormalizer]
|
||||
//
|
||||
// `wcc` optional WC config
|
||||
//
|
||||
func NewAverageETA(style TimeStyle, startTime time.Time, normalizer TimeNormalizer, wcc ...WC) Decorator {
|
||||
d := &averageETA{
|
||||
WC: initWC(wcc...),
|
@@ -10,12 +10,11 @@ import (
|
||||
// Merge wraps its decorator argument with intention to sync width
|
||||
// with several decorators of another bar. Visual example:
|
||||
//
|
||||
// +----+--------+---------+--------+
|
||||
// | B1 | MERGE(D, P1, Pn) |
|
||||
// +----+--------+---------+--------+
|
||||
// | B2 | D0 | D1 | Dn |
|
||||
// +----+--------+---------+--------+
|
||||
//
|
||||
// +----+--------+---------+--------+
|
||||
// | B1 | MERGE(D, P1, Pn) |
|
||||
// +----+--------+---------+--------+
|
||||
// | B2 | D0 | D1 | Dn |
|
||||
// +----+--------+---------+--------+
|
||||
func Merge(decorator Decorator, placeholders ...WC) Decorator {
|
||||
if decorator == nil {
|
||||
return nil
|
@@ -6,7 +6,6 @@ package decor
|
||||
// `str` string to display
|
||||
//
|
||||
// `wcc` optional WC config
|
||||
//
|
||||
func Name(str string, wcc ...WC) Decorator {
|
||||
return Any(func(Statistics) string { return str }, wcc...)
|
||||
}
|
@@ -7,7 +7,6 @@ package decor
|
||||
// `decorator` Decorator to wrap
|
||||
//
|
||||
// `message` message to display on abort event
|
||||
//
|
||||
func OnAbort(decorator Decorator, message string) Decorator {
|
||||
if decorator == nil {
|
||||
return nil
|
@@ -6,7 +6,6 @@ package decor
|
||||
// `decorator` Decorator to wrap
|
||||
//
|
||||
// `message` message to display on complete event
|
||||
//
|
||||
func OnComplete(decorator Decorator, message string) Decorator {
|
||||
if decorator == nil {
|
||||
return nil
|
@@ -5,7 +5,6 @@ package decor
|
||||
// `decorator` Decorator
|
||||
//
|
||||
// `cond` bool
|
||||
//
|
||||
func OnCondition(decorator Decorator, cond bool) Decorator {
|
||||
return Conditional(cond, decorator, nil)
|
||||
}
|
||||
@@ -15,7 +14,6 @@ func OnCondition(decorator Decorator, cond bool) Decorator {
|
||||
// `decorator` Decorator
|
||||
//
|
||||
// `predicate` func() bool
|
||||
//
|
||||
func OnPredicate(decorator Decorator, predicate func() bool) Decorator {
|
||||
return Predicative(predicate, decorator, nil)
|
||||
}
|
||||
@@ -28,7 +26,6 @@ func OnPredicate(decorator Decorator, predicate func() bool) Decorator {
|
||||
// `a` Decorator
|
||||
//
|
||||
// `b` Decorator
|
||||
//
|
||||
func Conditional(cond bool, a, b Decorator) Decorator {
|
||||
if cond {
|
||||
return a
|
||||
@@ -45,7 +42,6 @@ func Conditional(cond bool, a, b Decorator) Decorator {
|
||||
// `a` Decorator
|
||||
//
|
||||
// `b` Decorator
|
||||
//
|
||||
func Predicative(predicate func() bool, a, b Decorator) Decorator {
|
||||
if predicate() {
|
||||
return a
|
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/vbauerster/mpb/v7/internal"
|
||||
"github.com/vbauerster/mpb/v8/internal"
|
||||
)
|
||||
|
||||
type percentageType float64
|
||||
@@ -23,11 +23,18 @@ func (s percentageType) Format(st fmt.State, verb rune) {
|
||||
}
|
||||
}
|
||||
|
||||
mustWriteString(st, strconv.FormatFloat(float64(s), 'f', prec, 64))
|
||||
p := bytesPool.Get().(*[]byte)
|
||||
b := strconv.AppendFloat(*p, float64(s), 'f', prec, 64)
|
||||
if st.Flag(' ') {
|
||||
mustWriteString(st, " ")
|
||||
b = append(b, ' ', '%')
|
||||
} else {
|
||||
b = append(b, '%')
|
||||
}
|
||||
mustWriteString(st, "%")
|
||||
_, err := st.Write(b)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
bytesPool.Put(p)
|
||||
}
|
||||
|
||||
// Percentage returns percentage decorator. It's a wrapper of NewPercentage.
|
||||
@@ -43,7 +50,6 @@ func Percentage(wcc ...WC) Decorator {
|
||||
// format="% .1f" output: "1.0 %"
|
||||
// format="%d" output: "1%"
|
||||
// format="% d" output: "1 %"
|
||||
//
|
||||
func NewPercentage(format string, wcc ...WC) Decorator {
|
||||
if format == "" {
|
||||
format = "% d"
|
10
vendor/github.com/vbauerster/mpb/v8/decor/pool.go
generated
vendored
Normal file
10
vendor/github.com/vbauerster/mpb/v8/decor/pool.go
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
package decor
|
||||
|
||||
import "sync"
|
||||
|
||||
var bytesPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
b := make([]byte, 0, 32)
|
||||
return &b
|
||||
},
|
||||
}
|
@@ -49,11 +49,17 @@ func (self SizeB1024) Format(st fmt.State, verb rune) {
|
||||
unit = _iTiB
|
||||
}
|
||||
|
||||
mustWriteString(st, strconv.FormatFloat(float64(self)/float64(unit), 'f', prec, 64))
|
||||
p := bytesPool.Get().(*[]byte)
|
||||
b := strconv.AppendFloat(*p, float64(self)/float64(unit), 'f', prec, 64)
|
||||
if st.Flag(' ') {
|
||||
mustWriteString(st, " ")
|
||||
b = append(b, ' ')
|
||||
}
|
||||
mustWriteString(st, unit.String())
|
||||
b = append(b, []byte(unit.String())...)
|
||||
_, err := st.Write(b)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
bytesPool.Put(p)
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -97,9 +103,15 @@ func (self SizeB1000) Format(st fmt.State, verb rune) {
|
||||
unit = _TB
|
||||
}
|
||||
|
||||
mustWriteString(st, strconv.FormatFloat(float64(self)/float64(unit), 'f', prec, 64))
|
||||
p := bytesPool.Get().(*[]byte)
|
||||
b := strconv.AppendFloat(*p, float64(self)/float64(unit), 'f', prec, 64)
|
||||
if st.Flag(' ') {
|
||||
mustWriteString(st, " ")
|
||||
b = append(b, ' ')
|
||||
}
|
||||
mustWriteString(st, unit.String())
|
||||
b = append(b, []byte(unit.String())...)
|
||||
_, err := st.Write(b)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
bytesPool.Put(p)
|
||||
}
|
@@ -12,7 +12,6 @@ import (
|
||||
// used with SizeB1000 or SizeB1024 types, for example:
|
||||
//
|
||||
// fmt.Printf("%.1f", FmtAsSpeed(SizeB1024(2048)))
|
||||
//
|
||||
func FmtAsSpeed(input fmt.Formatter) fmt.Formatter {
|
||||
return &speedFormatter{input}
|
||||
}
|
||||
@@ -23,13 +22,15 @@ type speedFormatter struct {
|
||||
|
||||
func (self *speedFormatter) Format(st fmt.State, verb rune) {
|
||||
self.Formatter.Format(st, verb)
|
||||
mustWriteString(st, "/s")
|
||||
_, err := st.Write([]byte("/s"))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// EwmaSpeed exponential-weighted-moving-average based speed decorator.
|
||||
// For this decorator to work correctly you have to measure each
|
||||
// iteration's duration and pass it to the
|
||||
// *Bar.DecoratorEwmaUpdate(time.Duration) method after each increment.
|
||||
// For this decorator to work correctly you have to measure each iteration's
|
||||
// duration and pass it to one of the (*Bar).EwmaIncr... family methods.
|
||||
func EwmaSpeed(unit int, format string, age float64, wcc ...WC) Decorator {
|
||||
var average ewma.MovingAverage
|
||||
if age == 0 {
|
||||
@@ -57,7 +58,6 @@ func EwmaSpeed(unit int, format string, age float64, wcc ...WC) Decorator {
|
||||
// unit=UnitKiB, format="% .1f" output: "1.0 MiB/s"
|
||||
// unit=UnitKB, format="%.1f" output: "1.0MB/s"
|
||||
// unit=UnitKB, format="% .1f" output: "1.0 MB/s"
|
||||
//
|
||||
func MovingAverageSpeed(unit int, format string, average ewma.MovingAverage, wcc ...WC) Decorator {
|
||||
if format == "" {
|
||||
format = "%.0f"
|
||||
@@ -119,7 +119,6 @@ func AverageSpeed(unit int, format string, wcc ...WC) Decorator {
|
||||
// unit=UnitKiB, format="% .1f" output: "1.0 MiB/s"
|
||||
// unit=UnitKB, format="%.1f" output: "1.0MB/s"
|
||||
// unit=UnitKB, format="% .1f" output: "1.0 MB/s"
|
||||
//
|
||||
func NewAverageSpeed(unit int, format string, startTime time.Time, wcc ...WC) Decorator {
|
||||
if format == "" {
|
||||
format = "%.0f"
|
@@ -11,23 +11,26 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/vbauerster/mpb/v7/cwriter"
|
||||
"github.com/vbauerster/mpb/v8/cwriter"
|
||||
)
|
||||
|
||||
const (
|
||||
prr = 150 * time.Millisecond // default RefreshRate
|
||||
defaultRefreshRate = 150 * time.Millisecond
|
||||
)
|
||||
|
||||
// DoneError represents an error when `*mpb.Progress` is done but its functionality is requested.
|
||||
var DoneError = fmt.Errorf("%T instance can't be reused after it's done!", (*Progress)(nil))
|
||||
|
||||
// Progress represents a container that renders one or more progress bars.
|
||||
type Progress struct {
|
||||
ctx context.Context
|
||||
uwg *sync.WaitGroup
|
||||
cwg *sync.WaitGroup
|
||||
bwg *sync.WaitGroup
|
||||
operateState chan func(*pState)
|
||||
interceptIo chan func(io.Writer)
|
||||
done chan struct{}
|
||||
refreshCh chan time.Time
|
||||
once sync.Once
|
||||
shutdown chan struct{}
|
||||
cancel func()
|
||||
}
|
||||
|
||||
// pState holds bars in its priorityQueue, it gets passed to (*Progress).serve monitor goroutine.
|
||||
@@ -36,21 +39,23 @@ type pState struct {
|
||||
heapUpdated bool
|
||||
pMatrix map[int][]chan int
|
||||
aMatrix map[int][]chan int
|
||||
rows []io.Reader
|
||||
|
||||
// following are provided/overrided by user
|
||||
idCount int
|
||||
reqWidth int
|
||||
popPriority int
|
||||
popCompleted bool
|
||||
outputDiscarded bool
|
||||
rr time.Duration
|
||||
uwg *sync.WaitGroup
|
||||
externalRefresh <-chan interface{}
|
||||
renderDelay <-chan struct{}
|
||||
shutdownNotifier chan struct{}
|
||||
queueBars map[*Bar]*Bar
|
||||
output io.Writer
|
||||
debugOut io.Writer
|
||||
refreshRate time.Duration
|
||||
idCount int
|
||||
reqWidth int
|
||||
popPriority int
|
||||
popCompleted bool
|
||||
outputDiscarded bool
|
||||
disableAutoRefresh bool
|
||||
manualRefresh chan interface{}
|
||||
renderDelay <-chan struct{}
|
||||
shutdownNotifier chan struct{}
|
||||
queueBars map[*Bar]*Bar
|
||||
output io.Writer
|
||||
debugOut io.Writer
|
||||
uwg *sync.WaitGroup
|
||||
}
|
||||
|
||||
// New creates new Progress container instance. It's not possible to
|
||||
@@ -64,11 +69,13 @@ func New(options ...ContainerOption) *Progress {
|
||||
// method has been called.
|
||||
func NewWithContext(ctx context.Context, options ...ContainerOption) *Progress {
|
||||
s := &pState{
|
||||
bHeap: priorityQueue{},
|
||||
rr: prr,
|
||||
queueBars: make(map[*Bar]*Bar),
|
||||
output: os.Stdout,
|
||||
popPriority: math.MinInt32,
|
||||
rows: make([]io.Reader, 32),
|
||||
refreshRate: defaultRefreshRate,
|
||||
popPriority: math.MinInt32,
|
||||
manualRefresh: make(chan interface{}),
|
||||
queueBars: make(map[*Bar]*Bar),
|
||||
output: os.Stdout,
|
||||
debugOut: io.Discard,
|
||||
}
|
||||
|
||||
for _, opt := range options {
|
||||
@@ -77,16 +84,24 @@ func NewWithContext(ctx context.Context, options ...ContainerOption) *Progress {
|
||||
}
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
p := &Progress{
|
||||
ctx: ctx,
|
||||
uwg: s.uwg,
|
||||
cwg: new(sync.WaitGroup),
|
||||
bwg: new(sync.WaitGroup),
|
||||
operateState: make(chan func(*pState)),
|
||||
interceptIo: make(chan func(io.Writer)),
|
||||
done: make(chan struct{}),
|
||||
cancel: cancel,
|
||||
}
|
||||
|
||||
if s.shutdownNotifier != nil {
|
||||
p.shutdown = s.shutdownNotifier
|
||||
s.shutdownNotifier = nil
|
||||
} else {
|
||||
p.shutdown = make(chan struct{})
|
||||
}
|
||||
|
||||
p.cwg.Add(1)
|
||||
go p.serve(s, cwriter.New(s.output))
|
||||
return p
|
||||
}
|
||||
@@ -101,15 +116,15 @@ func (p *Progress) AddSpinner(total int64, options ...BarOption) *Bar {
|
||||
return p.New(total, SpinnerStyle(), options...)
|
||||
}
|
||||
|
||||
// New creates a bar with provided BarFillerBuilder.
|
||||
// New creates a bar by calling `Build` method on provided `BarFillerBuilder`.
|
||||
func (p *Progress) New(total int64, builder BarFillerBuilder, options ...BarOption) *Bar {
|
||||
return p.Add(total, builder.Build(), options...)
|
||||
return p.AddFiller(total, builder.Build(), options...)
|
||||
}
|
||||
|
||||
// Add creates a bar which renders itself by provided filler.
|
||||
// AddFiller creates a bar which renders itself by provided filler.
|
||||
// If `total <= 0` triggering complete event by increment methods is disabled.
|
||||
// Panics if *Progress instance is done, i.e. called after (*Progress).Wait().
|
||||
func (p *Progress) Add(total int64, filler BarFiller, options ...BarOption) *Bar {
|
||||
func (p *Progress) AddFiller(total int64, filler BarFiller, options ...BarOption) *Bar {
|
||||
if filler == nil {
|
||||
filler = NopStyle().Build()
|
||||
}
|
||||
@@ -132,7 +147,7 @@ func (p *Progress) Add(total int64, filler BarFiller, options ...BarOption) *Bar
|
||||
return bar
|
||||
case <-p.done:
|
||||
p.bwg.Done()
|
||||
panic(fmt.Sprintf("%T instance can't be reused after it's done!", p))
|
||||
panic(DoneError)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,13 +155,13 @@ func (p *Progress) traverseBars(cb func(b *Bar) bool) {
|
||||
sync := make(chan struct{})
|
||||
select {
|
||||
case p.operateState <- func(s *pState) {
|
||||
defer close(sync)
|
||||
for i := 0; i < s.bHeap.Len(); i++ {
|
||||
bar := s.bHeap[i]
|
||||
if !cb(bar) {
|
||||
break
|
||||
}
|
||||
}
|
||||
close(sync)
|
||||
}:
|
||||
<-sync
|
||||
case <-p.done:
|
||||
@@ -178,54 +193,110 @@ func (p *Progress) BarCount() int {
|
||||
}
|
||||
}
|
||||
|
||||
// Wait waits for all bars to complete and finally shutdowns container.
|
||||
// After this method has been called, there is no way to reuse *Progress
|
||||
// instance.
|
||||
// Write is implementation of io.Writer.
|
||||
// Writing to `*mpb.Progress` will print lines above a running bar.
|
||||
// Writes aren't flushed immediately, but at next refresh cycle.
|
||||
// If Write is called after `*mpb.Progress` is done, `mpb.DoneError`
|
||||
// is returned.
|
||||
func (p *Progress) Write(b []byte) (int, error) {
|
||||
type result struct {
|
||||
n int
|
||||
err error
|
||||
}
|
||||
ch := make(chan *result)
|
||||
select {
|
||||
case p.interceptIo <- func(w io.Writer) {
|
||||
n, err := w.Write(b)
|
||||
ch <- &result{n, err}
|
||||
}:
|
||||
res := <-ch
|
||||
return res.n, res.err
|
||||
case <-p.done:
|
||||
return 0, DoneError
|
||||
}
|
||||
}
|
||||
|
||||
// Wait waits for all bars to complete and finally shutdowns container. After
|
||||
// this method has been called, there is no way to reuse (*Progress) instance.
|
||||
func (p *Progress) Wait() {
|
||||
// wait for user wg, if any
|
||||
if p.uwg != nil {
|
||||
p.uwg.Wait()
|
||||
}
|
||||
|
||||
// wait for bars to quit, if any
|
||||
p.bwg.Wait()
|
||||
|
||||
p.once.Do(p.shutdown)
|
||||
|
||||
// wait for container to quit
|
||||
p.cwg.Wait()
|
||||
p.Shutdown()
|
||||
}
|
||||
|
||||
func (p *Progress) shutdown() {
|
||||
close(p.done)
|
||||
// Shutdown cancels any running bar immediately and then shutdowns (*Progress)
|
||||
// instance. Normally this method shouldn't be called unless you know what you
|
||||
// are doing. Proper way to shutdown is to call (*Progress).Wait() instead.
|
||||
func (p *Progress) Shutdown() {
|
||||
p.cancel()
|
||||
<-p.shutdown
|
||||
}
|
||||
|
||||
func (p *Progress) newTicker(s *pState) chan time.Time {
|
||||
ch := make(chan time.Time)
|
||||
go func() {
|
||||
var autoRefresh <-chan time.Time
|
||||
if !s.disableAutoRefresh && !s.outputDiscarded {
|
||||
if s.renderDelay != nil {
|
||||
<-s.renderDelay
|
||||
}
|
||||
ticker := time.NewTicker(s.refreshRate)
|
||||
defer ticker.Stop()
|
||||
autoRefresh = ticker.C
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case t := <-autoRefresh:
|
||||
ch <- t
|
||||
case x := <-s.manualRefresh:
|
||||
if t, ok := x.(time.Time); ok {
|
||||
ch <- t
|
||||
} else {
|
||||
ch <- time.Now()
|
||||
}
|
||||
case <-p.ctx.Done():
|
||||
close(p.done)
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
return ch
|
||||
}
|
||||
|
||||
func (p *Progress) serve(s *pState, cw *cwriter.Writer) {
|
||||
defer p.cwg.Done()
|
||||
defer close(p.shutdown)
|
||||
|
||||
p.refreshCh = s.newTicker(p.done)
|
||||
|
||||
render := func(debugOut io.Writer) {
|
||||
err := s.render(cw)
|
||||
for err != nil {
|
||||
if debugOut != nil {
|
||||
_, err = fmt.Fprintln(debugOut, err)
|
||||
} else {
|
||||
panic(err)
|
||||
}
|
||||
debugOut = nil
|
||||
}
|
||||
render := func() error {
|
||||
return s.render(cw)
|
||||
}
|
||||
|
||||
refreshCh := p.newTicker(s)
|
||||
|
||||
for {
|
||||
select {
|
||||
case op := <-p.operateState:
|
||||
op(s)
|
||||
case <-p.refreshCh:
|
||||
render(s.debugOut)
|
||||
case <-s.shutdownNotifier:
|
||||
case fn := <-p.interceptIo:
|
||||
fn(cw)
|
||||
case <-refreshCh:
|
||||
err := render()
|
||||
if err != nil {
|
||||
s.heapUpdated = false
|
||||
render = func() error { return nil }
|
||||
_, _ = fmt.Fprintln(s.debugOut, err.Error())
|
||||
p.cancel() // cancel all bars
|
||||
}
|
||||
case <-p.done:
|
||||
for s.heapUpdated {
|
||||
render(s.debugOut)
|
||||
err := render()
|
||||
if err != nil {
|
||||
_, _ = fmt.Fprintln(s.debugOut, err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -233,12 +304,13 @@ func (p *Progress) serve(s *pState, cw *cwriter.Writer) {
|
||||
}
|
||||
|
||||
func (s *pState) render(cw *cwriter.Writer) error {
|
||||
var wg sync.WaitGroup
|
||||
if s.heapUpdated {
|
||||
s.updateSyncMatrix()
|
||||
s.heapUpdated = false
|
||||
}
|
||||
syncWidth(s.pMatrix)
|
||||
syncWidth(s.aMatrix)
|
||||
syncWidth(&wg, s.pMatrix)
|
||||
syncWidth(&wg, s.aMatrix)
|
||||
|
||||
width, height, err := cw.GetTermSize()
|
||||
if err != nil {
|
||||
@@ -250,21 +322,27 @@ func (s *pState) render(cw *cwriter.Writer) error {
|
||||
go bar.render(width)
|
||||
}
|
||||
|
||||
return s.flush(cw, height)
|
||||
err = s.flush(&wg, cw, height)
|
||||
wg.Wait()
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *pState) flush(cw *cwriter.Writer, height int) error {
|
||||
var wg sync.WaitGroup
|
||||
func (s *pState) flush(wg *sync.WaitGroup, cw *cwriter.Writer, height int) error {
|
||||
var popCount int
|
||||
rows := make([]io.Reader, 0, height)
|
||||
pool := make([]*Bar, 0, s.bHeap.Len())
|
||||
s.rows = s.rows[:0]
|
||||
|
||||
for s.bHeap.Len() > 0 {
|
||||
var usedRows int
|
||||
b := heap.Pop(&s.bHeap).(*Bar)
|
||||
frame := <-b.frameCh
|
||||
if frame.err != nil {
|
||||
// b.frameCh is buffered it's ok to return here
|
||||
return frame.err
|
||||
}
|
||||
var usedRows int
|
||||
for i := len(frame.rows) - 1; i >= 0; i-- {
|
||||
if row := frame.rows[i]; len(rows) < height {
|
||||
rows = append(rows, row)
|
||||
if row := frame.rows[i]; len(s.rows) < height {
|
||||
s.rows = append(s.rows, row)
|
||||
usedRows++
|
||||
} else {
|
||||
wg.Add(1)
|
||||
@@ -274,24 +352,28 @@ func (s *pState) flush(cw *cwriter.Writer, height int) error {
|
||||
}()
|
||||
}
|
||||
}
|
||||
if frame.shutdown != 0 {
|
||||
if frame.shutdown {
|
||||
b.Wait() // waiting for b.done, so it's safe to read b.bs
|
||||
drop := b.bs.dropOnComplete
|
||||
if qb, ok := s.queueBars[b]; ok {
|
||||
delete(s.queueBars, b)
|
||||
qb.priority = b.priority
|
||||
pool = append(pool, qb)
|
||||
drop = true
|
||||
} else if s.popCompleted && !b.bs.noPop {
|
||||
if frame.shutdown > 1 {
|
||||
popCount += usedRows
|
||||
drop = true
|
||||
} else {
|
||||
s.popPriority++
|
||||
b.priority = s.popPriority
|
||||
}
|
||||
s.heapUpdated = true
|
||||
continue
|
||||
}
|
||||
if drop {
|
||||
if s.popCompleted && !b.bs.noPop {
|
||||
switch b.bs.shutdown++; b.bs.shutdown {
|
||||
case 1:
|
||||
b.priority = s.popPriority
|
||||
s.popPriority++
|
||||
default:
|
||||
if b.bs.dropOnComplete {
|
||||
popCount += usedRows
|
||||
s.heapUpdated = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
} else if b.bs.dropOnComplete {
|
||||
s.heapUpdated = true
|
||||
continue
|
||||
}
|
||||
@@ -299,58 +381,25 @@ func (s *pState) flush(cw *cwriter.Writer, height int) error {
|
||||
pool = append(pool, b)
|
||||
}
|
||||
|
||||
for _, b := range pool {
|
||||
heap.Push(&s.bHeap, b)
|
||||
if len(pool) != 0 {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
for _, b := range pool {
|
||||
heap.Push(&s.bHeap, b)
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
for i := len(rows) - 1; i >= 0; i-- {
|
||||
_, err := cw.ReadFrom(rows[i])
|
||||
for i := len(s.rows) - 1; i >= 0; i-- {
|
||||
_, err := cw.ReadFrom(s.rows[i])
|
||||
if err != nil {
|
||||
wg.Wait()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
return cw.Flush(len(rows) - popCount)
|
||||
}
|
||||
|
||||
func (s *pState) newTicker(done <-chan struct{}) chan time.Time {
|
||||
ch := make(chan time.Time)
|
||||
if s.shutdownNotifier == nil {
|
||||
s.shutdownNotifier = make(chan struct{})
|
||||
}
|
||||
go func() {
|
||||
if s.renderDelay != nil {
|
||||
<-s.renderDelay
|
||||
}
|
||||
var internalRefresh <-chan time.Time
|
||||
if !s.outputDiscarded {
|
||||
if s.externalRefresh == nil {
|
||||
ticker := time.NewTicker(s.rr)
|
||||
defer ticker.Stop()
|
||||
internalRefresh = ticker.C
|
||||
}
|
||||
} else {
|
||||
s.externalRefresh = nil
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case t := <-internalRefresh:
|
||||
ch <- t
|
||||
case x := <-s.externalRefresh:
|
||||
if t, ok := x.(time.Time); ok {
|
||||
ch <- t
|
||||
} else {
|
||||
ch <- time.Now()
|
||||
}
|
||||
case <-done:
|
||||
close(s.shutdownNotifier)
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
return ch
|
||||
err := cw.Flush(len(s.rows) - popCount)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *pState) updateSyncMatrix() {
|
||||
@@ -359,13 +408,12 @@ func (s *pState) updateSyncMatrix() {
|
||||
for i := 0; i < s.bHeap.Len(); i++ {
|
||||
bar := s.bHeap[i]
|
||||
table := bar.wSyncTable()
|
||||
pRow, aRow := table[0], table[1]
|
||||
|
||||
for i, ch := range pRow {
|
||||
for i, ch := range table[0] {
|
||||
s.pMatrix[i] = append(s.pMatrix[i], ch)
|
||||
}
|
||||
|
||||
for i, ch := range aRow {
|
||||
for i, ch := range table[1] {
|
||||
s.aMatrix[i] = append(s.aMatrix[i], ch)
|
||||
}
|
||||
}
|
||||
@@ -373,12 +421,12 @@ func (s *pState) updateSyncMatrix() {
|
||||
|
||||
func (s *pState) makeBarState(total int64, filler BarFiller, options ...BarOption) *bState {
|
||||
bs := &bState{
|
||||
id: s.idCount,
|
||||
priority: s.idCount,
|
||||
reqWidth: s.reqWidth,
|
||||
total: total,
|
||||
filler: filler,
|
||||
debugOut: s.debugOut,
|
||||
id: s.idCount,
|
||||
priority: s.idCount,
|
||||
reqWidth: s.reqWidth,
|
||||
total: total,
|
||||
filler: filler,
|
||||
manualRefresh: s.manualRefresh,
|
||||
}
|
||||
|
||||
if total > 0 {
|
||||
@@ -405,13 +453,14 @@ func (s *pState) makeBarState(total int64, filler BarFiller, options ...BarOptio
|
||||
return bs
|
||||
}
|
||||
|
||||
func syncWidth(matrix map[int][]chan int) {
|
||||
func syncWidth(wg *sync.WaitGroup, matrix map[int][]chan int) {
|
||||
for _, column := range matrix {
|
||||
go maxWidthDistributor(column)
|
||||
wg.Add(1)
|
||||
go maxWidthDistributor(wg, column)
|
||||
}
|
||||
}
|
||||
|
||||
func maxWidthDistributor(column []chan int) {
|
||||
func maxWidthDistributor(wg *sync.WaitGroup, column []chan int) {
|
||||
var maxWidth int
|
||||
for _, ch := range column {
|
||||
if w := <-ch; w > maxWidth {
|
||||
@@ -421,4 +470,5 @@ func maxWidthDistributor(column []chan int) {
|
||||
for _, ch := range column {
|
||||
ch <- maxWidth
|
||||
}
|
||||
wg.Done()
|
||||
}
|
96
vendor/github.com/vbauerster/mpb/v8/proxyreader.go
generated
vendored
Normal file
96
vendor/github.com/vbauerster/mpb/v8/proxyreader.go
generated
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
package mpb
|
||||
|
||||
import (
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
type proxyReader struct {
|
||||
io.ReadCloser
|
||||
bar *Bar
|
||||
}
|
||||
|
||||
func (x proxyReader) Read(p []byte) (int, error) {
|
||||
n, err := x.ReadCloser.Read(p)
|
||||
x.bar.IncrBy(n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
type proxyWriterTo struct {
|
||||
proxyReader
|
||||
}
|
||||
|
||||
func (x proxyWriterTo) WriteTo(w io.Writer) (int64, error) {
|
||||
n, err := x.ReadCloser.(io.WriterTo).WriteTo(w)
|
||||
x.bar.IncrInt64(n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
type ewmaProxyReader struct {
|
||||
io.ReadCloser
|
||||
bar *Bar
|
||||
}
|
||||
|
||||
func (x ewmaProxyReader) Read(p []byte) (int, error) {
|
||||
start := time.Now()
|
||||
n, err := x.ReadCloser.Read(p)
|
||||
x.bar.EwmaIncrBy(n, time.Since(start))
|
||||
return n, err
|
||||
}
|
||||
|
||||
type ewmaProxyWriterTo struct {
|
||||
ewmaProxyReader
|
||||
}
|
||||
|
||||
func (x ewmaProxyWriterTo) WriteTo(w io.Writer) (int64, error) {
|
||||
start := time.Now()
|
||||
n, err := x.ReadCloser.(io.WriterTo).WriteTo(w)
|
||||
x.bar.EwmaIncrInt64(n, time.Since(start))
|
||||
return n, err
|
||||
}
|
||||
|
||||
func newProxyReader(r io.Reader, b *Bar, hasEwma bool) io.ReadCloser {
|
||||
rc := toReadCloser(r)
|
||||
if hasEwma {
|
||||
epr := ewmaProxyReader{rc, b}
|
||||
if _, ok := r.(io.WriterTo); ok {
|
||||
return ewmaProxyWriterTo{epr}
|
||||
}
|
||||
return epr
|
||||
}
|
||||
pr := proxyReader{rc, b}
|
||||
if _, ok := r.(io.WriterTo); ok {
|
||||
return proxyWriterTo{pr}
|
||||
}
|
||||
return pr
|
||||
}
|
||||
|
||||
func toReadCloser(r io.Reader) io.ReadCloser {
|
||||
if rc, ok := r.(io.ReadCloser); ok {
|
||||
return rc
|
||||
}
|
||||
return toNopReadCloser(r)
|
||||
}
|
||||
|
||||
func toNopReadCloser(r io.Reader) io.ReadCloser {
|
||||
if _, ok := r.(io.WriterTo); ok {
|
||||
return nopReadCloserWriterTo{r}
|
||||
}
|
||||
return nopReadCloser{r}
|
||||
}
|
||||
|
||||
type nopReadCloser struct {
|
||||
io.Reader
|
||||
}
|
||||
|
||||
func (nopReadCloser) Close() error { return nil }
|
||||
|
||||
type nopReadCloserWriterTo struct {
|
||||
io.Reader
|
||||
}
|
||||
|
||||
func (nopReadCloserWriterTo) Close() error { return nil }
|
||||
|
||||
func (c nopReadCloserWriterTo) WriteTo(w io.Writer) (int64, error) {
|
||||
return c.Reader.(io.WriterTo).WriteTo(w)
|
||||
}
|
96
vendor/github.com/vbauerster/mpb/v8/proxywriter.go
generated
vendored
Normal file
96
vendor/github.com/vbauerster/mpb/v8/proxywriter.go
generated
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
package mpb
|
||||
|
||||
import (
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
type proxyWriter struct {
|
||||
io.WriteCloser
|
||||
bar *Bar
|
||||
}
|
||||
|
||||
func (x proxyWriter) Write(p []byte) (int, error) {
|
||||
n, err := x.WriteCloser.Write(p)
|
||||
x.bar.IncrBy(n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
type proxyReaderFrom struct {
|
||||
proxyWriter
|
||||
}
|
||||
|
||||
func (x proxyReaderFrom) ReadFrom(r io.Reader) (int64, error) {
|
||||
n, err := x.WriteCloser.(io.ReaderFrom).ReadFrom(r)
|
||||
x.bar.IncrInt64(n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
type ewmaProxyWriter struct {
|
||||
io.WriteCloser
|
||||
bar *Bar
|
||||
}
|
||||
|
||||
func (x ewmaProxyWriter) Write(p []byte) (int, error) {
|
||||
start := time.Now()
|
||||
n, err := x.WriteCloser.Write(p)
|
||||
x.bar.EwmaIncrBy(n, time.Since(start))
|
||||
return n, err
|
||||
}
|
||||
|
||||
type ewmaProxyReaderFrom struct {
|
||||
ewmaProxyWriter
|
||||
}
|
||||
|
||||
func (x ewmaProxyReaderFrom) ReadFrom(r io.Reader) (int64, error) {
|
||||
start := time.Now()
|
||||
n, err := x.WriteCloser.(io.ReaderFrom).ReadFrom(r)
|
||||
x.bar.EwmaIncrInt64(n, time.Since(start))
|
||||
return n, err
|
||||
}
|
||||
|
||||
func newProxyWriter(w io.Writer, b *Bar, hasEwma bool) io.WriteCloser {
|
||||
wc := toWriteCloser(w)
|
||||
if hasEwma {
|
||||
epw := ewmaProxyWriter{wc, b}
|
||||
if _, ok := w.(io.ReaderFrom); ok {
|
||||
return ewmaProxyReaderFrom{epw}
|
||||
}
|
||||
return epw
|
||||
}
|
||||
pw := proxyWriter{wc, b}
|
||||
if _, ok := w.(io.ReaderFrom); ok {
|
||||
return proxyReaderFrom{pw}
|
||||
}
|
||||
return pw
|
||||
}
|
||||
|
||||
func toWriteCloser(w io.Writer) io.WriteCloser {
|
||||
if wc, ok := w.(io.WriteCloser); ok {
|
||||
return wc
|
||||
}
|
||||
return toNopWriteCloser(w)
|
||||
}
|
||||
|
||||
func toNopWriteCloser(w io.Writer) io.WriteCloser {
|
||||
if _, ok := w.(io.ReaderFrom); ok {
|
||||
return nopWriteCloserReaderFrom{w}
|
||||
}
|
||||
return nopWriteCloser{w}
|
||||
}
|
||||
|
||||
type nopWriteCloser struct {
|
||||
io.Writer
|
||||
}
|
||||
|
||||
func (nopWriteCloser) Close() error { return nil }
|
||||
|
||||
type nopWriteCloserReaderFrom struct {
|
||||
io.Writer
|
||||
}
|
||||
|
||||
func (nopWriteCloserReaderFrom) Close() error { return nil }
|
||||
|
||||
func (c nopWriteCloserReaderFrom) ReadFrom(r io.Reader) (int64, error) {
|
||||
return c.Writer.(io.ReaderFrom).ReadFrom(r)
|
||||
}
|
Reference in New Issue
Block a user