vendor: upgrade "gopkg.in/cheggaaa/pb.v1"

Signed-off-by: Gyuho Lee <gyuhox@gmail.com>
This commit is contained in:
Gyuho Lee 2018-06-13 10:17:44 -07:00
parent 7e5770fa40
commit f9084d5d69
14 changed files with 361 additions and 203 deletions

4
Gopkg.lock generated
View File

@ -358,8 +358,8 @@
[[projects]]
name = "gopkg.in/cheggaaa/pb.v1"
packages = ["."]
revision = "226d21d43a305fac52b3a104ef83e721b15275e0"
version = "v1.0.2"
revision = "2af8bbdea9e99e83b3ac400d8f6b6d1b8cbbf338"
version = "v1.0.25"
[[projects]]
name = "gopkg.in/yaml.v2"

View File

@ -2,7 +2,6 @@ package pb
import (
"fmt"
"strings"
"time"
)
@ -11,12 +10,26 @@ type Units int
const (
// U_NO are default units, they represent a simple value and are not formatted at all.
U_NO Units = iota
// U_BYTES units are formatted in a human readable way (b, Bb, Mb, ...)
// U_BYTES units are formatted in a human readable way (B, KiB, MiB, ...)
U_BYTES
// U_BYTES_DEC units are like U_BYTES, but base 10 (B, KB, MB, ...)
U_BYTES_DEC
// U_DURATION units are formatted in a human readable way (3h14m15s)
U_DURATION
)
const (
KiB = 1024
MiB = 1048576
GiB = 1073741824
TiB = 1099511627776
KB = 1e3
MB = 1e6
GB = 1e9
TB = 1e12
)
func Format(i int64) *formatter {
return &formatter{n: i}
}
@ -28,11 +41,6 @@ type formatter struct {
perSec bool
}
func (f *formatter) Value(n int64) *formatter {
f.n = n
return f
}
func (f *formatter) To(unit Units) *formatter {
f.unit = unit
return f
@ -52,13 +60,10 @@ func (f *formatter) String() (out string) {
switch f.unit {
case U_BYTES:
out = formatBytes(f.n)
case U_BYTES_DEC:
out = formatBytesDec(f.n)
case U_DURATION:
d := time.Duration(f.n)
if d > time.Hour*24 {
out = fmt.Sprintf("%dd", d/24/time.Hour)
d -= (d / time.Hour / 24) * (time.Hour * 24)
}
out = fmt.Sprintf("%s%v", out, d)
out = formatDuration(f.n)
default:
out = fmt.Sprintf(fmt.Sprintf("%%%dd", f.width), f.n)
}
@ -68,20 +73,53 @@ func (f *formatter) String() (out string) {
return
}
// Convert bytes to human readable string. Like a 2 MB, 64.2 KB, 52 B
// Convert bytes to human readable string. Like 2 MiB, 64.2 KiB, 52 B
func formatBytes(i int64) (result string) {
switch {
case i > (1024 * 1024 * 1024 * 1024):
result = fmt.Sprintf("%.02f TB", float64(i)/1024/1024/1024/1024)
case i > (1024 * 1024 * 1024):
result = fmt.Sprintf("%.02f GB", float64(i)/1024/1024/1024)
case i > (1024 * 1024):
result = fmt.Sprintf("%.02f MB", float64(i)/1024/1024)
case i > 1024:
result = fmt.Sprintf("%.02f KB", float64(i)/1024)
case i >= TiB:
result = fmt.Sprintf("%.02f TiB", float64(i)/TiB)
case i >= GiB:
result = fmt.Sprintf("%.02f GiB", float64(i)/GiB)
case i >= MiB:
result = fmt.Sprintf("%.02f MiB", float64(i)/MiB)
case i >= KiB:
result = fmt.Sprintf("%.02f KiB", float64(i)/KiB)
default:
result = fmt.Sprintf("%d B", i)
}
result = strings.Trim(result, " ")
return
}
// Convert bytes to base-10 human readable string. Like 2 MB, 64.2 KB, 52 B
func formatBytesDec(i int64) (result string) {
switch {
case i >= TB:
result = fmt.Sprintf("%.02f TB", float64(i)/TB)
case i >= GB:
result = fmt.Sprintf("%.02f GB", float64(i)/GB)
case i >= MB:
result = fmt.Sprintf("%.02f MB", float64(i)/MB)
case i >= KB:
result = fmt.Sprintf("%.02f KB", float64(i)/KB)
default:
result = fmt.Sprintf("%d B", i)
}
return
}
func formatDuration(n int64) (result string) {
d := time.Duration(n)
if d > time.Hour*24 {
result = fmt.Sprintf("%dd", d/24/time.Hour)
d -= (d / time.Hour / 24) * (time.Hour * 24)
}
if d > time.Hour {
result = fmt.Sprintf("%s%dh", result, d/time.Hour)
d -= d / time.Hour * time.Hour
}
m := d / time.Minute
d -= m * time.Minute
s := d / time.Second
result = fmt.Sprintf("%s%02dm%02ds", result, m, s)
return
}

222
vendor/gopkg.in/cheggaaa/pb.v1/pb.go generated vendored
View File

@ -13,7 +13,7 @@ import (
)
// Current version
const Version = "1.0.2"
const Version = "1.0.25"
const (
// Default refresh rate - 200ms
@ -37,18 +37,17 @@ func New(total int) *ProgressBar {
// Create new progress bar object using int64 as total
func New64(total int64) *ProgressBar {
pb := &ProgressBar{
Total: total,
RefreshRate: DEFAULT_REFRESH_RATE,
ShowPercent: true,
ShowCounters: true,
ShowBar: true,
ShowTimeLeft: true,
ShowFinalTime: true,
Units: U_NO,
ManualUpdate: false,
finish: make(chan struct{}),
currentValue: -1,
mu: new(sync.Mutex),
Total: total,
RefreshRate: DEFAULT_REFRESH_RATE,
ShowPercent: true,
ShowCounters: true,
ShowBar: true,
ShowTimeLeft: true,
ShowElapsedTime: false,
ShowFinalTime: true,
Units: U_NO,
ManualUpdate: false,
finish: make(chan struct{}),
}
return pb.Format(FORMAT)
}
@ -67,13 +66,14 @@ func StartNew(total int) *ProgressBar {
type Callback func(out string)
type ProgressBar struct {
current int64 // current must be first member of struct (https://code.google.com/p/go/issues/detail?id=5278)
current int64 // current must be first member of struct (https://code.google.com/p/go/issues/detail?id=5278)
previous int64
Total int64
RefreshRate time.Duration
ShowPercent, ShowCounters bool
ShowSpeed, ShowTimeLeft, ShowBar bool
ShowFinalTime bool
ShowFinalTime, ShowElapsedTime bool
Output io.Writer
Callback Callback
NotPrint bool
@ -81,6 +81,7 @@ type ProgressBar struct {
Width int
ForceWidth bool
ManualUpdate bool
AutoStat bool
// Default width for the time box.
UnitsWidth int
@ -90,13 +91,14 @@ type ProgressBar struct {
finish chan struct{}
isFinish bool
startTime time.Time
startValue int64
currentValue int64
startTime time.Time
startValue int64
changeTime time.Time
prefix, postfix string
mu *sync.Mutex
mu sync.Mutex
lastPrint string
BarStart string
@ -111,10 +113,11 @@ type ProgressBar struct {
// Start print
func (pb *ProgressBar) Start() *ProgressBar {
pb.startTime = time.Now()
pb.startValue = pb.current
if pb.Total == 0 {
pb.startValue = atomic.LoadInt64(&pb.current)
if atomic.LoadInt64(&pb.Total) == 0 {
pb.ShowTimeLeft = false
pb.ShowPercent = false
pb.AutoStat = false
}
if !pb.ManualUpdate {
pb.Update() // Initial printing of the bar before running the bar refresher.
@ -128,6 +131,12 @@ func (pb *ProgressBar) Increment() int {
return pb.Add(1)
}
// Get current value
func (pb *ProgressBar) Get() int64 {
c := atomic.LoadInt64(&pb.current)
return c
}
// Set current value
func (pb *ProgressBar) Set(current int) *ProgressBar {
return pb.Set64(int64(current))
@ -165,7 +174,7 @@ func (pb *ProgressBar) Postfix(postfix string) *ProgressBar {
// Example: bar.Format("[\x00=\x00>\x00-\x00]") // \x00 is the delimiter
func (pb *ProgressBar) Format(format string) *ProgressBar {
var formatEntries []string
if len(format) == 5 {
if utf8.RuneCountInString(format) == 5 {
formatEntries = strings.Split(format, "")
} else {
formatEntries = strings.Split(format, "\x00")
@ -213,18 +222,34 @@ func (pb *ProgressBar) Finish() {
//Protect multiple calls
pb.finishOnce.Do(func() {
close(pb.finish)
pb.write(atomic.LoadInt64(&pb.current))
if !pb.NotPrint {
pb.write(atomic.LoadInt64(&pb.Total), atomic.LoadInt64(&pb.current))
pb.mu.Lock()
defer pb.mu.Unlock()
switch {
case pb.Output != nil:
fmt.Fprintln(pb.Output)
case !pb.NotPrint:
fmt.Println()
}
pb.isFinish = true
})
}
// IsFinished return boolean
func (pb *ProgressBar) IsFinished() bool {
pb.mu.Lock()
defer pb.mu.Unlock()
return pb.isFinish
}
// End print and write string 'str'
func (pb *ProgressBar) FinishPrint(str string) {
pb.Finish()
fmt.Println(str)
if pb.Output != nil {
fmt.Fprintln(pb.Output, str)
} else {
fmt.Println(str)
}
}
// implement io.Writer
@ -242,20 +267,21 @@ func (pb *ProgressBar) Read(p []byte) (n int, err error) {
}
// Create new proxy reader over bar
// Takes io.Reader or io.ReadCloser
func (pb *ProgressBar) NewProxyReader(r io.Reader) *Reader {
return &Reader{r, pb}
}
func (pb *ProgressBar) write(current int64) {
func (pb *ProgressBar) write(total, current int64) {
width := pb.GetWidth()
var percentBox, countersBox, timeLeftBox, speedBox, barBox, end, out string
var percentBox, countersBox, timeLeftBox, timeSpentBox, speedBox, barBox, end, out string
// percents
if pb.ShowPercent {
var percent float64
if pb.Total > 0 {
percent = float64(current) / (float64(pb.Total) / float64(100))
if total > 0 {
percent = float64(current) / (float64(total) / float64(100))
} else {
percent = float64(current) / float64(100)
}
@ -265,41 +291,49 @@ func (pb *ProgressBar) write(current int64) {
// counters
if pb.ShowCounters {
current := Format(current).To(pb.Units).Width(pb.UnitsWidth)
if pb.Total > 0 {
total := Format(pb.Total).To(pb.Units).Width(pb.UnitsWidth)
countersBox = fmt.Sprintf(" %s / %s ", current, total)
if total > 0 {
totalS := Format(total).To(pb.Units).Width(pb.UnitsWidth)
countersBox = fmt.Sprintf(" %s / %s ", current, totalS)
} else {
countersBox = fmt.Sprintf(" %s / ? ", current)
}
}
// time left
fromStart := time.Now().Sub(pb.startTime)
pb.mu.Lock()
currentFromStart := current - pb.startValue
fromStart := time.Now().Sub(pb.startTime)
lastChangeTime := pb.changeTime
fromChange := lastChangeTime.Sub(pb.startTime)
pb.mu.Unlock()
if pb.ShowElapsedTime {
timeSpentBox = fmt.Sprintf(" %s ", (fromStart/time.Second)*time.Second)
}
select {
case <-pb.finish:
if pb.ShowFinalTime {
var left time.Duration
if pb.Total > 0 {
left = (fromStart / time.Second) * time.Second
} else {
left = (time.Duration(currentFromStart) / time.Second) * time.Second
}
timeLeftBox = left.String()
left = (fromStart / time.Second) * time.Second
timeLeftBox = fmt.Sprintf(" %s", left.String())
}
default:
if pb.ShowTimeLeft && currentFromStart > 0 {
perEntry := fromStart / time.Duration(currentFromStart)
perEntry := fromChange / time.Duration(currentFromStart)
var left time.Duration
if pb.Total > 0 {
left = time.Duration(pb.Total-currentFromStart) * perEntry
if total > 0 {
left = time.Duration(total-currentFromStart) * perEntry
left -= time.Since(lastChangeTime)
left = (left / time.Second) * time.Second
} else {
left = time.Duration(currentFromStart) * perEntry
left = (left / time.Second) * time.Second
}
timeLeft := Format(int64(left)).To(U_DURATION).String()
timeLeftBox = fmt.Sprintf(" %s", timeLeft)
if left > 0 {
timeLeft := Format(int64(left)).To(U_DURATION).String()
timeLeftBox = fmt.Sprintf(" %s", timeLeft)
}
}
}
@ -314,30 +348,38 @@ func (pb *ProgressBar) write(current int64) {
speedBox = " " + Format(int64(speed)).To(pb.Units).Width(pb.UnitsWidth).PerSec().String()
}
barWidth := escapeAwareRuneCountInString(countersBox + pb.BarStart + pb.BarEnd + percentBox + timeLeftBox + speedBox + pb.prefix + pb.postfix)
barWidth := escapeAwareRuneCountInString(countersBox + pb.BarStart + pb.BarEnd + percentBox + timeSpentBox + timeLeftBox + speedBox + pb.prefix + pb.postfix)
// bar
if pb.ShowBar {
size := width - barWidth
if size > 0 {
if pb.Total > 0 {
curCount := int(math.Ceil((float64(current) / float64(pb.Total)) * float64(size)))
emptCount := size - curCount
if total > 0 {
curSize := int(math.Ceil((float64(current) / float64(total)) * float64(size)))
emptySize := size - curSize
barBox = pb.BarStart
if emptCount < 0 {
emptCount = 0
if emptySize < 0 {
emptySize = 0
}
if curCount > size {
curCount = size
if curSize > size {
curSize = size
}
if emptCount <= 0 {
barBox += strings.Repeat(pb.Current, curCount)
} else if curCount > 0 {
barBox += strings.Repeat(pb.Current, curCount-1) + pb.CurrentN
cursorLen := escapeAwareRuneCountInString(pb.Current)
if emptySize <= 0 {
barBox += strings.Repeat(pb.Current, curSize/cursorLen)
} else if curSize > 0 {
cursorEndLen := escapeAwareRuneCountInString(pb.CurrentN)
cursorRepetitions := (curSize - cursorEndLen) / cursorLen
barBox += strings.Repeat(pb.Current, cursorRepetitions)
barBox += pb.CurrentN
}
barBox += strings.Repeat(pb.Empty, emptCount) + pb.BarEnd
emptyLen := escapeAwareRuneCountInString(pb.Empty)
barBox += strings.Repeat(pb.Empty, emptySize/emptyLen)
barBox += pb.BarEnd
} else {
barBox = pb.BarStart
pos := size - int(current)%int(size)
barBox = pb.BarStart
if pos-1 > 0 {
barBox += strings.Repeat(pb.Empty, pos-1)
}
@ -351,17 +393,19 @@ func (pb *ProgressBar) write(current int64) {
}
// check len
out = pb.prefix + countersBox + barBox + percentBox + speedBox + timeLeftBox + pb.postfix
if escapeAwareRuneCountInString(out) < width {
end = strings.Repeat(" ", width-utf8.RuneCountInString(out))
out = pb.prefix + timeSpentBox + countersBox + barBox + percentBox + speedBox + timeLeftBox + pb.postfix
if cl := escapeAwareRuneCountInString(out); cl < width {
end = strings.Repeat(" ", width-cl)
}
// and print!
pb.mu.Lock()
defer pb.mu.Unlock()
pb.lastPrint = out + end
pb.mu.Unlock()
isFinish := pb.isFinish
switch {
case pb.isFinish:
case isFinish:
return
case pb.Output != nil:
fmt.Fprint(pb.Output, "\r"+out+end)
@ -394,16 +438,55 @@ func (pb *ProgressBar) GetWidth() int {
// Write the current state of the progressbar
func (pb *ProgressBar) Update() {
c := atomic.LoadInt64(&pb.current)
if pb.AlwaysUpdate || c != pb.currentValue {
pb.write(c)
pb.currentValue = c
p := atomic.LoadInt64(&pb.previous)
t := atomic.LoadInt64(&pb.Total)
if p != c {
pb.mu.Lock()
pb.changeTime = time.Now()
pb.mu.Unlock()
atomic.StoreInt64(&pb.previous, c)
}
pb.write(t, c)
if pb.AutoStat {
if c == 0 {
pb.startTime = time.Now()
pb.startValue = 0
} else if c >= t && pb.isFinish != true {
pb.Finish()
}
}
}
// String return the last bar print
func (pb *ProgressBar) String() string {
pb.mu.Lock()
defer pb.mu.Unlock()
return pb.lastPrint
}
// SetTotal atomically sets new total count
func (pb *ProgressBar) SetTotal(total int) *ProgressBar {
return pb.SetTotal64(int64(total))
}
// SetTotal64 atomically sets new total count
func (pb *ProgressBar) SetTotal64(total int64) *ProgressBar {
atomic.StoreInt64(&pb.Total, total)
return pb
}
// Reset bar and set new total count
// Does effect only on finished bar
func (pb *ProgressBar) Reset(total int) *ProgressBar {
pb.mu.Lock()
defer pb.mu.Unlock()
if pb.isFinish {
pb.SetTotal(total).Set(0)
atomic.StoreInt64(&pb.previous, 0)
}
return pb
}
// Internal loop for refreshing the progressbar
func (pb *ProgressBar) refresher() {
for {
@ -415,10 +498,3 @@ func (pb *ProgressBar) refresher() {
}
}
}
type window struct {
Row uint16
Col uint16
Xpixel uint16
Ypixel uint16
}

View File

@ -1,8 +0,0 @@
// +build linux darwin freebsd netbsd openbsd dragonfly
// +build !appengine
package pb
import "syscall"
const sysIoctl = syscall.SYS_IOCTL

View File

@ -1,6 +0,0 @@
// +build solaris
// +build !appengine
package pb
const sysIoctl = 54

View File

@ -75,7 +75,7 @@ func terminalWidth() (width int, err error) {
if e != 0 {
return 0, error(e)
}
return int(info.dwSize.X), nil
return int(info.dwSize.X) - 1, nil
}
func getCursorPos() (pos coordinates, err error) {
@ -102,7 +102,7 @@ var echoLockMutex sync.Mutex
var oldState word
func lockEcho() (quit chan int, err error) {
func lockEcho() (shutdownCh chan struct{}, err error) {
echoLockMutex.Lock()
defer echoLockMutex.Unlock()
if echoLocked {
@ -124,6 +124,8 @@ func lockEcho() (quit chan int, err error) {
err = fmt.Errorf("Can't set terminal settings: %v", e)
return
}
shutdownCh = make(chan struct{})
return
}

View File

@ -8,25 +8,24 @@ import (
"fmt"
"os"
"os/signal"
"runtime"
"sync"
"syscall"
"unsafe"
)
const (
TIOCGWINSZ = 0x5413
TIOCGWINSZ_OSX = 1074295912
"golang.org/x/sys/unix"
)
var tty *os.File
var ErrPoolWasStarted = errors.New("Bar pool was started")
var echoLocked bool
var echoLockMutex sync.Mutex
var (
echoLockMutex sync.Mutex
origTermStatePtr *unix.Termios
tty *os.File
)
func init() {
echoLockMutex.Lock()
defer echoLockMutex.Unlock()
var err error
tty, err = os.Open("/dev/tty")
if err != nil {
@ -36,73 +35,72 @@ func init() {
// terminalWidth returns width of the terminal.
func terminalWidth() (int, error) {
w := new(window)
tio := syscall.TIOCGWINSZ
if runtime.GOOS == "darwin" {
tio = TIOCGWINSZ_OSX
}
res, _, err := syscall.Syscall(sysIoctl,
tty.Fd(),
uintptr(tio),
uintptr(unsafe.Pointer(w)),
)
if int(res) == -1 {
echoLockMutex.Lock()
defer echoLockMutex.Unlock()
fd := int(tty.Fd())
ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ)
if err != nil {
return 0, err
}
return int(w.Col), nil
return int(ws.Col), nil
}
var oldState syscall.Termios
func lockEcho() (quit chan int, err error) {
func lockEcho() (shutdownCh chan struct{}, err error) {
echoLockMutex.Lock()
defer echoLockMutex.Unlock()
if echoLocked {
err = ErrPoolWasStarted
return
}
echoLocked = true
fd := tty.Fd()
if _, _, e := syscall.Syscall6(sysIoctl, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0); e != 0 {
err = fmt.Errorf("Can't get terminal settings: %v", e)
return
if origTermStatePtr != nil {
return shutdownCh, ErrPoolWasStarted
}
newState := oldState
newState.Lflag &^= syscall.ECHO
newState.Lflag |= syscall.ICANON | syscall.ISIG
newState.Iflag |= syscall.ICRNL
if _, _, e := syscall.Syscall6(sysIoctl, fd, ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); e != 0 {
err = fmt.Errorf("Can't set terminal settings: %v", e)
return
fd := int(tty.Fd())
origTermStatePtr, err = unix.IoctlGetTermios(fd, ioctlReadTermios)
if err != nil {
return nil, fmt.Errorf("Can't get terminal settings: %v", err)
}
quit = make(chan int, 1)
go catchTerminate(quit)
oldTermios := *origTermStatePtr
newTermios := oldTermios
newTermios.Lflag &^= syscall.ECHO
newTermios.Lflag |= syscall.ICANON | syscall.ISIG
newTermios.Iflag |= syscall.ICRNL
if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, &newTermios); err != nil {
return nil, fmt.Errorf("Can't set terminal settings: %v", err)
}
shutdownCh = make(chan struct{})
go catchTerminate(shutdownCh)
return
}
func unlockEcho() (err error) {
func unlockEcho() error {
echoLockMutex.Lock()
defer echoLockMutex.Unlock()
if !echoLocked {
return
if origTermStatePtr == nil {
return nil
}
echoLocked = false
fd := tty.Fd()
if _, _, e := syscall.Syscall6(sysIoctl, fd, ioctlWriteTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0); e != 0 {
err = fmt.Errorf("Can't set terminal settings")
fd := int(tty.Fd())
if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, origTermStatePtr); err != nil {
return fmt.Errorf("Can't set terminal settings: %v", err)
}
return
origTermStatePtr = nil
return nil
}
// listen exit signals and restore terminal state
func catchTerminate(quit chan int) {
func catchTerminate(shutdownCh chan struct{}) {
sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGKILL)
defer signal.Stop(sig)
select {
case <-quit:
case <-shutdownCh:
unlockEcho()
case <-sig:
unlockEcho()

View File

@ -3,6 +3,7 @@
package pb
import (
"io"
"sync"
"time"
)
@ -11,21 +12,36 @@ import (
// You need call pool.Stop() after work
func StartPool(pbs ...*ProgressBar) (pool *Pool, err error) {
pool = new(Pool)
if err = pool.start(); err != nil {
if err = pool.Start(); err != nil {
return
}
pool.add(pbs...)
pool.Add(pbs...)
return
}
// NewPool initialises a pool with progress bars, but
// doesn't start it. You need to call Start manually
func NewPool(pbs ...*ProgressBar) (pool *Pool) {
pool = new(Pool)
pool.Add(pbs...)
return
}
type Pool struct {
RefreshRate time.Duration
bars []*ProgressBar
quit chan int
finishOnce sync.Once
Output io.Writer
RefreshRate time.Duration
bars []*ProgressBar
lastBarsCount int
shutdownCh chan struct{}
workerCh chan struct{}
m sync.Mutex
finishOnce sync.Once
}
func (p *Pool) add(pbs ...*ProgressBar) {
// Add progress bars.
func (p *Pool) Add(pbs ...*ProgressBar) {
p.m.Lock()
defer p.m.Unlock()
for _, bar := range pbs {
bar.ManualUpdate = true
bar.NotPrint = true
@ -34,30 +50,38 @@ func (p *Pool) add(pbs ...*ProgressBar) {
}
}
func (p *Pool) start() (err error) {
func (p *Pool) Start() (err error) {
p.RefreshRate = DefaultRefreshRate
quit, err := lockEcho()
p.shutdownCh, err = lockEcho()
if err != nil {
return
}
p.quit = make(chan int)
go p.writer(quit)
p.workerCh = make(chan struct{})
go p.writer()
return
}
func (p *Pool) writer(finish chan int) {
func (p *Pool) writer() {
var first = true
defer func() {
if first == false {
p.print(false)
} else {
p.print(true)
p.print(false)
}
close(p.workerCh)
}()
for {
select {
case <-time.After(p.RefreshRate):
if p.print(first) {
p.print(false)
finish <- 1
return
}
first = false
case <-p.quit:
finish <- 1
case <-p.shutdownCh:
return
}
}
@ -65,11 +89,14 @@ func (p *Pool) writer(finish chan int) {
// Restore terminal state and close pool
func (p *Pool) Stop() error {
// Wait until one final refresh has passed.
time.Sleep(p.RefreshRate)
p.finishOnce.Do(func() {
close(p.quit)
close(p.shutdownCh)
})
// Wait for the worker to complete
select {
case <-p.workerCh:
}
return unlockEcho()
}

View File

@ -8,13 +8,18 @@ import (
)
func (p *Pool) print(first bool) bool {
p.m.Lock()
defer p.m.Unlock()
var out string
if !first {
coords, err := getCursorPos()
if err != nil {
log.Panic(err)
}
coords.Y -= int16(len(p.bars))
coords.Y -= int16(p.lastBarsCount)
if coords.Y < 0 {
coords.Y = 0
}
coords.X = 0
err = setCursorPos(coords)
@ -24,12 +29,17 @@ func (p *Pool) print(first bool) bool {
}
isFinished := true
for _, bar := range p.bars {
if !bar.isFinish {
if !bar.IsFinished() {
isFinished = false
}
bar.Update()
out += fmt.Sprintf("\r%s\n", bar.String())
}
fmt.Print(out)
if p.Output != nil {
fmt.Fprint(p.Output, out)
} else {
fmt.Print(out)
}
p.lastBarsCount = len(p.bars)
return isFinished
}

View File

@ -5,18 +5,25 @@ package pb
import "fmt"
func (p *Pool) print(first bool) bool {
p.m.Lock()
defer p.m.Unlock()
var out string
if !first {
out = fmt.Sprintf("\033[%dA", len(p.bars))
out = fmt.Sprintf("\033[%dA", p.lastBarsCount)
}
isFinished := true
for _, bar := range p.bars {
if !bar.isFinish {
if !bar.IsFinished() {
isFinished = false
}
bar.Update()
out += fmt.Sprintf("\r%s\n", bar.String())
}
fmt.Print(out)
if p.Output != nil {
fmt.Fprint(p.Output, out)
} else {
fmt.Print(out)
}
p.lastBarsCount = len(p.bars)
return isFinished
}

View File

@ -15,3 +15,11 @@ func (r *Reader) Read(p []byte) (n int, err error) {
r.bar.Add(n)
return
}
// Close the reader when it implements io.Closer
func (r *Reader) Close() (err error) {
if closer, ok := r.Reader.(io.Closer); ok {
return closer.Close()
}
return
}

View File

@ -1,17 +1,17 @@
package pb
import (
"github.com/mattn/go-runewidth"
"regexp"
"unicode/utf8"
)
// Finds the control character sequences (like colors)
var ctrlFinder = regexp.MustCompile("\x1b\x5b[0-9]+\x6d")
func escapeAwareRuneCountInString(s string) int {
n := utf8.RuneCountInString(s)
n := runewidth.StringWidth(s)
for _, sm := range ctrlFinder.FindAllString(s, -1) {
n -= len(sm)
n -= runewidth.StringWidth(sm)
}
return n
}

View File

@ -1,7 +0,0 @@
// +build linux solaris
// +build !appengine
package pb
const ioctlReadTermios = 0x5401 // syscall.TCGETS
const ioctlWriteTermios = 0x5402 // syscall.TCSETS

13
vendor/gopkg.in/cheggaaa/pb.v1/termios_sysv.go generated vendored Normal file
View File

@ -0,0 +1,13 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build linux solaris
// +build !appengine
package pb
import "golang.org/x/sys/unix"
const ioctlReadTermios = unix.TCGETS
const ioctlWriteTermios = unix.TCSETS