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  }