github.com/saracen/git-lfs@v2.5.2+incompatible/tasklog/percentage_task.go (about) 1 package tasklog 2 3 import ( 4 "fmt" 5 "math" 6 "sync/atomic" 7 "time" 8 ) 9 10 // PercentageTask is a task that is performed against a known number of 11 // elements. 12 type PercentageTask struct { 13 // members managed via sync/atomic must be aligned at the top of this 14 // structure (see: https://github.com/git-lfs/git-lfs/pull/2880). 15 16 // n is the number of elements whose work has been completed. It is 17 // managed sync/atomic. 18 n uint64 19 // total is the total number of elements to execute work upon. 20 total uint64 21 // msg is the task message. 22 msg string 23 // ch is a channel which is written to when the task state changes and 24 // is closed when the task is completed. 25 ch chan *Update 26 } 27 28 func NewPercentageTask(msg string, total uint64) *PercentageTask { 29 p := &PercentageTask{ 30 msg: msg, 31 total: total, 32 ch: make(chan *Update, 1), 33 } 34 p.Count(0) 35 36 return p 37 } 38 39 // Count indicates that work has been completed against "n" number of elements, 40 // marking the task as complete if the total "n" given to all invocations of 41 // this method is equal to total. 42 // 43 // Count returns the new total number of (atomically managed) elements that have 44 // been completed. 45 func (c *PercentageTask) Count(n uint64) (new uint64) { 46 if new = atomic.AddUint64(&c.n, n); new > c.total { 47 panic("tasklog: counted too many items") 48 } 49 50 var percentage float64 51 if c.total == 0 { 52 percentage = 100 53 } else { 54 percentage = 100 * float64(new) / float64(c.total) 55 } 56 57 c.ch <- &Update{ 58 S: fmt.Sprintf("%s: %3.f%% (%d/%d)", 59 c.msg, math.Floor(percentage), new, c.total), 60 At: time.Now(), 61 } 62 63 if new >= c.total { 64 close(c.ch) 65 } 66 67 return new 68 } 69 70 // Entry logs a line-delimited task entry. 71 func (t *PercentageTask) Entry(update string) { 72 t.ch <- &Update{ 73 S: fmt.Sprintf("%s\n", update), 74 At: time.Now(), 75 Force: true, 76 } 77 } 78 79 // Updates implements Task.Updates and returns a channel which is written to 80 // when the state of this task changes, and closed when the task is completed. 81 // has been completed. 82 func (c *PercentageTask) Updates() <-chan *Update { 83 return c.ch 84 } 85 86 // Throttled implements Task.Throttled and returns true, indicating that this 87 // task is throttled. 88 func (c *PercentageTask) Throttled() bool { return true }