Consolidated progress bar's appearance into the GetDefaultProgressBar() function. Updated dependency for cheggaaa's progress-bar from the gopkg.in location to the better maintained one on github.com.

This commit is contained in:
Ali Rizvi-Santiago 2018-01-02 17:26:25 -06:00
parent 8c6efe336c
commit ab4490b967
21 changed files with 373 additions and 297 deletions

View File

@ -20,8 +20,8 @@ import (
// imports related to each Downloader implementation
import (
"github.com/cheggaaa/pb"
"github.com/jlaffaye/ftp"
"gopkg.in/cheggaaa/pb.v1"
"io"
"net/http"
"path/filepath"
@ -83,22 +83,17 @@ func HashForType(t string) hash.Hash {
// NewDownloadClient returns a new DownloadClient for the given
// configuration.
func NewDownloadClient(c *DownloadConfig, bar *pb.ProgressBar) *DownloadClient {
func NewDownloadClient(c *DownloadConfig, bar pb.ProgressBar) *DownloadClient {
const mtu = 1500 /* ethernet */ - 20 /* ipv4 */ - 20 /* tcp */
// If no custom progress-bar was specified, then create a default one.
if bar == nil {
bar = pb.New64(0)
}
// Create downloader map if it hasn't been specified already.
if c.DownloaderMap == nil {
c.DownloaderMap = map[string]Downloader{
"file": &FileDownloader{progress: bar, bufferSize: nil},
"ftp": &FTPDownloader{progress: bar, userInfo: url.UserPassword("anonymous", "anonymous@"), mtu: mtu},
"http": &HTTPDownloader{progress: bar, userAgent: c.UserAgent},
"https": &HTTPDownloader{progress: bar, userAgent: c.UserAgent},
"smb": &SMBDownloader{progress: bar, bufferSize: nil},
"file": &FileDownloader{progress: &bar, bufferSize: nil},
"ftp": &FTPDownloader{progress: &bar, userInfo: url.UserPassword("anonymous", "anonymous@"), mtu: mtu},
"http": &HTTPDownloader{progress: &bar, userAgent: c.UserAgent},
"https": &HTTPDownloader{progress: &bar, userAgent: c.UserAgent},
"smb": &SMBDownloader{progress: &bar, bufferSize: nil},
}
}
return &DownloadClient{config: c}

View File

@ -7,10 +7,9 @@ import (
"log"
"time"
"github.com/cheggaaa/pb"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
"gopkg.in/cheggaaa/pb.v1"
)
// StepDownload downloads a remote file using the download client within
@ -63,6 +62,10 @@ func (s *StepDownload) Run(state multistep.StateBag) multistep.StepAction {
ui.Say(fmt.Sprintf("Downloading or copying %s", s.Description))
// Get a default-looking progress bar and connect it to the ui.
bar := GetDefaultProgressBar()
bar.Callback = ui.Message
// First try to use any already downloaded file
// If it fails, proceed to regualar download logic
@ -96,7 +99,7 @@ func (s *StepDownload) Run(state multistep.StateBag) multistep.StepAction {
}
downloadConfigs[i] = config
if match, _ := NewDownloadClient(config, nil).VerifyChecksum(config.TargetPath); match {
if match, _ := NewDownloadClient(config, bar).VerifyChecksum(config.TargetPath); match {
ui.Message(fmt.Sprintf("Found already downloaded, initial checksum matched, no download needed: %s", url))
finalPath = config.TargetPath
break
@ -138,11 +141,7 @@ func (s *StepDownload) Run(state multistep.StateBag) multistep.StepAction {
func (s *StepDownload) Cleanup(multistep.StateBag) {}
func (s *StepDownload) download(config *DownloadConfig, state multistep.StateBag) (string, error, bool) {
var path string
ui := state.Get("ui").(packer.Ui)
// design the appearance of the progress bar
func GetDefaultProgressBar() pb.ProgressBar {
bar := pb.New64(0)
bar.ShowPercent = true
bar.ShowCounters = true
@ -154,9 +153,19 @@ func (s *StepDownload) download(config *DownloadConfig, state multistep.StateBag
bar.Format("[=>-]")
bar.SetRefreshRate(1 * time.Second)
bar.SetWidth(25)
return *bar
}
func (s *StepDownload) download(config *DownloadConfig, state multistep.StateBag) (string, error, bool) {
var path string
ui := state.Get("ui").(packer.Ui)
// Get a default looking progress bar and connect it to the ui.
bar := GetDefaultProgressBar()
bar.Callback = ui.Message
// create download client with config and progress bar
// Create download client with config and progress bar
download := NewDownloadClient(config, bar)
downloadCompleteCh := make(chan error, 1)

View File

@ -1,7 +1,10 @@
# Terminal progress bar for Go
Simple progress bar for console programs.
[![Join the chat at https://gitter.im/cheggaaa/pb](https://badges.gitter.im/cheggaaa/pb.svg)](https://gitter.im/cheggaaa/pb?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
Simple progress bar for console programs.
Please check the new version https://github.com/cheggaaa/pb/tree/v2 (currently, it's beta)
## Installation

118
vendor/github.com/cheggaaa/pb/format.go generated vendored Normal file
View File

@ -0,0 +1,118 @@
package pb
import (
"fmt"
"time"
)
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, 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}
}
type formatter struct {
n int64
unit Units
width int
perSec bool
}
func (f *formatter) To(unit Units) *formatter {
f.unit = unit
return f
}
func (f *formatter) Width(width int) *formatter {
f.width = width
return f
}
func (f *formatter) PerSec() *formatter {
f.perSec = true
return f
}
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:
out = formatDuration(f.n)
default:
out = fmt.Sprintf(fmt.Sprintf("%%%dd", f.width), f.n)
}
if f.perSec {
out += "/s"
}
return
}
// Convert bytes to human readable string. Like 2 MiB, 64.2 KiB, 52 B
func formatBytes(i int64) (result string) {
switch {
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)
}
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)
}
result = fmt.Sprintf("%s%v", result, d)
return
}

View File

@ -13,7 +13,7 @@ import (
)
// Current version
const Version = "1.0.6"
const Version = "1.0.19"
const (
// Default refresh rate - 200ms
@ -47,8 +47,6 @@ func New64(total int64) *ProgressBar {
Units: U_NO,
ManualUpdate: false,
finish: make(chan struct{}),
currentValue: -1,
mu: new(sync.Mutex),
}
return pb.Format(FORMAT)
}
@ -67,7 +65,8 @@ 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
@ -91,13 +90,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
@ -112,7 +112,7 @@ type ProgressBar struct {
// Start print
func (pb *ProgressBar) Start() *ProgressBar {
pb.startTime = time.Now()
pb.startValue = pb.current
pb.startValue = atomic.LoadInt64(&pb.current)
if pb.Total == 0 {
pb.ShowTimeLeft = false
pb.ShowPercent = false
@ -173,7 +173,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")
@ -222,6 +222,8 @@ func (pb *ProgressBar) Finish() {
pb.finishOnce.Do(func() {
close(pb.finish)
pb.write(atomic.LoadInt64(&pb.current))
pb.mu.Lock()
defer pb.mu.Unlock()
switch {
case pb.Output != nil:
fmt.Fprintln(pb.Output)
@ -232,6 +234,13 @@ func (pb *ProgressBar) Finish() {
})
}
// 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()
@ -290,8 +299,12 @@ func (pb *ProgressBar) write(current int64) {
}
// 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()
select {
case <-pb.finish:
if pb.ShowFinalTime {
@ -301,17 +314,20 @@ func (pb *ProgressBar) write(current int64) {
}
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
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)
}
}
}
@ -332,24 +348,32 @@ func (pb *ProgressBar) write(current int64) {
size := width - barWidth
if size > 0 {
if pb.Total > 0 {
curCount := int(math.Ceil((float64(current) / float64(pb.Total)) * float64(size)))
emptCount := size - curCount
curSize := int(math.Ceil((float64(current) / float64(pb.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)
}
@ -364,16 +388,17 @@ 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))
if cl := escapeAwareRuneCountInString(out); cl < width {
end = strings.Repeat(" ", width-cl)
}
// and print!
pb.mu.Lock()
pb.lastPrint = out + end
isFinish := pb.isFinish
pb.mu.Unlock()
switch {
case pb.isFinish:
case isFinish:
return
case pb.Output != nil:
fmt.Fprint(pb.Output, "\r"+out+end)
@ -406,10 +431,14 @@ 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)
if p != c {
pb.mu.Lock()
pb.changeTime = time.Now()
pb.mu.Unlock()
atomic.StoreInt64(&pb.previous, c)
}
pb.write(c)
if pb.AutoStat {
if c == 0 {
pb.startTime = time.Now()
@ -420,7 +449,10 @@ func (pb *ProgressBar) Update() {
}
}
// String return the last bar print
func (pb *ProgressBar) String() string {
pb.mu.Lock()
defer pb.mu.Unlock()
return pb.lastPrint
}
@ -435,10 +467,3 @@ func (pb *ProgressBar) refresher() {
}
}
}
type window struct {
Row uint16
Col uint16
Xpixel uint16
Ypixel uint16
}

108
vendor/github.com/cheggaaa/pb/pb_x.go generated vendored Normal file
View File

@ -0,0 +1,108 @@
// +build linux darwin freebsd netbsd openbsd solaris dragonfly
// +build !appengine
package pb
import (
"errors"
"fmt"
"os"
"os/signal"
"sync"
"syscall"
"golang.org/x/sys/unix"
)
var ErrPoolWasStarted = errors.New("Bar pool was started")
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 {
tty = os.Stdin
}
}
// terminalWidth returns width of the terminal.
func terminalWidth() (int, error) {
echoLockMutex.Lock()
defer echoLockMutex.Unlock()
fd := int(tty.Fd())
ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ)
if err != nil {
return 0, err
}
return int(ws.Col), nil
}
func lockEcho() (quit chan int, err error) {
echoLockMutex.Lock()
defer echoLockMutex.Unlock()
if origTermStatePtr != nil {
return quit, ErrPoolWasStarted
}
fd := int(tty.Fd())
oldTermStatePtr, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
if err != nil {
return nil, fmt.Errorf("Can't get terminal settings: %v", err)
}
oldTermios := *oldTermStatePtr
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)
}
quit = make(chan int, 1)
go catchTerminate(quit)
return
}
func unlockEcho() error {
echoLockMutex.Lock()
defer echoLockMutex.Unlock()
if origTermStatePtr == nil {
return nil
}
fd := int(tty.Fd())
if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, origTermStatePtr); err != nil {
return fmt.Errorf("Can't set terminal settings: %v", err)
}
origTermStatePtr = nil
return nil
}
// listen exit signals and restore terminal state
func catchTerminate(quit chan int) {
sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGKILL)
defer signal.Stop(sig)
select {
case <-quit:
unlockEcho()
case <-sig:
unlockEcho()
}
}

View File

@ -3,6 +3,7 @@
package pb
import (
"io"
"sync"
"time"
)
@ -19,14 +20,19 @@ func StartPool(pbs ...*ProgressBar) (pool *Pool, err error) {
}
type Pool struct {
RefreshRate time.Duration
bars []*ProgressBar
quit chan int
finishOnce sync.Once
Output io.Writer
RefreshRate time.Duration
bars []*ProgressBar
lastBarsCount int
quit chan int
m sync.Mutex
finishOnce sync.Once
}
// 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

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

@ -11,7 +11,7 @@ var ctrlFinder = regexp.MustCompile("\x1b\x5b[0-9]+\x6d")
func escapeAwareRuneCountInString(s string) int {
n := runewidth.StringWidth(s)
for _, sm := range ctrlFinder.FindAllString(s, -1) {
n -= len(sm)
n -= runewidth.StringWidth(sm)
}
return n
}

13
vendor/github.com/cheggaaa/pb/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

View File

@ -1,87 +0,0 @@
package pb
import (
"fmt"
"strings"
"time"
)
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
// U_DURATION units are formatted in a human readable way (3h14m15s)
U_DURATION
)
func Format(i int64) *formatter {
return &formatter{n: i}
}
type formatter struct {
n int64
unit Units
width int
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
}
func (f *formatter) Width(width int) *formatter {
f.width = width
return f
}
func (f *formatter) PerSec() *formatter {
f.perSec = true
return f
}
func (f *formatter) String() (out string) {
switch f.unit {
case U_BYTES:
out = formatBytes(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)
default:
out = fmt.Sprintf(fmt.Sprintf("%%%dd", f.width), f.n)
}
if f.perSec {
out += "/s"
}
return
}
// Convert bytes to human readable string. Like a 2 MB, 64.2 KB, 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)
default:
result = fmt.Sprintf("%d B", i)
}
result = strings.Trim(result, " ")
return
}

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

@ -1,110 +0,0 @@
// +build linux darwin freebsd netbsd openbsd solaris dragonfly
// +build !appengine
package pb
import (
"errors"
"fmt"
"os"
"os/signal"
"runtime"
"sync"
"syscall"
"unsafe"
)
const (
TIOCGWINSZ = 0x5413
TIOCGWINSZ_OSX = 1074295912
)
var tty *os.File
var ErrPoolWasStarted = errors.New("Bar pool was started")
var echoLocked bool
var echoLockMutex sync.Mutex
func init() {
var err error
tty, err = os.Open("/dev/tty")
if err != nil {
tty = os.Stdin
}
}
// 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 {
return 0, err
}
return int(w.Col), nil
}
var oldState syscall.Termios
func lockEcho() (quit chan int, 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
}
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
}
quit = make(chan int, 1)
go catchTerminate(quit)
return
}
func unlockEcho() (err error) {
echoLockMutex.Lock()
defer echoLockMutex.Unlock()
if !echoLocked {
return
}
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")
}
return
}
// listen exit signals and restore terminal state
func catchTerminate(quit chan int) {
sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGKILL)
defer signal.Stop(sig)
select {
case <-quit:
unlockEcho()
case <-sig:
unlockEcho()
}
}

View File

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

12
vendor/vendor.json vendored
View File

@ -565,6 +565,12 @@
"path": "github.com/biogo/hts/bgzf",
"revision": "50da7d4131a3b5c9d063932461cab4d1fafb20b0"
},
{
"checksumSHA1": "ymc5+iJ+1ipls3ihqPdzMjFYCqo=",
"path": "github.com/cheggaaa/pb",
"revision": "18d384da9bdc1e5a08fc2a62a494c321d9ae74ea",
"revisionTime": "2017-12-14T13:20:59Z"
},
{
"checksumSHA1": "Lf3uUXTkKK5DJ37BxQvxO1Fq+K8=",
"comment": "v1.0.0-3-g6d21280",
@ -1493,12 +1499,6 @@
"path": "google.golang.org/cloud/internal",
"revision": "5a3b06f8b5da3b7c3a93da43163b872c86c509ef"
},
{
"checksumSHA1": "w3z2xM4+RT/OWvVusDgNXZZEEkE=",
"path": "gopkg.in/cheggaaa/pb.v1",
"revision": "d7e6ca3010b6f084d8056847f55d7f572f180678",
"revisionTime": "2016-11-21T09:29:06Z"
},
{
"checksumSHA1": "gY2M/3SCxqgrPz+P/N6JQ+m/wnA=",
"path": "gopkg.in/xmlpath.v2",