github.com/mattevans/edward@v1.9.2/output/tasks.go (about) 1 package output 2 3 import ( 4 "bytes" 5 "fmt" 6 "os" 7 "strings" 8 "sync" 9 "time" 10 11 "github.com/theothertomelliott/uilive" 12 "github.com/mattevans/edward/tracker" 13 ) 14 15 type Follower struct { 16 inProgress *InProgressRenderer 17 writer *uilive.Writer 18 19 complete map[string]struct{} 20 21 mtx sync.Mutex 22 } 23 24 func NewFollower() *Follower { 25 f := &Follower{ 26 inProgress: NewInProgressRenderer(), 27 complete: make(map[string]struct{}), 28 } 29 f.Reset() 30 return f 31 } 32 33 func (f *Follower) Reset() { 34 f.mtx.Lock() 35 defer f.mtx.Unlock() 36 37 if f.writer != nil { 38 panic("Follower not stopped correctly") 39 } 40 f.writer = uilive.New() 41 f.writer.RefreshInterval = time.Hour 42 f.writer.Start() 43 } 44 45 func (f *Follower) Handle(update tracker.Task) { 46 f.mtx.Lock() 47 defer f.mtx.Unlock() 48 49 updateLineage := lineageAsString(update) 50 51 if _, exists := f.complete[updateLineage]; exists || f.writer == nil { 52 return 53 } 54 55 state := update.State() 56 if state != tracker.TaskStatePending && 57 state != tracker.TaskStateInProgress { 58 bp := f.writer.Bypass() 59 renderer := NewCompletionRenderer(update) 60 renderer.Render(bp) 61 f.complete[updateLineage] = struct{}{} 62 } 63 var buf = &bytes.Buffer{} 64 f.inProgress.Render(buf, update) 65 fmt.Fprint(f.writer, buf.String()) 66 f.writer.Flush() 67 } 68 69 func lineageAsString(update tracker.Task) string { 70 var names []string 71 for _, t := range update.Lineage() { 72 names = append(names, t.Name()) 73 } 74 return strings.Join(names, "/") 75 } 76 77 func (f *Follower) Done() { 78 f.mtx.Lock() 79 defer f.mtx.Unlock() 80 81 f.writer.Stop() 82 f.writer = nil 83 } 84 85 type NonLiveFollower struct { 86 inProgress *InProgressRenderer 87 } 88 89 func NewNonLiveFollower() *NonLiveFollower { 90 f := &NonLiveFollower{ 91 inProgress: NewInProgressRenderer(), 92 } 93 return f 94 } 95 96 func (f *NonLiveFollower) Handle(update tracker.Task) { 97 state := update.State() 98 if state != tracker.TaskStatePending && 99 state != tracker.TaskStateInProgress { 100 renderer := NewCompletionRenderer(update) 101 renderer.Render(os.Stdout) 102 } 103 } 104 105 func (f *NonLiveFollower) Done() { 106 }