|
|
|
@ -11,6 +11,12 @@ import ( |
|
|
|
"golang.org/x/term" |
|
|
|
) |
|
|
|
|
|
|
|
type Stats struct { |
|
|
|
rate int64 |
|
|
|
value int64 |
|
|
|
remaining time.Duration |
|
|
|
} |
|
|
|
|
|
|
|
type Bar struct { |
|
|
|
message string |
|
|
|
messageWidth int |
|
|
|
@ -20,7 +26,9 @@ type Bar struct { |
|
|
|
currentValue int64 |
|
|
|
|
|
|
|
started time.Time |
|
|
|
stopped time.Time |
|
|
|
|
|
|
|
stats Stats |
|
|
|
statted time.Time |
|
|
|
} |
|
|
|
|
|
|
|
func NewBar(message string, maxValue, initialValue int64) *Bar { |
|
|
|
@ -57,12 +65,22 @@ func (b *Bar) String() string { |
|
|
|
} |
|
|
|
|
|
|
|
fmt.Fprintf(&pre, "%3.0f%% ", math.Floor(b.percent())) |
|
|
|
fmt.Fprintf(&suf, "(%s/%s", format.HumanBytes(b.currentValue), format.HumanBytes(b.maxValue)) |
|
|
|
|
|
|
|
fmt.Fprintf(&suf, "(%s/%s, %s/s, %s)", |
|
|
|
format.HumanBytes(b.currentValue), |
|
|
|
format.HumanBytes(b.maxValue), |
|
|
|
format.HumanBytes(int64(b.rate())), |
|
|
|
b.elapsed()) |
|
|
|
stats := b.Stats() |
|
|
|
rate := int64(stats.rate) |
|
|
|
if rate > 0 { |
|
|
|
fmt.Fprintf(&suf, ", %s/s", format.HumanBytes(rate)) |
|
|
|
} |
|
|
|
|
|
|
|
fmt.Fprintf(&suf, ")") |
|
|
|
|
|
|
|
elapsed := time.Since(b.started) |
|
|
|
if b.percent() < 100 && rate > 0 { |
|
|
|
fmt.Fprintf(&suf, " [%s:%s]", elapsed.Round(time.Second), stats.remaining) |
|
|
|
} else { |
|
|
|
fmt.Fprintf(&suf, " ") |
|
|
|
} |
|
|
|
|
|
|
|
mid.WriteString("▕") |
|
|
|
|
|
|
|
@ -86,7 +104,6 @@ func (b *Bar) String() string { |
|
|
|
func (b *Bar) Set(value int64) { |
|
|
|
if value >= b.maxValue { |
|
|
|
value = b.maxValue |
|
|
|
b.stopped = time.Now() |
|
|
|
} |
|
|
|
|
|
|
|
b.currentValue = value |
|
|
|
@ -100,20 +117,32 @@ func (b *Bar) percent() float64 { |
|
|
|
return 0 |
|
|
|
} |
|
|
|
|
|
|
|
func (b *Bar) rate() float64 { |
|
|
|
elapsed := b.elapsed() |
|
|
|
if elapsed.Seconds() > 0 { |
|
|
|
return (float64(b.currentValue) - float64(b.initialValue)) / elapsed.Seconds() |
|
|
|
func (b *Bar) Stats() Stats { |
|
|
|
if time.Since(b.statted) < time.Second || b.currentValue >= b.maxValue { |
|
|
|
return b.stats |
|
|
|
} |
|
|
|
|
|
|
|
return 0 |
|
|
|
} |
|
|
|
if b.statted.IsZero() { |
|
|
|
b.stats = Stats{ |
|
|
|
value: b.initialValue, |
|
|
|
rate: 0, |
|
|
|
remaining: 0, |
|
|
|
} |
|
|
|
} else { |
|
|
|
rate := b.currentValue - b.stats.value |
|
|
|
var remaining time.Duration |
|
|
|
if rate > 0 { |
|
|
|
remaining = time.Second * time.Duration((float64(b.maxValue-b.currentValue))/(float64(rate))) |
|
|
|
} |
|
|
|
|
|
|
|
func (b *Bar) elapsed() time.Duration { |
|
|
|
stopped := b.stopped |
|
|
|
if stopped.IsZero() { |
|
|
|
stopped = time.Now() |
|
|
|
b.stats = Stats{ |
|
|
|
value: b.currentValue, |
|
|
|
rate: rate, |
|
|
|
remaining: remaining, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return stopped.Sub(b.started).Round(time.Second) |
|
|
|
b.statted = time.Now() |
|
|
|
|
|
|
|
return b.stats |
|
|
|
} |
|
|
|
|