2017-11-22 22:07:24 +00:00
|
|
|
package tasklog
|
2017-06-14 21:55:50 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2017-09-22 22:28:22 +00:00
|
|
|
"math"
|
2017-06-14 21:55:50 +00:00
|
|
|
"sync/atomic"
|
2017-08-09 21:45:18 +00:00
|
|
|
"time"
|
2017-06-14 21:55:50 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// PercentageTask is a task that is performed against a known number of
|
|
|
|
// elements.
|
|
|
|
type PercentageTask struct {
|
2018-02-27 01:06:10 +00:00
|
|
|
// members managed via sync/atomic must be aligned at the top of this
|
|
|
|
// structure (see: https://github.com/git-lfs/git-lfs/pull/2880).
|
|
|
|
|
2017-06-14 21:55:50 +00:00
|
|
|
// n is the number of elements whose work has been completed. It is
|
|
|
|
// managed sync/atomic.
|
|
|
|
n uint64
|
|
|
|
// total is the total number of elements to execute work upon.
|
|
|
|
total uint64
|
2018-02-27 01:06:10 +00:00
|
|
|
// msg is the task message.
|
|
|
|
msg string
|
2017-06-14 21:55:50 +00:00
|
|
|
// ch is a channel which is written to when the task state changes and
|
|
|
|
// is closed when the task is completed.
|
2017-08-09 21:45:18 +00:00
|
|
|
ch chan *Update
|
2017-06-14 21:55:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewPercentageTask(msg string, total uint64) *PercentageTask {
|
|
|
|
p := &PercentageTask{
|
|
|
|
msg: msg,
|
|
|
|
total: total,
|
2017-08-09 21:45:18 +00:00
|
|
|
ch: make(chan *Update, 1),
|
2017-06-14 21:55:50 +00:00
|
|
|
}
|
|
|
|
p.Count(0)
|
|
|
|
|
|
|
|
return p
|
|
|
|
}
|
|
|
|
|
|
|
|
// Count indicates that work has been completed against "n" number of elements,
|
|
|
|
// marking the task as complete if the total "n" given to all invocations of
|
|
|
|
// this method is equal to total.
|
|
|
|
//
|
|
|
|
// Count returns the new total number of (atomically managed) elements that have
|
|
|
|
// been completed.
|
|
|
|
func (c *PercentageTask) Count(n uint64) (new uint64) {
|
2017-07-31 16:13:04 +00:00
|
|
|
if new = atomic.AddUint64(&c.n, n); new > c.total {
|
2017-11-22 22:07:24 +00:00
|
|
|
panic("tasklog: counted too many items")
|
2017-07-31 16:13:04 +00:00
|
|
|
}
|
2017-06-14 21:55:50 +00:00
|
|
|
|
2017-07-31 16:12:37 +00:00
|
|
|
var percentage float64
|
|
|
|
if c.total == 0 {
|
|
|
|
percentage = 100
|
|
|
|
} else {
|
|
|
|
percentage = 100 * float64(new) / float64(c.total)
|
|
|
|
}
|
|
|
|
|
2017-11-28 02:35:06 +00:00
|
|
|
c.ch <- &Update{
|
2017-08-09 21:45:18 +00:00
|
|
|
S: fmt.Sprintf("%s: %3.f%% (%d/%d)",
|
2017-09-22 22:28:22 +00:00
|
|
|
c.msg, math.Floor(percentage), new, c.total),
|
2017-08-09 21:45:18 +00:00
|
|
|
At: time.Now(),
|
|
|
|
}
|
2017-06-14 21:55:50 +00:00
|
|
|
|
|
|
|
if new >= c.total {
|
|
|
|
close(c.ch)
|
|
|
|
}
|
|
|
|
|
|
|
|
return new
|
|
|
|
}
|
|
|
|
|
2017-09-22 18:43:04 +00:00
|
|
|
// Entry logs a line-delimited task entry.
|
|
|
|
func (t *PercentageTask) Entry(update string) {
|
|
|
|
t.ch <- &Update{
|
|
|
|
S: fmt.Sprintf("%s\n", update),
|
|
|
|
At: time.Now(),
|
|
|
|
Force: true,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-14 21:55:50 +00:00
|
|
|
// Updates implements Task.Updates and returns a channel which is written to
|
|
|
|
// when the state of this task changes, and closed when the task is completed.
|
|
|
|
// has been completed.
|
2017-08-09 21:45:18 +00:00
|
|
|
func (c *PercentageTask) Updates() <-chan *Update {
|
2017-06-14 21:55:50 +00:00
|
|
|
return c.ch
|
|
|
|
}
|
2017-06-19 20:09:50 +00:00
|
|
|
|
2017-06-19 20:19:19 +00:00
|
|
|
// Throttled implements Task.Throttled and returns true, indicating that this
|
|
|
|
// task is throttled.
|
|
|
|
func (c *PercentageTask) Throttled() bool { return true }
|