github.com/grahambrereton-form3/tilt@v0.10.18/internal/engine/fake_notify_test.go (about)

     1  package engine
     2  
     3  import (
     4  	"path/filepath"
     5  	"sync"
     6  
     7  	"github.com/windmilleng/tilt/internal/ospath"
     8  	"github.com/windmilleng/tilt/internal/watch"
     9  	"github.com/windmilleng/tilt/pkg/logger"
    10  )
    11  
    12  type fakeMultiWatcher struct {
    13  	events chan watch.FileEvent
    14  	errors chan error
    15  
    16  	mu         sync.Mutex
    17  	watchers   []*fakeWatcher
    18  	subs       []chan watch.FileEvent
    19  	subsErrors []chan error
    20  }
    21  
    22  func newFakeMultiWatcher() *fakeMultiWatcher {
    23  	r := &fakeMultiWatcher{events: make(chan watch.FileEvent, 20), errors: make(chan error, 20)}
    24  	go r.loop()
    25  	return r
    26  }
    27  
    28  func (w *fakeMultiWatcher) newSub(paths []string, ignore watch.PathMatcher, _ logger.Logger) (watch.Notify, error) {
    29  	subCh := make(chan watch.FileEvent)
    30  	errorCh := make(chan error)
    31  	w.mu.Lock()
    32  	defer w.mu.Unlock()
    33  
    34  	watcher := newFakeWatcher(subCh, errorCh, paths, ignore)
    35  	w.watchers = append(w.watchers, watcher)
    36  	w.subs = append(w.subs, subCh)
    37  	w.subsErrors = append(w.subsErrors, errorCh)
    38  	return watcher, nil
    39  }
    40  
    41  func (w *fakeMultiWatcher) getSubs() []chan watch.FileEvent {
    42  	w.mu.Lock()
    43  	defer w.mu.Unlock()
    44  	return append([]chan watch.FileEvent{}, w.subs...)
    45  }
    46  
    47  func (w *fakeMultiWatcher) getSubErrors() []chan error {
    48  	w.mu.Lock()
    49  	defer w.mu.Unlock()
    50  	return append([]chan error{}, w.subsErrors...)
    51  }
    52  
    53  func (w *fakeMultiWatcher) loop() {
    54  	defer func() {
    55  		for _, sub := range w.getSubs() {
    56  			close(sub)
    57  		}
    58  	}()
    59  
    60  	defer func() {
    61  		for _, sub := range w.getSubErrors() {
    62  			close(sub)
    63  		}
    64  	}()
    65  
    66  	for {
    67  		select {
    68  		case e, ok := <-w.events:
    69  			if !ok {
    70  				return
    71  			}
    72  			for _, watcher := range w.watchers {
    73  				if watcher.matches(e.Path()) {
    74  					watcher.inboundCh <- e
    75  				}
    76  			}
    77  		case e, ok := <-w.errors:
    78  			if !ok {
    79  				return
    80  			}
    81  			for _, sub := range w.getSubErrors() {
    82  				sub <- e
    83  			}
    84  		}
    85  	}
    86  }
    87  
    88  type fakeWatcher struct {
    89  	inboundCh  chan watch.FileEvent
    90  	outboundCh chan watch.FileEvent
    91  	errorCh    chan error
    92  
    93  	paths  []string
    94  	ignore watch.PathMatcher
    95  }
    96  
    97  func newFakeWatcher(inboundCh chan watch.FileEvent, errorCh chan error, paths []string, ignore watch.PathMatcher) *fakeWatcher {
    98  	for i, path := range paths {
    99  		paths[i], _ = filepath.Abs(path)
   100  	}
   101  
   102  	return &fakeWatcher{
   103  		inboundCh:  inboundCh,
   104  		outboundCh: make(chan watch.FileEvent, 20),
   105  		errorCh:    errorCh,
   106  		paths:      paths,
   107  		ignore:     ignore,
   108  	}
   109  }
   110  
   111  func (w *fakeWatcher) matches(path string) bool {
   112  	ignore, _ := w.ignore.Matches(path)
   113  	if ignore {
   114  		return false
   115  	}
   116  
   117  	for _, watched := range w.paths {
   118  		if ospath.IsChild(watched, path) {
   119  			return true
   120  		}
   121  	}
   122  	return false
   123  }
   124  
   125  func (w *fakeWatcher) Start() error {
   126  	go w.loop()
   127  	return nil
   128  }
   129  
   130  func (w *fakeWatcher) Close() error {
   131  	return nil
   132  }
   133  
   134  func (w *fakeWatcher) Errors() chan error {
   135  	return w.errorCh
   136  }
   137  
   138  func (w *fakeWatcher) Events() chan watch.FileEvent {
   139  	return w.outboundCh
   140  }
   141  
   142  func (w *fakeWatcher) loop() {
   143  	var q []watch.FileEvent
   144  	for {
   145  		if len(q) == 0 {
   146  			select {
   147  			case e, ok := <-w.inboundCh:
   148  				if !ok {
   149  					close(w.outboundCh)
   150  					return
   151  				}
   152  				q = append(q, e)
   153  			}
   154  		} else {
   155  			e := q[0]
   156  			select {
   157  			case w.outboundCh <- e:
   158  				q = q[1:]
   159  			}
   160  		}
   161  	}
   162  }
   163  
   164  var _ watch.Notify = &fakeWatcher{}