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  }