pax_global_header00006660000000000000000000000064133005136660014515gustar00rootroot0000000000000052 comment=2af8bbdea9e99e83b3ac400d8f6b6d1b8cbbf338 golang-gopkg-cheggaaa-pb.v1-1.0.25/000077500000000000000000000000001330051366600166205ustar00rootroot00000000000000golang-gopkg-cheggaaa-pb.v1-1.0.25/.travis.yml000066400000000000000000000001111330051366600207220ustar00rootroot00000000000000language: go go: - 1.7.x - 1.10.x - master sudo: false os: - linux - osx golang-gopkg-cheggaaa-pb.v1-1.0.25/LICENSE000066400000000000000000000027071330051366600176330ustar00rootroot00000000000000Copyright (c) 2012-2015, Sergey Cherepanov All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.golang-gopkg-cheggaaa-pb.v1-1.0.25/README.md000066400000000000000000000064651330051366600201120ustar00rootroot00000000000000# Terminal progress bar for Go [![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 ``` go get gopkg.in/cheggaaa/pb.v1 ``` ## Usage ```Go package main import ( "gopkg.in/cheggaaa/pb.v1" "time" ) func main() { count := 100000 bar := pb.StartNew(count) for i := 0; i < count; i++ { bar.Increment() time.Sleep(time.Millisecond) } bar.FinishPrint("The End!") } ``` Result will be like this: ``` > go run test.go 37158 / 100000 [================>_______________________________] 37.16% 1m11s ``` ## Customization ```Go // create bar bar := pb.New(count) // refresh info every second (default 200ms) bar.SetRefreshRate(time.Second) // show percents (by default already true) bar.ShowPercent = true // show bar (by default already true) bar.ShowBar = true // no counters bar.ShowCounters = false // show "time left" bar.ShowTimeLeft = true // show average speed bar.ShowSpeed = true // sets the width of the progress bar bar.SetWidth(80) // sets the width of the progress bar, but if terminal size smaller will be ignored bar.SetMaxWidth(80) // convert output to readable format (like KB, MB) bar.SetUnits(pb.U_BYTES) // and start bar.Start() ``` ## Progress bar for IO Operations ```go // create and start bar bar := pb.New(myDataLen).SetUnits(pb.U_BYTES) bar.Start() // my io.Reader r := myReader // my io.Writer w := myWriter // create proxy reader reader := bar.NewProxyReader(r) // and copy from pb reader io.Copy(w, reader) ``` ```go // create and start bar bar := pb.New(myDataLen).SetUnits(pb.U_BYTES) bar.Start() // my io.Reader r := myReader // my io.Writer w := myWriter // create multi writer writer := io.MultiWriter(w, bar) // and copy io.Copy(writer, r) bar.Finish() ``` ## Custom Progress Bar Look-and-feel ```go bar.Format("<.- >") ``` ## Multiple Progress Bars (experimental and unstable) Do not print to terminal while pool is active. ```go package main import ( "math/rand" "sync" "time" "gopkg.in/cheggaaa/pb.v1" ) func main() { // create bars first := pb.New(200).Prefix("First ") second := pb.New(200).Prefix("Second ") third := pb.New(200).Prefix("Third ") // start pool pool, err := pb.StartPool(first, second, third) if err != nil { panic(err) } // update bars wg := new(sync.WaitGroup) for _, bar := range []*pb.ProgressBar{first, second, third} { wg.Add(1) go func(cb *pb.ProgressBar) { for n := 0; n < 200; n++ { cb.Increment() time.Sleep(time.Millisecond * time.Duration(rand.Intn(100))) } cb.Finish() wg.Done() }(bar) } wg.Wait() // close pool pool.Stop() } ``` The result will be as follows: ``` $ go run example/multiple.go First 34 / 200 [=========>---------------------------------------------] 17.00% 00m08s Second 42 / 200 [===========>------------------------------------------] 21.00% 00m06s Third 36 / 200 [=========>---------------------------------------------] 18.00% 00m08s ``` golang-gopkg-cheggaaa-pb.v1-1.0.25/example_copy_test.go000066400000000000000000000030761330051366600227010ustar00rootroot00000000000000package pb_test import ( "fmt" "io" "net/http" "os" "strconv" "strings" "time" "gopkg.in/cheggaaa/pb.v1" ) func Example_copy() { // check args if len(os.Args) < 3 { printUsage() return } sourceName, destName := os.Args[1], os.Args[2] // check source var source io.Reader var sourceSize int64 if strings.HasPrefix(sourceName, "http://") { // open as url resp, err := http.Get(sourceName) if err != nil { fmt.Printf("Can't get %s: %v\n", sourceName, err) return } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { fmt.Printf("Server return non-200 status: %v\n", resp.Status) return } i, _ := strconv.Atoi(resp.Header.Get("Content-Length")) sourceSize = int64(i) source = resp.Body } else { // open as file s, err := os.Open(sourceName) if err != nil { fmt.Printf("Can't open %s: %v\n", sourceName, err) return } defer s.Close() // get source size sourceStat, err := s.Stat() if err != nil { fmt.Printf("Can't stat %s: %v\n", sourceName, err) return } sourceSize = sourceStat.Size() source = s } // create dest dest, err := os.Create(destName) if err != nil { fmt.Printf("Can't create %s: %v\n", destName, err) return } defer dest.Close() // create bar bar := pb.New(int(sourceSize)).SetUnits(pb.U_BYTES).SetRefreshRate(time.Millisecond * 10) bar.ShowSpeed = true bar.Start() // create proxy reader reader := bar.NewProxyReader(source) // and copy from reader io.Copy(dest, reader) bar.Finish() } func printUsage() { fmt.Println("copy [source file or url] [dest file]") } golang-gopkg-cheggaaa-pb.v1-1.0.25/example_multiple_test.go000066400000000000000000000012661330051366600235610ustar00rootroot00000000000000package pb_test import ( "math/rand" "sync" "time" "gopkg.in/cheggaaa/pb.v1" ) func Example_multiple() { // create bars first := pb.New(200).Prefix("First ") second := pb.New(200).Prefix("Second ") third := pb.New(200).Prefix("Third ") // start pool pool, err := pb.StartPool(first, second, third) if err != nil { panic(err) } // update bars wg := new(sync.WaitGroup) for _, bar := range []*pb.ProgressBar{first, second, third} { wg.Add(1) go func(cb *pb.ProgressBar) { for n := 0; n < 200; n++ { cb.Increment() time.Sleep(time.Millisecond * time.Duration(rand.Intn(100))) } cb.Finish() wg.Done() }(bar) } wg.Wait() // close pool pool.Stop() } golang-gopkg-cheggaaa-pb.v1-1.0.25/example_test.go000066400000000000000000000006711330051366600216450ustar00rootroot00000000000000package pb_test import ( "time" "gopkg.in/cheggaaa/pb.v1" ) func Example() { count := 5000 bar := pb.New(count) // show percents (by default already true) bar.ShowPercent = true // show bar (by default already true) bar.ShowBar = true bar.ShowCounters = true bar.ShowTimeLeft = true // and start bar.Start() for i := 0; i < count; i++ { bar.Increment() time.Sleep(time.Millisecond) } bar.FinishPrint("The End!") } golang-gopkg-cheggaaa-pb.v1-1.0.25/format.go000066400000000000000000000047631330051366600204510ustar00rootroot00000000000000package 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) } 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 } golang-gopkg-cheggaaa-pb.v1-1.0.25/format_test.go000066400000000000000000000041571330051366600215050ustar00rootroot00000000000000package pb import ( "fmt" "strconv" "testing" "time" ) func Test_DefaultsToInteger(t *testing.T) { value := int64(1000) expected := strconv.Itoa(int(value)) actual := Format(value).String() if actual != expected { t.Error(fmt.Sprintf("Expected {%s} was {%s}", expected, actual)) } } func Test_CanFormatAsInteger(t *testing.T) { value := int64(1000) expected := strconv.Itoa(int(value)) actual := Format(value).To(U_NO).String() if actual != expected { t.Error(fmt.Sprintf("Expected {%s} was {%s}", expected, actual)) } } func Test_CanFormatAsBytes(t *testing.T) { inputs := []struct { v int64 e string }{ {v: 1000, e: "1000 B"}, {v: 1024, e: "1.00 KiB"}, {v: 3*MiB + 140*KiB, e: "3.14 MiB"}, {v: 2 * GiB, e: "2.00 GiB"}, {v: 2048 * GiB, e: "2.00 TiB"}, } for _, input := range inputs { actual := Format(input.v).To(U_BYTES).String() if actual != input.e { t.Error(fmt.Sprintf("Expected {%s} was {%s}", input.e, actual)) } } } func Test_CanFormatAsBytesDec(t *testing.T) { inputs := []struct { v int64 e string }{ {v: 999, e: "999 B"}, {v: 1024, e: "1.02 KB"}, {v: 3*MB + 140*KB, e: "3.14 MB"}, {v: 2 * GB, e: "2.00 GB"}, {v: 2048 * GB, e: "2.05 TB"}, } for _, input := range inputs { actual := Format(input.v).To(U_BYTES_DEC).String() if actual != input.e { t.Error(fmt.Sprintf("Expected {%s} was {%s}", input.e, actual)) } } } func Test_CanFormatDuration(t *testing.T) { value := 10 * time.Minute expected := "10m00s" actual := Format(int64(value)).To(U_DURATION).String() if actual != expected { t.Error(fmt.Sprintf("Expected {%s} was {%s}", expected, actual)) } } func Test_CanFormatLongDuration(t *testing.T) { value := 62 * time.Hour + 13 * time.Second expected := "2d14h00m13s" actual := Format(int64(value)).To(U_DURATION).String() if actual != expected { t.Error(fmt.Sprintf("Expected {%s} was {%s}", expected, actual)) } } func Test_DefaultUnitsWidth(t *testing.T) { value := 10 expected := " 10" actual := Format(int64(value)).Width(7).String() if actual != expected { t.Error(fmt.Sprintf("Expected {%s} was {%s}", expected, actual)) } } golang-gopkg-cheggaaa-pb.v1-1.0.25/pb.go000066400000000000000000000267331330051366600175630ustar00rootroot00000000000000// Simple console progress bars package pb import ( "fmt" "io" "math" "strings" "sync" "sync/atomic" "time" "unicode/utf8" ) // Current version const Version = "1.0.25" const ( // Default refresh rate - 200ms DEFAULT_REFRESH_RATE = time.Millisecond * 200 FORMAT = "[=>-]" ) // DEPRECATED // variables for backward compatibility, from now do not work // use pb.Format and pb.SetRefreshRate var ( DefaultRefreshRate = DEFAULT_REFRESH_RATE BarStart, BarEnd, Empty, Current, CurrentN string ) // Create new progress bar object func New(total int) *ProgressBar { return New64(int64(total)) } // 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, ShowElapsedTime: false, ShowFinalTime: true, Units: U_NO, ManualUpdate: false, finish: make(chan struct{}), } return pb.Format(FORMAT) } // Create new object and start func StartNew(total int) *ProgressBar { return New(total).Start() } // Callback for custom output // For example: // bar.Callback = func(s string) { // mySuperPrint(s) // } // 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) previous int64 Total int64 RefreshRate time.Duration ShowPercent, ShowCounters bool ShowSpeed, ShowTimeLeft, ShowBar bool ShowFinalTime, ShowElapsedTime bool Output io.Writer Callback Callback NotPrint bool Units Units Width int ForceWidth bool ManualUpdate bool AutoStat bool // Default width for the time box. UnitsWidth int TimeBoxWidth int finishOnce sync.Once //Guards isFinish finish chan struct{} isFinish bool startTime time.Time startValue int64 changeTime time.Time prefix, postfix string mu sync.Mutex lastPrint string BarStart string BarEnd string Empty string Current string CurrentN string AlwaysUpdate bool } // Start print func (pb *ProgressBar) Start() *ProgressBar { pb.startTime = time.Now() 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. go pb.refresher() } return pb } // Increment current value 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)) } // Set64 sets the current value as int64 func (pb *ProgressBar) Set64(current int64) *ProgressBar { atomic.StoreInt64(&pb.current, current) return pb } // Add to current value func (pb *ProgressBar) Add(add int) int { return int(pb.Add64(int64(add))) } func (pb *ProgressBar) Add64(add int64) int64 { return atomic.AddInt64(&pb.current, add) } // Set prefix string func (pb *ProgressBar) Prefix(prefix string) *ProgressBar { pb.prefix = prefix return pb } // Set postfix string func (pb *ProgressBar) Postfix(postfix string) *ProgressBar { pb.postfix = postfix return pb } // Set custom format for bar // Example: bar.Format("[=>_]") // Example: bar.Format("[\x00=\x00>\x00-\x00]") // \x00 is the delimiter func (pb *ProgressBar) Format(format string) *ProgressBar { var formatEntries []string if utf8.RuneCountInString(format) == 5 { formatEntries = strings.Split(format, "") } else { formatEntries = strings.Split(format, "\x00") } if len(formatEntries) == 5 { pb.BarStart = formatEntries[0] pb.BarEnd = formatEntries[4] pb.Empty = formatEntries[3] pb.Current = formatEntries[1] pb.CurrentN = formatEntries[2] } return pb } // Set bar refresh rate func (pb *ProgressBar) SetRefreshRate(rate time.Duration) *ProgressBar { pb.RefreshRate = rate return pb } // Set units // bar.SetUnits(U_NO) - by default // bar.SetUnits(U_BYTES) - for Mb, Kb, etc func (pb *ProgressBar) SetUnits(units Units) *ProgressBar { pb.Units = units return pb } // Set max width, if width is bigger than terminal width, will be ignored func (pb *ProgressBar) SetMaxWidth(width int) *ProgressBar { pb.Width = width pb.ForceWidth = false return pb } // Set bar width func (pb *ProgressBar) SetWidth(width int) *ProgressBar { pb.Width = width pb.ForceWidth = true return pb } // End print func (pb *ProgressBar) Finish() { //Protect multiple calls pb.finishOnce.Do(func() { close(pb.finish) 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() if pb.Output != nil { fmt.Fprintln(pb.Output, str) } else { fmt.Println(str) } } // implement io.Writer func (pb *ProgressBar) Write(p []byte) (n int, err error) { n = len(p) pb.Add(n) return } // implement io.Reader func (pb *ProgressBar) Read(p []byte) (n int, err error) { n = len(p) pb.Add(n) return } // 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(total, current int64) { width := pb.GetWidth() var percentBox, countersBox, timeLeftBox, timeSpentBox, speedBox, barBox, end, out string // percents if pb.ShowPercent { var percent float64 if total > 0 { percent = float64(current) / (float64(total) / float64(100)) } else { percent = float64(current) / float64(100) } percentBox = fmt.Sprintf(" %6.02f%%", percent) } // counters if pb.ShowCounters { current := Format(current).To(pb.Units).Width(pb.UnitsWidth) 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 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 left = (fromStart / time.Second) * time.Second timeLeftBox = fmt.Sprintf(" %s", left.String()) } default: if pb.ShowTimeLeft && currentFromStart > 0 { perEntry := fromChange / time.Duration(currentFromStart) var left time.Duration 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 } if left > 0 { timeLeft := Format(int64(left)).To(U_DURATION).String() timeLeftBox = fmt.Sprintf(" %s", timeLeft) } } } if len(timeLeftBox) < pb.TimeBoxWidth { timeLeftBox = fmt.Sprintf("%s%s", strings.Repeat(" ", pb.TimeBoxWidth-len(timeLeftBox)), timeLeftBox) } // speed if pb.ShowSpeed && currentFromStart > 0 { fromStart := time.Now().Sub(pb.startTime) speed := float64(currentFromStart) / (float64(fromStart) / float64(time.Second)) speedBox = " " + Format(int64(speed)).To(pb.Units).Width(pb.UnitsWidth).PerSec().String() } 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 total > 0 { curSize := int(math.Ceil((float64(current) / float64(total)) * float64(size))) emptySize := size - curSize barBox = pb.BarStart if emptySize < 0 { emptySize = 0 } if curSize > size { curSize = size } 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 } emptyLen := escapeAwareRuneCountInString(pb.Empty) barBox += strings.Repeat(pb.Empty, emptySize/emptyLen) barBox += pb.BarEnd } else { pos := size - int(current)%int(size) barBox = pb.BarStart if pos-1 > 0 { barBox += strings.Repeat(pb.Empty, pos-1) } barBox += pb.Current if size-pos-1 > 0 { barBox += strings.Repeat(pb.Empty, size-pos-1) } barBox += pb.BarEnd } } } // check len 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 isFinish := pb.isFinish switch { case isFinish: return case pb.Output != nil: fmt.Fprint(pb.Output, "\r"+out+end) case pb.Callback != nil: pb.Callback(out + end) case !pb.NotPrint: fmt.Print("\r" + out + end) } } // GetTerminalWidth - returns terminal width for all platforms. func GetTerminalWidth() (int, error) { return terminalWidth() } func (pb *ProgressBar) GetWidth() int { if pb.ForceWidth { return pb.Width } width := pb.Width termWidth, _ := terminalWidth() if width == 0 || termWidth <= width { width = termWidth } return width } // Write the current state of the progressbar func (pb *ProgressBar) Update() { c := atomic.LoadInt64(&pb.current) 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 { select { case <-pb.finish: return case <-time.After(pb.RefreshRate): pb.Update() } } } golang-gopkg-cheggaaa-pb.v1-1.0.25/pb_appengine.go000066400000000000000000000004221330051366600215740ustar00rootroot00000000000000// +build appengine package pb import "errors" // terminalWidth returns width of the terminal, which is not supported // and should always failed on appengine classic which is a sandboxed PaaS. func terminalWidth() (int, error) { return 0, errors.New("Not supported") } golang-gopkg-cheggaaa-pb.v1-1.0.25/pb_test.go000066400000000000000000000060461330051366600206150ustar00rootroot00000000000000package pb import ( "bytes" "strings" "sync" "testing" "time" "github.com/fatih/color" "github.com/mattn/go-colorable" ) func Test_IncrementAddsOne(t *testing.T) { count := 5000 bar := New(count) expected := 1 actual := bar.Increment() if actual != expected { t.Errorf("Expected {%d} was {%d}", expected, actual) } } func Test_Width(t *testing.T) { count := 5000 bar := New(count) width := 100 bar.SetWidth(100).Callback = func(out string) { if len(out) != width { t.Errorf("Bar width expected {%d} was {%d}", len(out), width) } } bar.Start() bar.Increment() bar.Finish() } func Test_MultipleFinish(t *testing.T) { bar := New(5000) bar.Add(2000) bar.Finish() bar.Finish() } func TestWriteRace(t *testing.T) { outBuffer := &bytes.Buffer{} totalCount := 20 bar := New(totalCount) bar.Output = outBuffer bar.Start() var wg sync.WaitGroup for i := 0; i < totalCount; i++ { wg.Add(1) go func() { bar.Increment() time.Sleep(250 * time.Millisecond) wg.Done() }() } wg.Wait() bar.Finish() } func Test_Format(t *testing.T) { bar := New(5000).Format(strings.Join([]string{ color.GreenString("["), color.New(color.BgGreen).SprintFunc()("o"), color.New(color.BgHiGreen).SprintFunc()("o"), color.New(color.BgRed).SprintFunc()("o"), color.GreenString("]"), }, "\x00")) w := colorable.NewColorableStdout() bar.Callback = func(out string) { w.Write([]byte(out)) } bar.Add(2000) bar.Finish() bar.Finish() } func Test_MultiCharacter(t *testing.T) { bar := New(5).Format(strings.Join([]string{"[[[", "---", ">>", "....", "]]"}, "\x00")) bar.Start() for i := 0; i < 5; i++ { time.Sleep(500 * time.Millisecond) bar.Increment() } time.Sleep(500 * time.Millisecond) bar.Finish() } func Test_AutoStat(t *testing.T) { bar := New(5) bar.AutoStat = true bar.Start() time.Sleep(2 * time.Second) //real start work for i := 0; i < 5; i++ { time.Sleep(500 * time.Millisecond) bar.Increment() } //real finish work time.Sleep(2 * time.Second) bar.Finish() } func Test_Finish_PrintNewline(t *testing.T) { bar := New(5) buf := &bytes.Buffer{} bar.Output = buf bar.Finish() expected := "\n" actual := buf.String() //Finish should write newline to bar.Output if !strings.HasSuffix(actual, expected) { t.Errorf("Expected %q to have suffix %q", expected, actual) } } func Test_FinishPrint(t *testing.T) { bar := New(5) buf := &bytes.Buffer{} bar.Output = buf bar.FinishPrint("foo") expected := "foo\n" actual := buf.String() //FinishPrint should write to bar.Output if !strings.HasSuffix(actual, expected) { t.Errorf("Expected %q to have suffix %q", expected, actual) } } func Test_Reset(t *testing.T) { bar := StartNew(5) for i := 0; i < 5; i++ { bar.Increment() } if actual := bar.Get(); actual != 5 { t.Errorf("Expected: %d; actual: %d", 5, actual) } bar.Finish() bar.Reset(10).Start() defer bar.Finish() if actual := bar.Get(); actual != 0 { t.Errorf("Expected: %d; actual: %d", 0, actual) } if actual := bar.Total; actual != 10 { t.Errorf("Expected: %d; actual: %d", 10, actual) } } golang-gopkg-cheggaaa-pb.v1-1.0.25/pb_win.go000066400000000000000000000101661330051366600204310ustar00rootroot00000000000000// +build windows package pb import ( "errors" "fmt" "os" "sync" "syscall" "unsafe" ) var tty = os.Stdin var ( kernel32 = syscall.NewLazyDLL("kernel32.dll") // GetConsoleScreenBufferInfo retrieves information about the // specified console screen buffer. // http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") // GetConsoleMode retrieves the current input mode of a console's // input buffer or the current output mode of a console screen buffer. // https://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx getConsoleMode = kernel32.NewProc("GetConsoleMode") // SetConsoleMode sets the input mode of a console's input buffer // or the output mode of a console screen buffer. // https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx setConsoleMode = kernel32.NewProc("SetConsoleMode") // SetConsoleCursorPosition sets the cursor position in the // specified console screen buffer. // https://msdn.microsoft.com/en-us/library/windows/desktop/ms686025(v=vs.85).aspx setConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition") ) type ( // Defines the coordinates of the upper left and lower right corners // of a rectangle. // See // http://msdn.microsoft.com/en-us/library/windows/desktop/ms686311(v=vs.85).aspx smallRect struct { Left, Top, Right, Bottom int16 } // Defines the coordinates of a character cell in a console screen // buffer. The origin of the coordinate system (0,0) is at the top, left cell // of the buffer. // See // http://msdn.microsoft.com/en-us/library/windows/desktop/ms682119(v=vs.85).aspx coordinates struct { X, Y int16 } word int16 // Contains information about a console screen buffer. // http://msdn.microsoft.com/en-us/library/windows/desktop/ms682093(v=vs.85).aspx consoleScreenBufferInfo struct { dwSize coordinates dwCursorPosition coordinates wAttributes word srWindow smallRect dwMaximumWindowSize coordinates } ) // terminalWidth returns width of the terminal. func terminalWidth() (width int, err error) { var info consoleScreenBufferInfo _, _, e := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(syscall.Stdout), uintptr(unsafe.Pointer(&info)), 0) if e != 0 { return 0, error(e) } return int(info.dwSize.X) - 1, nil } func getCursorPos() (pos coordinates, err error) { var info consoleScreenBufferInfo _, _, e := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(syscall.Stdout), uintptr(unsafe.Pointer(&info)), 0) if e != 0 { return info.dwCursorPosition, error(e) } return info.dwCursorPosition, nil } func setCursorPos(pos coordinates) error { _, _, e := syscall.Syscall(setConsoleCursorPosition.Addr(), 2, uintptr(syscall.Stdout), uintptr(uint32(uint16(pos.Y))<<16|uint32(uint16(pos.X))), 0) if e != 0 { return error(e) } return nil } var ErrPoolWasStarted = errors.New("Bar pool was started") var echoLocked bool var echoLockMutex sync.Mutex var oldState word func lockEcho() (shutdownCh chan struct{}, err error) { echoLockMutex.Lock() defer echoLockMutex.Unlock() if echoLocked { err = ErrPoolWasStarted return } echoLocked = true if _, _, e := syscall.Syscall(getConsoleMode.Addr(), 2, uintptr(syscall.Stdout), uintptr(unsafe.Pointer(&oldState)), 0); e != 0 { err = fmt.Errorf("Can't get terminal settings: %v", e) return } newState := oldState const ENABLE_ECHO_INPUT = 0x0004 const ENABLE_LINE_INPUT = 0x0002 newState = newState & (^(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT)) if _, _, e := syscall.Syscall(setConsoleMode.Addr(), 2, uintptr(syscall.Stdout), uintptr(newState), 0); e != 0 { err = fmt.Errorf("Can't set terminal settings: %v", e) return } shutdownCh = make(chan struct{}) return } func unlockEcho() (err error) { echoLockMutex.Lock() defer echoLockMutex.Unlock() if !echoLocked { return } echoLocked = false if _, _, e := syscall.Syscall(setConsoleMode.Addr(), 2, uintptr(syscall.Stdout), uintptr(oldState), 0); e != 0 { err = fmt.Errorf("Can't set terminal settings") } return } golang-gopkg-cheggaaa-pb.v1-1.0.25/pb_x.go000066400000000000000000000042271330051366600201040ustar00rootroot00000000000000// +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() (shutdownCh chan struct{}, err error) { echoLockMutex.Lock() defer echoLockMutex.Unlock() if origTermStatePtr != nil { return shutdownCh, ErrPoolWasStarted } fd := int(tty.Fd()) origTermStatePtr, err = unix.IoctlGetTermios(fd, ioctlReadTermios) if err != nil { return nil, fmt.Errorf("Can't get terminal settings: %v", err) } 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() 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(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 <-shutdownCh: unlockEcho() case <-sig: unlockEcho() } } golang-gopkg-cheggaaa-pb.v1-1.0.25/pool.go000066400000000000000000000033641330051366600201260ustar00rootroot00000000000000// +build linux darwin freebsd netbsd openbsd solaris dragonfly windows package pb import ( "io" "sync" "time" ) // Create and start new pool with given bars // You need call pool.Stop() after work func StartPool(pbs ...*ProgressBar) (pool *Pool, err error) { pool = new(Pool) if err = pool.Start(); err != nil { return } 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 { Output io.Writer RefreshRate time.Duration bars []*ProgressBar lastBarsCount int shutdownCh chan struct{} workerCh chan struct{} 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 bar.Start() p.bars = append(p.bars, bar) } } func (p *Pool) Start() (err error) { p.RefreshRate = DefaultRefreshRate p.shutdownCh, err = lockEcho() if err != nil { return } p.workerCh = make(chan struct{}) go p.writer() return } 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) return } first = false case <-p.shutdownCh: return } } } // Restore terminal state and close pool func (p *Pool) Stop() error { p.finishOnce.Do(func() { close(p.shutdownCh) }) // Wait for the worker to complete select { case <-p.workerCh: } return unlockEcho() } golang-gopkg-cheggaaa-pb.v1-1.0.25/pool_win.go000066400000000000000000000012631330051366600207770ustar00rootroot00000000000000// +build windows package pb import ( "fmt" "log" ) 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(p.lastBarsCount) if coords.Y < 0 { coords.Y = 0 } coords.X = 0 err = setCursorPos(coords) if err != nil { log.Panic(err) } } isFinished := true for _, bar := range p.bars { if !bar.IsFinished() { isFinished = false } bar.Update() out += fmt.Sprintf("\r%s\n", bar.String()) } if p.Output != nil { fmt.Fprint(p.Output, out) } else { fmt.Print(out) } p.lastBarsCount = len(p.bars) return isFinished } golang-gopkg-cheggaaa-pb.v1-1.0.25/pool_x.go000066400000000000000000000010341330051366600204450ustar00rootroot00000000000000// +build linux darwin freebsd netbsd openbsd solaris dragonfly 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", p.lastBarsCount) } isFinished := true for _, bar := range p.bars { if !bar.IsFinished() { isFinished = false } bar.Update() out += fmt.Sprintf("\r%s\n", bar.String()) } if p.Output != nil { fmt.Fprint(p.Output, out) } else { fmt.Print(out) } p.lastBarsCount = len(p.bars) return isFinished } golang-gopkg-cheggaaa-pb.v1-1.0.25/reader.go000066400000000000000000000006201330051366600204070ustar00rootroot00000000000000package pb import ( "io" ) // It's proxy reader, implement io.Reader type Reader struct { io.Reader bar *ProgressBar } func (r *Reader) Read(p []byte) (n int, err error) { n, err = r.Reader.Read(p) 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 } golang-gopkg-cheggaaa-pb.v1-1.0.25/runecount.go000066400000000000000000000005541330051366600211750ustar00rootroot00000000000000package pb import ( "github.com/mattn/go-runewidth" "regexp" ) // Finds the control character sequences (like colors) 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 -= runewidth.StringWidth(sm) } return n } golang-gopkg-cheggaaa-pb.v1-1.0.25/runecount_test.go000066400000000000000000000007741330051366600222400ustar00rootroot00000000000000package pb import "testing" func Test_RuneCount(t *testing.T) { s := string([]byte{ 27, 91, 51, 49, 109, // {Red} 72, 101, 108, 108, 111, // Hello 44, 32, // , 112, 108, 97, 121, 103, 114, 111, 117, 110, 100, // Playground 27, 91, 48, 109, // {Reset} }) if e, l := 17, escapeAwareRuneCountInString(s); l != e { t.Errorf("Invalid length %d, expected %d", l, e) } s = "進捗 " if e, l := 5, escapeAwareRuneCountInString(s); l != e { t.Errorf("Invalid length %d, expected %d", l, e) } } golang-gopkg-cheggaaa-pb.v1-1.0.25/termios_bsd.go000066400000000000000000000002731330051366600214630ustar00rootroot00000000000000// +build darwin freebsd netbsd openbsd dragonfly // +build !appengine package pb import "syscall" const ioctlReadTermios = syscall.TIOCGETA const ioctlWriteTermios = syscall.TIOCSETA golang-gopkg-cheggaaa-pb.v1-1.0.25/termios_sysv.go000066400000000000000000000005051330051366600217150ustar00rootroot00000000000000// 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