Codebase list golang-github-vbauerster-mpb / e9841df
io examples Vladimir Bauer 9 years ago
13 changed file(s) with 407 addition(s) and 215 deletion(s). Raw diff Collapse all Expand all
+75
-129
bar.go less more
00 package mpb
11
22 import (
3 "fmt"
43 "io"
5 "strconv"
64 "sync"
75 "time"
86 )
97
10 type decoratorFuncType uint
11
12 const (
13 decoratorAppend decoratorFuncType = iota
14 decoratorPrepend
15 )
16
17 // DecoratorFunc is a function that can be prepended and appended to the progress bar
18 type DecoratorFunc func(s *Statistics) string
19
20 type decorator struct {
21 kind decoratorFuncType
22 f DecoratorFunc
23 }
24
258 // Bar represents a progress Bar
269 type Bar struct {
27 total int
28 width int
29 alpha float64
30 stopped bool
10 total int
11 width int
12 alpha float64
3113
3214 fill byte
3315 empty byte
3517 leftEnd byte
3618 rightEnd byte
3719
38 incrCh chan int
39 redrawReqCh chan chan []byte
40 statusReqCh chan chan int
41 decoratorCh chan *decorator
42 flushedCh chan struct{}
43 stopCh chan struct{}
44 done chan struct{}
20 incrCh chan int
21 redrawReqCh chan chan []byte
22 currentReqCh chan chan int
23 statusReqCh chan chan int
24 decoratorCh chan *decorator
25 flushedCh chan struct{}
26 stopCh chan struct{}
27 done chan struct{}
4528 }
4629
4730 type Statistics struct {
5538
5639 func newBar(total, width int, wg *sync.WaitGroup) *Bar {
5740 b := &Bar{
58 fill: '=',
59 empty: '-',
60 tip: '>',
61 leftEnd: '[',
62 rightEnd: ']',
63 alpha: 0.25,
64 total: total,
65 width: width,
66 incrCh: make(chan int),
67 redrawReqCh: make(chan chan []byte),
68 statusReqCh: make(chan chan int),
69 decoratorCh: make(chan *decorator),
70 flushedCh: make(chan struct{}),
71 stopCh: make(chan struct{}),
72 done: make(chan struct{}),
41 fill: '=',
42 empty: '-',
43 tip: '>',
44 leftEnd: '[',
45 rightEnd: ']',
46 alpha: 0.25,
47 total: total,
48 width: width,
49 incrCh: make(chan int),
50 redrawReqCh: make(chan chan []byte),
51 currentReqCh: make(chan chan int),
52 statusReqCh: make(chan chan int),
53 decoratorCh: make(chan *decorator),
54 flushedCh: make(chan struct{}),
55 stopCh: make(chan struct{}),
56 done: make(chan struct{}),
7357 }
7458 go b.server(wg)
7559 return b
131115 return &Reader{r, b}
132116 }
133117
118 // Incr increments progress bar
119 func (b *Bar) Incr(n int) {
120 if !b.isDone() {
121 b.incrCh <- n
122 }
123 }
124
125 // Current returns the actual current.
126 // If bar was stopped by Stop(), subsequent calls to Current will return -1
127 func (b *Bar) Current() int {
128 if !b.isDone() {
129 respCh := make(chan int)
130 b.currentReqCh <- respCh
131 return <-respCh
132 }
133 return -1
134 }
135
136 // Stop stops rendering the bar
137 func (b *Bar) Stop() {
138 if !b.isDone() {
139 b.stopCh <- struct{}{}
140 }
141 }
142
143 func (b *Bar) InProgress() bool {
144 return !b.isDone()
145 }
146
147 func (b *Bar) PrependFunc(f DecoratorFunc) *Bar {
148 b.decoratorCh <- &decorator{decoratorPrepend, f}
149 return b
150 }
151
152 func (b *Bar) AppendFunc(f DecoratorFunc) *Bar {
153 b.decoratorCh <- &decorator{decoratorAppend, f}
154 return b
155 }
156
134157 // String returns the string representation of the bar
135158 func (b *Bar) String() string {
136 respCh := make(chan []byte)
137 b.redrawReqCh <- respCh
138 return string(<-respCh)
139 }
140
141 func (b *Bar) Incr(n int) {
142 if !b.isDone() {
143 b.incrCh <- n
144 }
145 }
146
147 func (b *Bar) Stop() {
148 if !b.stopped {
149 b.stopCh <- struct{}{}
150 b.stopped = true
151 }
152 }
153
154 func (b *Bar) InProgress() bool {
155 return !b.isDone()
156 }
157
158 func (b *Bar) PrependFunc(f DecoratorFunc) *Bar {
159 b.decoratorCh <- &decorator{decoratorPrepend, f}
160 return b
161 }
162
163 func (b *Bar) AppendFunc(f DecoratorFunc) *Bar {
164 b.decoratorCh <- &decorator{decoratorAppend, f}
165 return b
166 }
167
168 func (b *Bar) PrependName(name string, padding int) *Bar {
169 layout := "%" + strconv.Itoa(padding) + "s"
170 b.PrependFunc(func(s *Statistics) string {
171 return fmt.Sprintf(layout, name)
172 })
173 return b
174 }
175
176 func (b *Bar) PrependETA(padding int) *Bar {
177 layout := "ETA%" + strconv.Itoa(padding) + "s"
178 b.PrependFunc(func(s *Statistics) string {
179 return fmt.Sprintf(layout, time.Duration(s.eta().Seconds())*time.Second)
180 })
181 return b
182 }
183
184 func (b *Bar) AppendETA() *Bar {
185 b.AppendFunc(func(s *Statistics) string {
186 return fmt.Sprintf("ETA %s", time.Duration(s.eta().Seconds())*time.Second)
187 })
188 return b
189 }
190
191 func (b *Bar) PrependElapsed(padding int) *Bar {
192 layout := "%" + strconv.Itoa(padding) + "s"
193 b.PrependFunc(func(s *Statistics) string {
194 return fmt.Sprintf(layout, time.Duration(s.TimeElapsed.Seconds())*time.Second)
195 })
196 return b
197 }
198
199 func (b *Bar) AppendElapsed() *Bar {
200 b.AppendFunc(func(s *Statistics) string {
201 return fmt.Sprint(time.Duration(s.TimeElapsed.Seconds()) * time.Second)
202 })
203 return b
204 }
205
206 func (b *Bar) AppendPercentage() *Bar {
207 b.AppendFunc(func(s *Statistics) string {
208 completed := int(100 * float64(s.Current) / float64(s.Total))
209 return fmt.Sprintf("%3d %%", completed)
210 })
211 return b
212 }
213
214 func (b *Bar) PrependPercentage(padding int) *Bar {
215 layout := "%" + strconv.Itoa(padding) + "d %%"
216 b.PrependFunc(func(s *Statistics) string {
217 completed := int(100 * float64(s.Current) / float64(s.Total))
218 return fmt.Sprintf(layout, completed)
219 })
220 return b
159 if !b.isDone() {
160 respCh := make(chan []byte)
161 b.redrawReqCh <- respCh
162 return string(<-respCh)
163 }
164 return ""
221165 }
222166
223167 func (b *Bar) server(wg *sync.WaitGroup) {
253197 case decoratorPrepend:
254198 prependFuncs = append(prependFuncs, d.f)
255199 }
200 case respCh := <-b.currentReqCh:
201 respCh <- current
256202 case respCh := <-b.redrawReqCh:
257203 stat := &Statistics{b.total, current, timeElapsed, tpie}
258204 respCh <- b.draw(stat, buf, appendFuncs, prependFuncs)
264210 wg.Done()
265211 }
266212 case <-b.stopCh:
213 close(b.done)
267214 if !completed {
268 close(b.done)
269215 wg.Done()
270216 }
271217 return
0 package mpb
1
2 import (
3 "fmt"
4 "strconv"
5 "time"
6 )
7
8 type decoratorFuncType uint
9
10 const (
11 decoratorAppend decoratorFuncType = iota
12 decoratorPrepend
13 )
14
15 // DecoratorFunc is a function that can be prepended and appended to the progress bar
16 type DecoratorFunc func(s *Statistics) string
17
18 type decorator struct {
19 kind decoratorFuncType
20 f DecoratorFunc
21 }
22
23 func (b *Bar) PrependName(name string, padding int) *Bar {
24 layout := "%" + strconv.Itoa(padding) + "s"
25 b.PrependFunc(func(s *Statistics) string {
26 return fmt.Sprintf(layout, name)
27 })
28 return b
29 }
30
31 func (b *Bar) PrependCounters(unit Units, padding int) *Bar {
32 layout := "%" + strconv.Itoa(padding) + "s"
33 b.PrependFunc(func(s *Statistics) string {
34 current := Format(s.Current).To(unit)
35 total := Format(s.Total).To(unit)
36 str := fmt.Sprintf("%s / %s", current, total)
37 return fmt.Sprintf(layout, str)
38 })
39 return b
40 }
41
42 func (b *Bar) PrependETA(padding int) *Bar {
43 layout := "ETA%" + strconv.Itoa(padding) + "s"
44 b.PrependFunc(func(s *Statistics) string {
45 return fmt.Sprintf(layout, time.Duration(s.eta().Seconds())*time.Second)
46 })
47 return b
48 }
49
50 func (b *Bar) AppendETA() *Bar {
51 b.AppendFunc(func(s *Statistics) string {
52 return fmt.Sprintf("ETA %s", time.Duration(s.eta().Seconds())*time.Second)
53 })
54 return b
55 }
56
57 func (b *Bar) PrependElapsed(padding int) *Bar {
58 layout := "%" + strconv.Itoa(padding) + "s"
59 b.PrependFunc(func(s *Statistics) string {
60 return fmt.Sprintf(layout, time.Duration(s.TimeElapsed.Seconds())*time.Second)
61 })
62 return b
63 }
64
65 func (b *Bar) AppendElapsed() *Bar {
66 b.AppendFunc(func(s *Statistics) string {
67 return fmt.Sprint(time.Duration(s.TimeElapsed.Seconds()) * time.Second)
68 })
69 return b
70 }
71
72 func (b *Bar) AppendPercentage() *Bar {
73 b.AppendFunc(func(s *Statistics) string {
74 completed := int(100 * float64(s.Current) / float64(s.Total))
75 return fmt.Sprintf("%3d %%", completed)
76 })
77 return b
78 }
79
80 func (b *Bar) PrependPercentage(padding int) *Bar {
81 layout := "%" + strconv.Itoa(padding) + "d %%"
82 b.PrependFunc(func(s *Statistics) string {
83 completed := int(100 * float64(s.Current) / float64(s.Total))
84 return fmt.Sprintf(layout, completed)
85 })
86 return b
87 }
1919 }
2020
2121 p := mpb.New()
22 p.Wg.Add(1)
2223 bar := p.AddBar(totalItem).AppendETA().PrependFunc(decor)
2324
2425 blockSize := rand.Intn(maxBlockSize) + 1
0 package main
1
2 import (
3 "fmt"
4 "io"
5 "log"
6 "net/http"
7 "os"
8 "path/filepath"
9
10 "github.com/vbauerster/mpb"
11 )
12
13 func main() {
14 log.SetOutput(os.Stderr)
15
16 url1 := "https://homebrew.bintray.com/bottles/youtube-dl-2016.12.12.sierra.bottle.tar.gz"
17 url2 := "https://homebrew.bintray.com/bottles/libtiff-4.0.7.sierra.bottle.tar.gz"
18
19 p := mpb.New().SetWidth(60)
20
21 for i, url := range [...]string{url1, url2} {
22 p.Wg.Add(1) // if you omit this line, main will return without waiting for download goroutines
23 name := fmt.Sprintf("url%d:", i+1)
24 go download(p, name, url)
25 }
26
27 p.WaitAndStop()
28 fmt.Println("Finished")
29 }
30
31 func download(p *mpb.Progress, name, url string) {
32 resp, err := http.Get(url)
33 if err != nil {
34 log.Printf("%s: %v", name, err)
35 return
36 }
37 defer resp.Body.Close()
38
39 if resp.StatusCode != http.StatusOK {
40 err = fmt.Errorf("non-200 status: %s", resp.Status)
41 log.Printf("%s: %v", name, err)
42 return
43 }
44
45 size := resp.ContentLength
46
47 // create dest
48 destName := filepath.Base(url)
49 dest, err := os.Create(destName)
50 if err != nil {
51 err = fmt.Errorf("Can't create %s: %v", destName, err)
52 log.Printf("%s: %v", name, err)
53 return
54 }
55
56 // create bar with appropriate decorators
57 bar := p.AddBar(int(size)).
58 PrependCounters(mpb.UnitBytes, 19).
59 PrependName(name, len(name)).
60 AppendETA()
61 // create proxy reader
62 reader := bar.ProxyReader(resp.Body)
63 // and copy from reader
64 _, err = io.Copy(dest, reader)
65
66 if closeErr := dest.Close(); err == nil {
67 err = closeErr
68 }
69 if err != nil {
70 log.Printf("%s: %v", name, err)
71 }
72 }
0 package main
1
2 import (
3 "fmt"
4 "io"
5 "net/http"
6 "os"
7 "path/filepath"
8
9 "github.com/vbauerster/mpb"
10 )
11
12 func main() {
13 url := "https://homebrew.bintray.com/bottles/libtiff-4.0.7.sierra.bottle.tar.gz"
14
15 resp, err := http.Get(url)
16 if err != nil {
17 panic(err)
18 }
19 defer resp.Body.Close()
20
21 if resp.StatusCode != http.StatusOK {
22 fmt.Printf("Server return non-200 status: %s\n", resp.Status)
23 return
24 }
25
26 size := resp.ContentLength
27
28 // create dest
29 destName := filepath.Base(url)
30 dest, err := os.Create(destName)
31 if err != nil {
32 fmt.Printf("Can't create %s: %v\n", destName, err)
33 return
34 }
35 defer dest.Close()
36
37 p := mpb.New().SetWidth(64)
38 // if you omit following line, download will complete fine, but rendering bar
39 // may not complete, thus better always use even in single thread.
40 p.Wg.Add(1)
41
42 bar := p.AddBar(int(size)).PrependCounters(mpb.UnitBytes, 19).AppendETA()
43
44 // create proxy reader
45 reader := bar.ProxyReader(resp.Body)
46
47 // and copy from reader, ignoring errors
48 io.Copy(dest, reader)
49
50 p.WaitAndStop()
51 fmt.Println("Finished")
52 }
+0
-60
example/multi/multi.go less more
0 package main
1
2 import (
3 "fmt"
4 "math/rand"
5 "time"
6
7 "github.com/vbauerster/mpb"
8 )
9
10 const (
11 maxBlockSize = 12
12 )
13
14 func main() {
15 decor := func(s *mpb.Statistics) string {
16 str := fmt.Sprintf("%d/%d", s.Current, s.Total)
17 return fmt.Sprintf("%-7s", str)
18 }
19
20 p := mpb.New().RefreshRate(80 * time.Millisecond)
21
22 bar1 := p.AddBar(50).AppendETA().PrependFunc(decor)
23 go func() {
24 blockSize := rand.Intn(maxBlockSize) + 1
25 for i := 0; i < 50; i++ {
26 time.Sleep(time.Duration(blockSize) * (50*time.Millisecond + time.Duration(rand.Intn(5*int(time.Millisecond)))))
27 bar1.Incr(1)
28 blockSize = rand.Intn(maxBlockSize) + 1
29 }
30 }()
31
32 bar2 := p.AddBar(100).AppendETA().PrependFunc(decor)
33 go func() {
34 blockSize := rand.Intn(maxBlockSize) + 1
35 for i := 0; i < 100; i++ {
36 time.Sleep(time.Duration(blockSize) * (50*time.Millisecond + time.Duration(rand.Intn(5*int(time.Millisecond)))))
37 bar2.Incr(1)
38 blockSize = rand.Intn(maxBlockSize) + 1
39 }
40 }()
41
42 bar3 := p.AddBar(80).AppendETA().PrependFunc(decor)
43 go func() {
44 blockSize := rand.Intn(maxBlockSize) + 1
45 for i := 0; i < 80; i++ {
46 time.Sleep(time.Duration(blockSize) * (50*time.Millisecond + time.Duration(rand.Intn(5*int(time.Millisecond)))))
47 bar3.Incr(1)
48 blockSize = rand.Intn(maxBlockSize) + 1
49 }
50 }()
51
52 // time.Sleep(time.Second)
53 // p.RemoveBar(bar2)
54
55 p.WaitAndStop()
56 bar2.Incr(2)
57 fmt.Println("stop")
58 // p.AddBar(1) // panic: send on closed channnel
59 }
1313
1414 func main() {
1515
16 p := mpb.New().SetWidth(64)
1617 // p := mpb.New().RefreshRate(80 * time.Millisecond).SetWidth(64)
17 p := mpb.New().SetWidth(64)
1818
1919 name1 := "Bar#1:"
2020 bar1 := p.AddBar(50).AppendPercentage().PrependETA(4).PrependName(name1, len(name1))
21 p.Wg.Add(1)
2122 go func() {
2223 blockSize := rand.Intn(maxBlockSize) + 1
2324 for i := 0; i < 50; i++ {
2829 }()
2930
3031 bar2 := p.AddBar(100).AppendPercentage().PrependETA(4).PrependName("", 0-len(name1))
32 p.Wg.Add(1)
3133 go func() {
3234 blockSize := rand.Intn(maxBlockSize) + 1
3335 for i := 0; i < 100; i++ {
3840 }()
3941
4042 bar3 := p.AddBar(80).AppendPercentage().PrependETA(4).PrependName("Bar#3:", 0)
43 p.Wg.Add(1)
4144 go func() {
4245 blockSize := rand.Intn(maxBlockSize) + 1
4346 for i := 0; i < 80; i++ {
1414 func main() {
1515
1616 p := mpb.New().SetWidth(64)
17 // p := mpb.New().RefreshRate(80 * time.Millisecond).SetWidth(64)
1718
1819 name1 := "Bar#1:"
1920 bar1 := p.AddBar(50).AppendPercentage().PrependElapsed(3).PrependName(name1, len(name1))
21 p.Wg.Add(1)
2022 go func() {
2123 blockSize := rand.Intn(maxBlockSize) + 1
2224 for i := 0; i < 50; i++ {
2729 }()
2830
2931 bar2 := p.AddBar(100).AppendPercentage().PrependElapsed(3).PrependName("", 0-len(name1))
32 p.Wg.Add(1)
3033 go func() {
3134 blockSize := rand.Intn(maxBlockSize) + 1
3235 for i := 0; i < 100; i++ {
3740 }()
3841
3942 bar3 := p.AddBar(80).AppendPercentage().PrependElapsed(3).PrependName("Bar#3:", 0)
43 p.Wg.Add(1)
4044 go func() {
4145 blockSize := rand.Intn(maxBlockSize) + 1
4246 for i := 0; i < 80; i++ {
1313
1414 func main() {
1515
16 p := mpb.New().SetWidth(64)
1617 // p := mpb.New().RefreshRate(100 * time.Millisecond).SetWidth(64)
17 p := mpb.New().SetWidth(64)
1818
1919 name1 := "Bar#1:"
2020 bar1 := p.AddBar(50).AppendETA().PrependPercentage(3).PrependName(name1, len(name1))
21 p.Wg.Add(1)
2122 go func() {
2223 blockSize := rand.Intn(maxBlockSize) + 1
2324 for i := 0; i < 50; i++ {
2829 }()
2930
3031 bar2 := p.AddBar(100).AppendETA().PrependPercentage(3).PrependName("", 0-len(name1))
32 p.Wg.Add(1)
3133 go func() {
3234 blockSize := rand.Intn(maxBlockSize) + 1
3335 for i := 0; i < 100; i++ {
3840 }()
3941
4042 bar3 := p.AddBar(80).AppendETA().PrependPercentage(3).PrependName("Bar#3:", 0)
43 p.Wg.Add(1)
4144 go func() {
4245 blockSize := rand.Intn(maxBlockSize) + 1
4346 for i := 0; i < 80; i++ {
22 import (
33 "fmt"
44 "math/rand"
5 "runtime"
65 "time"
76
8 "github.com/vbauerster/uiprogress"
7 "github.com/vbauerster/mpb"
98 )
109
1110 const (
1211 totalItem = 100
13 maxBlockSize = 20
12 maxBlockSize = 14
1413 )
1514
1615 func main() {
17 runtime.GOMAXPROCS(runtime.NumCPU())
18 decor := func(s *uiprogress.Statistics) string {
19 str := fmt.Sprintf("%d/%d", s.Completed, s.Total)
16 decor := func(s *mpb.Statistics) string {
17 str := fmt.Sprintf("%d/%d", s.Current, s.Total)
2018 return fmt.Sprintf("%-7s", str)
2119 }
2220
23 p := uiprogress.New()
21 p := mpb.New()
2422 bar := p.AddBar(totalItem).AppendETA().PrependFunc(decor)
23 p.Wg.Add(1)
2524
2625 blockSize := rand.Intn(maxBlockSize) + 1
27 for i := 0; !bar.IsCompleted(); i += 1 {
26 for i := 0; bar.InProgress(); i++ {
2827 time.Sleep(time.Duration(blockSize) * (50*time.Millisecond + time.Duration(rand.Intn(5*int(time.Millisecond)))))
29 bar.Incr(1)
30 if i == 42 {
28 bar.Incr(blockSize)
29 if bar.Current() > 42 {
3130 p.RemoveBar(bar)
3231 }
3332 blockSize = rand.Intn(maxBlockSize) + 1
1717
1818 name1 := "Bar#1:"
1919 bar1 := p.AddBar(100).AppendETA().PrependFunc(getDecor()).PrependName(name1, len(name1))
20 p.Wg.Add(1)
2021 go func() {
2122 blockSize := rand.Intn(maxBlockSize) + 1
2223 for i := 0; i < 100; i++ {
2728 }()
2829
2930 bar2 := p.AddBar(60).AppendETA().PrependFunc(getDecor()).PrependName("", 0-len(name1))
31 p.Wg.Add(1)
3032 go func() {
3133 blockSize := rand.Intn(maxBlockSize) + 1
3234 for i := 0; i < 60; i++ {
3739 }()
3840
3941 bar3 := p.AddBar(80).AppendETA().PrependFunc(getDecor()).PrependName("Bar#3:", 0)
42 p.Wg.Add(1)
4043 go func() {
4144 blockSize := rand.Intn(maxBlockSize) + 1
4245 for i := 0; i < 80; i++ {
0 package mpb
1
2 import (
3 "fmt"
4 "strings"
5 )
6
7 const (
8 _ = iota
9 bytesInKiB = 1 << (iota * 10)
10 bytesInMiB
11 bytesInGiB
12 bytesInTiB
13 )
14
15 type Units uint
16
17 const (
18 UnitNone Units = iota
19 UnitBytes
20 )
21
22 func Format(i int) *formatter {
23 return &formatter{n: i}
24 }
25
26 type formatter struct {
27 n int
28 unit Units
29 width int
30 }
31
32 func (f *formatter) To(unit Units) *formatter {
33 f.unit = unit
34 return f
35 }
36
37 func (f *formatter) Width(width int) *formatter {
38 f.width = width
39 return f
40 }
41
42 func (f *formatter) String() string {
43 switch f.unit {
44 case UnitBytes:
45 return formatBytes(f.n)
46 default:
47 return fmt.Sprintf(fmt.Sprintf("%%%dd", f.width), f.n)
48 }
49 }
50
51 func formatBytes(i int) (result string) {
52 switch {
53 case i > bytesInTiB:
54 result = fmt.Sprintf("%.02fTiB", float64(i)/bytesInTiB)
55 case i > bytesInGiB:
56 result = fmt.Sprintf("%.02fGiB", float64(i)/bytesInGiB)
57 case i > bytesInMiB:
58 result = fmt.Sprintf("%.02fMiB", float64(i)/bytesInMiB)
59 case i > bytesInKiB:
60 result = fmt.Sprintf("%.02fKiB", float64(i)/bytesInKiB)
61 default:
62 result = fmt.Sprintf("%db", i)
63 }
64 result = strings.Trim(result, " ")
65 return
66 }
3030
3131 // Progress represents the container that renders Progress bars
3232 type Progress struct {
33 out io.Writer
34 width int
35 sort SortType
36 stopped bool
33 Wg *sync.WaitGroup
34
35 out io.Writer
36 width int
37 sort SortType
38 // stopped bool
3739
3840 op chan *operation
3941 rrChangeReqCh chan time.Duration
4042 outChangeReqCh chan io.Writer
4143 countReqCh chan chan int
42
43 wg *sync.WaitGroup
44 allDone chan struct{}
4445 }
4546
4647 type operation struct {
5758 rrChangeReqCh: make(chan time.Duration),
5859 outChangeReqCh: make(chan io.Writer),
5960 countReqCh: make(chan chan int),
60 wg: new(sync.WaitGroup),
61 allDone: make(chan struct{}),
62 Wg: new(sync.WaitGroup),
6163 }
6264 go p.server(cwriter.New(os.Stdout), time.NewTicker(rr*time.Millisecond))
6365 return p
6466 }
6567
68 // SetWidth sets the width for all underlying bars
6669 func (p *Progress) SetWidth(n int) *Progress {
6770 if n <= 0 {
6871 return p
8790 return p
8891 }
8992
93 // WithSort sorts the bars, while redering
9094 func (p *Progress) WithSort(sort SortType) *Progress {
9195 p.sort = sort
9296 return p
9498
9599 // AddBar creates a new progress bar and adds to the container
96100 func (p *Progress) AddBar(total int) *Bar {
97 p.wg.Add(1)
98 bar := newBar(total, p.width, p.wg)
101 bar := newBar(total, p.width, p.Wg)
99102 p.op <- &operation{opBarAdd, bar, nil}
100103 return bar
101104 }
102105
106 // RemoveBar removes bar at any time
103107 func (p *Progress) RemoveBar(b *Bar) bool {
104108 result := make(chan bool)
105109 p.op <- &operation{opBarRemove, b, result}
106110 return <-result
107111 }
108112
113 // BarsCount returns bars count in the container
109114 func (p *Progress) BarsCount() int {
110115 respCh := make(chan int)
111116 p.countReqCh <- respCh
114119
115120 // WaitAndStop stops listening
116121 func (p *Progress) WaitAndStop() {
117 if !p.stopped {
118 // fmt.Fprintln(os.Stderr, "p.WaitAndStop")
119 p.stopped = true
120 p.wg.Wait()
122 if !p.isAllDone() {
123 close(p.allDone)
124 p.Wg.Wait()
121125 close(p.op)
122126 }
123127 }
132136 cw = cwriter.New(w)
133137 case op, ok := <-p.op:
134138 if !ok {
135 // fmt.Fprintln(os.Stderr, "Sopping bars")
136139 for _, b := range bars {
137140 b.Stop()
138141 }
179182 }
180183 }
181184 }
185
186 func (p *Progress) isAllDone() bool {
187 select {
188 case <-p.allDone:
189 return true
190 default:
191 return false
192 }
193 }