parent
326f0cfa2f
commit
5c292c61c6
1437 changed files with 208886 additions and 87131 deletions
5
vendor/github.com/vbauerster/mpb/v8/.gitignore
generated
vendored
Normal file
5
vendor/github.com/vbauerster/mpb/v8/.gitignore
generated
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
119
vendor/github.com/vbauerster/mpb/v8/README.md
generated
vendored
Normal file
119
vendor/github.com/vbauerster/mpb/v8/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
# Multi Progress Bar
|
||||
|
||||
[](https://pkg.go.dev/github.com/vbauerster/mpb/v8)
|
||||
[](https://github.com/vbauerster/mpb/actions/workflows/test.yml)
|
||||
[](https://github.com/vbauerster/mpb/actions/workflows/golangci-lint.yml)
|
||||
|
||||
**mpb** is a Go lib for rendering progress bars in terminal applications.
|
||||
|
||||
## Features
|
||||
|
||||
- **Multiple Bars**: Multiple progress bars are supported
|
||||
- **Dynamic Total**: Set total while bar is running
|
||||
- **Dynamic Add/Remove**: Dynamically add or remove bars
|
||||
- **Cancellation**: Cancel whole rendering process
|
||||
- **Predefined Decorators**: Elapsed time, [ewma](https://github.com/VividCortex/ewma) based ETA, Percentage, Bytes counter
|
||||
- **Decorator's width sync**: Synchronized decorator's width among multiple bars
|
||||
|
||||
## Usage
|
||||
|
||||
#### [Rendering single bar](_examples/singleBar/main.go)
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/vbauerster/mpb/v8"
|
||||
"github.com/vbauerster/mpb/v8/decor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// initialize progress container, with custom width
|
||||
p := mpb.New(mpb.WithWidth(64))
|
||||
|
||||
total := 100
|
||||
name := "Single Bar:"
|
||||
// create a single bar, which will inherit container's width
|
||||
bar := p.New(int64(total),
|
||||
// BarFillerBuilder with custom style
|
||||
mpb.BarStyle().Lbound("╢").Filler("▌").Tip("▌").Padding("░").Rbound("╟"),
|
||||
mpb.PrependDecorators(
|
||||
// display our name with one space on the right
|
||||
decor.Name(name, decor.WC{W: len(name) + 1, C: decor.DidentRight}),
|
||||
// replace ETA decorator with "done" message, OnComplete event
|
||||
decor.OnComplete(
|
||||
decor.AverageETA(decor.ET_STYLE_GO, decor.WC{W: 4}), "done",
|
||||
),
|
||||
),
|
||||
mpb.AppendDecorators(decor.Percentage()),
|
||||
)
|
||||
// simulating some work
|
||||
max := 100 * time.Millisecond
|
||||
for i := 0; i < total; i++ {
|
||||
time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10)
|
||||
bar.Increment()
|
||||
}
|
||||
// wait for our bar to complete and flush
|
||||
p.Wait()
|
||||
}
|
||||
```
|
||||
|
||||
#### [Rendering multiple bars](_examples/multiBars/main.go)
|
||||
|
||||
```go
|
||||
var wg sync.WaitGroup
|
||||
// passed wg will be accounted at p.Wait() call
|
||||
p := mpb.New(mpb.WithWaitGroup(&wg))
|
||||
total, numBars := 100, 3
|
||||
wg.Add(numBars)
|
||||
|
||||
for i := 0; i < numBars; i++ {
|
||||
name := fmt.Sprintf("Bar#%d:", i)
|
||||
bar := p.AddBar(int64(total),
|
||||
mpb.PrependDecorators(
|
||||
// simple name decorator
|
||||
decor.Name(name),
|
||||
// decor.DSyncWidth bit enables column width synchronization
|
||||
decor.Percentage(decor.WCSyncSpace),
|
||||
),
|
||||
mpb.AppendDecorators(
|
||||
// replace ETA decorator with "done" message, OnComplete event
|
||||
decor.OnComplete(
|
||||
// ETA decorator with ewma age of 30
|
||||
decor.EwmaETA(decor.ET_STYLE_GO, 30, decor.WCSyncWidth), "done",
|
||||
),
|
||||
),
|
||||
)
|
||||
// simulating some work
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
max := 100 * time.Millisecond
|
||||
for i := 0; i < total; i++ {
|
||||
// start variable is solely for EWMA calculation
|
||||
// EWMA's unit of measure is an iteration's duration
|
||||
start := time.Now()
|
||||
time.Sleep(time.Duration(rng.Intn(10)+1) * max / 10)
|
||||
// we need to call EwmaIncrement to fulfill ewma decorator's contract
|
||||
bar.EwmaIncrement(time.Since(start))
|
||||
}
|
||||
}()
|
||||
}
|
||||
// wait for passed wg and for all bars to complete and flush
|
||||
p.Wait()
|
||||
```
|
||||
|
||||
#### [Dynamic total](_examples/dynTotal/main.go)
|
||||
|
||||

|
||||
|
||||
#### [Complex example](_examples/complex/main.go)
|
||||
|
||||

|
||||
|
||||
#### [Bytes counters](_examples/io/main.go)
|
||||
|
||||

|
||||
24
vendor/github.com/vbauerster/mpb/v8/UNLICENSE
generated
vendored
Normal file
24
vendor/github.com/vbauerster/mpb/v8/UNLICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
664
vendor/github.com/vbauerster/mpb/v8/bar.go
generated
vendored
Normal file
664
vendor/github.com/vbauerster/mpb/v8/bar.go
generated
vendored
Normal file
|
|
@ -0,0 +1,664 @@
|
|||
package mpb
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/acarl005/stripansi"
|
||||
"github.com/mattn/go-runewidth"
|
||||
"github.com/vbauerster/mpb/v8/decor"
|
||||
)
|
||||
|
||||
// Bar represents a progress bar.
|
||||
type Bar struct {
|
||||
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 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
|
||||
trimSpace bool
|
||||
completed bool
|
||||
aborted bool
|
||||
triggerComplete bool
|
||||
rmOnComplete bool
|
||||
noPop bool
|
||||
autoRefresh bool
|
||||
aDecorators []decor.Decorator
|
||||
pDecorators []decor.Decorator
|
||||
averageDecorators []decor.AverageDecorator
|
||||
ewmaDecorators []decor.EwmaDecorator
|
||||
shutdownListeners []decor.ShutdownListener
|
||||
buffers [3]*bytes.Buffer
|
||||
filler BarFiller
|
||||
extender extenderFunc
|
||||
renderReq chan<- time.Time
|
||||
waitBar *Bar // key for (*pState).queueBars
|
||||
}
|
||||
|
||||
type renderFrame struct {
|
||||
rows []io.Reader
|
||||
shutdown int
|
||||
rmOnComplete bool
|
||||
noPop bool
|
||||
done bool
|
||||
err error
|
||||
}
|
||||
|
||||
func newBar(ctx context.Context, container *Progress, bs *bState) *Bar {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
|
||||
bar := &Bar{
|
||||
priority: bs.priority,
|
||||
frameCh: make(chan *renderFrame, 1),
|
||||
operateState: make(chan func(*bState)),
|
||||
done: make(chan struct{}),
|
||||
container: container,
|
||||
cancel: cancel,
|
||||
}
|
||||
|
||||
container.bwg.Add(1)
|
||||
go bar.serve(ctx, bs)
|
||||
return bar
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
// ID returs id of the bar.
|
||||
func (b *Bar) ID() int {
|
||||
result := make(chan int)
|
||||
select {
|
||||
case b.operateState <- func(s *bState) { result <- s.id }:
|
||||
return <-result
|
||||
case <-b.done:
|
||||
return b.bs.id
|
||||
}
|
||||
}
|
||||
|
||||
// Current returns bar's current value, in other words sum of all increments.
|
||||
func (b *Bar) Current() int64 {
|
||||
result := make(chan int64)
|
||||
select {
|
||||
case b.operateState <- func(s *bState) { result <- s.current }:
|
||||
return <-result
|
||||
case <-b.done:
|
||||
return b.bs.current
|
||||
}
|
||||
}
|
||||
|
||||
// SetRefill sets refill flag with specified amount.
|
||||
// The underlying BarFiller will change its visual representation, to
|
||||
// indicate refill event. Refill event may be referred to some retry
|
||||
// operation for example.
|
||||
func (b *Bar) SetRefill(amount int64) {
|
||||
select {
|
||||
case b.operateState <- func(s *bState) { s.refill = amount }:
|
||||
case <-b.done:
|
||||
}
|
||||
}
|
||||
|
||||
// TraverseDecorators traverses all available decorators and calls cb func on each.
|
||||
func (b *Bar) TraverseDecorators(cb func(decor.Decorator)) {
|
||||
iter := make(chan decor.Decorator)
|
||||
select {
|
||||
case b.operateState <- func(s *bState) {
|
||||
for _, decorators := range [][]decor.Decorator{
|
||||
s.pDecorators,
|
||||
s.aDecorators,
|
||||
} {
|
||||
for _, d := range decorators {
|
||||
iter <- d
|
||||
}
|
||||
}
|
||||
close(iter)
|
||||
}:
|
||||
for d := range iter {
|
||||
cb(unwrap(d))
|
||||
}
|
||||
case <-b.done:
|
||||
}
|
||||
}
|
||||
|
||||
// EnableTriggerComplete enables triggering complete event. It's
|
||||
// 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.
|
||||
func (b *Bar) EnableTriggerComplete() {
|
||||
select {
|
||||
case b.operateState <- func(s *bState) {
|
||||
if s.triggerComplete || s.total <= 0 {
|
||||
return
|
||||
}
|
||||
if s.current >= s.total {
|
||||
s.current = s.total
|
||||
s.completed = true
|
||||
b.triggerCompletion(s)
|
||||
} else {
|
||||
s.triggerComplete = true
|
||||
}
|
||||
}:
|
||||
case <-b.done:
|
||||
}
|
||||
}
|
||||
|
||||
// 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) but faster.
|
||||
// If triggerCompletion is true, total value is set to current and
|
||||
// complete event is triggered right away.
|
||||
func (b *Bar) SetTotal(total int64, triggerCompletion bool) {
|
||||
select {
|
||||
case b.operateState <- func(s *bState) {
|
||||
if s.triggerComplete {
|
||||
return
|
||||
}
|
||||
if total < 0 {
|
||||
s.total = s.current
|
||||
} else {
|
||||
s.total = total
|
||||
}
|
||||
if triggerCompletion {
|
||||
s.current = s.total
|
||||
s.completed = true
|
||||
b.triggerCompletion(s)
|
||||
}
|
||||
}:
|
||||
case <-b.done:
|
||||
}
|
||||
}
|
||||
|
||||
// SetCurrent sets progress' current to an arbitrary value.
|
||||
func (b *Bar) SetCurrent(current int64) {
|
||||
if current < 0 {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case b.operateState <- func(s *bState) {
|
||||
s.current = current
|
||||
if s.triggerComplete && s.current >= s.total {
|
||||
s.current = s.total
|
||||
s.completed = true
|
||||
b.triggerCompletion(s)
|
||||
}
|
||||
}:
|
||||
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.decoratorEwmaUpdate(n, iterDur)
|
||||
}
|
||||
s.current = current
|
||||
if s.triggerComplete && s.current >= s.total {
|
||||
s.current = s.total
|
||||
s.completed = true
|
||||
b.triggerCompletion(s)
|
||||
}
|
||||
}:
|
||||
case <-b.done:
|
||||
}
|
||||
}
|
||||
|
||||
// Increment is a shorthand for b.IncrInt64(1).
|
||||
func (b *Bar) Increment() {
|
||||
b.IncrInt64(1)
|
||||
}
|
||||
|
||||
// IncrBy is a shorthand for b.IncrInt64(int64(n)).
|
||||
func (b *Bar) IncrBy(n int) {
|
||||
b.IncrInt64(int64(n))
|
||||
}
|
||||
|
||||
// IncrInt64 increments progress by amount of n.
|
||||
func (b *Bar) IncrInt64(n int64) {
|
||||
if n <= 0 {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case b.operateState <- func(s *bState) {
|
||||
s.current += n
|
||||
if s.triggerComplete && s.current >= s.total {
|
||||
s.current = s.total
|
||||
s.completed = true
|
||||
b.triggerCompletion(s)
|
||||
}
|
||||
}:
|
||||
case <-b.done:
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
s.decoratorEwmaUpdate(n, iterDur)
|
||||
s.current += n
|
||||
if s.triggerComplete && s.current >= s.total {
|
||||
s.current = s.total
|
||||
s.completed = true
|
||||
b.triggerCompletion(s)
|
||||
}
|
||||
}:
|
||||
case <-b.done:
|
||||
}
|
||||
}
|
||||
|
||||
// DecoratorAverageAdjust adjusts all average based decorators. Call
|
||||
// if you need to adjust start time of all average based decorators
|
||||
// or after progress resume.
|
||||
func (b *Bar) DecoratorAverageAdjust(start time.Time) {
|
||||
select {
|
||||
case b.operateState <- func(s *bState) { s.decoratorAverageAdjust(start) }:
|
||||
case <-b.done:
|
||||
}
|
||||
}
|
||||
|
||||
// SetPriority changes bar's order among multiple bars. Zero is highest
|
||||
// priority, i.e. bar will be on top. If you don't need to set priority
|
||||
// dynamically, better use BarPriority option.
|
||||
func (b *Bar) SetPriority(priority int) {
|
||||
b.container.UpdateBarPriority(b, priority)
|
||||
}
|
||||
|
||||
// Abort interrupts bar's running goroutine. Abort won't be engaged
|
||||
// if bar is already in complete state. If drop is true bar will be
|
||||
// removed as well. To make sure that bar has been removed call
|
||||
// (*Bar).Wait method.
|
||||
func (b *Bar) Abort(drop bool) {
|
||||
select {
|
||||
case b.operateState <- func(s *bState) {
|
||||
if s.completed || s.aborted {
|
||||
return
|
||||
}
|
||||
s.aborted = true
|
||||
s.rmOnComplete = drop
|
||||
b.triggerCompletion(s)
|
||||
}:
|
||||
case <-b.done:
|
||||
}
|
||||
}
|
||||
|
||||
// Aborted reports whether the bar is in aborted state.
|
||||
func (b *Bar) Aborted() bool {
|
||||
result := make(chan bool)
|
||||
select {
|
||||
case b.operateState <- func(s *bState) { result <- s.aborted }:
|
||||
return <-result
|
||||
case <-b.done:
|
||||
return b.bs.aborted
|
||||
}
|
||||
}
|
||||
|
||||
// Completed reports whether the bar is in completed state.
|
||||
func (b *Bar) Completed() bool {
|
||||
result := make(chan bool)
|
||||
select {
|
||||
case b.operateState <- func(s *bState) { result <- s.completed }:
|
||||
return <-result
|
||||
case <-b.done:
|
||||
return b.bs.completed
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
func (b *Bar) serve(ctx context.Context, bs *bState) {
|
||||
defer b.container.bwg.Done()
|
||||
for {
|
||||
select {
|
||||
case op := <-b.operateState:
|
||||
op(bs)
|
||||
case <-ctx.Done():
|
||||
bs.aborted = !bs.completed
|
||||
bs.decoratorShutdownNotify()
|
||||
b.bs = bs
|
||||
close(b.done)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Bar) render(tw int) {
|
||||
var done bool
|
||||
fn := func(s *bState) {
|
||||
var rows []io.Reader
|
||||
stat := newStatistics(tw, s)
|
||||
r, err := s.draw(stat)
|
||||
if err != nil {
|
||||
b.frameCh <- &renderFrame{err: err}
|
||||
return
|
||||
}
|
||||
rows = append(rows, r)
|
||||
if s.extender != nil {
|
||||
rows, err = s.extender(rows, stat)
|
||||
if err != nil {
|
||||
b.frameCh <- &renderFrame{err: err}
|
||||
return
|
||||
}
|
||||
}
|
||||
frame := &renderFrame{
|
||||
rows: rows,
|
||||
shutdown: s.shutdown,
|
||||
rmOnComplete: s.rmOnComplete,
|
||||
noPop: s.noPop,
|
||||
done: done,
|
||||
}
|
||||
if s.completed || s.aborted {
|
||||
// post increment makes sure OnComplete decorators are rendered
|
||||
s.shutdown++
|
||||
}
|
||||
b.frameCh <- frame
|
||||
}
|
||||
select {
|
||||
case b.operateState <- fn:
|
||||
case <-b.done:
|
||||
done = true
|
||||
fn(b.bs)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Bar) triggerCompletion(s *bState) {
|
||||
if s.autoRefresh {
|
||||
// Technically this call isn't required, but if refresh rate is set to
|
||||
// one hour for example and bar completes within a few minutes p.Wait()
|
||||
// will wait for one hour. This call helps to avoid unnecessary waiting.
|
||||
go b.tryEarlyRefresh(s.renderReq)
|
||||
} else {
|
||||
b.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Bar) tryEarlyRefresh(renderReq chan<- time.Time) {
|
||||
var anyOtherRunning bool
|
||||
b.container.traverseBars(func(bar *Bar) bool {
|
||||
anyOtherRunning = b != bar && bar.IsRunning()
|
||||
return anyOtherRunning
|
||||
})
|
||||
if !anyOtherRunning {
|
||||
for {
|
||||
select {
|
||||
case renderReq <- time.Now():
|
||||
case <-b.done:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Bar) wSyncTable() syncTable {
|
||||
result := make(chan syncTable)
|
||||
select {
|
||||
case b.operateState <- func(s *bState) { result <- s.wSyncTable() }:
|
||||
return <-result
|
||||
case <-b.done:
|
||||
return b.bs.wSyncTable()
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
return io.MultiReader(r, strings.NewReader("\n")), nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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]
|
||||
}
|
||||
}
|
||||
return table
|
||||
}
|
||||
|
||||
func (s bState) decoratorEwmaUpdate(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(n, dur)
|
||||
default:
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
d.EwmaUpdate(n, dur)
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func (s bState) decoratorAverageAdjust(start time.Time) {
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < len(s.averageDecorators); i++ {
|
||||
switch d := s.averageDecorators[i]; i {
|
||||
case len(s.averageDecorators) - 1:
|
||||
d.AverageAdjust(start)
|
||||
default:
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
d.AverageAdjust(start)
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func (s bState) decoratorShutdownNotify() {
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < len(s.shutdownListeners); i++ {
|
||||
switch d := s.shutdownListeners[i]; i {
|
||||
case len(s.shutdownListeners) - 1:
|
||||
d.OnShutdown()
|
||||
default:
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
d.OnShutdown()
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
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,
|
||||
Refill: s.refill,
|
||||
Completed: s.completed,
|
||||
Aborted: s.aborted,
|
||||
}
|
||||
}
|
||||
|
||||
func unwrap(d decor.Decorator) decor.Decorator {
|
||||
if d, ok := d.(decor.Wrapper); ok {
|
||||
return unwrap(d.Unwrap())
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func writeSpace(buf *bytes.Buffer) error {
|
||||
return buf.WriteByte(' ')
|
||||
}
|
||||
39
vendor/github.com/vbauerster/mpb/v8/bar_filler.go
generated
vendored
Normal file
39
vendor/github.com/vbauerster/mpb/v8/bar_filler.go
generated
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
package mpb
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/vbauerster/mpb/v8/decor"
|
||||
)
|
||||
|
||||
// BarFiller interface.
|
||||
// Bar (without decorators) renders itself by calling BarFiller's Fill method.
|
||||
type BarFiller interface {
|
||||
Fill(io.Writer, decor.Statistics) error
|
||||
}
|
||||
|
||||
// BarFillerBuilder interface.
|
||||
// Default implementations are:
|
||||
//
|
||||
// BarStyle()
|
||||
// SpinnerStyle()
|
||||
// NopStyle()
|
||||
type BarFillerBuilder interface {
|
||||
Build() BarFiller
|
||||
}
|
||||
|
||||
// BarFillerFunc is function type adapter to convert compatible function
|
||||
// into BarFiller interface.
|
||||
type BarFillerFunc func(io.Writer, decor.Statistics) error
|
||||
|
||||
func (f BarFillerFunc) Fill(w io.Writer, stat decor.Statistics) error {
|
||||
return f(w, stat)
|
||||
}
|
||||
|
||||
// BarFillerBuilderFunc is function type adapter to convert compatible
|
||||
// function into BarFillerBuilder interface.
|
||||
type BarFillerBuilderFunc func() BarFiller
|
||||
|
||||
func (f BarFillerBuilderFunc) Build() BarFiller {
|
||||
return f()
|
||||
}
|
||||
259
vendor/github.com/vbauerster/mpb/v8/bar_filler_bar.go
generated
vendored
Normal file
259
vendor/github.com/vbauerster/mpb/v8/bar_filler_bar.go
generated
vendored
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
package mpb
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/acarl005/stripansi"
|
||||
"github.com/mattn/go-runewidth"
|
||||
"github.com/vbauerster/mpb/v8/decor"
|
||||
"github.com/vbauerster/mpb/v8/internal"
|
||||
)
|
||||
|
||||
const (
|
||||
iLbound = iota
|
||||
iRbound
|
||||
iFiller
|
||||
iRefiller
|
||||
iPadding
|
||||
components
|
||||
)
|
||||
|
||||
// BarStyleComposer interface.
|
||||
type BarStyleComposer interface {
|
||||
BarFillerBuilder
|
||||
Lbound(string) BarStyleComposer
|
||||
Rbound(string) BarStyleComposer
|
||||
Filler(string) BarStyleComposer
|
||||
Refiller(string) BarStyleComposer
|
||||
Padding(string) BarStyleComposer
|
||||
TipOnComplete(string) BarStyleComposer
|
||||
Tip(frames ...string) BarStyleComposer
|
||||
Reverse() BarStyleComposer
|
||||
}
|
||||
|
||||
type bFiller struct {
|
||||
rev bool
|
||||
components [components]*component
|
||||
tip struct {
|
||||
count uint
|
||||
frames []*component
|
||||
onComplete *component
|
||||
}
|
||||
}
|
||||
|
||||
type component struct {
|
||||
width int
|
||||
bytes []byte
|
||||
}
|
||||
|
||||
type barStyle struct {
|
||||
lbound string
|
||||
rbound string
|
||||
filler string
|
||||
refiller string
|
||||
padding string
|
||||
tipOnComplete string
|
||||
tipFrames []string
|
||||
rev bool
|
||||
}
|
||||
|
||||
// BarStyle constructs default bar style which can be altered via
|
||||
// BarStyleComposer interface.
|
||||
func BarStyle() BarStyleComposer {
|
||||
return &barStyle{
|
||||
lbound: "[",
|
||||
rbound: "]",
|
||||
filler: "=",
|
||||
refiller: "+",
|
||||
padding: "-",
|
||||
tipFrames: []string{">"},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *barStyle) Lbound(bound string) BarStyleComposer {
|
||||
s.lbound = bound
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *barStyle) Rbound(bound string) BarStyleComposer {
|
||||
s.rbound = bound
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *barStyle) Filler(filler string) BarStyleComposer {
|
||||
s.filler = filler
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *barStyle) Refiller(refiller string) BarStyleComposer {
|
||||
s.refiller = refiller
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *barStyle) Padding(padding string) BarStyleComposer {
|
||||
s.padding = padding
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *barStyle) TipOnComplete(tip string) BarStyleComposer {
|
||||
s.tipOnComplete = tip
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *barStyle) Tip(frames ...string) BarStyleComposer {
|
||||
if len(frames) != 0 {
|
||||
s.tipFrames = append(s.tipFrames[:0], frames...)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *barStyle) Reverse() BarStyleComposer {
|
||||
s.rev = true
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *barStyle) Build() BarFiller {
|
||||
bf := &bFiller{rev: s.rev}
|
||||
bf.components[iLbound] = &component{
|
||||
width: runewidth.StringWidth(stripansi.Strip(s.lbound)),
|
||||
bytes: []byte(s.lbound),
|
||||
}
|
||||
bf.components[iRbound] = &component{
|
||||
width: runewidth.StringWidth(stripansi.Strip(s.rbound)),
|
||||
bytes: []byte(s.rbound),
|
||||
}
|
||||
bf.components[iFiller] = &component{
|
||||
width: runewidth.StringWidth(stripansi.Strip(s.filler)),
|
||||
bytes: []byte(s.filler),
|
||||
}
|
||||
bf.components[iRefiller] = &component{
|
||||
width: runewidth.StringWidth(stripansi.Strip(s.refiller)),
|
||||
bytes: []byte(s.refiller),
|
||||
}
|
||||
bf.components[iPadding] = &component{
|
||||
width: runewidth.StringWidth(stripansi.Strip(s.padding)),
|
||||
bytes: []byte(s.padding),
|
||||
}
|
||||
bf.tip.onComplete = &component{
|
||||
width: runewidth.StringWidth(stripansi.Strip(s.tipOnComplete)),
|
||||
bytes: []byte(s.tipOnComplete),
|
||||
}
|
||||
bf.tip.frames = make([]*component, len(s.tipFrames))
|
||||
for i, t := range s.tipFrames {
|
||||
bf.tip.frames[i] = &component{
|
||||
width: runewidth.StringWidth(stripansi.Strip(t)),
|
||||
bytes: []byte(t),
|
||||
}
|
||||
}
|
||||
return bf
|
||||
}
|
||||
|
||||
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 -= (s.components[iLbound].width + s.components[iRbound].width)
|
||||
if width < 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err = w.Write(s.components[iLbound].bytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if width == 0 {
|
||||
_, err = w.Write(s.components[iRbound].bytes)
|
||||
return err
|
||||
}
|
||||
|
||||
var filling [][]byte
|
||||
var padding [][]byte
|
||||
var tip *component
|
||||
var filled int
|
||||
var refWidth int
|
||||
curWidth := int(internal.PercentageRound(stat.Total, stat.Current, uint(width)))
|
||||
|
||||
if stat.Completed {
|
||||
tip = s.tip.onComplete
|
||||
} else {
|
||||
tip = s.tip.frames[s.tip.count%uint(len(s.tip.frames))]
|
||||
}
|
||||
|
||||
if curWidth > 0 {
|
||||
filling = append(filling, tip.bytes)
|
||||
filled += tip.width
|
||||
s.tip.count++
|
||||
}
|
||||
|
||||
if stat.Refill > 0 {
|
||||
refWidth = int(internal.PercentageRound(stat.Total, stat.Refill, uint(width)))
|
||||
curWidth -= refWidth
|
||||
refWidth += curWidth
|
||||
}
|
||||
|
||||
for filled < curWidth {
|
||||
if curWidth-filled >= s.components[iFiller].width {
|
||||
filling = append(filling, s.components[iFiller].bytes)
|
||||
if s.components[iFiller].width == 0 {
|
||||
break
|
||||
}
|
||||
filled += s.components[iFiller].width
|
||||
} else {
|
||||
filling = append(filling, []byte("…"))
|
||||
filled++
|
||||
}
|
||||
}
|
||||
|
||||
for filled < refWidth {
|
||||
if refWidth-filled >= s.components[iRefiller].width {
|
||||
filling = append(filling, s.components[iRefiller].bytes)
|
||||
if s.components[iRefiller].width == 0 {
|
||||
break
|
||||
}
|
||||
filled += s.components[iRefiller].width
|
||||
} else {
|
||||
filling = append(filling, []byte("…"))
|
||||
filled++
|
||||
}
|
||||
}
|
||||
|
||||
padWidth := width - filled
|
||||
for padWidth > 0 {
|
||||
if padWidth >= s.components[iPadding].width {
|
||||
padding = append(padding, s.components[iPadding].bytes)
|
||||
if s.components[iPadding].width == 0 {
|
||||
break
|
||||
}
|
||||
padWidth -= s.components[iPadding].width
|
||||
} else {
|
||||
padding = append(padding, []byte("…"))
|
||||
padWidth--
|
||||
}
|
||||
}
|
||||
|
||||
if s.rev {
|
||||
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) error {
|
||||
for i := len(filling) - 1; i >= 0; i-- {
|
||||
_, err := w.Write(filling[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(padding); i++ {
|
||||
_, err := w.Write(padding[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
16
vendor/github.com/vbauerster/mpb/v8/bar_filler_nop.go
generated
vendored
Normal file
16
vendor/github.com/vbauerster/mpb/v8/bar_filler_nop.go
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
package mpb
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"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, decor.Statistics) error {
|
||||
return nil
|
||||
})
|
||||
})
|
||||
}
|
||||
88
vendor/github.com/vbauerster/mpb/v8/bar_filler_spinner.go
generated
vendored
Normal file
88
vendor/github.com/vbauerster/mpb/v8/bar_filler_spinner.go
generated
vendored
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
package mpb
|
||||
|
||||
import (
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/acarl005/stripansi"
|
||||
"github.com/mattn/go-runewidth"
|
||||
"github.com/vbauerster/mpb/v8/decor"
|
||||
"github.com/vbauerster/mpb/v8/internal"
|
||||
)
|
||||
|
||||
const (
|
||||
positionLeft = 1 + iota
|
||||
positionRight
|
||||
)
|
||||
|
||||
// SpinnerStyleComposer interface.
|
||||
type SpinnerStyleComposer interface {
|
||||
BarFillerBuilder
|
||||
PositionLeft() SpinnerStyleComposer
|
||||
PositionRight() SpinnerStyleComposer
|
||||
}
|
||||
|
||||
type sFiller struct {
|
||||
count uint
|
||||
position uint
|
||||
frames []string
|
||||
}
|
||||
|
||||
type spinnerStyle struct {
|
||||
position uint
|
||||
frames []string
|
||||
}
|
||||
|
||||
// SpinnerStyle constructs default spinner style which can be altered via
|
||||
// SpinnerStyleComposer interface.
|
||||
func SpinnerStyle(frames ...string) SpinnerStyleComposer {
|
||||
ss := new(spinnerStyle)
|
||||
if len(frames) != 0 {
|
||||
ss.frames = append(ss.frames, frames...)
|
||||
} else {
|
||||
ss.frames = []string{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"}
|
||||
}
|
||||
return ss
|
||||
}
|
||||
|
||||
func (s *spinnerStyle) PositionLeft() SpinnerStyleComposer {
|
||||
s.position = positionLeft
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *spinnerStyle) PositionRight() SpinnerStyleComposer {
|
||||
s.position = positionRight
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *spinnerStyle) Build() BarFiller {
|
||||
sf := &sFiller{
|
||||
position: s.position,
|
||||
frames: s.frames,
|
||||
}
|
||||
return sf
|
||||
}
|
||||
|
||||
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 nil
|
||||
}
|
||||
|
||||
rest := width - frameWidth
|
||||
switch s.position {
|
||||
case positionLeft:
|
||||
_, err = io.WriteString(w, frame+strings.Repeat(" ", rest))
|
||||
case positionRight:
|
||||
_, err = io.WriteString(w, strings.Repeat(" ", rest)+frame)
|
||||
default:
|
||||
str := strings.Repeat(" ", rest/2) + frame + strings.Repeat(" ", rest/2+rest%2)
|
||||
_, err = io.WriteString(w, str)
|
||||
}
|
||||
s.count++
|
||||
return err
|
||||
}
|
||||
205
vendor/github.com/vbauerster/mpb/v8/bar_option.go
generated
vendored
Normal file
205
vendor/github.com/vbauerster/mpb/v8/bar_option.go
generated
vendored
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
package mpb
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
|
||||
"github.com/vbauerster/mpb/v8/decor"
|
||||
)
|
||||
|
||||
// BarOption is a func option to alter default behavior of a bar.
|
||||
type BarOption func(*bState)
|
||||
|
||||
func inspect(decorators []decor.Decorator) (dest []decor.Decorator) {
|
||||
for _, decorator := range decorators {
|
||||
if decorator == nil {
|
||||
continue
|
||||
}
|
||||
if d, ok := decorator.(interface {
|
||||
PlaceHolders() []decor.Decorator
|
||||
}); ok {
|
||||
dest = append(dest, d.PlaceHolders()...)
|
||||
}
|
||||
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.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.pDecorators = decorators
|
||||
}
|
||||
}
|
||||
|
||||
// BarID sets bar id.
|
||||
func BarID(id int) BarOption {
|
||||
return func(s *bState) {
|
||||
s.id = id
|
||||
}
|
||||
}
|
||||
|
||||
// BarWidth sets bar width independent of the container.
|
||||
func BarWidth(width int) BarOption {
|
||||
return func(s *bState) {
|
||||
s.reqWidth = width
|
||||
}
|
||||
}
|
||||
|
||||
// BarQueueAfter puts this (being constructed) bar into the queue.
|
||||
// BarPriority will be inherited from the argument bar.
|
||||
// When argument bar completes or aborts queued bar replaces its place.
|
||||
func BarQueueAfter(bar *Bar) BarOption {
|
||||
return func(s *bState) {
|
||||
s.waitBar = bar
|
||||
}
|
||||
}
|
||||
|
||||
// BarRemoveOnComplete removes both bar's filler and its decorators
|
||||
// on complete event.
|
||||
func BarRemoveOnComplete() BarOption {
|
||||
return func(s *bState) {
|
||||
s.rmOnComplete = true
|
||||
}
|
||||
}
|
||||
|
||||
// BarFillerClearOnComplete clears bar's filler on complete event.
|
||||
// It's shortcut for BarFillerOnComplete("").
|
||||
func BarFillerClearOnComplete() BarOption {
|
||||
return BarFillerOnComplete("")
|
||||
}
|
||||
|
||||
// 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, st decor.Statistics) error {
|
||||
if st.Completed {
|
||||
_, err := io.WriteString(w, message)
|
||||
return err
|
||||
}
|
||||
return base.Fill(w, st)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// BarFillerMiddleware provides a way to augment the underlying BarFiller.
|
||||
func BarFillerMiddleware(middle func(BarFiller) BarFiller) BarOption {
|
||||
return func(s *bState) {
|
||||
if middle == nil {
|
||||
return
|
||||
}
|
||||
s.filler = middle(s.filler)
|
||||
}
|
||||
}
|
||||
|
||||
// BarPriority sets bar's priority. Zero is highest priority, i.e. bar
|
||||
// will be on top. This option isn't effective with `BarQueueAfter` option.
|
||||
func BarPriority(priority int) BarOption {
|
||||
return func(s *bState) {
|
||||
s.priority = priority
|
||||
}
|
||||
}
|
||||
|
||||
// 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 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 = fn
|
||||
}
|
||||
}
|
||||
|
||||
func makeExtenderFunc(filler BarFiller, rev bool) extenderFunc {
|
||||
buf := new(bytes.Buffer)
|
||||
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 {
|
||||
break
|
||||
}
|
||||
rows = append(rows, bytes.NewReader(b))
|
||||
}
|
||||
buf.Reset()
|
||||
return rows, err
|
||||
}
|
||||
|
||||
if !rev {
|
||||
return base
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
// BarFillerTrim removes leading and trailing space around the underlying BarFiller.
|
||||
func BarFillerTrim() BarOption {
|
||||
return func(s *bState) {
|
||||
s.trimSpace = true
|
||||
}
|
||||
}
|
||||
|
||||
// BarNoPop disables bar pop out of container. Effective when
|
||||
// PopCompletedMode of container is enabled.
|
||||
func BarNoPop() BarOption {
|
||||
return func(s *bState) {
|
||||
s.noPop = true
|
||||
}
|
||||
}
|
||||
|
||||
// BarOptional will return provided option only when cond is true.
|
||||
func BarOptional(option BarOption, cond bool) BarOption {
|
||||
if cond {
|
||||
return option
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
135
vendor/github.com/vbauerster/mpb/v8/container_option.go
generated
vendored
Normal file
135
vendor/github.com/vbauerster/mpb/v8/container_option.go
generated
vendored
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
package mpb
|
||||
|
||||
import (
|
||||
"io"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ContainerOption is a func option to alter default behavior of a bar
|
||||
// container. Container term refers to a Progress struct which can
|
||||
// hold one or more Bars.
|
||||
type ContainerOption func(*pState)
|
||||
|
||||
// WithWaitGroup provides means to have a single joint point. If
|
||||
// *sync.WaitGroup is provided, you can safely call just p.Wait()
|
||||
// without calling Wait() on provided *sync.WaitGroup. Makes sense
|
||||
// when there are more than one bar to render.
|
||||
func WithWaitGroup(wg *sync.WaitGroup) ContainerOption {
|
||||
return func(s *pState) {
|
||||
s.uwg = wg
|
||||
}
|
||||
}
|
||||
|
||||
// WithWidth sets container width. If not set it defaults to terminal
|
||||
// width. A bar added to the container will inherit its width, unless
|
||||
// overridden by `func BarWidth(int) BarOption`.
|
||||
func WithWidth(width int) ContainerOption {
|
||||
return func(s *pState) {
|
||||
s.reqWidth = width
|
||||
}
|
||||
}
|
||||
|
||||
// WithRefreshRate overrides default 150ms refresh rate.
|
||||
func WithRefreshRate(d time.Duration) ContainerOption {
|
||||
return func(s *pState) {
|
||||
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 {
|
||||
return func(s *pState) {
|
||||
s.manualRC = ch
|
||||
}
|
||||
}
|
||||
|
||||
// WithRenderDelay delays rendering. By default rendering starts as
|
||||
// soon as bar is added, with this option it's possible to delay
|
||||
// rendering process by keeping provided chan unclosed. In other words
|
||||
// rendering will start as soon as provided chan is closed.
|
||||
func WithRenderDelay(ch <-chan struct{}) ContainerOption {
|
||||
return func(s *pState) {
|
||||
s.delayRC = ch
|
||||
}
|
||||
}
|
||||
|
||||
// WithShutdownNotifier value of type `[]*mpb.Bar` will be send into provided
|
||||
// channel upon container shutdown.
|
||||
func WithShutdownNotifier(ch chan<- interface{}) ContainerOption {
|
||||
return func(s *pState) {
|
||||
s.shutdownNotifier = ch
|
||||
}
|
||||
}
|
||||
|
||||
// WithOutput overrides default os.Stdout output. If underlying io.Writer
|
||||
// is not a terminal then auto refresh is disabled unless WithAutoRefresh
|
||||
// option is set.
|
||||
func WithOutput(w io.Writer) ContainerOption {
|
||||
if w == nil {
|
||||
w = io.Discard
|
||||
}
|
||||
return func(s *pState) {
|
||||
s.output = w
|
||||
}
|
||||
}
|
||||
|
||||
// WithDebugOutput sets debug output.
|
||||
func WithDebugOutput(w io.Writer) ContainerOption {
|
||||
if w == nil {
|
||||
w = io.Discard
|
||||
}
|
||||
return func(s *pState) {
|
||||
s.debugOut = w
|
||||
}
|
||||
}
|
||||
|
||||
// WithAutoRefresh force auto refresh regardless of what output is set to.
|
||||
// Applicable only if not WithManualRefresh set.
|
||||
func WithAutoRefresh() ContainerOption {
|
||||
return func(s *pState) {
|
||||
s.autoRefresh = true
|
||||
}
|
||||
}
|
||||
|
||||
// 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 return provided option only when cond is true.
|
||||
func ContainerOptional(option ContainerOption, cond bool) ContainerOption {
|
||||
if cond {
|
||||
return option
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
2
vendor/github.com/vbauerster/mpb/v8/cwriter/doc.go
generated
vendored
Normal file
2
vendor/github.com/vbauerster/mpb/v8/cwriter/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
// Package cwriter is a console writer abstraction for the underlying OS.
|
||||
package cwriter
|
||||
7
vendor/github.com/vbauerster/mpb/v8/cwriter/util_bsd.go
generated
vendored
Normal file
7
vendor/github.com/vbauerster/mpb/v8/cwriter/util_bsd.go
generated
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
//go:build darwin || dragonfly || freebsd || netbsd || openbsd
|
||||
|
||||
package cwriter
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
const ioctlReadTermios = unix.TIOCGETA
|
||||
7
vendor/github.com/vbauerster/mpb/v8/cwriter/util_linux.go
generated
vendored
Normal file
7
vendor/github.com/vbauerster/mpb/v8/cwriter/util_linux.go
generated
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
//go:build aix || linux
|
||||
|
||||
package cwriter
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
const ioctlReadTermios = unix.TCGETS
|
||||
7
vendor/github.com/vbauerster/mpb/v8/cwriter/util_solaris.go
generated
vendored
Normal file
7
vendor/github.com/vbauerster/mpb/v8/cwriter/util_solaris.go
generated
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
//go:build solaris
|
||||
|
||||
package cwriter
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
const ioctlReadTermios = unix.TCGETA
|
||||
7
vendor/github.com/vbauerster/mpb/v8/cwriter/util_zos.go
generated
vendored
Normal file
7
vendor/github.com/vbauerster/mpb/v8/cwriter/util_zos.go
generated
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
//go:build zos
|
||||
|
||||
package cwriter
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
const ioctlReadTermios = unix.TCGETS
|
||||
59
vendor/github.com/vbauerster/mpb/v8/cwriter/writer.go
generated
vendored
Normal file
59
vendor/github.com/vbauerster/mpb/v8/cwriter/writer.go
generated
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
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
|
||||
}
|
||||
|
||||
// IsTerminal tells whether underlying io.Writer is terminal.
|
||||
func (w *Writer) IsTerminal() bool {
|
||||
return w.terminal
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
101
vendor/github.com/vbauerster/mpb/v8/cwriter/writer_windows.go
generated
vendored
Normal file
101
vendor/github.com/vbauerster/mpb/v8/cwriter/writer_windows.go
generated
vendored
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
//go:build windows
|
||||
|
||||
package cwriter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var kernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
||||
|
||||
var (
|
||||
procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition")
|
||||
procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW")
|
||||
)
|
||||
|
||||
// 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.ew.ansiCuuAndEd(w.out, n)
|
||||
}
|
||||
|
||||
var info windows.ConsoleScreenBufferInfo
|
||||
if err := windows.GetConsoleScreenBufferInfo(windows.Handle(w.fd), &info); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
info.CursorPosition.Y -= int16(n)
|
||||
if info.CursorPosition.Y < 0 {
|
||||
info.CursorPosition.Y = 0
|
||||
}
|
||||
_, _, _ = procSetConsoleCursorPosition.Call(
|
||||
uintptr(w.fd),
|
||||
uintptr(uint32(uint16(info.CursorPosition.Y))<<16|uint32(uint16(info.CursorPosition.X))),
|
||||
)
|
||||
|
||||
// clear the lines
|
||||
cursor := &windows.Coord{
|
||||
X: info.Window.Left,
|
||||
Y: info.CursorPosition.Y,
|
||||
}
|
||||
count := uint32(info.Size.X) * uint32(n)
|
||||
_, _, _ = procFillConsoleOutputCharacter.Call(
|
||||
uintptr(w.fd),
|
||||
uintptr(' '),
|
||||
uintptr(count),
|
||||
*(*uintptr)(unsafe.Pointer(cursor)),
|
||||
uintptr(unsafe.Pointer(new(uint32))),
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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
|
||||
if err := windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info); err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
// terminal.GetSize from crypto/ssh adds "+ 1" to both width and height:
|
||||
// https://go.googlesource.com/crypto/+/refs/heads/release-branch.go1.14/ssh/terminal/util_windows.go#75
|
||||
// but looks like this is a root cause of issue #66, so removing both "+ 1" have fixed it.
|
||||
return int(info.Window.Right - info.Window.Left), int(info.Window.Bottom - info.Window.Top), nil
|
||||
}
|
||||
|
||||
// IsTerminal returns whether the given file descriptor is a terminal.
|
||||
func IsTerminal(fd int) bool {
|
||||
var st uint32
|
||||
err := windows.GetConsoleMode(windows.Handle(fd), &st)
|
||||
return err == nil
|
||||
}
|
||||
22
vendor/github.com/vbauerster/mpb/v8/decor/any.go
generated
vendored
Normal file
22
vendor/github.com/vbauerster/mpb/v8/decor/any.go
generated
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
package decor
|
||||
|
||||
var _ Decorator = (*any)(nil)
|
||||
|
||||
// Any decorator displays text, that can be changed during decorator's
|
||||
// lifetime via provided DecorFunc.
|
||||
//
|
||||
// `fn` DecorFunc callback
|
||||
//
|
||||
// `wcc` optional WC config
|
||||
func Any(fn DecorFunc, wcc ...WC) Decorator {
|
||||
return &any{initWC(wcc...), fn}
|
||||
}
|
||||
|
||||
type any struct {
|
||||
WC
|
||||
fn DecorFunc
|
||||
}
|
||||
|
||||
func (d *any) Decor(s Statistics) string {
|
||||
return d.FormatMsg(d.fn(s))
|
||||
}
|
||||
253
vendor/github.com/vbauerster/mpb/v8/decor/counters.go
generated
vendored
Normal file
253
vendor/github.com/vbauerster/mpb/v8/decor/counters.go
generated
vendored
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
package decor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// CountersNoUnit is a wrapper around Counters with no unit param.
|
||||
func CountersNoUnit(pairFmt string, wcc ...WC) Decorator {
|
||||
return Counters(0, pairFmt, wcc...)
|
||||
}
|
||||
|
||||
// CountersKibiByte is a wrapper around Counters with predefined unit
|
||||
// as SizeB1024(0).
|
||||
func CountersKibiByte(pairFmt string, wcc ...WC) Decorator {
|
||||
return Counters(SizeB1024(0), pairFmt, wcc...)
|
||||
}
|
||||
|
||||
// CountersKiloByte is a wrapper around Counters with predefined unit
|
||||
// as SizeB1000(0).
|
||||
func CountersKiloByte(pairFmt string, wcc ...WC) Decorator {
|
||||
return Counters(SizeB1000(0), pairFmt, wcc...)
|
||||
}
|
||||
|
||||
// Counters decorator with dynamic unit measure adjustment.
|
||||
//
|
||||
// `unit` one of [0|SizeB1024(0)|SizeB1000(0)]
|
||||
//
|
||||
// `pairFmt` printf compatible verbs for current and total
|
||||
//
|
||||
// `wcc` optional WC config
|
||||
//
|
||||
// pairFmt example if unit=SizeB1000(0):
|
||||
//
|
||||
// pairFmt="%d / %d" output: "1MB / 12MB"
|
||||
// pairFmt="% d / % d" output: "1 MB / 12 MB"
|
||||
// pairFmt="%.1f / %.1f" output: "1.0MB / 12.0MB"
|
||||
// pairFmt="% .1f / % .1f" output: "1.0 MB / 12.0 MB"
|
||||
// pairFmt="%f / %f" output: "1.000000MB / 12.000000MB"
|
||||
// pairFmt="% f / % f" output: "1.000000 MB / 12.000000 MB"
|
||||
func Counters(unit interface{}, pairFmt string, wcc ...WC) Decorator {
|
||||
producer := func() DecorFunc {
|
||||
switch unit.(type) {
|
||||
case SizeB1024:
|
||||
if pairFmt == "" {
|
||||
pairFmt = "% d / % d"
|
||||
}
|
||||
return func(s Statistics) string {
|
||||
return fmt.Sprintf(pairFmt, SizeB1024(s.Current), SizeB1024(s.Total))
|
||||
}
|
||||
case SizeB1000:
|
||||
if pairFmt == "" {
|
||||
pairFmt = "% d / % d"
|
||||
}
|
||||
return func(s Statistics) string {
|
||||
return fmt.Sprintf(pairFmt, SizeB1000(s.Current), SizeB1000(s.Total))
|
||||
}
|
||||
default:
|
||||
if pairFmt == "" {
|
||||
pairFmt = "%d / %d"
|
||||
}
|
||||
return func(s Statistics) string {
|
||||
return fmt.Sprintf(pairFmt, s.Current, s.Total)
|
||||
}
|
||||
}
|
||||
}
|
||||
return Any(producer(), wcc...)
|
||||
}
|
||||
|
||||
// TotalNoUnit is a wrapper around Total with no unit param.
|
||||
func TotalNoUnit(format string, wcc ...WC) Decorator {
|
||||
return Total(0, format, wcc...)
|
||||
}
|
||||
|
||||
// TotalKibiByte is a wrapper around Total with predefined unit
|
||||
// as SizeB1024(0).
|
||||
func TotalKibiByte(format string, wcc ...WC) Decorator {
|
||||
return Total(SizeB1024(0), format, wcc...)
|
||||
}
|
||||
|
||||
// TotalKiloByte is a wrapper around Total with predefined unit
|
||||
// as SizeB1000(0).
|
||||
func TotalKiloByte(format string, wcc ...WC) Decorator {
|
||||
return Total(SizeB1000(0), format, wcc...)
|
||||
}
|
||||
|
||||
// Total decorator with dynamic unit measure adjustment.
|
||||
//
|
||||
// `unit` one of [0|SizeB1024(0)|SizeB1000(0)]
|
||||
//
|
||||
// `format` printf compatible verb for Total
|
||||
//
|
||||
// `wcc` optional WC config
|
||||
//
|
||||
// format example if unit=SizeB1024(0):
|
||||
//
|
||||
// format="%d" output: "12MiB"
|
||||
// format="% d" output: "12 MiB"
|
||||
// format="%.1f" output: "12.0MiB"
|
||||
// format="% .1f" output: "12.0 MiB"
|
||||
// format="%f" output: "12.000000MiB"
|
||||
// format="% f" output: "12.000000 MiB"
|
||||
func Total(unit interface{}, format string, wcc ...WC) Decorator {
|
||||
producer := func() DecorFunc {
|
||||
switch unit.(type) {
|
||||
case SizeB1024:
|
||||
if format == "" {
|
||||
format = "% d"
|
||||
}
|
||||
return func(s Statistics) string {
|
||||
return fmt.Sprintf(format, SizeB1024(s.Total))
|
||||
}
|
||||
case SizeB1000:
|
||||
if format == "" {
|
||||
format = "% d"
|
||||
}
|
||||
return func(s Statistics) string {
|
||||
return fmt.Sprintf(format, SizeB1000(s.Total))
|
||||
}
|
||||
default:
|
||||
if format == "" {
|
||||
format = "%d"
|
||||
}
|
||||
return func(s Statistics) string {
|
||||
return fmt.Sprintf(format, s.Total)
|
||||
}
|
||||
}
|
||||
}
|
||||
return Any(producer(), wcc...)
|
||||
}
|
||||
|
||||
// CurrentNoUnit is a wrapper around Current with no unit param.
|
||||
func CurrentNoUnit(format string, wcc ...WC) Decorator {
|
||||
return Current(0, format, wcc...)
|
||||
}
|
||||
|
||||
// CurrentKibiByte is a wrapper around Current with predefined unit
|
||||
// as SizeB1024(0).
|
||||
func CurrentKibiByte(format string, wcc ...WC) Decorator {
|
||||
return Current(SizeB1024(0), format, wcc...)
|
||||
}
|
||||
|
||||
// CurrentKiloByte is a wrapper around Current with predefined unit
|
||||
// as SizeB1000(0).
|
||||
func CurrentKiloByte(format string, wcc ...WC) Decorator {
|
||||
return Current(SizeB1000(0), format, wcc...)
|
||||
}
|
||||
|
||||
// Current decorator with dynamic unit measure adjustment.
|
||||
//
|
||||
// `unit` one of [0|SizeB1024(0)|SizeB1000(0)]
|
||||
//
|
||||
// `format` printf compatible verb for Current
|
||||
//
|
||||
// `wcc` optional WC config
|
||||
//
|
||||
// format example if unit=SizeB1024(0):
|
||||
//
|
||||
// format="%d" output: "12MiB"
|
||||
// format="% d" output: "12 MiB"
|
||||
// format="%.1f" output: "12.0MiB"
|
||||
// format="% .1f" output: "12.0 MiB"
|
||||
// format="%f" output: "12.000000MiB"
|
||||
// format="% f" output: "12.000000 MiB"
|
||||
func Current(unit interface{}, format string, wcc ...WC) Decorator {
|
||||
producer := func() DecorFunc {
|
||||
switch unit.(type) {
|
||||
case SizeB1024:
|
||||
if format == "" {
|
||||
format = "% d"
|
||||
}
|
||||
return func(s Statistics) string {
|
||||
return fmt.Sprintf(format, SizeB1024(s.Current))
|
||||
}
|
||||
case SizeB1000:
|
||||
if format == "" {
|
||||
format = "% d"
|
||||
}
|
||||
return func(s Statistics) string {
|
||||
return fmt.Sprintf(format, SizeB1000(s.Current))
|
||||
}
|
||||
default:
|
||||
if format == "" {
|
||||
format = "%d"
|
||||
}
|
||||
return func(s Statistics) string {
|
||||
return fmt.Sprintf(format, s.Current)
|
||||
}
|
||||
}
|
||||
}
|
||||
return Any(producer(), wcc...)
|
||||
}
|
||||
|
||||
// InvertedCurrentNoUnit is a wrapper around InvertedCurrent with no unit param.
|
||||
func InvertedCurrentNoUnit(format string, wcc ...WC) Decorator {
|
||||
return InvertedCurrent(0, format, wcc...)
|
||||
}
|
||||
|
||||
// InvertedCurrentKibiByte is a wrapper around InvertedCurrent with predefined unit
|
||||
// as SizeB1024(0).
|
||||
func InvertedCurrentKibiByte(format string, wcc ...WC) Decorator {
|
||||
return InvertedCurrent(SizeB1024(0), format, wcc...)
|
||||
}
|
||||
|
||||
// InvertedCurrentKiloByte is a wrapper around InvertedCurrent with predefined unit
|
||||
// as SizeB1000(0).
|
||||
func InvertedCurrentKiloByte(format string, wcc ...WC) Decorator {
|
||||
return InvertedCurrent(SizeB1000(0), format, wcc...)
|
||||
}
|
||||
|
||||
// InvertedCurrent decorator with dynamic unit measure adjustment.
|
||||
//
|
||||
// `unit` one of [0|SizeB1024(0)|SizeB1000(0)]
|
||||
//
|
||||
// `format` printf compatible verb for InvertedCurrent
|
||||
//
|
||||
// `wcc` optional WC config
|
||||
//
|
||||
// format example if unit=SizeB1024(0):
|
||||
//
|
||||
// format="%d" output: "12MiB"
|
||||
// format="% d" output: "12 MiB"
|
||||
// format="%.1f" output: "12.0MiB"
|
||||
// format="% .1f" output: "12.0 MiB"
|
||||
// format="%f" output: "12.000000MiB"
|
||||
// format="% f" output: "12.000000 MiB"
|
||||
func InvertedCurrent(unit interface{}, format string, wcc ...WC) Decorator {
|
||||
producer := func() DecorFunc {
|
||||
switch unit.(type) {
|
||||
case SizeB1024:
|
||||
if format == "" {
|
||||
format = "% d"
|
||||
}
|
||||
return func(s Statistics) string {
|
||||
return fmt.Sprintf(format, SizeB1024(s.Total-s.Current))
|
||||
}
|
||||
case SizeB1000:
|
||||
if format == "" {
|
||||
format = "% d"
|
||||
}
|
||||
return func(s Statistics) string {
|
||||
return fmt.Sprintf(format, SizeB1000(s.Total-s.Current))
|
||||
}
|
||||
default:
|
||||
if format == "" {
|
||||
format = "%d"
|
||||
}
|
||||
return func(s Statistics) string {
|
||||
return fmt.Sprintf(format, s.Total-s.Current)
|
||||
}
|
||||
}
|
||||
}
|
||||
return Any(producer(), wcc...)
|
||||
}
|
||||
194
vendor/github.com/vbauerster/mpb/v8/decor/decorator.go
generated
vendored
Normal file
194
vendor/github.com/vbauerster/mpb/v8/decor/decorator.go
generated
vendored
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
package decor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/acarl005/stripansi"
|
||||
"github.com/mattn/go-runewidth"
|
||||
)
|
||||
|
||||
const (
|
||||
// DidentRight bit specifies identation direction.
|
||||
// |foo |b | With DidentRight
|
||||
// | foo| b| Without DidentRight
|
||||
DidentRight = 1 << iota
|
||||
|
||||
// DextraSpace bit adds extra space, makes sense with DSyncWidth only.
|
||||
// When DidentRight bit set, the space will be added to the right,
|
||||
// otherwise to the left.
|
||||
DextraSpace
|
||||
|
||||
// DSyncWidth bit enables same column width synchronization.
|
||||
// Effective with multiple bars only.
|
||||
DSyncWidth
|
||||
|
||||
// DSyncWidthR is shortcut for DSyncWidth|DidentRight
|
||||
DSyncWidthR = DSyncWidth | DidentRight
|
||||
|
||||
// DSyncSpace is shortcut for DSyncWidth|DextraSpace
|
||||
DSyncSpace = DSyncWidth | DextraSpace
|
||||
|
||||
// DSyncSpaceR is shortcut for DSyncWidth|DextraSpace|DidentRight
|
||||
DSyncSpaceR = DSyncWidth | DextraSpace | DidentRight
|
||||
)
|
||||
|
||||
// TimeStyle enum.
|
||||
type TimeStyle int
|
||||
|
||||
// TimeStyle kinds.
|
||||
const (
|
||||
ET_STYLE_GO TimeStyle = iota
|
||||
ET_STYLE_HHMMSS
|
||||
ET_STYLE_HHMM
|
||||
ET_STYLE_MMSS
|
||||
)
|
||||
|
||||
// Statistics contains fields which are necessary for implementing
|
||||
// `decor.Decorator` and `mpb.BarFiller` interfaces.
|
||||
type Statistics struct {
|
||||
AvailableWidth int // calculated width initially equal to terminal width
|
||||
RequestedWidth int // width set by `mpb.WithWidth`
|
||||
ID int
|
||||
Total int64
|
||||
Current int64
|
||||
Refill int64
|
||||
Completed bool
|
||||
Aborted bool
|
||||
}
|
||||
|
||||
// Decorator interface.
|
||||
// Most of the time there is no need to implement this interface
|
||||
// manually, as decor package already provides a wide range of decorators
|
||||
// which implement this interface. If however built-in decorators don't
|
||||
// meet your needs, you're free to implement your own one by implementing
|
||||
// this particular interface. The easy way to go is to convert a
|
||||
// `DecorFunc` into a `Decorator` interface by using provided
|
||||
// `func Any(DecorFunc, ...WC) Decorator`.
|
||||
type Decorator interface {
|
||||
Configurator
|
||||
Synchronizer
|
||||
Decor(Statistics) string
|
||||
}
|
||||
|
||||
// DecorFunc func type.
|
||||
// To be used with `func Any`(DecorFunc, ...WC) Decorator`.
|
||||
type DecorFunc func(Statistics) string
|
||||
|
||||
// Synchronizer interface.
|
||||
// All decorators implement this interface implicitly. Its Sync
|
||||
// method exposes width sync channel, if DSyncWidth bit is set.
|
||||
type Synchronizer interface {
|
||||
Sync() (chan int, bool)
|
||||
}
|
||||
|
||||
// Configurator interface.
|
||||
type Configurator interface {
|
||||
GetConf() WC
|
||||
SetConf(WC)
|
||||
}
|
||||
|
||||
// Wrapper interface.
|
||||
// If you're implementing custom Decorator by wrapping a built-in one,
|
||||
// it is necessary to implement this interface to retain functionality
|
||||
// of built-in Decorator.
|
||||
type Wrapper interface {
|
||||
Unwrap() Decorator
|
||||
}
|
||||
|
||||
// EwmaDecorator interface.
|
||||
// EWMA based decorators should implement this one.
|
||||
type EwmaDecorator interface {
|
||||
EwmaUpdate(int64, time.Duration)
|
||||
}
|
||||
|
||||
// AverageDecorator interface.
|
||||
// Average decorators should implement this interface to provide start
|
||||
// time adjustment facility, for resume-able tasks.
|
||||
type AverageDecorator interface {
|
||||
AverageAdjust(time.Time)
|
||||
}
|
||||
|
||||
// ShutdownListener interface.
|
||||
// If decorator needs to be notified once upon bar shutdown event, so
|
||||
// this is the right interface to implement.
|
||||
type ShutdownListener interface {
|
||||
OnShutdown()
|
||||
}
|
||||
|
||||
// Global convenience instances of WC with sync width bit set.
|
||||
// To be used with multiple bars only, i.e. not effective for single bar usage.
|
||||
var (
|
||||
WCSyncWidth = WC{C: DSyncWidth}
|
||||
WCSyncWidthR = WC{C: DSyncWidthR}
|
||||
WCSyncSpace = WC{C: DSyncSpace}
|
||||
WCSyncSpaceR = WC{C: DSyncSpaceR}
|
||||
)
|
||||
|
||||
// WC is a struct with two public fields W and C, both of int type.
|
||||
// W represents width and C represents bit set of width related config.
|
||||
// A decorator should embed WC, to enable width synchronization.
|
||||
type WC struct {
|
||||
W int
|
||||
C int
|
||||
fill func(s string, w int) string
|
||||
wsync chan int
|
||||
}
|
||||
|
||||
// FormatMsg formats final message according to WC.W and WC.C.
|
||||
// Should be called by any Decorator implementation.
|
||||
func (wc WC) FormatMsg(msg string) string {
|
||||
pureWidth := runewidth.StringWidth(msg)
|
||||
viewWidth := runewidth.StringWidth(stripansi.Strip(msg))
|
||||
max := wc.W
|
||||
if (wc.C & DSyncWidth) != 0 {
|
||||
viewWidth := viewWidth
|
||||
if (wc.C & DextraSpace) != 0 {
|
||||
viewWidth++
|
||||
}
|
||||
wc.wsync <- viewWidth
|
||||
max = <-wc.wsync
|
||||
}
|
||||
return wc.fill(msg, max-viewWidth+pureWidth)
|
||||
}
|
||||
|
||||
// Init initializes width related config.
|
||||
func (wc *WC) Init() WC {
|
||||
if (wc.C & DidentRight) != 0 {
|
||||
wc.fill = runewidth.FillRight
|
||||
} else {
|
||||
wc.fill = runewidth.FillLeft
|
||||
}
|
||||
if (wc.C & DSyncWidth) != 0 {
|
||||
// it's deliberate choice to override wsync on each Init() call,
|
||||
// this way globals like WCSyncSpace can be reused
|
||||
wc.wsync = make(chan int)
|
||||
}
|
||||
return *wc
|
||||
}
|
||||
|
||||
// Sync is implementation of Synchronizer interface.
|
||||
func (wc WC) Sync() (chan int, bool) {
|
||||
if (wc.C&DSyncWidth) != 0 && wc.wsync == nil {
|
||||
panic(fmt.Sprintf("%T is not initialized", wc))
|
||||
}
|
||||
return wc.wsync, (wc.C & DSyncWidth) != 0
|
||||
}
|
||||
|
||||
// GetConf is implementation of Configurator interface.
|
||||
func (wc *WC) GetConf() WC {
|
||||
return *wc
|
||||
}
|
||||
|
||||
// SetConf is implementation of Configurator interface.
|
||||
func (wc *WC) SetConf(conf WC) {
|
||||
*wc = conf.Init()
|
||||
}
|
||||
|
||||
func initWC(wcc ...WC) WC {
|
||||
var wc WC
|
||||
for _, nwc := range wcc {
|
||||
wc = nwc
|
||||
}
|
||||
return wc.Init()
|
||||
}
|
||||
19
vendor/github.com/vbauerster/mpb/v8/decor/doc.go
generated
vendored
Normal file
19
vendor/github.com/vbauerster/mpb/v8/decor/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// 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
|
||||
// *mpb.Bar instances. To avoid data races, create new decorator per *mpb.Bar instance.
|
||||
//
|
||||
// Don't:
|
||||
//
|
||||
// p := mpb.New()
|
||||
// name := decor.Name("bar")
|
||||
// p.AddBar(100, mpb.AppendDecorators(name))
|
||||
// p.AddBar(100, mpb.AppendDecorators(name))
|
||||
//
|
||||
// Do:
|
||||
//
|
||||
// p := mpb.New()
|
||||
// p.AddBar(100, mpb.AppendDecorators(decor.Name("bar1")))
|
||||
// p.AddBar(100, mpb.AppendDecorators(decor.Name("bar2")))
|
||||
package decor
|
||||
33
vendor/github.com/vbauerster/mpb/v8/decor/elapsed.go
generated
vendored
Normal file
33
vendor/github.com/vbauerster/mpb/v8/decor/elapsed.go
generated
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
package decor
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Elapsed decorator. It's wrapper of NewElapsed.
|
||||
//
|
||||
// `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...)
|
||||
}
|
||||
|
||||
// NewElapsed returns elapsed time decorator.
|
||||
//
|
||||
// `style` one of [ET_STYLE_GO|ET_STYLE_HHMMSS|ET_STYLE_HHMM|ET_STYLE_MMSS]
|
||||
//
|
||||
// `startTime` start time
|
||||
//
|
||||
// `wcc` optional WC config
|
||||
func NewElapsed(style TimeStyle, startTime time.Time, wcc ...WC) Decorator {
|
||||
var msg string
|
||||
producer := chooseTimeProducer(style)
|
||||
fn := func(s Statistics) string {
|
||||
if !s.Completed {
|
||||
msg = producer(time.Since(startTime))
|
||||
}
|
||||
return msg
|
||||
}
|
||||
return Any(fn, wcc...)
|
||||
}
|
||||
205
vendor/github.com/vbauerster/mpb/v8/decor/eta.go
generated
vendored
Normal file
205
vendor/github.com/vbauerster/mpb/v8/decor/eta.go
generated
vendored
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
package decor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"github.com/VividCortex/ewma"
|
||||
)
|
||||
|
||||
var (
|
||||
_ Decorator = (*movingAverageETA)(nil)
|
||||
_ EwmaDecorator = (*movingAverageETA)(nil)
|
||||
_ Decorator = (*averageETA)(nil)
|
||||
_ AverageDecorator = (*averageETA)(nil)
|
||||
)
|
||||
|
||||
// TimeNormalizer interface. Implementors could be passed into
|
||||
// MovingAverageETA, in order to affect i.e. normalize its output.
|
||||
type TimeNormalizer interface {
|
||||
Normalize(time.Duration) time.Duration
|
||||
}
|
||||
|
||||
// TimeNormalizerFunc is function type adapter to convert function
|
||||
// into TimeNormalizer.
|
||||
type TimeNormalizerFunc func(time.Duration) time.Duration
|
||||
|
||||
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 one of the (*Bar).EwmaIncr... family methods.
|
||||
func EwmaETA(style TimeStyle, age float64, wcc ...WC) Decorator {
|
||||
var average ewma.MovingAverage
|
||||
if age == 0 {
|
||||
average = ewma.NewMovingAverage()
|
||||
} else {
|
||||
average = ewma.NewMovingAverage(age)
|
||||
}
|
||||
return MovingAverageETA(style, NewThreadSafeMovingAverage(average), nil, wcc...)
|
||||
}
|
||||
|
||||
// MovingAverageETA decorator relies on MovingAverage implementation to calculate its average.
|
||||
//
|
||||
// `style` one of [ET_STYLE_GO|ET_STYLE_HHMMSS|ET_STYLE_HHMM|ET_STYLE_MMSS]
|
||||
//
|
||||
// `average` implementation of MovingAverage interface
|
||||
//
|
||||
// `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...),
|
||||
average: average,
|
||||
normalizer: normalizer,
|
||||
producer: chooseTimeProducer(style),
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
type movingAverageETA struct {
|
||||
WC
|
||||
average ewma.MovingAverage
|
||||
normalizer TimeNormalizer
|
||||
producer func(time.Duration) string
|
||||
}
|
||||
|
||||
func (d *movingAverageETA) Decor(s Statistics) string {
|
||||
v := math.Round(d.average.Value())
|
||||
remaining := time.Duration((s.Total - s.Current) * int64(v))
|
||||
if d.normalizer != nil {
|
||||
remaining = d.normalizer.Normalize(remaining)
|
||||
}
|
||||
return d.FormatMsg(d.producer(remaining))
|
||||
}
|
||||
|
||||
func (d *movingAverageETA) EwmaUpdate(n int64, dur time.Duration) {
|
||||
durPerItem := float64(dur) / float64(n)
|
||||
if math.IsInf(durPerItem, 0) || math.IsNaN(durPerItem) {
|
||||
return
|
||||
}
|
||||
d.average.Add(durPerItem)
|
||||
}
|
||||
|
||||
// AverageETA decorator. It's wrapper of NewAverageETA.
|
||||
//
|
||||
// `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...)
|
||||
}
|
||||
|
||||
// NewAverageETA decorator with user provided start time.
|
||||
//
|
||||
// `style` one of [ET_STYLE_GO|ET_STYLE_HHMMSS|ET_STYLE_HHMM|ET_STYLE_MMSS]
|
||||
//
|
||||
// `startTime` start time
|
||||
//
|
||||
// `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...),
|
||||
startTime: startTime,
|
||||
normalizer: normalizer,
|
||||
producer: chooseTimeProducer(style),
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
type averageETA struct {
|
||||
WC
|
||||
startTime time.Time
|
||||
normalizer TimeNormalizer
|
||||
producer func(time.Duration) string
|
||||
}
|
||||
|
||||
func (d *averageETA) Decor(s Statistics) string {
|
||||
var remaining time.Duration
|
||||
if s.Current != 0 {
|
||||
durPerItem := float64(time.Since(d.startTime)) / float64(s.Current)
|
||||
durPerItem = math.Round(durPerItem)
|
||||
remaining = time.Duration((s.Total - s.Current) * int64(durPerItem))
|
||||
if d.normalizer != nil {
|
||||
remaining = d.normalizer.Normalize(remaining)
|
||||
}
|
||||
}
|
||||
return d.FormatMsg(d.producer(remaining))
|
||||
}
|
||||
|
||||
func (d *averageETA) AverageAdjust(startTime time.Time) {
|
||||
d.startTime = startTime
|
||||
}
|
||||
|
||||
// MaxTolerateTimeNormalizer returns implementation of TimeNormalizer.
|
||||
func MaxTolerateTimeNormalizer(maxTolerate time.Duration) TimeNormalizer {
|
||||
var normalized time.Duration
|
||||
var lastCall time.Time
|
||||
return TimeNormalizerFunc(func(remaining time.Duration) time.Duration {
|
||||
if diff := normalized - remaining; diff <= 0 || diff > maxTolerate || remaining < time.Minute {
|
||||
normalized = remaining
|
||||
lastCall = time.Now()
|
||||
return remaining
|
||||
}
|
||||
normalized -= time.Since(lastCall)
|
||||
lastCall = time.Now()
|
||||
return normalized
|
||||
})
|
||||
}
|
||||
|
||||
// FixedIntervalTimeNormalizer returns implementation of TimeNormalizer.
|
||||
func FixedIntervalTimeNormalizer(updInterval int) TimeNormalizer {
|
||||
var normalized time.Duration
|
||||
var lastCall time.Time
|
||||
var count int
|
||||
return TimeNormalizerFunc(func(remaining time.Duration) time.Duration {
|
||||
if count == 0 || remaining < time.Minute {
|
||||
count = updInterval
|
||||
normalized = remaining
|
||||
lastCall = time.Now()
|
||||
return remaining
|
||||
}
|
||||
count--
|
||||
normalized -= time.Since(lastCall)
|
||||
lastCall = time.Now()
|
||||
return normalized
|
||||
})
|
||||
}
|
||||
|
||||
func chooseTimeProducer(style TimeStyle) func(time.Duration) string {
|
||||
switch style {
|
||||
case ET_STYLE_HHMMSS:
|
||||
return func(remaining time.Duration) string {
|
||||
hours := int64(remaining/time.Hour) % 60
|
||||
minutes := int64(remaining/time.Minute) % 60
|
||||
seconds := int64(remaining/time.Second) % 60
|
||||
return fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds)
|
||||
}
|
||||
case ET_STYLE_HHMM:
|
||||
return func(remaining time.Duration) string {
|
||||
hours := int64(remaining/time.Hour) % 60
|
||||
minutes := int64(remaining/time.Minute) % 60
|
||||
return fmt.Sprintf("%02d:%02d", hours, minutes)
|
||||
}
|
||||
case ET_STYLE_MMSS:
|
||||
return func(remaining time.Duration) string {
|
||||
hours := int64(remaining/time.Hour) % 60
|
||||
minutes := int64(remaining/time.Minute) % 60
|
||||
seconds := int64(remaining/time.Second) % 60
|
||||
if hours > 0 {
|
||||
return fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds)
|
||||
}
|
||||
return fmt.Sprintf("%02d:%02d", minutes, seconds)
|
||||
}
|
||||
default:
|
||||
return func(remaining time.Duration) string {
|
||||
return remaining.Truncate(time.Second).String()
|
||||
}
|
||||
}
|
||||
}
|
||||
111
vendor/github.com/vbauerster/mpb/v8/decor/merge.go
generated
vendored
Normal file
111
vendor/github.com/vbauerster/mpb/v8/decor/merge.go
generated
vendored
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
package decor
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/acarl005/stripansi"
|
||||
"github.com/mattn/go-runewidth"
|
||||
)
|
||||
|
||||
var (
|
||||
_ Decorator = (*mergeDecorator)(nil)
|
||||
_ Wrapper = (*mergeDecorator)(nil)
|
||||
_ Decorator = (*placeHolderDecorator)(nil)
|
||||
)
|
||||
|
||||
// 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 |
|
||||
// +----+--------+---------+--------+
|
||||
func Merge(decorator Decorator, placeholders ...WC) Decorator {
|
||||
if decorator == nil {
|
||||
return nil
|
||||
}
|
||||
if _, ok := decorator.Sync(); !ok || len(placeholders) == 0 {
|
||||
return decorator
|
||||
}
|
||||
md := &mergeDecorator{
|
||||
Decorator: decorator,
|
||||
wc: decorator.GetConf(),
|
||||
placeHolders: make([]Decorator, len(placeholders)),
|
||||
}
|
||||
decorator.SetConf(WC{})
|
||||
for i, wc := range placeholders {
|
||||
if (wc.C & DSyncWidth) == 0 {
|
||||
return decorator
|
||||
}
|
||||
md.placeHolders[i] = &placeHolderDecorator{wc.Init()}
|
||||
}
|
||||
return md
|
||||
}
|
||||
|
||||
type mergeDecorator struct {
|
||||
Decorator
|
||||
wc WC
|
||||
placeHolders []Decorator
|
||||
}
|
||||
|
||||
func (d *mergeDecorator) GetConf() WC {
|
||||
return d.wc
|
||||
}
|
||||
|
||||
func (d *mergeDecorator) SetConf(conf WC) {
|
||||
d.wc = conf.Init()
|
||||
}
|
||||
|
||||
func (d *mergeDecorator) PlaceHolders() []Decorator {
|
||||
return d.placeHolders
|
||||
}
|
||||
|
||||
func (d *mergeDecorator) Sync() (chan int, bool) {
|
||||
return d.wc.Sync()
|
||||
}
|
||||
|
||||
func (d *mergeDecorator) Unwrap() Decorator {
|
||||
return d.Decorator
|
||||
}
|
||||
|
||||
func (d *mergeDecorator) Decor(s Statistics) string {
|
||||
msg := d.Decorator.Decor(s)
|
||||
pureWidth := runewidth.StringWidth(msg)
|
||||
stripWidth := runewidth.StringWidth(stripansi.Strip(msg))
|
||||
cellCount := stripWidth
|
||||
if (d.wc.C & DextraSpace) != 0 {
|
||||
cellCount++
|
||||
}
|
||||
|
||||
total := runewidth.StringWidth(d.placeHolders[0].GetConf().FormatMsg(""))
|
||||
pw := (cellCount - total) / len(d.placeHolders)
|
||||
rem := (cellCount - total) % len(d.placeHolders)
|
||||
|
||||
var diff int
|
||||
for i := 1; i < len(d.placeHolders); i++ {
|
||||
wc := d.placeHolders[i].GetConf()
|
||||
width := pw - diff
|
||||
if (wc.C & DextraSpace) != 0 {
|
||||
width--
|
||||
if width < 0 {
|
||||
width = 0
|
||||
}
|
||||
}
|
||||
max := runewidth.StringWidth(wc.FormatMsg(strings.Repeat(" ", width)))
|
||||
total += max
|
||||
diff = max - pw
|
||||
}
|
||||
|
||||
d.wc.wsync <- pw + rem
|
||||
max := <-d.wc.wsync
|
||||
return d.wc.fill(msg, max+total+(pureWidth-stripWidth))
|
||||
}
|
||||
|
||||
type placeHolderDecorator struct {
|
||||
WC
|
||||
}
|
||||
|
||||
func (d *placeHolderDecorator) Decor(Statistics) string {
|
||||
return ""
|
||||
}
|
||||
74
vendor/github.com/vbauerster/mpb/v8/decor/moving_average.go
generated
vendored
Normal file
74
vendor/github.com/vbauerster/mpb/v8/decor/moving_average.go
generated
vendored
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
package decor
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"github.com/VividCortex/ewma"
|
||||
)
|
||||
|
||||
var (
|
||||
_ ewma.MovingAverage = (*threadSafeMovingAverage)(nil)
|
||||
_ ewma.MovingAverage = (*medianWindow)(nil)
|
||||
_ sort.Interface = (*medianWindow)(nil)
|
||||
)
|
||||
|
||||
type threadSafeMovingAverage struct {
|
||||
ewma.MovingAverage
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func (s *threadSafeMovingAverage) Add(value float64) {
|
||||
s.mu.Lock()
|
||||
s.MovingAverage.Add(value)
|
||||
s.mu.Unlock()
|
||||
}
|
||||
|
||||
func (s *threadSafeMovingAverage) Value() float64 {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return s.MovingAverage.Value()
|
||||
}
|
||||
|
||||
func (s *threadSafeMovingAverage) Set(value float64) {
|
||||
s.mu.Lock()
|
||||
s.MovingAverage.Set(value)
|
||||
s.mu.Unlock()
|
||||
}
|
||||
|
||||
// NewThreadSafeMovingAverage converts provided ewma.MovingAverage
|
||||
// into thread safe ewma.MovingAverage.
|
||||
func NewThreadSafeMovingAverage(average ewma.MovingAverage) ewma.MovingAverage {
|
||||
if tsma, ok := average.(*threadSafeMovingAverage); ok {
|
||||
return tsma
|
||||
}
|
||||
return &threadSafeMovingAverage{MovingAverage: average}
|
||||
}
|
||||
|
||||
type medianWindow [3]float64
|
||||
|
||||
func (s *medianWindow) Len() int { return len(s) }
|
||||
func (s *medianWindow) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
func (s *medianWindow) Less(i, j int) bool { return s[i] < s[j] }
|
||||
|
||||
func (s *medianWindow) Add(value float64) {
|
||||
s[0], s[1] = s[1], s[2]
|
||||
s[2] = value
|
||||
}
|
||||
|
||||
func (s *medianWindow) Value() float64 {
|
||||
tmp := *s
|
||||
sort.Sort(&tmp)
|
||||
return tmp[1]
|
||||
}
|
||||
|
||||
func (s *medianWindow) Set(value float64) {
|
||||
for i := 0; i < len(s); i++ {
|
||||
s[i] = value
|
||||
}
|
||||
}
|
||||
|
||||
// NewMedian is fixed last 3 samples median MovingAverage.
|
||||
func NewMedian() ewma.MovingAverage {
|
||||
return NewThreadSafeMovingAverage(new(medianWindow))
|
||||
}
|
||||
11
vendor/github.com/vbauerster/mpb/v8/decor/name.go
generated
vendored
Normal file
11
vendor/github.com/vbauerster/mpb/v8/decor/name.go
generated
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
package decor
|
||||
|
||||
// Name decorator displays text that is set once and can't be changed
|
||||
// during decorator's lifetime.
|
||||
//
|
||||
// `str` string to display
|
||||
//
|
||||
// `wcc` optional WC config
|
||||
func Name(str string, wcc ...WC) Decorator {
|
||||
return Any(func(Statistics) string { return str }, wcc...)
|
||||
}
|
||||
44
vendor/github.com/vbauerster/mpb/v8/decor/on_abort.go
generated
vendored
Normal file
44
vendor/github.com/vbauerster/mpb/v8/decor/on_abort.go
generated
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
package decor
|
||||
|
||||
var (
|
||||
_ Decorator = (*onAbortWrapper)(nil)
|
||||
_ Wrapper = (*onAbortWrapper)(nil)
|
||||
)
|
||||
|
||||
// OnAbort returns decorator, which wraps provided decorator with sole
|
||||
// purpose to display provided message on abort event. It has no effect
|
||||
// if bar.Abort(drop bool) is called with true argument.
|
||||
//
|
||||
// `decorator` Decorator to wrap
|
||||
//
|
||||
// `message` message to display on abort event
|
||||
func OnAbort(decorator Decorator, message string) Decorator {
|
||||
if decorator == nil {
|
||||
return nil
|
||||
}
|
||||
d := &onAbortWrapper{
|
||||
Decorator: decorator,
|
||||
msg: message,
|
||||
}
|
||||
if md, ok := decorator.(*mergeDecorator); ok {
|
||||
d.Decorator, md.Decorator = md.Decorator, d
|
||||
return md
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
type onAbortWrapper struct {
|
||||
Decorator
|
||||
msg string
|
||||
}
|
||||
|
||||
func (d *onAbortWrapper) Decor(s Statistics) string {
|
||||
if s.Aborted {
|
||||
return d.GetConf().FormatMsg(d.msg)
|
||||
}
|
||||
return d.Decorator.Decor(s)
|
||||
}
|
||||
|
||||
func (d *onAbortWrapper) Unwrap() Decorator {
|
||||
return d.Decorator
|
||||
}
|
||||
43
vendor/github.com/vbauerster/mpb/v8/decor/on_complete.go
generated
vendored
Normal file
43
vendor/github.com/vbauerster/mpb/v8/decor/on_complete.go
generated
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
package decor
|
||||
|
||||
var (
|
||||
_ Decorator = (*onCompleteWrapper)(nil)
|
||||
_ Wrapper = (*onCompleteWrapper)(nil)
|
||||
)
|
||||
|
||||
// OnComplete returns decorator, which wraps provided decorator with
|
||||
// sole purpose to display provided message on complete event.
|
||||
//
|
||||
// `decorator` Decorator to wrap
|
||||
//
|
||||
// `message` message to display on complete event
|
||||
func OnComplete(decorator Decorator, message string) Decorator {
|
||||
if decorator == nil {
|
||||
return nil
|
||||
}
|
||||
d := &onCompleteWrapper{
|
||||
Decorator: decorator,
|
||||
msg: message,
|
||||
}
|
||||
if md, ok := decorator.(*mergeDecorator); ok {
|
||||
d.Decorator, md.Decorator = md.Decorator, d
|
||||
return md
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
type onCompleteWrapper struct {
|
||||
Decorator
|
||||
msg string
|
||||
}
|
||||
|
||||
func (d *onCompleteWrapper) Decor(s Statistics) string {
|
||||
if s.Completed {
|
||||
return d.GetConf().FormatMsg(d.msg)
|
||||
}
|
||||
return d.Decorator.Decor(s)
|
||||
}
|
||||
|
||||
func (d *onCompleteWrapper) Unwrap() Decorator {
|
||||
return d.Decorator
|
||||
}
|
||||
51
vendor/github.com/vbauerster/mpb/v8/decor/on_condition.go
generated
vendored
Normal file
51
vendor/github.com/vbauerster/mpb/v8/decor/on_condition.go
generated
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
package decor
|
||||
|
||||
// OnCondition applies decorator only if a condition is true.
|
||||
//
|
||||
// `decorator` Decorator
|
||||
//
|
||||
// `cond` bool
|
||||
func OnCondition(decorator Decorator, cond bool) Decorator {
|
||||
return Conditional(cond, decorator, nil)
|
||||
}
|
||||
|
||||
// OnPredicate applies decorator only if a predicate evaluates to true.
|
||||
//
|
||||
// `decorator` Decorator
|
||||
//
|
||||
// `predicate` func() bool
|
||||
func OnPredicate(decorator Decorator, predicate func() bool) Decorator {
|
||||
return Predicative(predicate, decorator, nil)
|
||||
}
|
||||
|
||||
// Conditional returns decorator `a` if condition is true, otherwise
|
||||
// decorator `b`.
|
||||
//
|
||||
// `cond` bool
|
||||
//
|
||||
// `a` Decorator
|
||||
//
|
||||
// `b` Decorator
|
||||
func Conditional(cond bool, a, b Decorator) Decorator {
|
||||
if cond {
|
||||
return a
|
||||
} else {
|
||||
return b
|
||||
}
|
||||
}
|
||||
|
||||
// Predicative returns decorator `a` if predicate evaluates to true,
|
||||
// otherwise decorator `b`.
|
||||
//
|
||||
// `predicate` func() bool
|
||||
//
|
||||
// `a` Decorator
|
||||
//
|
||||
// `b` Decorator
|
||||
func Predicative(predicate func() bool, a, b Decorator) Decorator {
|
||||
if predicate() {
|
||||
return a
|
||||
} else {
|
||||
return b
|
||||
}
|
||||
}
|
||||
68
vendor/github.com/vbauerster/mpb/v8/decor/percentage.go
generated
vendored
Normal file
68
vendor/github.com/vbauerster/mpb/v8/decor/percentage.go
generated
vendored
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
package decor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/vbauerster/mpb/v8/internal"
|
||||
)
|
||||
|
||||
var _ fmt.Formatter = percentageType(0)
|
||||
|
||||
type percentageType float64
|
||||
|
||||
func (s percentageType) Format(st fmt.State, verb rune) {
|
||||
prec := -1
|
||||
switch verb {
|
||||
case 'f', 'e', 'E':
|
||||
prec = 6 // default prec of fmt.Printf("%f|%e|%E")
|
||||
fallthrough
|
||||
case 'b', 'g', 'G', 'x', 'X':
|
||||
if p, ok := st.Precision(); ok {
|
||||
prec = p
|
||||
}
|
||||
default:
|
||||
verb, prec = 'f', 0
|
||||
}
|
||||
|
||||
b := strconv.AppendFloat(make([]byte, 0, 16), float64(s), byte(verb), prec, 64)
|
||||
if st.Flag(' ') {
|
||||
b = append(b, ' ', '%')
|
||||
} else {
|
||||
b = append(b, '%')
|
||||
}
|
||||
_, err := st.Write(b)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Percentage returns percentage decorator. It's a wrapper of NewPercentage.
|
||||
func Percentage(wcc ...WC) Decorator {
|
||||
return NewPercentage("% d", wcc...)
|
||||
}
|
||||
|
||||
// NewPercentage percentage decorator with custom format string.
|
||||
//
|
||||
// `format` printf compatible verb
|
||||
//
|
||||
// `wcc` optional WC config
|
||||
//
|
||||
// format examples:
|
||||
//
|
||||
// format="%d" output: "1%"
|
||||
// format="% d" output: "1 %"
|
||||
// format="%.1f" output: "1.0%"
|
||||
// format="% .1f" output: "1.0 %"
|
||||
// format="%f" output: "1.000000%"
|
||||
// format="% f" output: "1.000000 %"
|
||||
func NewPercentage(format string, wcc ...WC) Decorator {
|
||||
if format == "" {
|
||||
format = "% d"
|
||||
}
|
||||
f := func(s Statistics) string {
|
||||
p := internal.Percentage(s.Total, s.Current, 100)
|
||||
return fmt.Sprintf(format, percentageType(p))
|
||||
}
|
||||
return Any(f, wcc...)
|
||||
}
|
||||
120
vendor/github.com/vbauerster/mpb/v8/decor/size_type.go
generated
vendored
Normal file
120
vendor/github.com/vbauerster/mpb/v8/decor/size_type.go
generated
vendored
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
package decor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
//go:generate stringer -type=SizeB1024 -trimprefix=_i
|
||||
//go:generate stringer -type=SizeB1000 -trimprefix=_
|
||||
|
||||
var (
|
||||
_ fmt.Formatter = SizeB1024(0)
|
||||
_ fmt.Stringer = SizeB1024(0)
|
||||
_ fmt.Formatter = SizeB1000(0)
|
||||
_ fmt.Stringer = SizeB1000(0)
|
||||
)
|
||||
|
||||
const (
|
||||
_ib SizeB1024 = iota + 1
|
||||
_iKiB SizeB1024 = 1 << (iota * 10)
|
||||
_iMiB
|
||||
_iGiB
|
||||
_iTiB
|
||||
)
|
||||
|
||||
// SizeB1024 named type, which implements fmt.Formatter interface. It
|
||||
// adjusts its value according to byte size multiple by 1024 and appends
|
||||
// appropriate size marker (KiB, MiB, GiB, TiB).
|
||||
type SizeB1024 int64
|
||||
|
||||
func (self SizeB1024) Format(st fmt.State, verb rune) {
|
||||
prec := -1
|
||||
switch verb {
|
||||
case 'f', 'e', 'E':
|
||||
prec = 6 // default prec of fmt.Printf("%f|%e|%E")
|
||||
fallthrough
|
||||
case 'b', 'g', 'G', 'x', 'X':
|
||||
if p, ok := st.Precision(); ok {
|
||||
prec = p
|
||||
}
|
||||
default:
|
||||
verb, prec = 'f', 0
|
||||
}
|
||||
|
||||
var unit SizeB1024
|
||||
switch {
|
||||
case self < _iKiB:
|
||||
unit = _ib
|
||||
case self < _iMiB:
|
||||
unit = _iKiB
|
||||
case self < _iGiB:
|
||||
unit = _iMiB
|
||||
case self < _iTiB:
|
||||
unit = _iGiB
|
||||
default:
|
||||
unit = _iTiB
|
||||
}
|
||||
|
||||
b := strconv.AppendFloat(make([]byte, 0, 24), float64(self)/float64(unit), byte(verb), prec, 64)
|
||||
if st.Flag(' ') {
|
||||
b = append(b, ' ')
|
||||
}
|
||||
b = append(b, []byte(unit.String())...)
|
||||
_, err := st.Write(b)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
_b SizeB1000 = 1
|
||||
_KB SizeB1000 = _b * 1000
|
||||
_MB SizeB1000 = _KB * 1000
|
||||
_GB SizeB1000 = _MB * 1000
|
||||
_TB SizeB1000 = _GB * 1000
|
||||
)
|
||||
|
||||
// SizeB1000 named type, which implements fmt.Formatter interface. It
|
||||
// adjusts its value according to byte size multiple by 1000 and appends
|
||||
// appropriate size marker (KB, MB, GB, TB).
|
||||
type SizeB1000 int64
|
||||
|
||||
func (self SizeB1000) Format(st fmt.State, verb rune) {
|
||||
prec := -1
|
||||
switch verb {
|
||||
case 'f', 'e', 'E':
|
||||
prec = 6 // default prec of fmt.Printf("%f|%e|%E")
|
||||
fallthrough
|
||||
case 'b', 'g', 'G', 'x', 'X':
|
||||
if p, ok := st.Precision(); ok {
|
||||
prec = p
|
||||
}
|
||||
default:
|
||||
verb, prec = 'f', 0
|
||||
}
|
||||
|
||||
var unit SizeB1000
|
||||
switch {
|
||||
case self < _KB:
|
||||
unit = _b
|
||||
case self < _MB:
|
||||
unit = _KB
|
||||
case self < _GB:
|
||||
unit = _MB
|
||||
case self < _TB:
|
||||
unit = _GB
|
||||
default:
|
||||
unit = _TB
|
||||
}
|
||||
|
||||
b := strconv.AppendFloat(make([]byte, 0, 24), float64(self)/float64(unit), byte(verb), prec, 64)
|
||||
if st.Flag(' ') {
|
||||
b = append(b, ' ')
|
||||
}
|
||||
b = append(b, []byte(unit.String())...)
|
||||
_, err := st.Write(b)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
41
vendor/github.com/vbauerster/mpb/v8/decor/sizeb1000_string.go
generated
vendored
Normal file
41
vendor/github.com/vbauerster/mpb/v8/decor/sizeb1000_string.go
generated
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// Code generated by "stringer -type=SizeB1000 -trimprefix=_"; DO NOT EDIT.
|
||||
|
||||
package decor
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[_b-1]
|
||||
_ = x[_KB-1000]
|
||||
_ = x[_MB-1000000]
|
||||
_ = x[_GB-1000000000]
|
||||
_ = x[_TB-1000000000000]
|
||||
}
|
||||
|
||||
const (
|
||||
_SizeB1000_name_0 = "b"
|
||||
_SizeB1000_name_1 = "KB"
|
||||
_SizeB1000_name_2 = "MB"
|
||||
_SizeB1000_name_3 = "GB"
|
||||
_SizeB1000_name_4 = "TB"
|
||||
)
|
||||
|
||||
func (i SizeB1000) String() string {
|
||||
switch {
|
||||
case i == 1:
|
||||
return _SizeB1000_name_0
|
||||
case i == 1000:
|
||||
return _SizeB1000_name_1
|
||||
case i == 1000000:
|
||||
return _SizeB1000_name_2
|
||||
case i == 1000000000:
|
||||
return _SizeB1000_name_3
|
||||
case i == 1000000000000:
|
||||
return _SizeB1000_name_4
|
||||
default:
|
||||
return "SizeB1000(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
}
|
||||
41
vendor/github.com/vbauerster/mpb/v8/decor/sizeb1024_string.go
generated
vendored
Normal file
41
vendor/github.com/vbauerster/mpb/v8/decor/sizeb1024_string.go
generated
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// Code generated by "stringer -type=SizeB1024 -trimprefix=_i"; DO NOT EDIT.
|
||||
|
||||
package decor
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[_ib-1]
|
||||
_ = x[_iKiB-1024]
|
||||
_ = x[_iMiB-1048576]
|
||||
_ = x[_iGiB-1073741824]
|
||||
_ = x[_iTiB-1099511627776]
|
||||
}
|
||||
|
||||
const (
|
||||
_SizeB1024_name_0 = "b"
|
||||
_SizeB1024_name_1 = "KiB"
|
||||
_SizeB1024_name_2 = "MiB"
|
||||
_SizeB1024_name_3 = "GiB"
|
||||
_SizeB1024_name_4 = "TiB"
|
||||
)
|
||||
|
||||
func (i SizeB1024) String() string {
|
||||
switch {
|
||||
case i == 1:
|
||||
return _SizeB1024_name_0
|
||||
case i == 1024:
|
||||
return _SizeB1024_name_1
|
||||
case i == 1048576:
|
||||
return _SizeB1024_name_2
|
||||
case i == 1073741824:
|
||||
return _SizeB1024_name_3
|
||||
case i == 1099511627776:
|
||||
return _SizeB1024_name_4
|
||||
default:
|
||||
return "SizeB1024(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
}
|
||||
179
vendor/github.com/vbauerster/mpb/v8/decor/speed.go
generated
vendored
Normal file
179
vendor/github.com/vbauerster/mpb/v8/decor/speed.go
generated
vendored
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
package decor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"github.com/VividCortex/ewma"
|
||||
)
|
||||
|
||||
var (
|
||||
_ Decorator = (*movingAverageSpeed)(nil)
|
||||
_ EwmaDecorator = (*movingAverageSpeed)(nil)
|
||||
_ Decorator = (*averageSpeed)(nil)
|
||||
_ AverageDecorator = (*averageSpeed)(nil)
|
||||
)
|
||||
|
||||
// FmtAsSpeed adds "/s" to the end of the input formatter. To be
|
||||
// used with SizeB1000 or SizeB1024 types, for example:
|
||||
//
|
||||
// fmt.Printf("%.1f", FmtAsSpeed(SizeB1024(2048)))
|
||||
func FmtAsSpeed(input fmt.Formatter) fmt.Formatter {
|
||||
return speedFormatter{input}
|
||||
}
|
||||
|
||||
type speedFormatter struct {
|
||||
fmt.Formatter
|
||||
}
|
||||
|
||||
func (self speedFormatter) Format(st fmt.State, verb rune) {
|
||||
self.Formatter.Format(st, verb)
|
||||
_, err := io.WriteString(st, "/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 one of the (*Bar).EwmaIncr... family methods.
|
||||
func EwmaSpeed(unit interface{}, format string, age float64, wcc ...WC) Decorator {
|
||||
var average ewma.MovingAverage
|
||||
if age == 0 {
|
||||
average = ewma.NewMovingAverage()
|
||||
} else {
|
||||
average = ewma.NewMovingAverage(age)
|
||||
}
|
||||
return MovingAverageSpeed(unit, format, NewThreadSafeMovingAverage(average), wcc...)
|
||||
}
|
||||
|
||||
// MovingAverageSpeed decorator relies on MovingAverage implementation
|
||||
// to calculate its average.
|
||||
//
|
||||
// `unit` one of [0|SizeB1024(0)|SizeB1000(0)]
|
||||
//
|
||||
// `format` printf compatible verb for value, like "%f" or "%d"
|
||||
//
|
||||
// `average` MovingAverage implementation
|
||||
//
|
||||
// `wcc` optional WC config
|
||||
//
|
||||
// format examples:
|
||||
//
|
||||
// unit=SizeB1024(0), format="%.1f" output: "1.0MiB/s"
|
||||
// unit=SizeB1024(0), format="% .1f" output: "1.0 MiB/s"
|
||||
// unit=SizeB1000(0), format="%.1f" output: "1.0MB/s"
|
||||
// unit=SizeB1000(0), format="% .1f" output: "1.0 MB/s"
|
||||
func MovingAverageSpeed(unit interface{}, format string, average ewma.MovingAverage, wcc ...WC) Decorator {
|
||||
d := &movingAverageSpeed{
|
||||
WC: initWC(wcc...),
|
||||
average: average,
|
||||
producer: chooseSpeedProducer(unit, format),
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
type movingAverageSpeed struct {
|
||||
WC
|
||||
producer func(float64) string
|
||||
average ewma.MovingAverage
|
||||
msg string
|
||||
}
|
||||
|
||||
func (d *movingAverageSpeed) Decor(s Statistics) string {
|
||||
if !s.Completed {
|
||||
var speed float64
|
||||
if v := d.average.Value(); v > 0 {
|
||||
speed = 1 / v
|
||||
}
|
||||
d.msg = d.producer(speed * 1e9)
|
||||
}
|
||||
return d.FormatMsg(d.msg)
|
||||
}
|
||||
|
||||
func (d *movingAverageSpeed) EwmaUpdate(n int64, dur time.Duration) {
|
||||
durPerByte := float64(dur) / float64(n)
|
||||
if math.IsInf(durPerByte, 0) || math.IsNaN(durPerByte) {
|
||||
return
|
||||
}
|
||||
d.average.Add(durPerByte)
|
||||
}
|
||||
|
||||
// AverageSpeed decorator with dynamic unit measure adjustment. It's
|
||||
// a wrapper of NewAverageSpeed.
|
||||
func AverageSpeed(unit interface{}, format string, wcc ...WC) Decorator {
|
||||
return NewAverageSpeed(unit, format, time.Now(), wcc...)
|
||||
}
|
||||
|
||||
// NewAverageSpeed decorator with dynamic unit measure adjustment and
|
||||
// user provided start time.
|
||||
//
|
||||
// `unit` one of [0|SizeB1024(0)|SizeB1000(0)]
|
||||
//
|
||||
// `format` printf compatible verb for value, like "%f" or "%d"
|
||||
//
|
||||
// `startTime` start time
|
||||
//
|
||||
// `wcc` optional WC config
|
||||
//
|
||||
// format examples:
|
||||
//
|
||||
// unit=SizeB1024(0), format="%.1f" output: "1.0MiB/s"
|
||||
// unit=SizeB1024(0), format="% .1f" output: "1.0 MiB/s"
|
||||
// unit=SizeB1000(0), format="%.1f" output: "1.0MB/s"
|
||||
// unit=SizeB1000(0), format="% .1f" output: "1.0 MB/s"
|
||||
func NewAverageSpeed(unit interface{}, format string, startTime time.Time, wcc ...WC) Decorator {
|
||||
d := &averageSpeed{
|
||||
WC: initWC(wcc...),
|
||||
startTime: startTime,
|
||||
producer: chooseSpeedProducer(unit, format),
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
type averageSpeed struct {
|
||||
WC
|
||||
startTime time.Time
|
||||
producer func(float64) string
|
||||
msg string
|
||||
}
|
||||
|
||||
func (d *averageSpeed) Decor(s Statistics) string {
|
||||
if !s.Completed {
|
||||
speed := float64(s.Current) / float64(time.Since(d.startTime))
|
||||
d.msg = d.producer(speed * 1e9)
|
||||
}
|
||||
return d.FormatMsg(d.msg)
|
||||
}
|
||||
|
||||
func (d *averageSpeed) AverageAdjust(startTime time.Time) {
|
||||
d.startTime = startTime
|
||||
}
|
||||
|
||||
func chooseSpeedProducer(unit interface{}, format string) func(float64) string {
|
||||
switch unit.(type) {
|
||||
case SizeB1024:
|
||||
if format == "" {
|
||||
format = "% d"
|
||||
}
|
||||
return func(speed float64) string {
|
||||
return fmt.Sprintf(format, FmtAsSpeed(SizeB1024(math.Round(speed))))
|
||||
}
|
||||
case SizeB1000:
|
||||
if format == "" {
|
||||
format = "% d"
|
||||
}
|
||||
return func(speed float64) string {
|
||||
return fmt.Sprintf(format, FmtAsSpeed(SizeB1000(math.Round(speed))))
|
||||
}
|
||||
default:
|
||||
if format == "" {
|
||||
format = "%f"
|
||||
}
|
||||
return func(speed float64) string {
|
||||
return fmt.Sprintf(format, speed)
|
||||
}
|
||||
}
|
||||
}
|
||||
21
vendor/github.com/vbauerster/mpb/v8/decor/spinner.go
generated
vendored
Normal file
21
vendor/github.com/vbauerster/mpb/v8/decor/spinner.go
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
package decor
|
||||
|
||||
var defaultSpinnerStyle = []string{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"}
|
||||
|
||||
// Spinner returns spinner decorator.
|
||||
//
|
||||
// `frames` spinner frames, if nil or len==0, default is used
|
||||
//
|
||||
// `wcc` optional WC config
|
||||
func Spinner(frames []string, wcc ...WC) Decorator {
|
||||
if len(frames) == 0 {
|
||||
frames = defaultSpinnerStyle
|
||||
}
|
||||
var count uint
|
||||
f := func(s Statistics) string {
|
||||
frame := frames[count%uint(len(frames))]
|
||||
count++
|
||||
return frame
|
||||
}
|
||||
return Any(f, wcc...)
|
||||
}
|
||||
2
vendor/github.com/vbauerster/mpb/v8/doc.go
generated
vendored
Normal file
2
vendor/github.com/vbauerster/mpb/v8/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
// Package mpb is a library for rendering progress bars in terminal applications.
|
||||
package mpb
|
||||
174
vendor/github.com/vbauerster/mpb/v8/heap_manager.go
generated
vendored
Normal file
174
vendor/github.com/vbauerster/mpb/v8/heap_manager.go
generated
vendored
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
package mpb
|
||||
|
||||
import (
|
||||
"container/heap"
|
||||
)
|
||||
|
||||
type heapManager chan heapRequest
|
||||
|
||||
type heapCmd int
|
||||
|
||||
const (
|
||||
h_sync heapCmd = iota
|
||||
h_push
|
||||
h_iter
|
||||
h_drain
|
||||
h_fix
|
||||
h_state
|
||||
h_end
|
||||
)
|
||||
|
||||
type heapRequest struct {
|
||||
cmd heapCmd
|
||||
data interface{}
|
||||
}
|
||||
|
||||
type iterData struct {
|
||||
iter chan<- *Bar
|
||||
drop <-chan struct{}
|
||||
}
|
||||
|
||||
type pushData struct {
|
||||
bar *Bar
|
||||
sync bool
|
||||
}
|
||||
|
||||
type fixData struct {
|
||||
bar *Bar
|
||||
priority int
|
||||
}
|
||||
|
||||
func (m heapManager) run() {
|
||||
var bHeap priorityQueue
|
||||
var pMatrix, aMatrix map[int][]chan int
|
||||
|
||||
var l int
|
||||
var sync bool
|
||||
|
||||
for req := range m {
|
||||
next:
|
||||
switch req.cmd {
|
||||
case h_push:
|
||||
data := req.data.(pushData)
|
||||
heap.Push(&bHeap, data.bar)
|
||||
if !sync {
|
||||
sync = data.sync
|
||||
}
|
||||
case h_sync:
|
||||
if sync || l != bHeap.Len() {
|
||||
pMatrix = make(map[int][]chan int)
|
||||
aMatrix = make(map[int][]chan int)
|
||||
for _, b := range bHeap {
|
||||
table := b.wSyncTable()
|
||||
for i, ch := range table[0] {
|
||||
pMatrix[i] = append(pMatrix[i], ch)
|
||||
}
|
||||
for i, ch := range table[1] {
|
||||
aMatrix[i] = append(aMatrix[i], ch)
|
||||
}
|
||||
}
|
||||
sync = false
|
||||
l = bHeap.Len()
|
||||
}
|
||||
drop := req.data.(<-chan struct{})
|
||||
syncWidth(pMatrix, drop)
|
||||
syncWidth(aMatrix, drop)
|
||||
case h_iter:
|
||||
data := req.data.(iterData)
|
||||
for _, b := range bHeap {
|
||||
select {
|
||||
case data.iter <- b:
|
||||
case <-data.drop:
|
||||
close(data.iter)
|
||||
break next
|
||||
}
|
||||
}
|
||||
close(data.iter)
|
||||
case h_drain:
|
||||
data := req.data.(iterData)
|
||||
for bHeap.Len() != 0 {
|
||||
select {
|
||||
case data.iter <- heap.Pop(&bHeap).(*Bar):
|
||||
case <-data.drop:
|
||||
close(data.iter)
|
||||
break next
|
||||
}
|
||||
}
|
||||
close(data.iter)
|
||||
case h_fix:
|
||||
data := req.data.(fixData)
|
||||
bar, priority := data.bar, data.priority
|
||||
if bar.index < 0 {
|
||||
break
|
||||
}
|
||||
bar.priority = priority
|
||||
heap.Fix(&bHeap, bar.index)
|
||||
case h_state:
|
||||
ch := req.data.(chan<- bool)
|
||||
ch <- sync || l != bHeap.Len()
|
||||
case h_end:
|
||||
ch := req.data.(chan<- interface{})
|
||||
if ch != nil {
|
||||
go func() {
|
||||
ch <- []*Bar(bHeap)
|
||||
}()
|
||||
}
|
||||
close(m)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m heapManager) sync(drop <-chan struct{}) {
|
||||
m <- heapRequest{cmd: h_sync, data: drop}
|
||||
}
|
||||
|
||||
func (m heapManager) push(b *Bar, sync bool) {
|
||||
data := pushData{b, sync}
|
||||
m <- heapRequest{cmd: h_push, data: data}
|
||||
}
|
||||
|
||||
func (m heapManager) iter(iter chan<- *Bar, drop <-chan struct{}) {
|
||||
data := iterData{iter, drop}
|
||||
m <- heapRequest{cmd: h_iter, data: data}
|
||||
}
|
||||
|
||||
func (m heapManager) drain(iter chan<- *Bar, drop <-chan struct{}) {
|
||||
data := iterData{iter, drop}
|
||||
m <- heapRequest{cmd: h_drain, data: data}
|
||||
}
|
||||
|
||||
func (m heapManager) fix(b *Bar, priority int) {
|
||||
data := fixData{b, priority}
|
||||
m <- heapRequest{cmd: h_fix, data: data}
|
||||
}
|
||||
|
||||
func (m heapManager) state(ch chan<- bool) {
|
||||
m <- heapRequest{cmd: h_state, data: ch}
|
||||
}
|
||||
|
||||
func (m heapManager) end(ch chan<- interface{}) {
|
||||
m <- heapRequest{cmd: h_end, data: ch}
|
||||
}
|
||||
|
||||
func syncWidth(matrix map[int][]chan int, drop <-chan struct{}) {
|
||||
for _, column := range matrix {
|
||||
go maxWidthDistributor(column, drop)
|
||||
}
|
||||
}
|
||||
|
||||
func maxWidthDistributor(column []chan int, drop <-chan struct{}) {
|
||||
var maxWidth int
|
||||
for _, ch := range column {
|
||||
select {
|
||||
case w := <-ch:
|
||||
if w > maxWidth {
|
||||
maxWidth = w
|
||||
}
|
||||
case <-drop:
|
||||
return
|
||||
}
|
||||
}
|
||||
for _, ch := range column {
|
||||
ch <- maxWidth
|
||||
}
|
||||
}
|
||||
19
vendor/github.com/vbauerster/mpb/v8/internal/percentage.go
generated
vendored
Normal file
19
vendor/github.com/vbauerster/mpb/v8/internal/percentage.go
generated
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
package internal
|
||||
|
||||
import "math"
|
||||
|
||||
// Percentage is a helper function, to calculate percentage.
|
||||
func Percentage(total, current int64, width uint) float64 {
|
||||
if total <= 0 {
|
||||
return 0
|
||||
}
|
||||
if current >= total {
|
||||
return float64(width)
|
||||
}
|
||||
return float64(int64(width)*current) / float64(total)
|
||||
}
|
||||
|
||||
// PercentageRound same as Percentage but with math.Round.
|
||||
func PercentageRound(total, current int64, width uint) float64 {
|
||||
return math.Round(Percentage(total, current, width))
|
||||
}
|
||||
10
vendor/github.com/vbauerster/mpb/v8/internal/width.go
generated
vendored
Normal file
10
vendor/github.com/vbauerster/mpb/v8/internal/width.go
generated
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
package internal
|
||||
|
||||
// CheckRequestedWidth checks that requested width doesn't overflow
|
||||
// available width
|
||||
func CheckRequestedWidth(requested, available int) int {
|
||||
if requested < 1 || requested >= available {
|
||||
return available
|
||||
}
|
||||
return requested
|
||||
}
|
||||
36
vendor/github.com/vbauerster/mpb/v8/priority_queue.go
generated
vendored
Normal file
36
vendor/github.com/vbauerster/mpb/v8/priority_queue.go
generated
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
package mpb
|
||||
|
||||
import "container/heap"
|
||||
|
||||
var _ heap.Interface = (*priorityQueue)(nil)
|
||||
|
||||
type priorityQueue []*Bar
|
||||
|
||||
func (pq priorityQueue) Len() int { return len(pq) }
|
||||
|
||||
func (pq priorityQueue) Less(i, j int) bool {
|
||||
// greater priority pops first
|
||||
return pq[i].priority > pq[j].priority
|
||||
}
|
||||
|
||||
func (pq priorityQueue) Swap(i, j int) {
|
||||
pq[i], pq[j] = pq[j], pq[i]
|
||||
pq[i].index = i
|
||||
pq[j].index = j
|
||||
}
|
||||
|
||||
func (pq *priorityQueue) Push(x interface{}) {
|
||||
s := *pq
|
||||
bar := x.(*Bar)
|
||||
bar.index = len(s)
|
||||
s = append(s, bar)
|
||||
*pq = s
|
||||
}
|
||||
|
||||
func (pq *priorityQueue) Pop() interface{} {
|
||||
s := *pq
|
||||
*pq = s[0 : len(s)-1]
|
||||
bar := s[len(s)-1]
|
||||
bar.index = -1 // for safety
|
||||
return bar
|
||||
}
|
||||
451
vendor/github.com/vbauerster/mpb/v8/progress.go
generated
vendored
Normal file
451
vendor/github.com/vbauerster/mpb/v8/progress.go
generated
vendored
Normal file
|
|
@ -0,0 +1,451 @@
|
|||
package mpb
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/vbauerster/mpb/v8/cwriter"
|
||||
"github.com/vbauerster/mpb/v8/decor"
|
||||
)
|
||||
|
||||
const (
|
||||
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 {
|
||||
uwg *sync.WaitGroup
|
||||
pwg, bwg sync.WaitGroup
|
||||
operateState chan func(*pState)
|
||||
interceptIO chan func(io.Writer)
|
||||
done <-chan struct{}
|
||||
cancel func()
|
||||
}
|
||||
|
||||
// pState holds bars in its priorityQueue, it gets passed to (*Progress).serve monitor goroutine.
|
||||
type pState struct {
|
||||
ctx context.Context
|
||||
hm heapManager
|
||||
dropS, dropD chan struct{}
|
||||
renderReq chan time.Time
|
||||
idCount int
|
||||
popPriority int
|
||||
|
||||
// following are provided/overrided by user
|
||||
refreshRate time.Duration
|
||||
reqWidth int
|
||||
popCompleted bool
|
||||
autoRefresh bool
|
||||
delayRC <-chan struct{}
|
||||
manualRC <-chan interface{}
|
||||
shutdownNotifier chan<- interface{}
|
||||
queueBars map[*Bar]*Bar
|
||||
output io.Writer
|
||||
debugOut io.Writer
|
||||
uwg *sync.WaitGroup
|
||||
}
|
||||
|
||||
// New creates new Progress container instance. It's not possible to
|
||||
// reuse instance after (*Progress).Wait method has been called.
|
||||
func New(options ...ContainerOption) *Progress {
|
||||
return NewWithContext(context.Background(), options...)
|
||||
}
|
||||
|
||||
// NewWithContext creates new Progress container instance with provided
|
||||
// context. It's not possible to reuse instance after (*Progress).Wait
|
||||
// method has been called.
|
||||
func NewWithContext(ctx context.Context, options ...ContainerOption) *Progress {
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
}
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
s := &pState{
|
||||
ctx: ctx,
|
||||
hm: make(heapManager),
|
||||
dropS: make(chan struct{}),
|
||||
dropD: make(chan struct{}),
|
||||
renderReq: make(chan time.Time),
|
||||
refreshRate: defaultRefreshRate,
|
||||
popPriority: math.MinInt32,
|
||||
queueBars: make(map[*Bar]*Bar),
|
||||
output: os.Stdout,
|
||||
debugOut: io.Discard,
|
||||
}
|
||||
|
||||
for _, opt := range options {
|
||||
if opt != nil {
|
||||
opt(s)
|
||||
}
|
||||
}
|
||||
|
||||
p := &Progress{
|
||||
uwg: s.uwg,
|
||||
operateState: make(chan func(*pState)),
|
||||
interceptIO: make(chan func(io.Writer)),
|
||||
cancel: cancel,
|
||||
}
|
||||
|
||||
cw := cwriter.New(s.output)
|
||||
if s.manualRC != nil {
|
||||
done := make(chan struct{})
|
||||
p.done = done
|
||||
s.autoRefresh = false
|
||||
go s.manualRefreshListener(done)
|
||||
} else if cw.IsTerminal() || s.autoRefresh {
|
||||
done := make(chan struct{})
|
||||
p.done = done
|
||||
s.autoRefresh = true
|
||||
go s.autoRefreshListener(done)
|
||||
} else {
|
||||
p.done = ctx.Done()
|
||||
s.autoRefresh = false
|
||||
}
|
||||
|
||||
p.pwg.Add(1)
|
||||
go p.serve(s, cw)
|
||||
go s.hm.run()
|
||||
return p
|
||||
}
|
||||
|
||||
// AddBar creates a bar with default bar filler.
|
||||
func (p *Progress) AddBar(total int64, options ...BarOption) *Bar {
|
||||
return p.New(total, BarStyle(), options...)
|
||||
}
|
||||
|
||||
// AddSpinner creates a bar with default spinner filler.
|
||||
func (p *Progress) AddSpinner(total int64, options ...BarOption) *Bar {
|
||||
return p.New(total, SpinnerStyle(), options...)
|
||||
}
|
||||
|
||||
// New creates a bar by calling `Build` method on provided `BarFillerBuilder`.
|
||||
func (p *Progress) New(total int64, builder BarFillerBuilder, options ...BarOption) *Bar {
|
||||
return p.MustAdd(total, builder.Build(), options...)
|
||||
}
|
||||
|
||||
// MustAdd creates a bar which renders itself by provided BarFiller.
|
||||
// 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) MustAdd(total int64, filler BarFiller, options ...BarOption) *Bar {
|
||||
bar, err := p.Add(total, filler, options...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return bar
|
||||
}
|
||||
|
||||
// Add creates a bar which renders itself by provided BarFiller.
|
||||
// If `total <= 0` triggering complete event by increment methods
|
||||
// is disabled. If *Progress instance is done, i.e. called after
|
||||
// (*Progress).Wait(), return error == DoneError.
|
||||
func (p *Progress) Add(total int64, filler BarFiller, options ...BarOption) (*Bar, error) {
|
||||
if filler == nil {
|
||||
filler = NopStyle().Build()
|
||||
}
|
||||
type result struct {
|
||||
bar *Bar
|
||||
bs *bState
|
||||
}
|
||||
ch := make(chan result)
|
||||
select {
|
||||
case p.operateState <- func(ps *pState) {
|
||||
bs := ps.makeBarState(total, filler, options...)
|
||||
bar := newBar(ps.ctx, p, bs)
|
||||
if bs.waitBar != nil {
|
||||
ps.queueBars[bs.waitBar] = bar
|
||||
} else {
|
||||
ps.hm.push(bar, true)
|
||||
}
|
||||
ps.idCount++
|
||||
ch <- result{bar, bs}
|
||||
}:
|
||||
res := <-ch
|
||||
bar, bs := res.bar, res.bs
|
||||
bar.TraverseDecorators(func(d decor.Decorator) {
|
||||
if d, ok := d.(decor.AverageDecorator); ok {
|
||||
bs.averageDecorators = append(bs.averageDecorators, d)
|
||||
}
|
||||
if d, ok := d.(decor.EwmaDecorator); ok {
|
||||
bs.ewmaDecorators = append(bs.ewmaDecorators, d)
|
||||
}
|
||||
if d, ok := d.(decor.ShutdownListener); ok {
|
||||
bs.shutdownListeners = append(bs.shutdownListeners, d)
|
||||
}
|
||||
})
|
||||
return bar, nil
|
||||
case <-p.done:
|
||||
return nil, DoneError
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Progress) traverseBars(cb func(b *Bar) bool) {
|
||||
iter, drop := make(chan *Bar), make(chan struct{})
|
||||
select {
|
||||
case p.operateState <- func(s *pState) { s.hm.iter(iter, drop) }:
|
||||
for b := range iter {
|
||||
if cb(b) {
|
||||
close(drop)
|
||||
break
|
||||
}
|
||||
}
|
||||
case <-p.done:
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateBarPriority same as *Bar.SetPriority(int).
|
||||
func (p *Progress) UpdateBarPriority(b *Bar, priority int) {
|
||||
select {
|
||||
case p.operateState <- func(s *pState) { s.hm.fix(b, priority) }:
|
||||
case <-p.done:
|
||||
}
|
||||
}
|
||||
|
||||
// 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()
|
||||
}
|
||||
|
||||
p.bwg.Wait()
|
||||
p.Shutdown()
|
||||
}
|
||||
|
||||
// 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.pwg.Wait()
|
||||
}
|
||||
|
||||
func (p *Progress) serve(s *pState, cw *cwriter.Writer) {
|
||||
defer p.pwg.Done()
|
||||
render := func() error { return s.render(cw) }
|
||||
var err error
|
||||
|
||||
for {
|
||||
select {
|
||||
case op := <-p.operateState:
|
||||
op(s)
|
||||
case fn := <-p.interceptIO:
|
||||
fn(cw)
|
||||
case <-s.renderReq:
|
||||
e := render()
|
||||
if e != nil {
|
||||
p.cancel() // cancel all bars
|
||||
render = func() error { return nil }
|
||||
err = e
|
||||
}
|
||||
case <-p.done:
|
||||
update := make(chan bool)
|
||||
for s.autoRefresh && err == nil {
|
||||
s.hm.state(update)
|
||||
if <-update {
|
||||
err = render()
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
_, _ = fmt.Fprintln(s.debugOut, err.Error())
|
||||
}
|
||||
s.hm.end(s.shutdownNotifier)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s pState) autoRefreshListener(done chan struct{}) {
|
||||
if s.delayRC != nil {
|
||||
<-s.delayRC
|
||||
}
|
||||
ticker := time.NewTicker(s.refreshRate)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case t := <-ticker.C:
|
||||
s.renderReq <- t
|
||||
case <-s.ctx.Done():
|
||||
close(done)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s pState) manualRefreshListener(done chan struct{}) {
|
||||
for {
|
||||
select {
|
||||
case x := <-s.manualRC:
|
||||
if t, ok := x.(time.Time); ok {
|
||||
s.renderReq <- t
|
||||
} else {
|
||||
s.renderReq <- time.Now()
|
||||
}
|
||||
case <-s.ctx.Done():
|
||||
close(done)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *pState) render(cw *cwriter.Writer) (err error) {
|
||||
s.hm.sync(s.dropS)
|
||||
iter := make(chan *Bar)
|
||||
go s.hm.iter(iter, s.dropS)
|
||||
|
||||
var width, height int
|
||||
if cw.IsTerminal() {
|
||||
width, height, err = cw.GetTermSize()
|
||||
if err != nil {
|
||||
close(s.dropS)
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if s.reqWidth > 0 {
|
||||
width = s.reqWidth
|
||||
} else {
|
||||
width = 100
|
||||
}
|
||||
height = 100
|
||||
}
|
||||
|
||||
for b := range iter {
|
||||
go b.render(width)
|
||||
}
|
||||
|
||||
return s.flush(cw, height)
|
||||
}
|
||||
|
||||
func (s *pState) flush(cw *cwriter.Writer, height int) error {
|
||||
var wg sync.WaitGroup
|
||||
defer wg.Wait() // waiting for all s.hm.push to complete
|
||||
|
||||
var popCount int
|
||||
var rows []io.Reader
|
||||
|
||||
iter := make(chan *Bar)
|
||||
s.hm.drain(iter, s.dropD)
|
||||
|
||||
for b := range iter {
|
||||
frame := <-b.frameCh
|
||||
if frame.err != nil {
|
||||
close(s.dropD)
|
||||
b.cancel()
|
||||
return frame.err // b.frameCh is buffered it's ok to return here
|
||||
}
|
||||
var usedRows int
|
||||
for i := len(frame.rows) - 1; i >= 0; i-- {
|
||||
if row := frame.rows[i]; len(rows) < height {
|
||||
rows = append(rows, row)
|
||||
usedRows++
|
||||
} else {
|
||||
_, _ = io.Copy(io.Discard, row)
|
||||
}
|
||||
}
|
||||
if frame.shutdown != 0 && !frame.done {
|
||||
if qb, ok := s.queueBars[b]; ok {
|
||||
b.cancel()
|
||||
delete(s.queueBars, b)
|
||||
qb.priority = b.priority
|
||||
wg.Add(1)
|
||||
go func(b *Bar) {
|
||||
s.hm.push(b, true)
|
||||
wg.Done()
|
||||
}(qb)
|
||||
continue
|
||||
}
|
||||
if s.popCompleted && !frame.noPop {
|
||||
switch frame.shutdown {
|
||||
case 1:
|
||||
b.priority = s.popPriority
|
||||
s.popPriority++
|
||||
default:
|
||||
b.cancel()
|
||||
popCount += usedRows
|
||||
continue
|
||||
}
|
||||
} else if frame.rmOnComplete {
|
||||
b.cancel()
|
||||
continue
|
||||
} else {
|
||||
b.cancel()
|
||||
}
|
||||
}
|
||||
wg.Add(1)
|
||||
go func(b *Bar) {
|
||||
s.hm.push(b, false)
|
||||
wg.Done()
|
||||
}(b)
|
||||
}
|
||||
|
||||
for i := len(rows) - 1; i >= 0; i-- {
|
||||
_, err := cw.ReadFrom(rows[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return cw.Flush(len(rows) - popCount)
|
||||
}
|
||||
|
||||
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,
|
||||
renderReq: s.renderReq,
|
||||
autoRefresh: s.autoRefresh,
|
||||
}
|
||||
|
||||
if total > 0 {
|
||||
bs.triggerComplete = true
|
||||
}
|
||||
|
||||
for _, opt := range options {
|
||||
if opt != nil {
|
||||
opt(bs)
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < len(bs.buffers); i++ {
|
||||
bs.buffers[i] = bytes.NewBuffer(make([]byte, 0, 512))
|
||||
}
|
||||
|
||||
return bs
|
||||
}
|
||||
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)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue