github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/pkg/logger/progress_bar.go (about) 1 package logger 2 3 import ( 4 "fmt" 5 "sync/atomic" 6 "time" 7 8 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/colors" 9 ) 10 11 type BarType int 12 13 const ( 14 Fixed BarType = iota 15 Expanding 16 ) 17 18 type BarOptions struct { 19 Enabled bool // enable progress bar 20 Type BarType // if Expanding, the bar doesn't know how many object there will be, so grows 21 Prefix string // the string to display first 22 Fill string // the fill value for progress bar 23 Start int64 // the starting value (defaults to zero) 24 Total int64 // the total (possibly estimated for Expanding) number of objects 25 PrefixColor string // the color of the prefix 26 } 27 28 type ProgressBar struct { 29 BarOptions 30 graphic string // the actual progress bar to be printed 31 percent int64 // progress percentage 32 cur int64 // current progress 33 startTime time.Time 34 } 35 36 func NewBar(opts BarOptions) (bar *ProgressBar) { 37 if opts.Fill == "" { 38 opts.Fill = "." 39 } 40 41 bar = new(ProgressBar) 42 bar.Prefix = opts.Prefix 43 bar.Fill = opts.Fill 44 bar.Enabled = opts.Enabled 45 bar.Type = opts.Type 46 bar.Start = opts.Start 47 bar.Total = opts.Total 48 49 bar.cur = opts.Start 50 bar.percent = int64(float32(bar.cur) * 100 / float32(bar.Total)) 51 for i := 0; i < int(bar.percent); i += 2 { 52 bar.graphic += bar.Fill // initial progress position 53 } 54 55 if opts.Type == Expanding && bar.Total == 0 { 56 bar.Total = 1 57 } 58 59 return bar 60 } 61 62 func (bar *ProgressBar) Bump() { 63 atomic.AddInt64(&bar.cur, 1) 64 } 65 66 func (bar *ProgressBar) Tick() { 67 atomic.AddInt64(&bar.cur, 1) 68 if bar.Type == Expanding && bar.cur >= bar.Total { 69 bar.Total = bar.Total * 2 // grow by 50% but at least 100 70 bar.cur = bar.cur / 2 71 bar.percent = int64(float32(bar.cur) * 100 / float32(bar.Total)) 72 bar.graphic = "" 73 for i := 0; i < int(bar.percent); i += 2 { 74 bar.graphic += bar.Fill // initial progress position 75 } 76 } 77 bar.display() 78 } 79 80 func (bar *ProgressBar) Finish(newLine bool) time.Duration { 81 if bar.Enabled && loggerWriter != nil { 82 atomic.StoreInt64(&bar.Total, bar.cur) 83 if bar.Type == Expanding { 84 bar.cur = bar.Total 85 bar.percent = 100 86 } 87 bar.graphic = "" 88 for i := 0; i < 100; i += 2 { 89 bar.graphic += bar.Fill 90 } 91 bar.display() 92 if newLine { 93 fmt.Fprintf(loggerWriter, "\n") 94 } 95 } 96 return time.Since(bar.startTime) 97 } 98 99 func (bar *ProgressBar) display() { 100 if bar.Enabled && loggerWriter != nil { 101 last := bar.percent 102 if bar.Total == 0 { 103 bar.percent = 99 104 } else { 105 bar.percent = int64(float32(bar.cur) * 100 / float32(bar.Total)) 106 } 107 if bar.percent != last && bar.percent%2 == 0 { 108 bar.graphic += bar.Fill 109 } 110 if bar.Total == 0 { 111 bar.percent = 100 112 } 113 timeDatePart := "DATE|TIME" 114 if timingMode { 115 now := time.Now() 116 timeDatePart = now.Format("02-01|15:04:05.000") 117 } 118 ofMarker := "" 119 fmt.Fprintf(loggerWriter, "\r%s[%s] [%s%-50s%s]%3d%% %5d/% 5d %s\r", 120 severityToLabel[progress], 121 timeDatePart, 122 colors.BrightGreen, 123 bar.graphic, 124 colors.Off, 125 bar.percent, 126 bar.cur, 127 bar.Total, 128 colors.BrightGreen+ofMarker+bar.Prefix+colors.Off) 129 } 130 }