pax_global_header00006660000000000000000000000064135066317530014523gustar00rootroot0000000000000052 comment=11d8df0cfef0bcb94e149d1189e5739e275f4df6 golang-gopkg-cheggaaa-pb.v2-2.0.7/000077500000000000000000000000001350663175300165505ustar00rootroot00000000000000golang-gopkg-cheggaaa-pb.v2-2.0.7/.gitignore000066400000000000000000000000101350663175300205270ustar00rootroot00000000000000vendor/ golang-gopkg-cheggaaa-pb.v2-2.0.7/.travis.yml000066400000000000000000000003251350663175300206610ustar00rootroot00000000000000language: go go: - 1.7 - 1.8 sudo: false gobuild_args: -v -race os: - linux - osx before_install: - go get github.com/mattn/goveralls script: - $HOME/gopath/bin/goveralls -service=travis-ci -ignore=termutil/* golang-gopkg-cheggaaa-pb.v2-2.0.7/Gopkg.lock000066400000000000000000000031271350663175300204740ustar00rootroot00000000000000# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. [[projects]] name = "github.com/mattn/go-colorable" packages = ["."] revision = "ed8eb9e318d7a84ce5915b495b7d35e0cfe7b5a8" version = "v0.0.6" [[projects]] name = "github.com/mattn/go-isatty" packages = ["."] revision = "3a115632dcd687f9c8cd01679c83a06a0e21c1f3" version = "v0.0.1" [[projects]] branch = "master" name = "golang.org/x/sys" packages = ["unix"] revision = "b90f89a1e7a9c1f6b918820b3daa7f08488c8594" [[projects]] name = "gopkg.in/VividCortex/ewma.v1" packages = ["."] revision = "2f8aa9741ab4b5b80945c750b871131b88ef5b7f" version = "v1.0" [[projects]] name = "gopkg.in/cheggaaa/pb.v2" packages = ["termutil"] revision = "180c76fdb3025713f501cd481e47810a9c715bd7" version = "v2.0.1" [[projects]] name = "gopkg.in/fatih/color.v1" packages = ["."] revision = "570b54cabe6b8eb0bc2dfce68d964677d63b5260" version = "v1.5.0" [[projects]] name = "gopkg.in/mattn/go-colorable.v0" packages = ["."] revision = "d228849504861217f796da67fae4f6e347643f15" version = "v0.0.7" [[projects]] name = "gopkg.in/mattn/go-isatty.v0" packages = ["."] revision = "fc9e8d8ef48496124e79ae0df75490096eccf6fe" version = "v0.0.2" [[projects]] name = "gopkg.in/mattn/go-runewidth.v0" packages = ["."] revision = "9e777a8366cce605130a531d2cd6363d07ad7317" version = "v0.0.2" [solve-meta] analyzer-name = "dep" analyzer-version = 1 inputs-digest = "cf10fbfc96962122f1a56c1752a1d5dab64799ffedc58460e1ab1465d2bef5e2" solver-name = "gps-cdcl" solver-version = 1 golang-gopkg-cheggaaa-pb.v2-2.0.7/Gopkg.toml000066400000000000000000000063701350663175300205220ustar00rootroot00000000000000 ## Gopkg.toml example (these lines may be deleted) ## "metadata" defines metadata about the project that could be used by other independent ## systems. The metadata defined here will be ignored by dep. # [metadata] # key1 = "value that convey data to other systems" # system1-data = "value that is used by a system" # system2-data = "value that is used by another system" ## "required" lists a set of packages (not projects) that must be included in ## Gopkg.lock. This list is merged with the set of packages imported by the current ## project. Use it when your project needs a package it doesn't explicitly import - ## including "main" packages. # required = ["github.com/user/thing/cmd/thing"] ## "ignored" lists a set of packages (not projects) that are ignored when ## dep statically analyzes source code. Ignored packages can be in this project, ## or in a dependency. # ignored = ["github.com/user/project/badpkg"] ## Constraints are rules for how directly imported projects ## may be incorporated into the depgraph. They are respected by ## dep whether coming from the Gopkg.toml of the current project or a dependency. # [[constraint]] ## Required: the root import path of the project being constrained. # name = "github.com/user/project" # ## Recommended: the version constraint to enforce for the project. ## Only one of "branch", "version" or "revision" can be specified. # version = "1.0.0" # branch = "master" # revision = "abc123" # ## Optional: an alternate location (URL or import path) for the project's source. # source = "https://github.com/myfork/package.git" # ## "metadata" defines metadata about the dependency or override that could be used ## by other independent systems. The metadata defined here will be ignored by dep. # [metadata] # key1 = "value that convey data to other systems" # system1-data = "value that is used by a system" # system2-data = "value that is used by another system" ## Overrides have the same structure as [[constraint]], but supersede all ## [[constraint]] declarations from all projects. Only [[override]] from ## the current project's are applied. ## ## Overrides are a sledgehammer. Use them only as a last resort. # [[override]] ## Required: the root import path of the project being constrained. # name = "github.com/user/project" # ## Optional: specifying a version constraint override will cause all other ## constraints on this project to be ignored; only the overridden constraint ## need be satisfied. ## Again, only one of "branch", "version" or "revision" can be specified. # version = "1.0.0" # branch = "master" # revision = "abc123" # ## Optional: specifying an alternate source location as an override will ## enforce that the alternate location is used for that project, regardless of ## what source location any dependent projects specify. # source = "https://github.com/myfork/package.git" [[constraint]] name = "gopkg.in/VividCortex/ewma.v1" version = "1.0.0" [[constraint]] name = "gopkg.in/cheggaaa/pb.v2" version = "2.0.1" [[constraint]] name = "gopkg.in/fatih/color.v1" version = "1.5.0" [[constraint]] name = "gopkg.in/mattn/go-colorable.v0" version = "0.0.7" [[constraint]] name = "gopkg.in/mattn/go-isatty.v0" version = "0.0.2" [[constraint]] name = "gopkg.in/mattn/go-runewidth.v0" version = "0.0.2" golang-gopkg-cheggaaa-pb.v2-2.0.7/LICENSE000066400000000000000000000027071350663175300175630ustar00rootroot00000000000000Copyright (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.v2-2.0.7/README.md000066400000000000000000000032701350663175300200310ustar00rootroot00000000000000### Warning Please use v3 version ```go get github.com/cheggaaa/v3``` - it's a continuation of the v2, but in the master branch and with the support of go modules # Terminal progress bar for Go [![Coverage Status](https://coveralls.io/repos/github/cheggaaa/pb/badge.svg?branch=v2)](https://coveralls.io/github/cheggaaa/pb?branch=v2) ### It's beta, some features may be changed This is proposal for the second version of progress bar - based on text/template - can take custom elements - using colors is easy ## Installation ``` go get gopkg.in/cheggaaa/pb.v2 ``` ## Usage ```Go package main import ( "gopkg.in/cheggaaa/pb.v2" "time" ) func main() { simple() fromPreset() customTemplate(`Custom template: {{counters . }}`) customTemplate(`{{ red "With colors:" }} {{bar . | green}} {{speed . | blue }}`) customTemplate(`{{ red "With funcs:" }} {{ bar . "<" "-" (cycle . "↖" "↗" "↘" "↙" ) "." ">"}} {{speed . | rndcolor }}`) customTemplate(`{{ bar . "[<" "·····•·····" (rnd "ᗧ" "◔" "◕" "◷" ) "•" ">]"}}`) } func simple() { count := 1000 bar := pb.StartNew(count) for i := 0; i < count; i++ { bar.Increment() time.Sleep(time.Millisecond * 2) } bar.Finish() } func fromPreset() { count := 1000 //bar := pb.Default.Start(total) //bar := pb.Simple.Start(total) bar := pb.Full.Start(count) defer bar.Finish() bar.Set("prefix", "fromPreset(): ") for i := 0; i < count/2; i++ { bar.Add(2) time.Sleep(time.Millisecond * 4) } } func customTemplate(tmpl string) { count := 1000 bar := pb.ProgressBarTemplate(tmpl).Start(count) defer bar.Finish() for i := 0; i < count/2; i++ { bar.Add(2) time.Sleep(time.Millisecond * 4) } } ``` golang-gopkg-cheggaaa-pb.v2-2.0.7/element.go000066400000000000000000000174001350663175300205320ustar00rootroot00000000000000package pb import ( "bytes" "fmt" "math" "sync" "time" ) const ( adElPlaceholder = "%_ad_el_%" adElPlaceholderLen = len(adElPlaceholder) ) var ( defaultBarEls = [5]string{"[", "-", ">", "_", "]"} ) // Element is an interface for bar elements type Element interface { ProgressElement(state *State, args ...string) string } // ElementFunc type implements Element interface and created for simplify elements type ElementFunc func(state *State, args ...string) string // ProgressElement just call self func func (e ElementFunc) ProgressElement(state *State, args ...string) string { return e(state, args...) } var elementsM sync.Mutex var elements = map[string]Element{ "percent": ElementPercent, "counters": ElementCounters, "bar": adaptiveWrap(ElementBar), "speed": ElementSpeed, "rtime": ElementRemainingTime, "etime": ElementElapsedTime, "string": ElementString, "cycle": ElementCycle, } // RegisterElement give you a chance to use custom elements func RegisterElement(name string, el Element, adaptive bool) { if adaptive { el = adaptiveWrap(el) } elementsM.Lock() elements[name] = el elementsM.Unlock() } type argsHelper []string func (args argsHelper) getOr(n int, value string) string { if len(args) > n { return args[n] } return value } func (args argsHelper) getNotEmptyOr(n int, value string) (v string) { if v = args.getOr(n, value); v == "" { return value } return } func adaptiveWrap(el Element) Element { return ElementFunc(func(state *State, args ...string) string { state.recalc = append(state.recalc, ElementFunc(func(s *State, _ ...string) (result string) { s.adaptive = true result = el.ProgressElement(s, args...) s.adaptive = false return })) return adElPlaceholder }) } // ElementPercent shows current percent of progress. // Optionally can take one or two string arguments. // First string will be used as value for format float64, default is "%.02f%%". // Second string will be used when percent can't be calculated, default is "?%" // In template use as follows: {{percent .}} or {{percent . "%.03f%%"}} or {{percent . "%.03f%%" "?"}} var ElementPercent ElementFunc = func(state *State, args ...string) string { argsh := argsHelper(args) if state.Total() > 0 { return fmt.Sprintf( argsh.getNotEmptyOr(0, "%.02f%%"), float64(state.Value())/(float64(state.Total())/float64(100)), ) } return argsh.getOr(1, "?%") } // ElementCounters shows current and total values. // Optionally can take one or two string arguments. // First string will be used as format value when Total is present (>0). Default is "%s / %s" // Second string will be used when total <= 0. Default is "%[1]s" // In template use as follows: {{counters .}} or {{counters . "%s/%s"}} or {{counters . "%s/%s" "%s/?"}} var ElementCounters ElementFunc = func(state *State, args ...string) string { var f string if state.Total() > 0 { f = argsHelper(args).getNotEmptyOr(0, "%s / %s") } else { f = argsHelper(args).getNotEmptyOr(1, "%[1]s") } return fmt.Sprintf(f, state.Format(state.Value()), state.Format(state.Total())) } type elementKey int const ( barObj elementKey = iota speedObj cycleObj ) type bar struct { eb [5][]byte // elements in bytes cc [5]int // cell counts buf *bytes.Buffer } func (p *bar) write(state *State, eln, width int) int { repeat := width / p.cc[eln] for i := 0; i < repeat; i++ { p.buf.Write(p.eb[eln]) } StripStringToBuffer(string(p.eb[eln]), width%p.cc[eln], p.buf) return width } func getProgressObj(state *State, args ...string) (p *bar) { var ok bool if p, ok = state.Get(barObj).(*bar); !ok { p = &bar{ buf: bytes.NewBuffer(nil), } state.Set(barObj, p) } argsH := argsHelper(args) for i := range p.eb { arg := argsH.getNotEmptyOr(i, defaultBarEls[i]) if string(p.eb[i]) != arg { p.cc[i] = CellCount(arg) p.eb[i] = []byte(arg) if p.cc[i] == 0 { p.cc[i] = 1 p.eb[i] = []byte(" ") } } } return } // ElementBar make progress bar view [-->__] // Optionally can take up to 5 string arguments. Defaults is "[", "-", ">", "_", "]" // In template use as follows: {{bar . }} or {{bar . "<" "oOo" "|" "~" ">"}} // Color args: {{bar . (red "[") (green "-") ... var ElementBar ElementFunc = func(state *State, args ...string) string { // init var p = getProgressObj(state, args...) total, value := state.Total(), state.Value() if total < 0 { total = -total } if value < 0 { value = -value } // check for overflow if total != 0 && value > total { total = value } p.buf.Reset() var widthLeft = state.AdaptiveElWidth() if widthLeft <= 0 || !state.IsAdaptiveWidth() { widthLeft = 30 } // write left border if p.cc[0] < widthLeft { widthLeft -= p.write(state, 0, p.cc[0]) } else { p.write(state, 0, widthLeft) return p.buf.String() } // check right border size if p.cc[4] < widthLeft { // write later widthLeft -= p.cc[4] } else { p.write(state, 4, widthLeft) return p.buf.String() } var curCount int if total > 0 { // calculate count of currenct space curCount = int(math.Ceil((float64(value) / float64(total)) * float64(widthLeft))) } // write bar if total == value && state.IsFinished() { widthLeft -= p.write(state, 1, curCount) } else if toWrite := curCount - p.cc[2]; toWrite > 0 { widthLeft -= p.write(state, 1, toWrite) widthLeft -= p.write(state, 2, p.cc[2]) } else if curCount > 0 { widthLeft -= p.write(state, 2, curCount) } if widthLeft > 0 { widthLeft -= p.write(state, 3, widthLeft) } // write right border p.write(state, 4, p.cc[4]) // cut result and return string return p.buf.String() } // ElementRemainingTime calculates remaining time based on speed (EWMA) // Optionally can take one or two string arguments. // First string will be used as value for format time duration string, default is "%s". // Second string will be used when bar finished and value indicates elapsed time, default is "%s" // Third string will be used when value not available, default is "?" // In template use as follows: {{rtime .}} or {{rtime . "%s remain"}} or {{rtime . "%s remain" "%s total" "???"}} var ElementRemainingTime ElementFunc = func(state *State, args ...string) string { var rts string sp := getSpeedObj(state).value(state) if !state.IsFinished() { if sp > 0 { remain := float64(state.Total() - state.Value()) remainDur := time.Duration(remain/sp) * time.Second rts = remainDur.String() } else { return argsHelper(args).getOr(2, "?") } } else { rts = state.Time().Truncate(time.Second).Sub(state.StartTime().Truncate(time.Second)).String() return fmt.Sprintf(argsHelper(args).getOr(1, "%s"), rts) } return fmt.Sprintf(argsHelper(args).getOr(0, "%s"), rts) } // ElementElapsedTime shows elapsed time // Optionally cat take one argument - it's format for time string. // In template use as follows: {{etime .}} or {{etime . "%s elapsed"}} var ElementElapsedTime ElementFunc = func(state *State, args ...string) string { etm := state.Time().Truncate(time.Second).Sub(state.StartTime().Truncate(time.Second)) return fmt.Sprintf(argsHelper(args).getOr(0, "%s"), etm.String()) } // ElementString get value from bar by given key and print them // bar.Set("myKey", "string to print") // In template use as follows: {{string . "myKey"}} var ElementString ElementFunc = func(state *State, args ...string) string { if len(args) == 0 { return "" } v := state.Get(args[0]) if v == nil { return "" } return fmt.Sprint(v) } // ElementCycle return next argument for every call // In template use as follows: {{cycle . "1" "2" "3"}} // Or mix width other elements: {{ bar . "" "" (cycle . "↖" "↗" "↘" "↙" )}} var ElementCycle ElementFunc = func(state *State, args ...string) string { if len(args) == 0 { return "" } n, _ := state.Get(cycleObj).(int) if n >= len(args) { n = 0 } state.Set(cycleObj, n+1) return args[n] } golang-gopkg-cheggaaa-pb.v2-2.0.7/element_test.go000066400000000000000000000227251350663175300215770ustar00rootroot00000000000000package pb import ( "fmt" "strings" "testing" "time" "gopkg.in/fatih/color.v1" ) func testState(total, value int64, maxWidth int, bools ...bool) (s *State) { s = &State{ total: total, current: value, adaptiveElWidth: maxWidth, ProgressBar: new(ProgressBar), } if len(bools) > 0 { s.Set(Bytes, bools[0]) } if len(bools) > 1 && bools[1] { s.adaptive = true } return } func testElementBarString(t *testing.T, state *State, el Element, want string, args ...string) { if state.ProgressBar == nil { state.ProgressBar = new(ProgressBar) } res := el.ProgressElement(state, args...) if res != want { t.Errorf("Unexpected result: '%s'; want: '%s'", res, want) } if state.IsAdaptiveWidth() && state.AdaptiveElWidth() != CellCount(res) { t.Errorf("Unepected width: %d; want: %d", CellCount(res), state.AdaptiveElWidth()) } } func TestElementPercent(t *testing.T) { testElementBarString(t, testState(100, 50, 0), ElementPercent, "50.00%") testElementBarString(t, testState(100, 50, 0), ElementPercent, "50 percent", "%v percent") testElementBarString(t, testState(0, 50, 0), ElementPercent, "?%") testElementBarString(t, testState(0, 50, 0), ElementPercent, "unkn", "%v%%", "unkn") } func TestElementCounters(t *testing.T) { testElementBarString(t, testState(100, 50, 0), ElementCounters, "50 / 100") testElementBarString(t, testState(100, 50, 0), ElementCounters, "50 of 100", "%s of %s") testElementBarString(t, testState(100, 50, 0, true), ElementCounters, "50 B of 100 B", "%s of %s") testElementBarString(t, testState(100, 50, 0, true), ElementCounters, "50 B / 100 B") testElementBarString(t, testState(0, 50, 0, true), ElementCounters, "50 B") testElementBarString(t, testState(0, 50, 0, true), ElementCounters, "50 B / ?", "", "%[1]s / ?") } func TestElementBar(t *testing.T) { // short testElementBarString(t, testState(100, 50, 1, false, true), ElementBar, "[") testElementBarString(t, testState(100, 50, 2, false, true), ElementBar, "[]") testElementBarString(t, testState(100, 50, 3, false, true), ElementBar, "[>]") testElementBarString(t, testState(100, 50, 4, false, true), ElementBar, "[>_]") testElementBarString(t, testState(100, 50, 5, false, true), ElementBar, "[->_]") // middle testElementBarString(t, testState(100, 50, 10, false, true), ElementBar, "[--->____]") testElementBarString(t, testState(100, 50, 10, false, true), ElementBar, "<--->____>", "<", "", "", "", ">") // finished st := testState(100, 100, 10, false, true) st.finished = true testElementBarString(t, st, ElementBar, "[--------]") // empty color st = testState(100, 50, 10, false, true) st.Set(Terminal, true) color.NoColor = false testElementBarString(t, st, ElementBar, " --->____]", color.RedString("%s", "")) // empty testElementBarString(t, testState(0, 50, 10, false, true), ElementBar, "[________]") // full testElementBarString(t, testState(20, 20, 10, false, true), ElementBar, "[------->]") // everflow testElementBarString(t, testState(20, 50, 10, false, true), ElementBar, "[------->]") // small width testElementBarString(t, testState(20, 50, 2, false, true), ElementBar, "[]") testElementBarString(t, testState(20, 50, 1, false, true), ElementBar, "[") // negative counters testElementBarString(t, testState(-50, -150, 10, false, true), ElementBar, "[------->]") testElementBarString(t, testState(-150, -50, 10, false, true), ElementBar, "[-->_____]") testElementBarString(t, testState(50, -150, 10, false, true), ElementBar, "[------->]") testElementBarString(t, testState(-50, 150, 10, false, true), ElementBar, "[------->]") // long entities / unicode f1 := []string{"進捗|", "многобайт", "active", "пусто", "|end"} testElementBarString(t, testState(100, 50, 1, false, true), ElementBar, " ", f1...) testElementBarString(t, testState(100, 50, 3, false, true), ElementBar, "進 ", f1...) testElementBarString(t, testState(100, 50, 4, false, true), ElementBar, "進捗", f1...) testElementBarString(t, testState(100, 50, 29, false, true), ElementBar, "進捗|многactiveпустопусто|end", f1...) testElementBarString(t, testState(100, 50, 11, false, true), ElementBar, "進捗|aп|end", f1...) // unicode f2 := []string{"⚑", "⚒", "⚟", "⟞", "⚐"} testElementBarString(t, testState(100, 50, 10, false, true), ElementBar, "⚑⚒⚒⚒⚟⟞⟞⟞⟞⚐", f2...) // no adaptive testElementBarString(t, testState(0, 50, 10), ElementBar, "[____________________________]") var formats = [][]string{ []string{}, f1, f2, } // all widths / extreme values // check for panic and correct width for _, f := range formats { for tt := int64(-2); tt < 12; tt++ { for v := int64(-2); v < 12; v++ { state := testState(tt, v, 0, false, true) for w := -2; w < 20; w++ { state.adaptiveElWidth = w res := ElementBar(state, f...) var we = w if we <= 0 { we = 30 } if CellCount(res) != we { t.Errorf("Unexpected len(%d): '%s'", we, res) } } } } } } func TestElementSpeed(t *testing.T) { var state = testState(1000, 0, 0, false) state.time = time.Now() for i := int64(0); i < 10; i++ { state.id = uint64(i) + 1 state.current += 42 state.time = state.time.Add(time.Second) state.finished = i == 9 if state.finished { state.current += 100 } r := ElementSpeed(state) r2 := ElementSpeed(state) if r != r2 { t.Errorf("Must be the same: '%s' vs '%s'", r, r2) } if i < 1 { // do not calc first result if w := "? p/s"; r != w { t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w) } } else if state.finished { if w := "58 p/s"; r != w { t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w) } state.time = state.time.Add(-time.Hour) r = ElementSpeed(state) if w := "? p/s"; r != w { t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w) } } else { if w := "42 p/s"; r != w { t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w) } } } } func TestElementRemainingTime(t *testing.T) { var state = testState(100, 0, 0, false) state.time = time.Now() state.startTime = state.time for i := int64(0); i < 10; i++ { state.id = uint64(i) + 1 state.time = state.time.Add(time.Second) state.finished = i == 9 r := ElementRemainingTime(state) if i < 1 { // do not calc first two results if w := "?"; r != w { t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w) } } else if state.finished { // final elapsed time if w := "10s"; r != w { t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w) } } else { w := fmt.Sprintf("%ds", 10-i) if r != w { t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w) } } state.current += 10 } } func TestElementElapsedTime(t *testing.T) { var state = testState(1000, 0, 0, false) state.startTime = time.Now() state.time = state.startTime for i := int64(0); i < 10; i++ { r := ElementElapsedTime(state) if w := fmt.Sprintf("%ds", i); r != w { t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w) } state.time = state.time.Add(time.Second) } } func TestElementString(t *testing.T) { var state = testState(0, 0, 0, false) testElementBarString(t, state, ElementString, "", "myKey") state.Set("myKey", "my value") testElementBarString(t, state, ElementString, "my value", "myKey") state.Set("myKey", "my value1") testElementBarString(t, state, ElementString, "my value1", "myKey") testElementBarString(t, state, ElementString, "") } func TestElementCycle(t *testing.T) { var state = testState(0, 0, 0, false) testElementBarString(t, state, ElementCycle, "") testElementBarString(t, state, ElementCycle, "1", "1", "2", "3") testElementBarString(t, state, ElementCycle, "2", "1", "2", "3") testElementBarString(t, state, ElementCycle, "3", "1", "2", "3") testElementBarString(t, state, ElementCycle, "1", "1", "2", "3") testElementBarString(t, state, ElementCycle, "2", "1", "2") testElementBarString(t, state, ElementCycle, "1", "1", "2") } func TestAdaptiveWrap(t *testing.T) { var state = testState(0, 0, 0, false) state.id = 1 state.Set("myKey", "my value") el := adaptiveWrap(ElementString) testElementBarString(t, state, el, adElPlaceholder, "myKey") if v := state.recalc[0].ProgressElement(state); v != "my value" { t.Errorf("Unexpected result: %s", v) } state.id = 2 testElementBarString(t, state, el, adElPlaceholder, "myKey1") state.Set("myKey", "my value1") if v := state.recalc[0].ProgressElement(state); v != "my value1" { t.Errorf("Unexpected result: %s", v) } } func TestRegisterElement(t *testing.T) { var testEl ElementFunc = func(state *State, args ...string) string { return strings.Repeat("*", state.AdaptiveElWidth()) } RegisterElement("testEl", testEl, true) result := ProgressBarTemplate(`{{testEl . }}`).New(0).SetWidth(5).String() if result != "*****" { t.Errorf("Unexpected result: '%v'", result) } } func BenchmarkBar(b *testing.B) { var formats = map[string][]string{ "simple": []string{".", ".", ".", ".", "."}, "unicode": []string{"⚑", "⚒", "⚟", "⟞", "⚐"}, "color": []string{color.RedString("%s", "."), color.RedString("%s", "."), color.RedString("%s", "."), color.RedString("%s", "."), color.RedString("%s", ".")}, "long": []string{"..", "..", "..", "..", ".."}, "longunicode": []string{"⚑⚑", "⚒⚒", "⚟⚟", "⟞⟞", "⚐⚐"}, } for name, args := range formats { state := testState(100, 50, 100, false, true) b.Run(name, func(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { ElementBar(state, args...) } }) } } golang-gopkg-cheggaaa-pb.v2-2.0.7/pb.go000066400000000000000000000271051350663175300175050ustar00rootroot00000000000000package pb import ( "bytes" "fmt" "io" "os" "strconv" "strings" "sync" "sync/atomic" "text/template" "time" "gopkg.in/cheggaaa/pb.v2/termutil" "gopkg.in/mattn/go-colorable.v0" "gopkg.in/mattn/go-isatty.v0" ) // Version of ProgressBar library const Version = "2.0.6" type key int const ( // Bytes means we're working with byte sizes. Numbers will print as Kb, Mb, etc // bar.Set(pb.Bytes, true) Bytes key = 1 << iota // Terminal means we're will print to terminal and can use ascii sequences // Also we're will try to use terminal width Terminal // Static means progress bar will not update automaticly Static // ReturnSymbol - by default in terminal mode it's '\r' ReturnSymbol // Color by default is true when output is tty, but you can set to false for disabling colors Color ) const ( defaultBarWidth = 100 defaultRefreshRate = time.Millisecond * 200 ) // New creates new ProgressBar object func New(total int) *ProgressBar { return New64(int64(total)) } // New64 creates new ProgressBar object using int64 as total func New64(total int64) *ProgressBar { pb := new(ProgressBar) return pb.SetTotal(total) } // StartNew starts new ProgressBar with Default template func StartNew(total int) *ProgressBar { return New(total).Start() } // Start64 starts new ProgressBar with Default template. Using int64 as total. func Start64(total int64) *ProgressBar { return New64(total).Start() } var ( terminalWidth = termutil.TerminalWidth isTerminal = isatty.IsTerminal isCygwinTerminal = isatty.IsCygwinTerminal ) // ProgressBar is the main object of bar type ProgressBar struct { current, total int64 width int mu sync.RWMutex rm sync.Mutex vars map[interface{}]interface{} elements map[string]Element output io.Writer coutput io.Writer nocoutput io.Writer startTime time.Time refreshRate time.Duration tmpl *template.Template state *State buf *bytes.Buffer ticker *time.Ticker finish chan struct{} finished bool configured bool err error } func (pb *ProgressBar) configure() { if pb.configured { return } pb.configured = true if pb.vars == nil { pb.vars = make(map[interface{}]interface{}) } if pb.output == nil { pb.output = os.Stderr } if pb.tmpl == nil { pb.tmpl, pb.err = getTemplate(string(Default)) if pb.err != nil { return } } if pb.vars[Terminal] == nil { if f, ok := pb.output.(*os.File); ok { if isTerminal(f.Fd()) || isCygwinTerminal(f.Fd()) { pb.vars[Terminal] = true } } } if pb.vars[ReturnSymbol] == nil { if tm, ok := pb.vars[Terminal].(bool); ok && tm { pb.vars[ReturnSymbol] = "\r" } } if pb.vars[Color] == nil { if tm, ok := pb.vars[Terminal].(bool); ok && tm { pb.vars[Color] = true } } if pb.refreshRate == 0 { pb.refreshRate = defaultRefreshRate } if f, ok := pb.output.(*os.File); ok { pb.coutput = colorable.NewColorable(f) } else { pb.coutput = pb.output } pb.nocoutput = colorable.NewNonColorable(pb.output) } // Start starts the bar func (pb *ProgressBar) Start() *ProgressBar { pb.mu.Lock() defer pb.mu.Unlock() if pb.finish != nil { return pb } pb.configure() pb.finished = false pb.state = nil pb.startTime = time.Now() if st, ok := pb.vars[Static].(bool); ok && st { return pb } pb.finish = make(chan struct{}) pb.ticker = time.NewTicker(pb.refreshRate) go pb.writer(pb.finish) return pb } func (pb *ProgressBar) writer(finish chan struct{}) { for { select { case <-pb.ticker.C: pb.write(false) case <-finish: pb.ticker.Stop() pb.write(true) finish <- struct{}{} return } } } // Write performs write to the output func (pb *ProgressBar) Write() *ProgressBar { pb.mu.RLock() finished := pb.finished pb.mu.RUnlock() pb.write(finished) return pb } func (pb *ProgressBar) write(finish bool) { result, width := pb.render() if pb.Err() != nil { return } if pb.GetBool(Terminal) { if r := (width - CellCount(result)); r > 0 { result += strings.Repeat(" ", r) } } if ret, ok := pb.Get(ReturnSymbol).(string); ok { result = ret + result if finish && ret == "\r" { result += "\n" } } if pb.GetBool(Color) { pb.coutput.Write([]byte(result)) } else { pb.nocoutput.Write([]byte(result)) } } // Total return current total bar value func (pb *ProgressBar) Total() int64 { return atomic.LoadInt64(&pb.total) } // SetTotal sets the total bar value func (pb *ProgressBar) SetTotal(value int64) *ProgressBar { atomic.StoreInt64(&pb.total, value) return pb } // SetCurrent sets the current bar value func (pb *ProgressBar) SetCurrent(value int64) *ProgressBar { atomic.StoreInt64(&pb.current, value) return pb } // Current return current bar value func (pb *ProgressBar) Current() int64 { return atomic.LoadInt64(&pb.current) } // Add adding given int64 value to bar value func (pb *ProgressBar) Add64(value int64) *ProgressBar { atomic.AddInt64(&pb.current, value) return pb } // Add adding given int value to bar value func (pb *ProgressBar) Add(value int) *ProgressBar { return pb.Add64(int64(value)) } // Increment atomically increments the progress func (pb *ProgressBar) Increment() *ProgressBar { return pb.Add64(1) } // Set sets any value by any key func (pb *ProgressBar) Set(key, value interface{}) *ProgressBar { pb.mu.Lock() defer pb.mu.Unlock() if pb.vars == nil { pb.vars = make(map[interface{}]interface{}) } pb.vars[key] = value return pb } // Get return value by key func (pb *ProgressBar) Get(key interface{}) interface{} { pb.mu.RLock() defer pb.mu.RUnlock() if pb.vars == nil { return nil } return pb.vars[key] } // GetBool return value by key and try to convert there to boolean // If value doesn't set or not boolean - return false func (pb *ProgressBar) GetBool(key interface{}) bool { if v, ok := pb.Get(key).(bool); ok { return v } return false } // SetWidth sets the bar width // When given value <= 0 would be using the terminal width (if possible) or default value. func (pb *ProgressBar) SetWidth(width int) *ProgressBar { pb.mu.Lock() pb.width = width pb.mu.Unlock() return pb } // Width return the bar width // It's current terminal width or settled over 'SetWidth' value. func (pb *ProgressBar) Width() (width int) { defer func() { if r := recover(); r != nil { width = defaultBarWidth } }() pb.mu.RLock() width = pb.width pb.mu.RUnlock() if width <= 0 { var err error if width, err = terminalWidth(); err != nil { return defaultBarWidth } } return } func (pb *ProgressBar) SetRefreshRate(dur time.Duration) *ProgressBar { pb.mu.Lock() if dur > 0 { pb.refreshRate = dur } pb.mu.Unlock() return pb } // SetWriter sets the io.Writer. Bar will write in this writer // By default this is os.Stderr func (pb *ProgressBar) SetWriter(w io.Writer) *ProgressBar { pb.mu.Lock() pb.output = w pb.configured = false pb.configure() pb.mu.Unlock() return pb } // StartTime return the time when bar started func (pb *ProgressBar) StartTime() time.Time { pb.mu.RLock() defer pb.mu.RUnlock() return pb.startTime } // Format convert int64 to string according to the current settings func (pb *ProgressBar) Format(v int64) string { if pb.GetBool(Bytes) { return formatBytes(v) } return strconv.FormatInt(v, 10) } // Finish stops the bar func (pb *ProgressBar) Finish() *ProgressBar { pb.mu.Lock() if pb.finished { pb.mu.Unlock() return pb } finishChan := pb.finish pb.finished = true pb.mu.Unlock() if finishChan != nil { finishChan <- struct{}{} <-finishChan pb.mu.Lock() pb.finish = nil pb.mu.Unlock() } return pb } // IsStarted indicates progress bar state func (pb *ProgressBar) IsStarted() bool { pb.mu.RLock() defer pb.mu.RUnlock() return pb.finish != nil } // SetTemplateString sets ProgressBar tempate string and parse it func (pb *ProgressBar) SetTemplateString(tmpl string) *ProgressBar { pb.mu.Lock() defer pb.mu.Unlock() pb.tmpl, pb.err = getTemplate(tmpl) return pb } // SetTemplateString sets ProgressBarTempate and parse it func (pb *ProgressBar) SetTemplate(tmpl ProgressBarTemplate) *ProgressBar { return pb.SetTemplateString(string(tmpl)) } // NewProxyReader creates a wrapper for given reader, but with progress handle // Takes io.Reader or io.ReadCloser // Also, it automatically switches progress bar to handle units as bytes func (pb *ProgressBar) NewProxyReader(r io.Reader) *Reader { pb.Set(Bytes, true) return &Reader{r, pb} } func (pb *ProgressBar) render() (result string, width int) { defer func() { if r := recover(); r != nil { pb.SetErr(fmt.Errorf("render panic: %v", r)) } }() pb.rm.Lock() defer pb.rm.Unlock() pb.mu.Lock() pb.configure() if pb.state == nil { pb.state = &State{ProgressBar: pb} pb.buf = bytes.NewBuffer(nil) } if pb.startTime.IsZero() { pb.startTime = time.Now() } pb.state.id++ pb.state.finished = pb.finished pb.state.time = time.Now() pb.mu.Unlock() pb.state.width = pb.Width() width = pb.state.width pb.state.total = pb.Total() pb.state.current = pb.Current() pb.buf.Reset() if e := pb.tmpl.Execute(pb.buf, pb.state); e != nil { pb.SetErr(e) return "", 0 } result = pb.buf.String() aec := len(pb.state.recalc) if aec == 0 { // no adaptive elements return } staticWidth := CellCount(result) - (aec * adElPlaceholderLen) if pb.state.Width()-staticWidth <= 0 { result = strings.Replace(result, adElPlaceholder, "", -1) result = StripString(result, pb.state.Width()) } else { pb.state.adaptiveElWidth = (width - staticWidth) / aec for _, el := range pb.state.recalc { result = strings.Replace(result, adElPlaceholder, el.ProgressElement(pb.state), 1) } } pb.state.recalc = pb.state.recalc[:0] return } // SetErr sets error to the ProgressBar // Error will be available over Err() func (pb *ProgressBar) SetErr(err error) *ProgressBar { pb.mu.Lock() pb.err = err pb.mu.Unlock() return pb } // Err return possible error // When all ok - will be nil // May contain template.Execute errors func (pb *ProgressBar) Err() error { pb.mu.RLock() defer pb.mu.RUnlock() return pb.err } // String return currrent string representation of ProgressBar func (pb *ProgressBar) String() string { res, _ := pb.render() return res } // ProgressElement implements Element interface func (pb *ProgressBar) ProgressElement(s *State, args ...string) string { if s.IsAdaptiveWidth() { pb.SetWidth(s.AdaptiveElWidth()) } return pb.String() } // State represents the current state of bar // Need for bar elements type State struct { *ProgressBar id uint64 total, current int64 width, adaptiveElWidth int finished, adaptive bool time time.Time recalc []Element } // Id it's the current state identifier // - incremental // - starts with 1 // - resets after finish/start func (s *State) Id() uint64 { return s.id } // Total it's bar int64 total func (s *State) Total() int64 { return s.total } // Value it's current value func (s *State) Value() int64 { return s.current } // Width of bar func (s *State) Width() int { return s.width } // AdaptiveElWidth - adaptive elements must return string with given cell count (when AdaptiveElWidth > 0) func (s *State) AdaptiveElWidth() int { return s.adaptiveElWidth } // IsAdaptiveWidth returns true when element must be shown as adaptive func (s *State) IsAdaptiveWidth() bool { return s.adaptive } // IsFinished return true when bar is finished func (s *State) IsFinished() bool { return s.finished } // IsFirst return true only in first render func (s *State) IsFirst() bool { return s.id == 1 } // Time when state was created func (s *State) Time() time.Time { return s.time } golang-gopkg-cheggaaa-pb.v2-2.0.7/pb_test.go000066400000000000000000000130021350663175300205330ustar00rootroot00000000000000package pb import ( "bytes" "errors" "fmt" "strings" "testing" "time" "gopkg.in/fatih/color.v1" ) func TestPBBasic(t *testing.T) { bar := new(ProgressBar) var a, e int64 if a, e = bar.Total(), 0; a != e { t.Errorf("Unexpected total: actual: %v; expected: %v", a, e) } if a, e = bar.Current(), 0; a != e { t.Errorf("Unexpected current: actual: %v; expected: %v", a, e) } bar.SetCurrent(10).SetTotal(20) if a, e = bar.Total(), 20; a != e { t.Errorf("Unexpected total: actual: %v; expected: %v", a, e) } if a, e = bar.Current(), 10; a != e { t.Errorf("Unexpected current: actual: %v; expected: %v", a, e) } bar.Add(5) if a, e = bar.Current(), 15; a != e { t.Errorf("Unexpected current: actual: %v; expected: %v", a, e) } bar.Increment() if a, e = bar.Current(), 16; a != e { t.Errorf("Unexpected current: actual: %v; expected: %v", a, e) } } func TestPBWidth(t *testing.T) { terminalWidth = func() (int, error) { return 50, nil } // terminal width bar := new(ProgressBar) if a, e := bar.Width(), 50; a != e { t.Errorf("Unexpected width: actual: %v; expected: %v", a, e) } // terminal width error terminalWidth = func() (int, error) { return 0, errors.New("test error") } if a, e := bar.Width(), defaultBarWidth; a != e { t.Errorf("Unexpected width: actual: %v; expected: %v", a, e) } // terminal width panic terminalWidth = func() (int, error) { panic("test") return 0, nil } if a, e := bar.Width(), defaultBarWidth; a != e { t.Errorf("Unexpected width: actual: %v; expected: %v", a, e) } // set negative terminal width bar.SetWidth(-42) if a, e := bar.Width(), defaultBarWidth; a != e { t.Errorf("Unexpected width: actual: %v; expected: %v", a, e) } // set terminal width bar.SetWidth(42) if a, e := bar.Width(), 42; a != e { t.Errorf("Unexpected width: actual: %v; expected: %v", a, e) } } func TestPBTemplate(t *testing.T) { bar := new(ProgressBar) result := bar.SetTotal(100).SetCurrent(50).SetWidth(40).String() expected := "50 / 100 [------->________] 50.00% ? p/s" if result != expected { t.Errorf("Unexpected result: (actual/expected)\n%s\n%s", result, expected) } // check strip result = bar.SetWidth(8).String() expected = "50 / 100" if result != expected { t.Errorf("Unexpected result: (actual/expected)\n%s\n%s", result, expected) } // invalid template for _, invalidTemplate := range []string{ `{{invalid template`, `{{speed}}`, } { bar.SetTemplateString(invalidTemplate) result = bar.String() expected = "" if result != expected { t.Errorf("Unexpected result: (actual/expected)\n%s\n%s", result, expected) } if err := bar.Err(); err == nil { t.Errorf("Must be error") } } // simple template without adaptive elemnts bar.SetTemplateString(`{{counters . }}`) result = bar.String() expected = "50 / 100" if result != expected { t.Errorf("Unexpected result: (actual/expected)\n%s\n%s", result, expected) } } func TestPBStartFinish(t *testing.T) { bar := ProgressBarTemplate(`{{counters . }}`).New(0) for i := int64(0); i < 2; i++ { if bar.IsStarted() { t.Error("Must be false") } var buf = bytes.NewBuffer(nil) bar.SetTotal(100). SetCurrent(int64(i)). SetWidth(7). Set(Terminal, true). SetWriter(buf). SetRefreshRate(time.Millisecond * 20). Start() if !bar.IsStarted() { t.Error("Must be true") } time.Sleep(time.Millisecond * 100) bar.Finish() if buf.Len() == 0 { t.Error("no writes") } var resultsString = strings.TrimPrefix(buf.String(), "\r") if !strings.HasSuffix(resultsString, "\n") { t.Error("No end \\n symb") } else { resultsString = resultsString[:len(resultsString)-1] } var results = strings.Split(resultsString, "\r") if len(results) < 3 { t.Errorf("Unexpected writes count: %v", len(results)) } exp := fmt.Sprintf("%d / 100", i) for i, res := range results { if res != exp { t.Errorf("Unexpected result[%d]: '%v'", i, res) } } // test second finish call bar.Finish() } } func TestPBFlags(t *testing.T) { // Static color.NoColor = false buf := bytes.NewBuffer(nil) bar := ProgressBarTemplate(`{{counters . | red}}`).New(100) bar.Set(Static, true).SetCurrent(50).SetWidth(10).SetWriter(buf).Start() if bar.IsStarted() { t.Error("Must be false") } bar.Write() result := buf.String() expected := "50 / 100" if result != expected { t.Errorf("Unexpected result: (actual/expected)\n'%s'\n'%s'", result, expected) } if !bar.state.IsFirst() { t.Error("must be true") } // Color bar.Set(Color, true) buf.Reset() bar.Write() result = buf.String() expected = color.RedString("50 / 100") if result != expected { t.Errorf("Unexpected result: (actual/expected)\n'%s'\n'%s'", result, expected) } if bar.state.IsFirst() { t.Error("must be false") } // Terminal bar.Set(Terminal, true).SetWriter(buf) buf.Reset() bar.Write() result = buf.String() expected = "\r" + color.RedString("50 / 100") + " " if result != expected { t.Errorf("Unexpected result: (actual/expected)\n'%s'\n'%s'", result, expected) } } func BenchmarkRender(b *testing.B) { var formats = []string{ string(Simple), string(Default), string(Full), `{{string . "prefix" | red}}{{counters . | green}} {{bar . | yellow}} {{percent . | cyan}} {{speed . | cyan}}{{string . "suffix" | cyan}}`, } var names = []string{ "Simple", "Default", "Full", "Color", } for i, tmpl := range formats { bar := new(ProgressBar) bar.SetTemplateString(tmpl).SetWidth(100) b.Run(names[i], func(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { bar.String() } }) } } golang-gopkg-cheggaaa-pb.v2-2.0.7/preset.go000066400000000000000000000014411350663175300204010ustar00rootroot00000000000000package pb import () var ( // Full - preset with all default available elements // Example: 'Prefix 20/100 [-->______] 20% 1 p/s ETA 1m Suffix' Full ProgressBarTemplate = `{{string . "prefix"}}{{counters . }} {{bar . }} {{percent . }} {{speed . }} {{rtime . "ETA %s"}}{{string . "suffix"}}` // Default - preset like Full but without elapsed time // Example: 'Prefix 20/100 [-->______] 20% 1 p/s ETA 1m Suffix' Default ProgressBarTemplate = `{{string . "prefix"}}{{counters . }} {{bar . }} {{percent . }} {{speed . }}{{string . "suffix"}}` // Simple - preset without speed and any timers. Only counters, bar and percents // Example: 'Prefix 20/100 [-->______] 20% Suffix' Simple ProgressBarTemplate = `{{string . "prefix"}}{{counters . }} {{bar . }} {{percent . }}{{string . "suffix"}}` ) golang-gopkg-cheggaaa-pb.v2-2.0.7/reader.go000066400000000000000000000010021350663175300203320ustar00rootroot00000000000000package pb import ( "io" ) // Reader it's a wrapper for given reader, but with progress handle type Reader struct { io.Reader bar *ProgressBar } // Read reads bytes from wrapped reader and add amount of bytes to progress bar func (r *Reader) Read(p []byte) (n int, err error) { n, err = r.Reader.Read(p) r.bar.Add(n) return } // Close the wrapped 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.v2-2.0.7/reader_test.go000066400000000000000000000023701350663175300214020ustar00rootroot00000000000000package pb import ( "testing" ) func TestPBProxyReader(t *testing.T) { bar := new(ProgressBar) if bar.GetBool(Bytes) { t.Errorf("By default bytes must be false") } testReader := new(testReaderCloser) proxyReader := bar.NewProxyReader(testReader) if !bar.GetBool(Bytes) { t.Errorf("Bytes must be true after call NewProxyReader") } for i := 0; i < 10; i++ { buf := make([]byte, 10) n, e := proxyReader.Read(buf) if e != nil { t.Errorf("Proxy reader return err: %v", e) } if n != len(buf) { t.Errorf("Proxy reader return unexpected N: %d (wand %d)", n, len(buf)) } for _, b := range buf { if b != 'f' { t.Errorf("Unexpected read value: %v (want %v)", b, 'f') } } if want := int64((i + 1) * len(buf)); bar.Current() != want { t.Errorf("Unexpected bar current value: %d (want %d)", bar.Current(), want) } } proxyReader.Close() if !testReader.closed { t.Errorf("Reader must be closed after call ProxyReader.Close") } proxyReader.Reader = nil proxyReader.Close() } type testReaderCloser struct { closed bool } func (tr *testReaderCloser) Read(p []byte) (n int, err error) { for i := range p { p[i] = 'f' } return len(p), nil } func (tr *testReaderCloser) Close() (err error) { tr.closed = true return } golang-gopkg-cheggaaa-pb.v2-2.0.7/speed.go000066400000000000000000000040311350663175300201750ustar00rootroot00000000000000package pb import ( "fmt" "math" "time" "gopkg.in/VividCortex/ewma.v1" ) var speedAddLimit = time.Second / 2 type speed struct { ewma ewma.MovingAverage lastStateId uint64 prevValue, startValue int64 prevTime, startTime time.Time } func (s *speed) value(state *State) float64 { if s.ewma == nil { s.ewma = ewma.NewMovingAverage() } if state.IsFirst() || state.Id() < s.lastStateId { s.reset(state) return 0 } if state.Id() == s.lastStateId { return s.ewma.Value() } if state.IsFinished() { return s.absValue(state) } dur := state.Time().Sub(s.prevTime) if dur < speedAddLimit { return s.ewma.Value() } diff := math.Abs(float64(state.Value() - s.prevValue)) lastSpeed := diff / dur.Seconds() s.prevTime = state.Time() s.prevValue = state.Value() s.lastStateId = state.Id() s.ewma.Add(lastSpeed) return s.ewma.Value() } func (s *speed) reset(state *State) { s.lastStateId = state.Id() s.startTime = state.Time() s.prevTime = state.Time() s.startValue = state.Value() s.prevValue = state.Value() s.ewma = ewma.NewMovingAverage() } func (s *speed) absValue(state *State) float64 { if dur := state.Time().Sub(s.startTime); dur > 0 { return float64(state.Value()) / dur.Seconds() } return 0 } func getSpeedObj(state *State) (s *speed) { if sObj, ok := state.Get(speedObj).(*speed); ok { return sObj } s = new(speed) state.Set(speedObj, s) return } // ElementSpeed calculates current speed by EWMA // Optionally can take one or two string arguments. // First string will be used as value for format speed, default is "%s p/s". // Second string will be used when speed not available, default is "? p/s" // In template use as follows: {{speed .}} or {{speed . "%s per second"}} or {{speed . "%s ps" "..."} var ElementSpeed ElementFunc = func(state *State, args ...string) string { sp := getSpeedObj(state).value(state) if sp == 0 { return argsHelper(args).getNotEmptyOr(1, "? p/s") } return fmt.Sprintf(argsHelper(args).getNotEmptyOr(0, "%s p/s"), state.Format(int64(round(sp)))) } golang-gopkg-cheggaaa-pb.v2-2.0.7/template.go000066400000000000000000000040221350663175300207100ustar00rootroot00000000000000package pb import ( "math/rand" "sync" "text/template" "gopkg.in/fatih/color.v1" ) // ProgressBarTemplate that template string type ProgressBarTemplate string // New creates new bar from template func (pbt ProgressBarTemplate) New(total int) *ProgressBar { return New(total).SetTemplate(pbt) } // Start64 create and start new bar with given int64 total value func (pbt ProgressBarTemplate) Start64(total int64) *ProgressBar { return New64(total).SetTemplate(pbt).Start() } // Start create and start new bar with given int total value func (pbt ProgressBarTemplate) Start(total int) *ProgressBar { return pbt.Start64(int64(total)) } var templateCacheMu sync.Mutex var templateCache = make(map[string]*template.Template) var defaultTemplateFuncs = template.FuncMap{ // colors "black": color.New(color.FgBlack).SprintFunc(), "red": color.New(color.FgRed).SprintFunc(), "green": color.New(color.FgGreen).SprintFunc(), "yellow": color.New(color.FgYellow).SprintFunc(), "blue": color.New(color.FgBlue).SprintFunc(), "magenta": color.New(color.FgMagenta).SprintFunc(), "cyan": color.New(color.FgCyan).SprintFunc(), "white": color.New(color.FgWhite).SprintFunc(), "rndcolor": rndcolor, "rnd": rnd, } func getTemplate(tmpl string) (t *template.Template, err error) { templateCacheMu.Lock() defer templateCacheMu.Unlock() t = templateCache[tmpl] if t != nil { // found in cache return } t = template.New("") fillTemplateFuncs(t) _, err = t.Parse(tmpl) if err != nil { t = nil return } templateCache[tmpl] = t return } func fillTemplateFuncs(t *template.Template) { t.Funcs(defaultTemplateFuncs) emf := make(template.FuncMap) elementsM.Lock() for k, v := range elements { emf[k] = v } elementsM.Unlock() t.Funcs(emf) return } func rndcolor(s string) string { c := rand.Intn(int(color.FgWhite-color.FgBlack)) + int(color.FgBlack) return color.New(color.Attribute(c)).Sprint(s) } func rnd(args ...string) string { if len(args) == 0 { return "" } return args[rand.Intn(len(args))] } golang-gopkg-cheggaaa-pb.v2-2.0.7/template_test.go000066400000000000000000000022531350663175300217530ustar00rootroot00000000000000package pb import ( "bytes" "testing" ) func TestProgressBarTemplate(t *testing.T) { // test New bar := ProgressBarTemplate(`{{counters . }}`).New(0) result := bar.String() expected := "0" if result != expected { t.Errorf("Unexpected result: (actual/expected)\n%s\n%s", result, expected) } if bar.IsStarted() { t.Error("Must be false") } // test Start bar = ProgressBarTemplate(`{{counters . }}`).Start(42).SetWriter(bytes.NewBuffer(nil)) result = bar.String() expected = "0 / 42" if result != expected { t.Errorf("Unexpected result: (actual/expected)\n%s\n%s", result, expected) } if !bar.IsStarted() { t.Error("Must be true") } } func TestTemplateFuncs(t *testing.T) { var results = make(map[string]int) for i := 0; i < 100; i++ { r := rndcolor("s") results[r] = results[r] + 1 } if len(results) < 6 { t.Errorf("Unexpected rndcolor results count: %v", len(results)) } results = make(map[string]int) for i := 0; i < 100; i++ { r := rnd("1", "2", "3") results[r] = results[r] + 1 } if len(results) != 3 { t.Errorf("Unexpected rnd results count: %v", len(results)) } if r := rnd(); r != "" { t.Errorf("Unexpected rnd result: '%v'", r) } } golang-gopkg-cheggaaa-pb.v2-2.0.7/termutil/000077500000000000000000000000001350663175300204155ustar00rootroot00000000000000golang-gopkg-cheggaaa-pb.v2-2.0.7/termutil/term.go000066400000000000000000000020251350663175300217120ustar00rootroot00000000000000package termutil import ( "errors" "os" "os/signal" "sync" "syscall" ) var echoLocked bool var echoLockMutex sync.Mutex var errLocked = errors.New("terminal locked") // RawModeOn switches terminal to raw mode func RawModeOn() (quit chan struct{}, err error) { echoLockMutex.Lock() defer echoLockMutex.Unlock() if echoLocked { err = errLocked return } if err = lockEcho(); err != nil { return } echoLocked = true quit = make(chan struct{}, 1) go catchTerminate(quit) return } // RawModeOff restore previous terminal state func RawModeOff() (err error) { echoLockMutex.Lock() defer echoLockMutex.Unlock() if !echoLocked { return } if err = unlockEcho(); err != nil { return } echoLocked = false return } // listen exit signals and restore terminal state func catchTerminate(quit 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: RawModeOff() case <-sig: RawModeOff() } } golang-gopkg-cheggaaa-pb.v2-2.0.7/termutil/term_appengine.go000066400000000000000000000004301350663175300237360ustar00rootroot00000000000000// +build appengine package termutil 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.v2-2.0.7/termutil/term_bsd.go000066400000000000000000000003011350663175300225350ustar00rootroot00000000000000// +build darwin freebsd netbsd openbsd dragonfly // +build !appengine package termutil import "syscall" const ioctlReadTermios = syscall.TIOCGETA const ioctlWriteTermios = syscall.TIOCSETA golang-gopkg-cheggaaa-pb.v2-2.0.7/termutil/term_linux.go000066400000000000000000000002361350663175300231330ustar00rootroot00000000000000// +build linux // +build !appengine package termutil const ioctlReadTermios = 0x5401 // syscall.TCGETS const ioctlWriteTermios = 0x5402 // syscall.TCSETS golang-gopkg-cheggaaa-pb.v2-2.0.7/termutil/term_nix.go000066400000000000000000000002251350663175300225700ustar00rootroot00000000000000// +build linux darwin freebsd netbsd openbsd dragonfly // +build !appengine package termutil import "syscall" const sysIoctl = syscall.SYS_IOCTL golang-gopkg-cheggaaa-pb.v2-2.0.7/termutil/term_solaris.go000066400000000000000000000002641350663175300234510ustar00rootroot00000000000000// +build solaris // +build !appengine package termutil const ioctlReadTermios = 0x5401 // syscall.TCGETS const ioctlWriteTermios = 0x5402 // syscall.TCSETS const sysIoctl = 54 golang-gopkg-cheggaaa-pb.v2-2.0.7/termutil/term_win.go000066400000000000000000000105201350663175300225660ustar00rootroot00000000000000// +build windows package termutil import ( "fmt" "os" "os/exec" "strconv" "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") mingw = isMingw() ) 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) { if mingw { return termWidthTPut() } return termWidthCmd() } func termWidthCmd() (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 isMingw() bool { return os.Getenv("MINGW_PREFIX") != "" || os.Getenv("MSYSTEM") == "MINGW64" } func termWidthTPut() (width int, err error) { // TODO: maybe anybody knows a better way to get it on mintty... var res []byte cmd := exec.Command("tput", "cols") cmd.Stdin = os.Stdin if res, err = cmd.CombinedOutput(); err != nil { return 0, fmt.Errorf("%s: %v", string(res), err) } if len(res) > 1 { res = res[:len(res)-1] } return strconv.Atoi(string(res)) } 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 oldState word func lockEcho() (err error) { 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 } return } func unlockEcho() (err error) { 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.v2-2.0.7/termutil/term_x.go000066400000000000000000000027011350663175300222420ustar00rootroot00000000000000// +build linux darwin freebsd netbsd openbsd solaris dragonfly // +build !appengine package termutil import ( "fmt" "os" "syscall" "unsafe" ) var tty *os.File type window struct { Row uint16 Col uint16 Xpixel uint16 Ypixel uint16 } 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) res, _, err := syscall.Syscall(sysIoctl, tty.Fd(), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(w)), ) if int(res) == -1 { return 0, err } return int(w.Col), nil } var oldState syscall.Termios func lockEcho() (err error) { 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 } return } func unlockEcho() (err error) { 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 } golang-gopkg-cheggaaa-pb.v2-2.0.7/util.go000066400000000000000000000033751350663175300200640ustar00rootroot00000000000000package pb import ( "bytes" "fmt" "gopkg.in/mattn/go-runewidth.v0" "math" "regexp" //"unicode/utf8" ) const ( _KiB = 1024 _MiB = 1048576 _GiB = 1073741824 _TiB = 1099511627776 ) var ctrlFinder = regexp.MustCompile("\x1b\x5b[0-9]+\x6d") func CellCount(s string) int { n := runewidth.StringWidth(s) for _, sm := range ctrlFinder.FindAllString(s, -1) { n -= runewidth.StringWidth(sm) } return n } func StripString(s string, w int) string { l := CellCount(s) if l <= w { return s } var buf = bytes.NewBuffer(make([]byte, 0, len(s))) StripStringToBuffer(s, w, buf) return buf.String() } func StripStringToBuffer(s string, w int, buf *bytes.Buffer) { var seqs = ctrlFinder.FindAllStringIndex(s, -1) mainloop: for i, r := range s { for _, seq := range seqs { if i >= seq[0] && i < seq[1] { buf.WriteRune(r) continue mainloop } } if rw := CellCount(string(r)); rw <= w { w -= rw buf.WriteRune(r) } else { break } } for w > 0 { buf.WriteByte(' ') w-- } return } func round(val float64) (newVal float64) { roundOn := 0.5 places := 0 var round float64 pow := math.Pow(10, float64(places)) digit := pow * val _, div := math.Modf(digit) if div >= roundOn { round = math.Ceil(digit) } else { round = math.Floor(digit) } newVal = round / pow return } // Convert bytes to human readable string. Like a 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 } golang-gopkg-cheggaaa-pb.v2-2.0.7/util_test.go000066400000000000000000000031031350663175300211100ustar00rootroot00000000000000package pb import ( "gopkg.in/fatih/color.v1" "testing" ) var testColorString = color.RedString("red") + color.GreenString("hello") + "simple" + color.WhiteString("進捗") func TestUtilCellCount(t *testing.T) { if e, l := 18, CellCount(testColorString); l != e { t.Errorf("Invalid length %d, expected %d", l, e) } } func TestUtilStripString(t *testing.T) { if r, e := StripString("12345", 4), "1234"; r != e { t.Errorf("Invalid result '%s', expected '%s'", r, e) } if r, e := StripString("12345", 5), "12345"; r != e { t.Errorf("Invalid result '%s', expected '%s'", r, e) } if r, e := StripString("12345", 10), "12345"; r != e { t.Errorf("Invalid result '%s', expected '%s'", r, e) } s := color.RedString("1") + "23" e := color.RedString("1") + "2" if r := StripString(s, 2); r != e { t.Errorf("Invalid result '%s', expected '%s'", r, e) } return } func TestUtilRound(t *testing.T) { if v := round(4.4); v != 4 { t.Errorf("Unexpected result: %v", v) } if v := round(4.501); v != 5 { t.Errorf("Unexpected result: %v", v) } } func TestUtilFormatBytes(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 := formatBytes(input.v) if actual != input.e { t.Errorf("Expected {%s} was {%s}", input.e, actual) } } } func BenchmarkUtilsCellCount(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { CellCount(testColorString) } }